How delete vertex (node) on Polygon with Hole (Google Maps V3) - google-maps-api-3

I have taken this example (solution) from Ian Grainger, but I added a Polygon with inner hole.
This example work fine for outer vertex path, but not for inner vertex path.
I need implement event Listener for internal and external node, because on fire event on internal vertex, delete external vertex. It doesn't work well.
Can someone provide some sample on how to solve this issue?

One of your issues is polygon with a hole in it has multiple (in this case two) paths, and you aren't adding listeners for changes on both paths. Below is a proof of concept, it isn't perfect, sometimes markers are orphaned, but should be a starting point. Double click on the blue markers underneath the vertices to delete them (I couldn't get your "X" to reliably work).
proof of concept fiddle
updated proof of concept with white markers
code snippet:
var G = google.maps;
var zoom = 8;
var centerPoint = new G.LatLng(37.286172, -121.80929);
var map;
$(function() {
// create options object
var myOptions = {
center: centerPoint,
zoom: zoom,
mapTypeId: G.MapTypeId.ROADMAP
};
// create map with options
map = new G.Map($("#map_canvas")[0], myOptions);
addPolygon(map);
});
function addPolygon(map) {
var paths = [
[new G.LatLng(37.686172, -122.20929),
new G.LatLng(37.696172, -121.40929),
new G.LatLng(36.706172, -121.40929),
new G.LatLng(36.716172, -122.20929),
new G.LatLng(37.686172, -122.20929)
],
[new G.LatLng(37.486172, -122.00929),
new G.LatLng(37.086172, -122.00929),
new G.LatLng(37.086172, -121.60929),
new G.LatLng(37.486172, -121.60929),
new G.LatLng(37.486172, -122.00929)
]
];
poly = new G.Polygon({
clickable: false,
paths: paths,
map: map
});
polygonBinder(poly);
poly.setEditable(true);
G.event.addListener(poly.getPaths().getAt(0), 'insert_at', addClickMarker0);
G.event.addListener(poly.getPaths().getAt(1), 'insert_at', addClickMarker1);
}
function polygonBinder(poly) {
poly.binder0 = new MVCArrayBinder(poly.getPaths().getAt(0));
poly.binder1 = new MVCArrayBinder(poly.getPaths().getAt(1));
poly.markers = [];
for (var i = 0; i < poly.getPaths().getLength(); i++) {
poly.markers[i] = [];
for (var j = 0; j < poly.getPaths().getAt(i).getLength(); j++) {
var mark = new G.Marker({
map: map,
icon: {
path: G.SymbolPath.CIRCLE,
scale: 8,
strokeWeight: 2,
strokeColor: 'blue',
fillColor: 'blue',
fillOpacity: 1
},
draggable: true,
title: "double click to delete [" + i + "," + j + "]",
position: poly.getPaths().getAt(i).getAt(j)
});
poly.markers[i][j] = mark;
mark.bindTo('position', poly["binder" + i], (j).toString());
G.event.addListener(mark, "dblclick", deleteMark);
}
}
}
function addClickMarker0(index) {
addClickMarker(index, 0);
}
function addClickMarker1(index) {
addClickMarker(index, 1);
}
function deleteMark(evt) {
var minDist = Number.MAX_VALUE;
var minPathIdx = -1;
var minIdx = -1;
var i, j;
for (i = 0; i < poly.getPaths().getLength(); i++) {
for (j = 0; j < poly.getPaths().getAt(i).getLength(); j++) {
var distance = G.geometry.spherical.computeDistanceBetween(evt.latLng, poly.getPaths().getAt(i).getAt(j));
if (distance < minDist) {
minDist = distance;
minPathIdx = i;
minIdx = j;
}
if (distance < 10) {
document.getElementById('info').innerHTML = "deleted path=" + i + " idx=" + j + " dist<10 minDist=" + minDist + " meters";
poly.getPaths().getAt(i).removeAt(j);
break;
}
}
}
if ((i == poly.getPaths().getLength()) && (j == poly.getPaths(i - 1).getLength())) {
poly.getPaths().getAt(minPathIdx).removeAt(minIdx);
document.getElementById('info').innerHTML = "deleted path=" + minPathIdx + " idx=" + minIdx + " dist=" + minDist + " meters";
}
this.setMap(null);
}
function addClickMarker(index, pathIdx) {
var path = this;
// rebind binder
for (var i = 0; i < poly.markers[pathIdx].length; i++) {
poly.markers[pathIdx][i].setMap(null);
}
poly.markers[pathIdx] = [];
for (var i = 0; i < poly.getPaths().getAt(pathIdx).getLength(); i++) {
var mark = new G.Marker({
map: map,
icon: {
path: G.SymbolPath.CIRCLE,
scale: 8,
strokeWeight: 2,
strokeColor: 'blue',
fillColor: 'blue',
fillOpacity: 1
},
draggable: true,
title: "double click to delete [" + pathIdx + "," + i + "]",
position: poly.getPaths().getAt(pathIdx).getAt(i)
});
poly.markers[pathIdx][i] = mark;
mark.bindTo('position', poly["binder" + pathIdx], (i).toString());
G.event.addListener(mark, "dblclick", deleteMark);
}
}
function MVCArrayBinder(mvcArray) {
this.array_ = mvcArray;
}
MVCArrayBinder.prototype = new google.maps.MVCObject();
MVCArrayBinder.prototype.get = function(key) {
if (!isNaN(parseInt(key))) {
return this.array_.getAt(parseInt(key));
} else {
this.array_.get(key);
}
}
MVCArrayBinder.prototype.set = function(key, val) {
if (!isNaN(parseInt(key))) {
this.array_.setAt(parseInt(key), val);
} else {
this.array_.set(key, val);
}
}
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0;
padding: 0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=drawing,geometry"></script>
<div id="info"></div>
<div id="map_canvas" style="width:100%; height:100%"></div>

Related

How to remove maplabel library and polygon in Google Map API

I'm using google maps API to allow the user draw polygons and display the length of every single border using maplabel library. But I have a problem when removing polygon and map label, I don't know how to remove them from Google Map.
My code looks like this:
HTML
<button id="enablePolygon">draw</button>
<button id="removePolygon">remove</button>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=drawing"></script>
<script src="https://cdn.jsdelivr.net/npm/js-map-label#1.0.1/src/maplabel.js"></script>
JS
var labels = [];
var allOverlays = [];
function setSelection(shape) {
selectedShape = shape;
shape.setEditable(true);
}
function initMap() {
var options = {
zoom: 14,
center: {
lat: 52.250618,
lng: 20.9774
}
};
var map = new google.maps.Map(document.getElementById("map"), options);
var drawingManager = new google.maps.drawing.DrawingManager({
polygonOptions: {
draggable: false,
fillColor: "#0e97fa",
fillOpacity: 0.2,
strokeWeight: 2,
strokeColor: "#0e97fa",
editable: true,
zIndex: 1
},
drawingControl: false,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes:
[
google.maps.drawing.OverlayType.POLYGON,
/* google.maps.drawing.OverlayType.POLYLINE, */
]
},
map: map,
drawingMode: 'polygon'
});
function attachPolygonInfoWindow(polygon) {
if (!polygon.labels) polygon.labels = [];
for (var i = 0; i < polygon.labels.length; i++) {
polygon.labels[i].setMap(null);
}
polygon.labels = [];
var path = polygon.getPath();
var points = path.getArray();
var area = google.maps.geometry.spherical
.computeArea(path.getArray())
.toFixed(0);
var bounds = new google.maps.LatLngBounds();
var i;
for (i = 0; i < points.length; i++) {
bounds.extend(points[i]);
}
var boundsCenter = bounds.getCenter();
var centerLabel = new MapLabel({
map: map,
position: boundsCenter,
fontSize: 14,
align: "center",
zIndex: 3
});
polygon.labels.push(centerLabel);
centerLabel.set("position", bounds.getCenter());
centerLabel.set("text", area + " m2");
if (path.getLength() < 2) return;
for (var i = 0; i < polygon.getPath().getLength(); i++) {
// for each side in path, compute center and length
var start = polygon.getPath().getAt(i);
var end = polygon.getPath().getAt(i < polygon.getPath().getLength() - 1 ? i + 1 : 0);
var sideLength = google.maps.geometry.spherical.computeDistanceBetween(start, end);
console.log(sideLength)
var sideCenter = google.maps.geometry.spherical.interpolate(start, end, 0.5);
/* console.log("sideCenter=" + sideCenter.toUrlValue(6)); */
var sideLabel = new MapLabel({
map: map,
fontSize: 14,
align: "center",
zIndex: 3
});
sideLabel.set("position", sideCenter);
sideLabel.set("text", sideLength.toFixed(2) + "m");
polygon.labels.push(sideLabel);
}
}
function removePolygonInfoWindow() {
for (var i = 0; i < labels.length; i++) {
labels[i].setMap(null);
}
labels = [];
}
google.maps.event.addListener(drawingManager, "overlaycomplete", function(e) {
allOverlays.push(e);
if (e.type != google.maps.drawing.OverlayType.MARKER) {
drawingManager.setDrawingMode(null);
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, "click", function() {
setSelection(newShape);
});
if (newShape.type == "polygon") {
var path = newShape.getPath();
google.maps.event.addListener(path, "insert_at", function() {
attachPolygonInfoWindow(newShape);
});
google.maps.event.addListener(path, "set_at", function() {
attachPolygonInfoWindow(newShape);
});
attachPolygonInfoWindow(newShape);
}
setSelection(newShape);
}
});
var enablePolygon = document.getElementById('enablePolygon');
enablePolygon.addEventListener('click', function(){
drawingManager.setMap(map);
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
});
var removePolygon = document.getElementById('removePolygon');
removePolygon.addEventListener('click', function(){
selectedShape.setMap(null);
drawingManager.setMap(null);
centerLabel.setRemoveLabel(true);
});
}
initMap();
Here is demo
I get a javascript error with the posted code: Uncaught ReferenceError: centerLabel is not defined. Not sure why you are using that variable, you are saving the labels in a property of the polygons labels. To remove them, iterate through that array, calling .setMap(null) on each label.
removePolygon.addEventListener('click', function() {
selectedShape.setMap(null);
drawingManager.setMap(null);
for (var i = 0; i < selectedShape.labels.length; i++) {
selectedShape.labels[i].setMap(null);
}
});
updated fiddle
code snippet:
var labels = [];
var allOverlays = [];
function setSelection(shape) {
selectedShape = shape;
shape.setEditable(true);
}
function initMap() {
var options = {
zoom: 14,
center: {
lat: 52.250618,
lng: 20.9774
}
};
var map = new google.maps.Map(document.getElementById("map"), options);
var drawingManager = new google.maps.drawing.DrawingManager({
polygonOptions: {
draggable: false,
fillColor: "#0e97fa",
fillOpacity: 0.2,
strokeWeight: 2,
strokeColor: "#0e97fa",
editable: true,
zIndex: 1
},
drawingControl: false,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.POLYGON,
/* google.maps.drawing.OverlayType.POLYLINE, */
]
},
map: map,
drawingMode: 'polygon'
});
function attachPolygonInfoWindow(polygon) {
if (!polygon.labels) polygon.labels = [];
for (var i = 0; i < polygon.labels.length; i++) {
polygon.labels[i].setMap(null);
}
polygon.labels = [];
var path = polygon.getPath();
var points = path.getArray();
var area = google.maps.geometry.spherical
.computeArea(path.getArray())
.toFixed(0);
var bounds = new google.maps.LatLngBounds();
var i;
for (i = 0; i < points.length; i++) {
bounds.extend(points[i]);
}
var boundsCenter = bounds.getCenter();
var centerLabel = new MapLabel({
map: map,
position: boundsCenter,
fontSize: 14,
align: "center",
zIndex: 3
});
polygon.labels.push(centerLabel);
centerLabel.set("position", bounds.getCenter());
centerLabel.set("text", area + " m2");
if (path.getLength() < 2) return;
for (var i = 0; i < polygon.getPath().getLength(); i++) {
// for each side in path, compute center and length
var start = polygon.getPath().getAt(i);
var end = polygon.getPath().getAt(i < polygon.getPath().getLength() - 1 ? i + 1 : 0);
var sideLength = google.maps.geometry.spherical.computeDistanceBetween(start, end);
console.log(sideLength)
var sideCenter = google.maps.geometry.spherical.interpolate(start, end, 0.5);
/* console.log("sideCenter=" + sideCenter.toUrlValue(6)); */
var sideLabel = new MapLabel({
map: map,
fontSize: 14,
align: "center",
zIndex: 3
});
sideLabel.set("position", sideCenter);
sideLabel.set("text", sideLength.toFixed(2) + "m");
polygon.labels.push(sideLabel);
}
}
function removePolygonInfoWindow() {
for (var i = 0; i < labels.length; i++) {
labels[i].setMap(null);
}
labels = [];
}
google.maps.event.addListener(drawingManager, "overlaycomplete", function(e) {
allOverlays.push(e);
if (e.type != google.maps.drawing.OverlayType.MARKER) {
drawingManager.setDrawingMode(null);
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, "click", function() {
setSelection(newShape);
});
if (newShape.type == "polygon") {
var path = newShape.getPath();
google.maps.event.addListener(path, "insert_at", function() {
attachPolygonInfoWindow(newShape);
});
google.maps.event.addListener(path, "set_at", function() {
attachPolygonInfoWindow(newShape);
});
attachPolygonInfoWindow(newShape);
}
setSelection(newShape);
}
});
var enablePolygon = document.getElementById('enablePolygon');
enablePolygon.addEventListener('click', function() {
drawingManager.setMap(map);
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
});
var removePolygon = document.getElementById('resetPolygon');
removePolygon.addEventListener('click', function() {
selectedShape.setMap(null);
drawingManager.setMap(null);
for (var i = 0; i < selectedShape.labels.length; i++) {
selectedShape.labels[i].setMap(null);
}
});
}
initMap();
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
<button id="enablePolygon">draw</button>
<button id="resetPolygon">remove</button>
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=drawing"></script>
<script src="https://cdn.jsdelivr.net/npm/js-map-label#1.0.1/src/maplabel.js"></script>

