I have a lot of polygonal features loaded with loadGeoJson and I'd like to get the latLngBounds of each. Do I need to write a function that iterates through every lat long pair in the polygon and does an extend() on a LatLngBounds for each, or is there a better way? (If not, I can probably figure out how to iterate through the polygon vertices but pointers to an example of that would be welcome)
The Polygon-features doesn't have a property that exposes the bounds, you have to calculate it on your own.
Example:
//loadGeoJson runs asnchronously, listen to the addfeature-event
google.maps.event.addListener(map.data,'addfeature',function(e){
//check for a polygon
if(e.feature.getGeometry().getType()==='Polygon'){
//initialize the bounds
var bounds=new google.maps.LatLngBounds();
//iterate over the paths
e.feature.getGeometry().getArray().forEach(function(path){
//iterate over the points in the path
path.getArray().forEach(function(latLng){
//extend the bounds
bounds.extend(latLng);
});
});
//now use the bounds
e.feature.setProperty('bounds',bounds);
}
});
Demo: http://jsfiddle.net/doktormolle/qtDR6/
In Google Maps JavaScript API v2, Polygon had a getBounds() method, but that doesn’t exist for v3 Polygon. Here’s the solution:
if (!google.maps.Polygon.prototype.getBounds) {
google.maps.Polygon.prototype.getBounds = function () {
var bounds = new google.maps.LatLngBounds();
this.getPath().forEach(function (element, index) { bounds.extend(element); });
return bounds;
}
}
Here's another solution for v3 Polygon :
var bounds = new google.maps.LatLngBounds();
map.data.forEach(function(feature){
if(feature.getGeometry().getType() === 'Polygon'){
feature.getGeometry().forEachLatLng(function(latlng){
bounds.extend(latlng);
});
}
});
Related
I have draggable markers on a Here Map, and I'd like to detect when a marker is dragged and dropped onto a Polyline. I haven't been able to find a good way to detect that the marker is dropped on or near the polyline. It would be nice if I could add an "dragend" event listener to the Polyline object, but that doesn't seem to be supported on objects other than the actual map.
Another approach would be to determine the distance to the Polyline from the point that the dragend occurs, but I haven't found a straightforward way to calculate that distance. (Though I've found the example for finding the nearest marker to a point.)
Any suggestions?
It is possible to add dragend event listener on map objects.
This code should work for you (in 3.0 API version):
var lineString = new H.geo.LineString([0, 0, 0, 50, 50, 0]),
polyline = new H.map.Polyline(lineString, {style: {lineWidth: 15, strokeColor: 'red'}}),
marker = new H.map.Marker({lat: 30, lng: 0});
// Ensure that the marker can receive drag events
marker.draggable = true;
// add objects to the map
map.addObjects([polyline, marker]);
// set map center and zoom
map.setCenter({lat: 30, lng: 0});
map.setZoom(3);
// disable map's behavior and calculate the offset between mouse and target's position
// when starting to drag a marker object:
marker.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer,
targetPosition = map.geoToScreen(target.getGeometry());
target['offset'] = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}, false);
// Listen to the drag event and move the position of the marker
marker.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
target.setGeometry(map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));
}, false);
// re-enable behavior and check if marker was dropped on polyline
marker.addEventListener('dragend', function(ev) {
behavior.enable();
var pointer = ev.currentPointer,
objects = map.getObjectsAt(pointer.viewportX, pointer.viewportY),
droppedOnPolyline = false;
objects.forEach(function(object) {
if (object === polyline) {
droppedOnPolyline = true;
}
});
console.log('marker dropped on polyline? %s', droppedOnPolyline);
}, false);
I am creating a walkthrough for the interior of a building and am wondering how to draw a marker on a StreetViewPanorama. Maybe I'm missing something basic, but everything I have read indicates that you need a lat and lng to draw the marker.
Here is what I have:
var initPosPanoID, streetView;
function initPano() {
// Set StreetView provider.
var streetViewOptions = {
zoom: 0,
panoProvider: getCustomPanorama,
pano : "lobby",
addressControlOptions: {
position: google.maps.ControlPosition.BOTTOM_CENTER
}
};
// Create a StreetView object.
var streetViewDiv = document.getElementById('map');
streetView = new google.maps.StreetViewPanorama(streetViewDiv, streetViewOptions);
// Add links when it happens "links_change" event.
google.maps.event.addListener(streetView, "links_changed", createCustomLink);
google.maps.event.addListener(streetView, "pano_changed", function() {
var panoCell = document.getElementById('pano-cell');
panoCell.innerHTML = panorama.getPano();
});
}
function getCustomPanoramaTileUrl(panoID, zoom, tileX, tileY) {
// Return a pano image given the panoID.
return "images/he/" + panoID + '.jpg';
}
function getHeading(panoID) {
var heading;
switch(panoID) {
case "lobby":
heading = 0;
break;
case "secorner":
heading = 100;
break;
}
return heading;
}
function getCustomPanorama(panoID) {
// get a custom heading for the pano
var heading = getHeading(panoID);
var streetViewPanoramaData = {
links: [],
copyright: 'Imagery (c) HumanElement',
tiles: {
tileSize : new google.maps.Size(1024, 512),
worldSize : new google.maps.Size(1024, 512),
// The heading in degrees at the origin of the panorama
// tile set.
centerHeading : heading,
getTileUrl : getCustomPanoramaTileUrl
}
};
switch(panoID) {
case "lobby":
// Description of this point.
streetViewPanoramaData["location"] = {
pano: 'lobby',
description: "Human Element",
latLng: new google.maps.LatLng(42.282138, -83.751471)
};
return streetViewPanoramaData;
case "secorner":
streetViewPanoramaData["location"] = {
pano: 'secorner',
description: "SouthEast Corner",
latLng: new google.maps.LatLng(42.282078, -83.751413)
};
return streetViewPanoramaData;
}
}
function createCustomLink() {
var links = streetView.getLinks();
var panoID = streetView.getPano();
switch(panoID) {
case "lobby":
links.push({
description : "SouthEast Corner",
pano : "secorner",
heading : 280
});
break;
case "secorner":
links.push({
description : "HumanElement Lobby",
pano : "lobby",
heading : 90
});
break;
}
}
I would like to have different markers or touchpoints at different locations, but am not sure how to get them on there.
Trying to draw a standard marker does not work without the lat/lng.
I thought about trying to create it around a google.maps.Point thinking I might be able to use the x and y from my tiles, but couldn't seem to get that working.
The other options I see are related to google.maps.drawing.DrawingManager.
Does anyone have any advice on this?
Setting up the map this way helped: It creates the map and panorama separately and then sets the panorama into the map, rather than just having the panorama object by itself.
map = new google.maps.Map(document.getElementById('map'), {
center: position,
zoom: 10
});
// Create the panorama and set it into the map
panorama = new google.maps.StreetViewPanorama(
document.getElementById('map'), {
position: position,
pov: {
heading: 0,
pitch: -10
},
// Override the default panoId to outside the building to start
pano:'e_giRekRylYAAAQn7y2xAg'
});
map.setStreetView(panorama);
For placing markers on the map, I found an excellent plugin which creates points and then places elements on those points.
https://github.com/marmat/google-maps-api-addons/tree/master/panomarker
So far this is working very well. If you have an interior walkthrough, you should be able to toggle markers based on the PanoId. You can even add click listeners to open up dialogs.
I would like to show an info window when I'm moving a vertex on an editable polyline.
This info will show the distance and heading to the prior vertex on the polyline. When I drop the vertex, the info window must be closed.
The problem is polyline hasn't a drag event over vertex. I'll try with polyline's mousemove but It is fired after move has finished.
In the next code, I show an example what I said. I have a polyline (flightPath). If I click on the last vertex I will like to move a marker at the same time. But It doesn't work. The marker is moved after movement is finished.
google.maps.event.addListener(flightPath, 'mousemove', function (event) {
if (typeof event.vertex === "undefined") {
moveline = 0
}
else {
if (event.vertex == (flightPath.getPath().getLength()-1)) {
var path = flightPath.getPath();
marker.setPosition(path.getAt(event.vertex));
}
}
});
Some suggestion?
Note: My polyline is editable.
Thanks
You could manage a drag end event on the marker and change de latLng of the vertex:
google.maps.event.addListener(marker, 'dragend', function(evt){
var vertex = marker.get('vertex');
var path = flightPath.getPath();
var newPath = Array.prototype.slice.call(path).filter(
function(element, index){
return index < vertex;
}).concat([evt.latLng],
Array.prototype.slice.call(path).filter(
function(element, index){
return index > vertex;
}));
flightPath.setPath(newPath);
});
I'm sorry for my bad english but i hope it helps.
I write JS app where I draw a lot of polylines using array of points, but in avery point I have some additional properties in this point (GPS data, speed etc).
I want to show these additional props onmouseover or onmouseclick event.
I have two ways:
use the standard polylines and event handler. But in this case I can't to determine additional properties for start point of this polyline cause I can't to save these props in polyline properties. There is one solution - save in array additional properties and try to find them by LatLng of first point of the polyline, but it's too slow I guess..
extend polyline and save additional properties in new Object, but I can't to extend mouse events :(
To extend polyline I use this code:
function myPolyline(prop, opts){
this.prop = prop;
this.Polyline = new google.maps.Polyline(opts);
}
myPolyline.prototype.setMap = function(map) {
return this.Polyline.setMap(map);
}
myPolyline.prototype.getPath = function() {
return this.Polyline.getPath();
}
myPolyline.prototype.addListener= function(prop) {
return this.Polyline.addListener();
}
myPolyline.prototype.getProp= function() {
return this.prop;
}
myPolyline.prototype.setProp= function(prop) {
return this.prop = prop;
}
and create new object in for loop (i - index of current point in array of points) like that:
var polyline_opts = {
path: line_points,
strokeColor: color,
geodesic: true,
strokeOpacity: 0.5,
strokeWeight: 4,
icons: [
{
icon: lineSymbol,
offset: '25px',
repeat: '50px'
}
],
map: map
};
var add_prop = {
id: i,
device_id: device_id
};
...
devices_properties[device_id].tracks[(i-1)] = new myPolyline(add_prop, polyline_opts);
Where:
line_points - array of points (just two points),
i - current point index
devices_properties[device_id].tracks - array of extended polylines (with add properties) by my device_id index
After that I set event handler like that:
var tmp = devices_properties[device_id].tracks[(i-1)];
google.maps.event.addListener(tmp.Polyline, 'click', function(e) {
...
console.log(tmp.prop.id);
...
}
But in this case I always get the same id in console..
When I use
google.maps.event.addListener(devices_properties[device_id].tracks[(i-1)].Polyline, 'click', function(e) {
...
console.log(???); // How to get parent of polyline fired the event?
...
}
I don't know how to get parent of polyline fired the event?
I answer my own question - It's done, I've just have some troubles with using "for" instead "$.each" :)
Before I use:
for ( i = 1; i < devices_properties[device_id].history_points.length; i++ ) {
...
create myPolyline
...
}
and it's doesn't work - created one event handle.
After:
$.each(devices_properties[device_id].history_points, function(i, tmp){
...
create myPolyline ()
...
}
and it works - create a lot of event handlers.
To handle event I use this:
google.maps.event.addListener(c_polyline.Polyline, 'mouseover', function(e) {
var prop = c_polyline.getProp();
...
console.log(prop.id, prop.device_id);
}
I'm not sure this is the right group. If not, please let me know.
My dilemma:
I need to add Polylines to Google Earth from the results I get back from the Google Maps v3 DirectionsService. There seems to be nothing on the web to that extent. It has to be possible, because Roman does this in his driving simulator: http://earth-api-samples.googlecode.com/svn/trunk/demos/drive-simulator/index.html
Unfortunately, he is using Google Maps v2 there and I can't seem to figure out how to transfer this code into Google Maps v3.
If anyone is interested, here is how I managed to solve it:
function DrawLinesOnEarth() {
var sLat;
var sLon;
//var start = document.getElementById("start").value;
//var end = document.getElementById("end").value;
var request = {
origin: '40.306134,-74.05018',
destination: '40.313223,-74.043496',
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
var steps = result.routes[0].legs[0].steps;
//Step through array of step legs and create polylines one by one
var lineStringPlacemark = IMC_ge.createPlacemark('');
var lineString = IMC_ge.createLineString('');
lineStringPlacemark.setGeometry(lineString);
// Add LineString points
for (var x in steps) {
for (var y in steps[x].path) {
sLat = steps[x].path[y].Na;
sLon = steps[x].path[y].Oa;
lineString.getCoordinates().pushLatLngAlt(sLat, sLon, 0);
}
}
// Add the feature to Earth
IMC_ge.getFeatures().appendChild(lineStringPlacemark);
}
});
}