Leaflet-markercluster default icons missing

Default icons not showing for MarkerCluster plugin after using IconCreateFunction.
I want to use the default icons for the plugin but when using attached code I loose all the icons functions, I only get the numbers with no icons and if I activate the "childCount" I get one type of circle with the numbers offcenter within the icon. The markers has already been clustered and I want to add this value to the markercluster that is why I'm using the IconCreateFuncton so the numbers on the map shows correctly but I have lost all the icons and its beautiful functions... what is missing?
Result below using "var childCount"
$.getJSON("../test/test.geojson", function(json) {
geoLayer = L.geoJson(json, {
pointToLayer: function(feature, latlng) {
var log_p = feature.properties.log_p;
var marker;
if (log_p > 0){
marker = new L.shapeMarker(latlng, {radius: log_p*25, fillColor: '#2b83ba', fillOpacity: 0.5, color: '#000000', weight: 1, shape: 'circle'});
}
else {
marker = null
}
return marker;
},
onEachFeature: function(feature, layer) {
var popupText = "Amount per day: " + '<b>' + feature.properties.total + '</b>';
layer.bindPopup(popupText, {
closeButton: true,
offset: L.point(0, -20)
});
layer.on('click', function() {
layer.openPopup();
});
},
});
var markers = new L.MarkerClusterGroup({
iconCreateFunction: function(cluster) {
var children = cluster.getAllChildMarkers();
var sum = 0;
for (var i = 0; i < children.length; i++) {
sum += children[i].feature.properties.total;
}
/*
var childCount = cluster.getAllChildMarkers();
var c = ' marker-cluster-';
if (childCount < 10) {
c += 'small';
} else if (childCount < 500) {
c += 'medium';
} else {
c += 'large';
}
*/
return new L.DivIcon({ html: '<b>' + sum + '</b>', className: 'marker-cluster'/* + c */, iconSize: new L.Point(40, 40) });
}
});
markers.addLayer(geoLayer)
map.addLayer(markers);
});
Markercluster icons, styles and functions are lost
I manage to solve the problem, a few lines of code was missing. I added them to the original JavaScript code as follows.
$.getJSON("../test/test.geojson", function(json) {
geoLayer = L.geoJson(json, {
pointToLayer: function(feature, latlng) {
var log_p = feature.properties.log_p;
var marker;
if (log_p > 0) {
marker = new L.shapeMarker(latlng, {
radius: log_p * 25,
fillColor: '#2b83ba',
fillOpacity: 0.5,
color: '#000000',
weight: 1,
shape: 'circle'
});
} else {
marker = null
}
return marker;
},
onEachFeature: function(feature, layer) {
var popupText = "Amount per day: " + '<b>' + feature.properties.total + '</b>';
layer.bindPopup(popupText, {
closeButton: true,
offset: L.point(0, -20)
});
layer.on('click', function() {
layer.openPopup();
});
},
});
var clusters = new L.MarkerClusterGroup({
maxClusterRadius: 125,
iconCreateFunction: function(cluster) {
var children = cluster.getAllChildMarkers();
var sum = 0;
for (var i = 0; i < children.length; i++) {
sum += children[i].feature.properties.total;
}
var childCount = cluster.getChildCount()
var c = ' marker-cluster-';
if (childCount + sum <= 50) {
c += 'small';
} else if (childCount + sum <= 250) {
c += 'medium';
} else {
c += 'large';
}
return new L.DivIcon({
html: '<div><span>' + sum + '</span></div>',
className: 'marker-cluster marker-cluster-' + c,
iconSize: new L.Point(40, 40)
});
},
});
clusters.addLayer(geoLayer)
map.addLayer(clusters);
});

Change the color of the line between 2 waypoints

I use this function to draw my route between A and Z via the Waypoints array.
Is it possible to change the line color (default blue) but just between certain waypoints ?
I mean i want blue between A and B, red between C and D, ....
I found how to change the color of the line
var directionsDisplay = new google.maps.DirectionsRenderer({polylineOptions: { strokeColor: "#8b0013" },
but i can't find how to do it in waypoints...?
thanks for your help
function calcRoute(origin_lat,origin_lng,destination_lat,destination_lng) {
console.log ("Entrée CALC ROUTE");
var origin = new google.maps.LatLng(origin_lat,origin_lng);
var destination = new google.maps.LatLng(destination_lat,destination_lng);
var waypointsArray = document.getElementById('waypoints').value.split("|");
var waypts = [];
for (i = 0; i < waypointsArray.length; i++) {
if (waypointsArray[i]!="") {
var waypoint = waypointsArray[i];
var waypointArray = waypoint.split(",");
var waypointLat = waypointArray[0];
var waypointLng = waypointArray[1];
console.log("waypts lat " + waypointLat);
console.log("waypts lng " + waypointLng);
waypts.push({
location: new google.maps.LatLng(waypointLat,waypointLng),
stopover: true
})
}
}
console.log("waypts " + waypts.length);
var request = {
origin:origin,
destination:destination,
travelMode: google.maps.TravelMode.DRIVING,
waypoints: waypts,
provideRouteAlternatives: true
};
console.log ("Calc request "+JSON.stringify(request));
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
}
});
}
You can't modify just a single segment of the output of the DirectionsRenderer. You can either render each segment with a separate DirectionsRenderer or create your own custom renderer that allows you to create individual polylines for each step of the route and color each one independently.
proof of concept fiddle with a custom renderer
code snippet:
var map;
var directionsService;
var directionsDisplay;
function initialize() {
map = new google.maps.Map(
document.getElementById("map_canvas"), {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer({
map: map,
suppressPolylines: true
});
// Baltimore, MD, USA (39.2903848, -76.61218930000001)
// Boston, MA, USA (42.3600825, -71.05888010000001)
// Philadelphia, PA, USA (39.9525839, -75.16522150000003)
// New York, NY, USA (40.7127837, -74.00594130000002)
calcRoute(39.2903848, -76.6121893, 42.3600825, -71.05888);
}
google.maps.event.addDomListener(window, "load", initialize);
function calcRoute(origin_lat, origin_lng, destination_lat, destination_lng) {
console.log("Entrée CALC ROUTE");
var origin = new google.maps.LatLng(origin_lat, origin_lng);
var destination = new google.maps.LatLng(destination_lat, destination_lng);
var waypointsArray = document.getElementById('waypoints').value.split("|");
var waypts = [];
for (i = 0; i < waypointsArray.length; i++) {
if (waypointsArray[i] != "") {
var waypoint = waypointsArray[i];
var waypointArray = waypoint.split(",");
var waypointLat = waypointArray[0];
var waypointLng = waypointArray[1];
console.log("waypts lat " + waypointLat);
console.log("waypts lng " + waypointLng);
waypts.push({
location: new google.maps.LatLng(waypointLat, waypointLng),
stopover: true
})
}
}
console.log("waypts " + waypts.length);
var request = {
origin: origin,
destination: destination,
travelMode: google.maps.TravelMode.DRIVING,
waypoints: waypts,
provideRouteAlternatives: true
};
console.log("Calc request " + JSON.stringify(request));
directionsService.route(request, customDirectionsRenderer);
}
function customDirectionsRenderer(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var bounds = new google.maps.LatLngBounds();
var route = response.routes[0];
var path = response.routes[0].overview_path;
var legs = response.routes[0].legs;
for (i = 0; i < legs.length; i++) {
var polyline = new google.maps.Polyline({
map: map,
strokeColor: "blue",
path: []
})
if (i == 1) {
polyline.setOptions({
strokeColor: "red"
});
}
var steps = legs[i].steps;
for (j = 0; j < steps.length; j++) {
var nextSegment = steps[j].path;
for (k = 0; k < nextSegment.length; k++) {
polyline.getPath().push(nextSegment[k]);
bounds.extend(nextSegment[k]);
}
}
}
polyline.setMap(map);
map.fitBounds(bounds);
}
};
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<input id="waypoints" value="39.9525839,-75.1652215|40.7127837,-74.0059413" />
<div id="map_canvas"></div>

latLng from polyLine Percentage

How do I return a latLng value from a given percentage along a polyLine?
I have spent a day on this using interpolate and individual nodes. Is their an easier function out there that does the grunt work?
Google maps API v3
thanks!
http://www.geocodezip.com/scripts/v3_epoly.js
written for the Google Maps Javascript API v2 ported to v3. Documentation for the v2 version
Has these two methods:
.Distance() returns the length of the poly path
.GetPointAtDistance() returns a GLatLng at the specified distance
along the path.
The distance is specified in metres
Returns null if the path is shorter than that
This should work (if you include that script and your polyline variable is "polyline"):
var latlng = polyline.GetPointAtDistance(polyline.Distance()*(desired percentage)/100);
of course if you polyline isn't changing in length, it would be more efficient to compute the length once an use it each time you want to find a point on the polyline.
var polylength = polyline.Distance();
var latlng = polylength*(desired percentage)/100);
live example
code snippet:
var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var polyline = null;
var marker;
var infowindow;
function createMarker(latlng, label, html) {
// alert("createMarker("+latlng+","+label+","+html+","+color+")");
var contentString = '<b>' + label + '</b><br>' + html;
var marker = new google.maps.Marker({
position: latlng,
map: map,
title: label,
zIndex: Math.round(latlng.lat() * -100000) << 5,
contentString: contentString
});
marker.myname = label;
// gmarkers.push(marker);
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(this.contentString);
infowindow.open(map, marker);
});
return marker;
}
var myLatLng = null;
var lat;
var lng;
var zoom = 2;
var maptype;
function initialize() {
infowindow = new google.maps.InfoWindow();
myLatLng = new google.maps.LatLng(37.422104808, -122.0838851);
maptype = google.maps.MapTypeId.ROADMAP;
// If there are any parameters at eh end of the URL, they will be in location.search
// looking something like "?marker=3"
// skip the first character, we are not interested in the "?"
var query = location.search.substring(1);
// split the rest at each "&" character to give a list of "argname=value" pairs
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
// break each pair at the first "=" to obtain the argname and value
var pos = pairs[i].indexOf("=");
var argname = pairs[i].substring(0, pos).toLowerCase();
var value = pairs[i].substring(pos + 1);
// process each possible argname - use unescape() if theres any chance of spaces
if (argname == "filename") {
filename = unescape(value);
}
if (argname == "lat") {
lat = parseFloat(value);
}
if (argname == "lng") {
lng = parseFloat(value);
}
if (argname == "start") {
document.getElementById("start").value = decodeURI(value);
}
if (argname == "end") {
document.getElementById("end").value = decodeURI(value);
}
if (argname == "time") {
document.getElementById("time").value = decodeURI(value);
// putMarkerOnRoute(parseFloat(document.getElementById('time').value));
}
if (argname == "zoom") {
zoom = parseInt(value);
}
if (argname == "type") {
// from the v3 documentation 8/24/2010
// HYBRID This map type displays a transparent layer of major streets on satellite images.
// ROADMAP This map type displays a normal street map.
// SATELLITE This map type displays satellite images.
// TERRAIN This map type displays maps with physical features such as terrain and vegetation.
if (value == "m") {
maptype = google.maps.MapTypeId.ROADMAP;
}
if (value == "k") {
maptype = google.maps.MapTypeId.SATELLITE;
}
if (value == "h") {
maptype = google.maps.MapTypeId.HYBRID;
}
if (value == "t") {
maptype = google.maps.MapTypeId.TERRAIN;
}
}
}
if (!isNaN(lat) && !isNaN(lng)) {
myLatLng = new google.maps.LatLng(lat, lng);
}
var myOptions = {
zoom: zoom,
center: myLatLng,
mapTypeId: maptype
};
directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true
});
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
polyline = new google.maps.Polyline({
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
});
directionsDisplay.setMap(map);
calcRoute();
}
function calcRoute() {
var start = document.getElementById("start").value;
var end = document.getElementById("end").value;
var travelMode = google.maps.DirectionsTravelMode.DRIVING
var request = {
origin: start,
destination: end,
travelMode: travelMode
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
polyline.setPath([]);
var bounds = new google.maps.LatLngBounds();
startLocation = new Object();
endLocation = new Object();
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("directions_panel");
summaryPanel.innerHTML = "";
// For each route, display summary information.
var path = response.routes[0].overview_path;
var legs = response.routes[0].legs;
for (i = 0; i < legs.length; i++) {
if (i == 0) {
startLocation.latlng = legs[i].start_location;
startLocation.address = legs[i].start_address;
// marker = google.maps.Marker({map:map,position: startLocation.latlng});
// marker = createMarker(legs[i].start_location,"start",legs[i].start_address,"green");
}
endLocation.latlng = legs[i].end_location;
endLocation.address = legs[i].end_address;
var steps = legs[i].steps;
for (j = 0; j < steps.length; j++) {
var nextSegment = steps[j].path;
for (k = 0; k < nextSegment.length; k++) {
polyline.getPath().push(nextSegment[k]);
bounds.extend(nextSegment[k]);
}
}
}
polyline.setMap(map);
computeTotalDistance(response);
putMarkerOnRoute(parseFloat(document.getElementById('percent').value));
} else {
alert("directions response " + status);
}
});
}
var totalDist = 0;
var totalTime = 0;
function computeTotalDistance(result) {
totalDist = 0;
totalTime = 0;
var myroute = result.routes[0];
for (i = 0; i < myroute.legs.length; i++) {
totalDist += myroute.legs[i].distance.value;
totalTime += myroute.legs[i].duration.value;
}
totalDist = totalDist / 1000.
document.getElementById("total").innerHTML = "total distance is: " + totalDist + " km<br>total time is: " + (totalTime / 60).toFixed(2) + " minutes<br>average speed is: " + (totalDist / (totalTime / 3600)).toFixed(2) + " kph";
document.getElementById("totalTime").value = (totalTime / 60.).toFixed(2);
}
function putMarkerOnRoute(percent) {
if (percent > 100) {
percent = 100;
document.getElementById('percent').value = percent;
}
var distance = percent / 100 * totalDist * 1000;
// time = ((percentage/100) * totalTIme/60).toFixed(2);
// alert("Time:"+time+" totalTime:"+totalTime+" totalDist:"+totalDist+" dist:"+distance);
if (!marker) {
marker = createMarker(polyline.GetPointAtDistance(distance), "percent: " + percent, "marker");
} else {
marker.setPosition(polyline.GetPointAtDistance(distance));
marker.setTitle("percent:" + percent);
marker.contentString = "<b>percent: " + percent + "</b><br>distance: " + (distance / 1000).toFixed(2) + " km<br>marker";
google.maps.event.trigger(marker, "click");
}
}
google.maps.event.addDomListener(window, 'load', initialize);
// from epoly_v3.js
// modified to use geometry library for length of line segments
// === A method which returns a GLatLng of a point a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
google.maps.Polyline.prototype.GetPointAtDistance = function(metres) {
// some awkward special cases
if (metres == 0) return this.getPath().getAt(0);
if (metres < 0) return null;
if (this.getPath().getLength() < 2) return null;
var dist = 0;
var olddist = 0;
for (var i = 1;
(i < this.getPath().getLength() && dist < metres); i++) {
olddist = dist;
dist += google.maps.geometry.spherical.computeDistanceBetween(this.getPath().getAt(i), this.getPath().getAt(i - 1));
}
if (dist < metres) {
return null;
}
var p1 = this.getPath().getAt(i - 2);
var p2 = this.getPath().getAt(i - 1);
var m = (metres - olddist) / (dist - olddist);
return new google.maps.LatLng(p1.lat() + (p2.lat() - p1.lat()) * m, p1.lng() + (p2.lng() - p1.lng()) * m);
}
html {
height: 100%
}
body {
height: 100%;
margin: 0px;
padding: 0px
}
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
<div id="tools">
start:
<input type="text" name="start" id="start" value="Hyderabad" /> end:
<input type="text" name="end" id="end" value="Bangalore" />
<input type="submit" onclick="calcRoute();" /><br /> percentage:
<input type="text" name="percent" id="percent" value="0" />
<input type="submit" onclick="putMarkerOnRoute(parseFloat(document.getElementById('percent').value));" /> total time:<input type="text" name="totalTime" id="totalTime" value="0" />
</div>
<div id="map_canvas" style="float:left;width:70%;height:100%;"></div>
<div id="control_panel" style="float:right;width:30%;text-align:left;padding-top:20px">
<div id="directions_panel" style="margin:20px;background-color:#FFEE77;"></div>
<div id="total"></div>
</div>

Center map and zoom to fit the markers on the screen

I have the following code to detect the visitors GPS position and show it on the Google Maps JavaScript v3 map. Everything works as I want it but the code will not center or zoom as I want - it simple use the standard position (right over Asia)! I want it to fit the markers on the map.
var rendererOptions = {
draggable: false
};
if(navigator.geolocation) {
var timeoutVal = 10 * 1000 * 1000;
navigator.geolocation.watchPosition(
displayPosition,
displayError,
{ enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 }
);
} else {
alert('Din webbläsare stödjer inte någon geologisk lokalisering med hjälp av HTML5');
}
var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var directionsService = new google.maps.DirectionsService();
var marker_gps;
var map_gps;
var options_gps;
function displayPosition(position) {
/***********************
** GPS-POSITION **
************************/
directionsDisplay = new google.maps.DirectionsRenderer();
localStorage.coor = position.coords.latitude.toFixed(6) + ',' + position.coords.longitude.toFixed(6);
var gps_coor = new google.maps.LatLng(position.coords.latitude.toFixed(6), position.coords.longitude.toFixed(6));
if(typeof(marker) != 'undefined') marker.setMap(null);
localStorage.accuracy = position.coords.accuracy;
document.getElementById('accuracy').innerHTML = number_format(localStorage.accuracy) + ' meter';
directionsDisplay.setMap(map_gps);
directionsDisplay.setPanel(document.getElementById('directions-panel'));
marker_gps = new google.maps.Marker({
position: gps_coor,
draggable: false,
map: map_gps
});
var circle_gps = new google.maps.Circle({
center: gps_coor,
radius: position.coords.accuracy,
map: map_gps,
fillColor: '#3333ff',
fillOpacity: 0.2,
strokeColor: '#3333ff',
strokeOpacity: 0.5,
strokeWeight: 1
});
/*****************************
** FÄRDSÄTT (DISTANS) **
******************************/
var start = new google.maps.LatLng(position.coords.latitude.toFixed(6), position.coords.longitude.toFixed(6));
var stop = new google.maps.LatLng(<?php echo $photo['coordinates_latitude'].','.$photo['coordinates_longitude']; ?>);
var request = {
origin: start,
destination: stop,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if(status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
directionsService.route(request, function(response, status) {
if(status == google.maps.DirectionsStatus.OK) {
var distance = (response.routes[0].legs[0].distance.value / 1000).toFixed(0);
var duration = secondsToString(response.routes[0].legs[0].duration.value);
document.getElementById('distance').innerHTML = 'Cirka ' + distance + ' kilometer';
document.getElementById('duration').innerHTML = 'Cirka ' + duration;
directionsDisplay.setDirections(response);
}
});
}
function initialize_gps() {
var coor = new google.maps.LatLng(localStorage.coor);
var bounds = new google.maps.LatLngBounds();
options_gps = {
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: google.maps.LatLng(localStorage.coor),
streetViewControl: false
}
map_gps = new google.maps.Map(document.getElementById('map-distance'), options_gps);
map_gps.fitBounds(bounds);
}
function secondsToString(seconds) {
var numdays = Math.floor(seconds / 86400);
var numhours = Math.floor((seconds % 86400) / 3600);
var numminutes = Math.floor(((seconds % 86400) % 3600) / 60);
return (numdays != 0 ? (numdays == 1 ? '1 dag' : numdays + ' dagar') + ', ' : '')
+ (numhours != 0 ? (numhours == 1 ? '1 timme' : numhours + ' timmar') + (numdays != 0 ? ', ' : ' och ') : '')
+ (numminutes != 0 ? (numminutes == 1 ? '1 minut' : numminutes + ' minuter') : '');
}
function displayError(error) {
var errors = {
1: 'Permission denied',
2: 'Position unavailable',
3: 'Request timeout'
};
alert('Error: ' + errors[error.code]);
}
How can I make this to work?
Thanks in advance.
EDIT
Here's the edited part of the initialize_gps function. This part didn't work - nothing new happened. It just center the map over Asia like before.
function initialize_gps() {
var coor = new google.maps.LatLng(localStorage.coor);
var bounds = new google.maps.LatLngBounds();
options_gps = {
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: google.maps.LatLng(localStorage.coor),
streetViewControl: false
}
map_gps = new google.maps.Map(document.getElementById('map-distance'), options_gps);
map_gps.fitBounds(bounds);
}
EDIT
I have copy-pasted the whole code to jsFiddle. Link: http://jsfiddle.net/edgren/WRxt4/
The general solution to fitting the map display to a set of markers is to add them to an empty google.maps.LatLngBounds object (by calling bounds.extend), then calling map.fitBounds with that bounds.
function setMarkers(map) {
var bounds = new google.maps.LatLngBounds();
// Adds markers to the map.
for (let i = 0; i < beaches.length; i++) {
const beach = beaches[i];
var marker = new google.maps.Marker({
position: { lat: beach[1], lng: beach[2] },
map,
title: beach[0],
});
bounds.extend(marker.getPosition());
}
map.fitBounds(bounds);
}
// The following example creates complex markers to indicate beaches near
// Sydney, NSW, Australia. Note that the anchor is set to (0,32) to correspond
// to the base of the flagpole.
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 10,
center: { lat: 0, lng: 0 },
});
setMarkers(map);
}
// Data for the markers consisting of a name, a LatLng and a zIndex for the
// order in which these markers should display on top of each other.
const beaches = [
["Bondi Beach", -33.890542, 151.274856, 4],
["Coogee Beach", -33.923036, 151.259052, 5],
["Cronulla Beach", -34.028249, 151.157507, 3],
["Manly Beach", -33.80010128657071, 151.28747820854187, 2],
["Maroubra Beach", -33.950198, 151.259302, 1],
];
function setMarkers(map) {
var bounds = new google.maps.LatLngBounds();
// Adds markers to the map.
for (let i = 0; i < beaches.length; i++) {
const beach = beaches[i];
var marker = new google.maps.Marker({
position: { lat: beach[1], lng: beach[2] },
map,
title: beach[0],
});
bounds.extend(marker.getPosition());
}
map.fitBounds(bounds);
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Complex Marker Icons</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="map"></div>
<!-- Async script executes immediately and must be after any DOM elements used in callback. -->
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly"
async
></script>
</body>
</html>

Resources