I have the following polygon string:
POLYGON ((5.031728766 52.016855117, 5.039437914 52.018712029, 5.038732065 52.01933205, 5.03880625 52.019536002, 5.036666299 52.021123062, 5.037225302 52.021436208, 5.036494826 52.021980534, 5.040069034 52.024180983, 5.041131857 52.023541011, 5.041485972 52.023745389, 5.042328698 52.023235595, 5.043167194 52.022781293, 5.043379189 52.022938683, 5.04366399 52.022788333, 5.044615961 52.023393034, 5.046878469 52.022023355, 5.047609948 52.02119413, 5.048777737 52.022018526, 5.049465821 52.022060318, 5.05135083 52.021274278999996, 5.053039915 52.020873436, 5.052288001 52.019935439, 5.052174884 52.019294199, 5.053026298 52.019318482, 5.053120663 52.018982405, 5.05237284 52.018935127, 5.051442801 52.019120203, 5.046607457 52.016128313, 5.046220739 52.015628312, 5.04412241 52.015134981, 5.043853082 52.015544473, 5.043410675 52.015932024, 5.042704158 52.016254485, 5.042235947 52.016357569, 5.040118936 52.0166409, 5.039579367 52.015163505, 5.034087326 52.015907152, 5.03224395 52.016039016, 5.031728766 52.016855117), (5.043324081 52.017406693, 5.046676295 52.019354241, 5.048003676 52.020235065, 5.046772806 52.021010583, 5.045897693 52.02180469, 5.043619067 52.020981305, 5.042189351 52.020258164, 5.039736347 52.018909018, 5.041350353 52.018037167, 5.042763839 52.01739758, 5.042763839 52.01739758, 5.043324081 52.017406693))
I would like to use it to plot a simple polygon using the Google Maps API, e.g.:
var triangleCoords = [
new google.maps.LatLng(25.774252, -80.190262),
new google.maps.LatLng(18.466465, -66.118292),
new google.maps.LatLng(32.321384, -64.75737),
new google.maps.LatLng(25.774252, -80.190262)
];
How can I:
either iterate over the text and grab the coordinates
use an alternative more efficient way with google.maps.LatLng(POLYGONTEXTSTRING)
Using modified code from this related question: Polygon array does not work in Google map API. Your string is formatted slightly differently, don't know if that was on purpose.
proof of concept fiddle
code snippet:
var map;
var bounds = new google.maps.LatLngBounds();
// your POLYGON
var polygonStr = "POLYGON ((5.031728766 52.016855117, 5.039437914 52.018712029, 5.038732065 52.01933205, 5.03880625 52.019536002, 5.036666299 52.021123062, 5.037225302 52.021436208, 5.036494826 52.021980534, 5.040069034 52.024180983, 5.041131857 52.023541011, 5.041485972 52.023745389, 5.042328698 52.023235595, 5.043167194 52.022781293, 5.043379189 52.022938683, 5.04366399 52.022788333, 5.044615961 52.023393034, 5.046878469 52.022023355, 5.047609948 52.02119413, 5.048777737 52.022018526, 5.049465821 52.022060318, 5.05135083 52.021274278999996, 5.053039915 52.020873436, 5.052288001 52.019935439, 5.052174884 52.019294199, 5.053026298 52.019318482, 5.053120663 52.018982405, 5.05237284 52.018935127, 5.051442801 52.019120203, 5.046607457 52.016128313, 5.046220739 52.015628312, 5.04412241 52.015134981, 5.043853082 52.015544473, 5.043410675 52.015932024, 5.042704158 52.016254485, 5.042235947 52.016357569, 5.040118936 52.0166409, 5.039579367 52.015163505, 5.034087326 52.015907152, 5.03224395 52.016039016, 5.031728766 52.016855117), (5.043324081 52.017406693, 5.046676295 52.019354241, 5.048003676 52.020235065, 5.046772806 52.021010583, 5.045897693 52.02180469, 5.043619067 52.020981305, 5.042189351 52.020258164, 5.039736347 52.018909018, 5.041350353 52.018037167, 5.042763839 52.01739758, 5.042763839 52.01739758, 5.043324081 52.017406693))";
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
});
drawPoly(polygonStr);
map.fitBounds(bounds);
}
function drawPoly(multipolygonWKT) {
var polylines = [];
var toReturn = [];
multipolygonWKT = multipolygonWKT.replace("POLYGON ", "");
var formattedValues = multipolygonWKT.replace("))", "");
formattedValues = formattedValues.replace("((", "");
var linesCoords = formattedValues.split("), (");
for (i = 0; i < linesCoords.length; i++) {
polylines[i] = [];
var singleLine = linesCoords[i].split(", ");
for (j = 0; j < singleLine.length; j++) {
var coordinates = singleLine[j].split(" ");
var latlng = new google.maps.LatLng(parseFloat(coordinates[1]), parseFloat(coordinates[0]));
bounds.extend(latlng);
polylines[i].push(latlng);
}
}
toReturn.push(
new google.maps.Polygon({
map: map,
paths: polylines,
strokeColor: 'red',
strokeOpacity: 1,
strokeWeight: 2,
zIndex: 1
}));
return toReturn;
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"border: 2px solid #3872ac;"></div>
Since paths parameter of google.maps.Polygon object expects the array of google.maps.LatLng to be specified, the following example demonstrates how to parse input string:
function parsePolygonPaths(svalue)
{
var result = [];
var r = /\(([^)]+)\)/g;
svalue = svalue.slice(9, -1);
while (matches = r.exec(svalue)) {
var vals = matches[1].split(',');
var coords = vals.map(function(val){
var ll = val.trim().split(' ');
return new google.maps.LatLng(ll[0], ll[1]);
});
result.push(coords);
}
return result;
}
It is assumed that input string has the following format:
POLYGON ((lat11 lng11,..lat1n,lng1n),(lat21 lng21,..lat2n,lng2n),..(latn1 lngn1,..latnn,lngnn))
Returned value:
[
[google.maps.LatLng(lat11,lng11),..google.maps.LatLng(lat1n,lng1n)]
[google.maps.LatLng(lat21,lng21),..google.maps.LatLng(lat2n,lng2n)]
..
[google.maps.LatLng(latn1,lngn1),..google.maps.LatLng(latnn,lngnn)]
]
Example
var polygonString = 'POLYGON ((5.031728766 52.016855117, 5.039437914 52.018712029, 5.038732065 52.01933205, 5.03880625 52.019536002, 5.036666299 52.021123062, 5.037225302 52.021436208, 5.036494826 52.021980534, 5.040069034 52.024180983, 5.041131857 52.023541011, 5.041485972 52.023745389, 5.042328698 52.023235595, 5.043167194 52.022781293, 5.043379189 52.022938683, 5.04366399 52.022788333, 5.044615961 52.023393034, 5.046878469 52.022023355, 5.047609948 52.02119413, 5.048777737 52.022018526, 5.049465821 52.022060318, 5.05135083 52.021274278999996, 5.053039915 52.020873436, 5.052288001 52.019935439, 5.052174884 52.019294199, 5.053026298 52.019318482, 5.053120663 52.018982405, 5.05237284 52.018935127, 5.051442801 52.019120203, 5.046607457 52.016128313, 5.046220739 52.015628312, 5.04412241 52.015134981, 5.043853082 52.015544473, 5.043410675 52.015932024, 5.042704158 52.016254485, 5.042235947 52.016357569, 5.040118936 52.0166409, 5.039579367 52.015163505, 5.034087326 52.015907152, 5.03224395 52.016039016, 5.031728766 52.016855117), (5.043324081 52.017406693, 5.046676295 52.019354241, 5.048003676 52.020235065, 5.046772806 52.021010583, 5.045897693 52.02180469, 5.043619067 52.020981305, 5.042189351 52.020258164, 5.039736347 52.018909018, 5.041350353 52.018037167, 5.042763839 52.01739758, 5.042763839 52.01739758, 5.043324081 52.017406693))';
function initialize() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
var result = parsePolygonPaths(polygonString);
var bounds = new google.maps.LatLngBounds();
// Construct the polygon.
result.forEach(function(coords){
coords.forEach(function(loc){
bounds.extend(loc);
});
var poly = new google.maps.Polygon({
paths: coords,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
poly.setMap(map);
});
map.fitBounds(bounds);
map.panToBounds(bounds);
}
google.maps.event.addDomListener(window, 'load', initialize);
function parsePolygonPaths(svalue)
{
var result = [];
var r = /\(([^)]+)\)/g;
svalue= svalue.slice(9, -1);
while (matches = r.exec(svalue)) {
var vals = matches[1].split(',');
var coords = vals.map(function(val){
var ll = val.trim().split(' ');
return new google.maps.LatLng(ll[1], ll[0]);
});
result.push(coords);
}
return result;
}
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<div id="map-canvas"></div>
Related
I'm using google maps API to allow user draw custom polygons on the map. I need to check and display length of every single border.
I already use Geometry Library and Map Label Library to get and show computed area of polygon (also changing on 'insert_at' and 'set_at' events), but unfortunately I do not know how to get border lengths. Any help will be appreciated.
Used code sample:
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({
markerOption: {
draggable: false
},
polygonOptions: {
draggable: false,
fillColor: '#5C6BC0',
fillOpacity: 0.45,
strokeWeight: 0,
editable: true,
zIndex: 1
},
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: ['circle', 'polygon']
},
circleOptions: {
fillColor: '#5C6BC0',
fillOpacity: 0.45,
strokeWeight: 0,
editable: true,
zIndex: 1
},
map: map
});
function attachPolygonInfoWindow(polygon) {
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 mapLabel = new MapLabel({
map: map,
fontSize: 20,
align: 'left'
});
if (!labels.length) {
labels.push(mapLabel)
}
showPolygonInfoWindow(labels, boundsCenter, area);
}
function showPolygonInfoWindow(arr, position, text) {
arr.forEach((el) => {
el.set('position', position);
el.set('text', text + 'm2')
})
}
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);
}
});
}
initMap();
<script src="https://maps.google.com/maps/api/js?sensor=false&libraries=drawing,geometry">
</script>
<script type="text/javascript" src="https://cdn.rawgit.com/googlemaps/js-map-label/gh-pages/src/maplabel.js"></script>
Working example Codepen
I would like to display the length of each border on the side of each border.
My suggestion would be to when you create the center label, also process thru the paths of the polygon, compute their lengths and centers; then create MapLabel objects for each and place it at the center of the side. Something like:
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);
var sideCenter = google.maps.geometry.spherical.interpolate(start, end, 0.5);
var sideLabel = new MapLabel({
map: map,
fontSize: 20,
align: "center"
});
sideLabel.set("position", sideCenter);
sideLabel.set("text", sideLength.toFixed(2)+"m");
polygon.labels.push(sideLabel);
}
proof of concept 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: "#5C6BC0",
fillOpacity: 0.45,
strokeWeight: 0,
editable: true,
zIndex: 1
},
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: ["polygon"]
},
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,
fontSize: 20,
align: "left"
});
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);
var sideCenter = google.maps.geometry.spherical.interpolate(start, end, 0.5);
var sideLabel = new MapLabel({
map: map,
fontSize: 20,
align: "center"
});
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);
}
});
}
initMap();
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<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>
I am working on google map directions I am following the google's navigation app.
I am able to get all the possible alternative routes by DirectionsService and can give the polylines different colors I want the user to be able to select his desired path just bu clicking on the poly lines some how have have not found any thing for this.
My code:
directionsService.route(request, function(response, status) {
var points = [];
if (status == google.maps.DirectionsStatus.OK) {
try {
var polycolour = "";
var Opacity = 0;
//var PolyLine = '';
for (var i = 0, len = response.routes.length; i < len; i++) {
if (i == 0) {
polycolour = "Blue";
Opacity = 5;
}
else {
polycolour = "grey";
Opacity = 2;
}
directionsDisplay = new google.maps.DirectionsRenderer({
map: map,
directions: response,
routeIndex: i,
draggable : true,
polylineOptions: {
strokeColor: polycolour,
strokeWeight: Opacity
}
});
var infowindow2 = new google.maps.InfoWindow();
//var step = 10;
//alert(angular.toJson(response.routes[0].legs[0].steps[i]));
infowindow2.setContent(""+((response.routes[i].legs[0].distance.value)/1000)+" KM");
infowindow2.setPosition(response.routes[i].legs[0].steps[8].end_location);
infowindow2.open(map);
}
//directionsDisplay.setMap(map);
google.maps.event.addListener(directionsDisplay, 'click', function(){
alert("helo");
});
//for (var k = 0, len = response.routes.length; k < len; k++) {
//var myRoute = response.routes[k].legs[0];
//for (var i = 0; i < myRoute.steps.length; i++) {
//for (var j = 0; j < myRoute.steps[i].lat_lngs.length; j++) {
// points.push(myRoute.steps[i].lat_lngs[j]);
//}
//}
//var routLine = new google.maps.Polyline(
//{
//path: points,
//strokeColor: "Red",
//strokeOpacity: 0.5,
// strokeWeight: 10
// }
// );
// }
// routLine.setMap(map)
// Add a listener for the rightclick event on the routLine
//google.maps.event.addListener(routLine, 'click', function(e){
//try {
//alert(angular.toJson(e));
//}
//catch (err)
//{
// alert(err);
//}
// });
//alert(angular.toJson(response.routes[0].legs[0].steps));
//google.maps.event.addListener(PolyLine, 'routeindex_changed', function() {
//alert("Bingo");
//computeTotalDistance(directionsDisplay.getRouteIndex());
//});
//alert(response.routes.length);
//directionsDisplay.setDirections(response);
}
catch (err)
{
alert(err);
}
}
});
First you need to tell the request that you want alternative routes, like this
// for example
var request = {
origin: start,
destination: end,
provideRouteAlternatives: true,
travelMode: google.maps.TravelMode[DRIVING]
};
Then you have multiple response.routes objects (notice, sometimes you only get 1 route).
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
for(var i in response.routes ) {
// ...
}
}
}
Now you can use response.routes[i] as the source for direction render.
Or you make your own polyline. Use response.routes[i].overview_path as the path
var line = new google.maps.Polyline({
path: response.routes[i].overview_path,
strokeColor: "#ff0000", // you might want different colors per suggestion
strokeOpacity: 0.7,
strokeWeight: 3
});
line.setMap(map);
Here is an functioning example.
Just change your API key.
As you asked for, clicking on a route highlights it
UPDATE: I like it this way.
Both grey lines and colored lines are generated. But highlighting only shows 1 of the suggestions on the map.
The big, grey line is nice to click on. So it gets the click event instead of the colored line.
This is also the easiest way to avoid the Z-index problem.
And I store data (duration, distance), that I show on an infoWindow
<!DOCTYPE html>
<html>
<head>
<title>Google Map Direction Render Alternate Route How To Select Desired Path</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 90%;
}
</style>
</head>
<body>
<form id="form">
<input id="from" placeholder="From" value="Brussel" />
<input id="to" placeholder="To" value="Antwerpen" />
<input type="submit" value="GO" />
</form>
<div id="map"></div>
<div id="info">
Stackoverflow
</div>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"></script>
<script>
var map;
var directionsService;
var polylines = [];
var shadows = [];
var data = [];
var infowindow;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 50.84659376378408, lng: 4.3531406857355215},
zoom: 12,
mapTypeId: 'terrain'
});
google.maps.event.addDomListener(document.getElementById('form'), 'submit', function(e) {
calcRoute(
document.getElementById('from').value,
document.getElementById('to').value
);
// prevent the form from really submitting
e.preventDefault();
return false;
});
directionsService = new google.maps.DirectionsService();
// get the bounds of the polyline
// http://stackoverflow.com/questions/3284808/getting-the-bounds-of-a-polyine-in-google-maps-api-v3
google.maps.Polyline.prototype.getBounds = function(startBounds) {
if(startBounds) {
var bounds = startBounds;
}
else {
var bounds = new google.maps.LatLngBounds();
}
this.getPath().forEach(function(item, index) {
bounds.extend(new google.maps.LatLng(item.lat(), item.lng()));
});
return bounds;
};
}
// this function calculates multiple suggested routes.
// We will draw 3 (broad stroke) suggested routs in grey. These are broad to click on them easier.
// We duplicate these routes with a thin, colored line; only route 0 is shown.
function calcRoute(start, end) {
var request = {
origin: start,
destination: end,
provideRouteAlternatives: true,
unitSystem: google.maps.UnitSystem.METRIC,
travelMode: google.maps.TravelMode['DRIVING']
};
directionsService.route(request, function(response, status) {
// clear former polylines
for(var j in polylines ) {
polylines[j].setMap(null);
shadows[j].setMap(null);
}
polylines = [];
shadows = [];
data = [];
if (status == google.maps.DirectionsStatus.OK) {
var bounds = new google.maps.LatLngBounds();
for(var i in response.routes) {
// let's make the first suggestion highlighted;
var hide = (i==0 ? false : true);
var shadow = drawPolylineShadow(response.routes[i].overview_path, '#666666');
var line = drawPolyline(response.routes[i].overview_path, '#0000ff', hide);
polylines.push(line);
shadows.push(shadow);
// let's add some data for the infoWindow
data.push({
distance: response.routes[i].legs[0].distance,
duration: response.routes[i].legs[0].duration,
end_address: response.routes[i].legs[0].end_address,
start_address: response.routes[i].legs[0].start_address,
end_location: response.routes[i].legs[0].end_location,
start_location: response.routes[i].legs[0].start_location
});
bounds = line.getBounds(bounds);
google.maps.event.addListener(shadow, 'click', function(e) {
// detect which route was clicked on
var index = shadows.indexOf(this);
highlightRoute(index, e);
});
}
map.fitBounds(bounds);
}
});
}
// this makes one of the colored routes visible.
function highlightRoute(index, e) {
for(var j in polylines ) {
if(j==index) {
//var color = '#0000ff';
polylines[j].setMap(map);
// feel free to customise this string
var contentString =
'<span>'+ data[j].distance.text +'</span><br/>'+
'<span>'+ data[j].duration.text +'</span><br/>'+
'<span>route: '+ j +'</span><br/>'+
//'From: <span>'+ data[j].start_address +'</span><br/>'+
//'To: <span>'+ data[j].end_address +'</span><br/>'+
'';
if(e) {
var position = new google.maps.LatLng(e.latLng.lat(), e.latLng.lng());
// it may be needed to close the previous infoWindow
if(infowindow) {
infowindow.close();
infowindow = null;
}
infowindow = new google.maps.InfoWindow({
content: contentString,
position: position,
map: map
});
//infowindow.open(map, polylines[j]);
}
}
else {
polylines[j].setMap(null);
}
}
}
// returns a polyline.
// if hide is set to true, the line is not put on the map
function drawPolyline(path, color, hide) {
var line = new google.maps.Polyline({
path: path,
strokeColor: color,
strokeOpacity: 0.9,
strokeWeight: 3
});
if(! hide) {
line.setMap(map);
}
return line;
}
function drawPolylineShadow(path, color, hide) {
var line = new google.maps.Polyline({
path: path,
strokeColor: color,
strokeOpacity: 0.4,
strokeWeight: 7
});
if(! hide) {
line.setMap(map);
}
return line;
}
google.maps.event.addDomListener(window, 'load', initMap);
</script>
</body>
</html>
earlier code. this changes the color of the polyLine
<!DOCTYPE html>
<html>
<head>
<title>Suggested routes</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 90%;
}
</style>
</head>
<body>
<form id="form">
<input id="from" placeholder="From" value="Brussel" />
<input id="to" placeholder="To" value="Antwerpen" />
<input type="submit" value="GO" />
</form>
<div id="map"></div>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"></script>
<script>
var map;
var directionsService;
var polylines = [];
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 50.84659376378408, lng: 4.3531406857355215},
zoom: 12,
mapTypeId: 'terrain'
});
google.maps.event.addDomListener(document.getElementById('form'), 'submit', function(e) {
calcRoute(
document.getElementById('from').value,
document.getElementById('to').value
);
// prevent the form from really submitting
e.preventDefault();
return false;
});
directionsService = new google.maps.DirectionsService();
// get the bounds of the polyline
// http://stackoverflow.com/questions/3284808/getting-the-bounds-of-a-polyine-in-google-maps-api-v3
google.maps.Polyline.prototype.getBounds = function(startBounds) {
if(startBounds) {
var bounds = startBounds;
}
else {
var bounds = new google.maps.LatLngBounds();
}
this.getPath().forEach(function(item, index) {
bounds.extend(new google.maps.LatLng(item.lat(), item.lng()));
});
return bounds;
};
}
function calcRoute(start, end) {
var request = {
origin: start,
destination: end,
provideRouteAlternatives: true,
unitSystem: google.maps.UnitSystem.METRIC,
travelMode: google.maps.TravelMode['DRIVING']
};
directionsService.route(request, function(response, status) {
// clear former polylines
for(var j in polylines ) {
polylines[j].setMap(null);
}
polylines = [];
if (status == google.maps.DirectionsStatus.OK) {
var bounds = new google.maps.LatLngBounds();
// draw the lines in reverse orde, so the first one is on top (z-index)
for(var i=response.routes.length - 1; i>=0; i-- ) {
// let's make the first suggestion highlighted;
if(i==0) {
var color = '#0000ff';
}
else {
var color = '#999999';
}
var line = drawPolyline(response.routes[i].overview_path, color);
polylines.push(line);
bounds = line.getBounds(bounds);
google.maps.event.addListener(line, 'click', function() {
// detect which route was clicked on
var index = polylines.indexOf(this);
highlightRoute(index);
});
}
map.fitBounds(bounds);
}
});
}
function highlightRoute(index) {
for(var j in polylines ) {
if(j==index) {
var color = '#0000ff';
}
else {
var color = '#999999';
}
polylines[j].setOptions({strokeColor: color});
}
}
function drawPolyline(path, color) {
var line = new google.maps.Polyline({
path: path,
strokeColor: color,
strokeOpacity: 0.7,
strokeWeight: 3
});
line.setMap(map);
return line;
}
google.maps.event.addDomListener(window, 'load', initMap);
</script>
</body>
</html>
I am trying to return the markers as the object but when i run the function it just returns [ ], but printing it inside i can see the object data, can anyone explain how to return the object batch2 please?
google.maps.event.addListener(mgr, 'loaded', function(){
mgr.addMarkers(getMarkers(),6); //add all the markers! documentation for viewports with totals for city count, look at viewport
mgr.addMarkers(getMarkers2(),14); //get markers for zoomed out place, add click function to zoom in
//mgr.addMarkers(getMarkers(1000), 8);
console.log("added");
mgr.refresh();
});
function getMarkers2() {
var batch2 = [];
var clusters = new Parse.Query("cityfreqcoords");
var clusterresults = new Parse.Object("cityfreqcoords");
clusters.find({
success: function (results) {
for (i = 1; i < results.length; i++) {
var city = (results[i]["attributes"]["city"]);
var count = (results[i]["attributes"]["count"]);
var lat = (results[i]["attributes"]["lat"]);
var lng = (results[i]["attributes"]["lng"]);
var markerLatlong = new google.maps.LatLng(lat, lng);
//icon =
//adding the marker
var marker2 = new google.maps.Marker({
position: markerLatlong,
title: city,
clickable: true,
animation: google.maps.Animation.DROP
//icon:icon
});
//adding the click event and info window
google.maps.event.addListener(marker2, 'click', function () {
map.setZoom(6);
map.setCenter(marker2.getPosition());
});
batch2.push(marker2);
}
}
})
return batch2;
}
It would appear that clusters.find is asynchronous. You return batch2 before cluster.find succeeds. There are a handful of patterns for working with asynchronous code in JavaScript -- one common one is to use a callback. You would need to rewrite your code like so:
function getMarkers2(callback) {
var batch2 = [];
var clusters = new Parse.Query("cityfreqcoords");
var clusterresults = new Parse.Object("cityfreqcoords");
clusters.find({
success: function (results) {
for (i = 1; i < results.length; i++) {
var city = (results[i]["attributes"]["city"]);
var count = (results[i]["attributes"]["count"]);
var lat = (results[i]["attributes"]["lat"]);
var lng = (results[i]["attributes"]["lng"]);
var markerLatlong = new google.maps.LatLng(lat, lng);
//icon =
//adding the marker
var marker2 = new google.maps.Marker({
position: markerLatlong,
title: city,
clickable: true,
animation: google.maps.Animation.DROP
//icon:icon
});
//adding the click event and info window
google.maps.event.addListener(marker2, 'click', function () {
map.setZoom(6);
map.setCenter(marker2.getPosition());
});
batch2.push(marker2);
}
}
callback(batch2);
})
}
Then call it like so:
getMarkers2(function(markers) {
mgr.addMarkers(markers, 14);
});
If you're interested, take a look at how promises work as you might prefer that approach over using callbacks.
With callbacks in javascript, you generally don't return data. You pass in another function reference into the handler as a callback.
EG:
function getMarkers2(f) {
// do stuff
//when done
f(batch2)
}
Ended up just passing making the marker manager global and passing mgr into the query which worked, probably not the most efficient way to do it
function getMarkers2(mgr) {
Parse.initialize("X", "Y");
var batch2 = [];
var clusters = new Parse.Query("cityfrequency2");
var clusterresults = new Parse.Object("cityfrequency2");
clusters.find({
success: function (results) {
for (i = 0; i < (results.length); i++) {
var city = (results[i]["attributes"]["city"]);
var lat = (results[i]["attributes"]["lat"]);
var lng = (results[i]["attributes"]["lng"]);
var markerLatlong = new google.maps.LatLng(lat, lng);
var image = {
url: 'warning.png',
size: new google.maps.Size(50, 46),
// The origin
origin: new google.maps.Point(0, 0),
// The anchor
anchor: new google.maps.Point(25, 0)
};
//adding the marker
var marker2 = new google.maps.Marker({
position: markerLatlong,
title: city,
clickable: true,
animation: google.maps.Animation.DROP,
icon:image
});
//adding the click event and info window
google.maps.event.addListener(marker2, 'click', function () {
map.setZoom(6);
map.setCenter();
});
batch2.push(marker2);
mgr.addMarkers(batch2,0,6);
mgr.refresh();
}
}
})
}
function setupMarkers() {
var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: true };
mgr = new MarkerManager(map,mgrOptions);
google.maps.event.addListener(mgr, 'loaded', function(){
getMarkers2(mgr);
getMarkers(mgr);
console.log("added");
});
}
I have a asp.net 4.0 page that loads a Google map, with over 6,000 markers (and growing!)
I am loading the markers from my SQL DB, using a repeater control in the javascript like in this [this example:] (http://www.aspsnippets.com/Articles/ASPNet-Populate-Google-Maps-V3-with-Multiple-Markers-using-Address-Latitude-and-Longitude-values-stored-in-database.aspx)
I have already added marker clustering and done everything I can think of to speed it up.
Some of the markers are added during the initial load, but are not displayed on the map until the user zooms in. (via height:1 width:1 for the cluster icon)
Here is what I want to do, but I'm not sure if it is possible. I want to have my vb codebehind/asp:Repeater load the markers that will display initially. Then in the "Idle" listner, have it load the other markers so that they are ready once the map is zoomed in.
BUT, I can't figure out how to accomplish this. Any ideas?
Here is the bulk of the javascript:
// configure options
var map;
var locations = new Array();
var markers = new Array();
var markerCluster1 = null;
var markerCluster2 = null;
var markerCluster3 = null;
var markerCluster4 = null;
var Style1 = [{url: '../images/m1.png',
height: 48,
width: 48
}];
var Style2 = [{url: '../images/m2.png',
height: 48,
width: 48
}];
var Style3 = [{url: '../images/m3.png',
height: 48,
width: 48
}];
var Style4 = [{url: '../images/m4.png',
textSize: 1,
height: 1,
width: 1
}];
var mcOA1 = {gridSize: 50, maxZoom: 10, styles: Style1};
var mcOA2 = {gridSize: 50, maxZoom: 10, styles: Style2};
var mcOA3 = {gridSize: 50, maxZoom: 10, styles: Style3};
var mcOA4 = {gridSize: 300, maxZoom: 9, styles: Style4, minimumClusterSize: 2};
var infoWindow = new google.maps.InfoWindow();
<asp:Repeater ID="rptMarkers" runat="server" EnableViewState = false>
<ItemTemplate>locations[<%# Eval("i")%>]=new Array(),locations[<%# Eval("i")%>][0]='<%# Eval("PType")%>',locations[<%# Eval("i")%>][1]='<%# Eval("Lat")%>',locations[<%# Eval("i")%>][2]='<%# Eval("Lon")%>',locations[<%# Eval("i")%>][3]='<div class=\"info-window\"><%# Eval("MDesc")%></div>',locations[<%# Eval("i")%>][4]='<%# Eval("Name") %>';
</ItemTemplate>
<SeparatorTemplate></SeparatorTemplate>
</asp:Repeater>
function initialize() {
var myOptions =
<asp:Repeater ID="MapOptions" runat="server">
<ItemTemplate>
{
center: new google.maps.LatLng(<%# Eval("center")%>),
zoom: <%# Eval("zoom")%>,
streetViewControl: false,
mapTypeId: <%# Eval("mapTypeId")%>
}
</ItemTemplate>
</asp:Repeater>
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
for (i = 1; i < locations.length; i++) {
if (typeof(locations[i]) == 'object') {
var icon = "";
switch (locations[i][0]) {
case "A1":
icon = "../images/A13.png";
break;
case "A2":
icon = "../images/A23.png";
break;
case "A3":
icon = "../images/A33.png";
break;
case "A4":
icon="../images/A44.png"
break;
case "Furniture":
icon="../images/Furniture3.png"
break;
case "Property Manager":
icon="../images/PropertyManager3.png"
break;
default:
icon="../images/A13.png"
break;
}
var point = new google.maps.LatLng(locations[i][1], locations[i][2]);
markers[i] = new google.maps.Marker({
position: point,
icon: new google.maps.MarkerImage(icon),
animation: google.maps.Animation.DROP,
title: locations[i][4]
});
markers[i].setMap(map);
google.maps.event.addListener(markers[i], 'click', function() {infoWindow.setContent(locations[i][3]);infoWindow.open(map, markers[i]);});
}
} // for
// check to see which category is selected
var location_selector = document.getElementsByName('loc_sel');
for (var i=0; i < location_selector.length; i++) {
if (location_selector[i].checked) {
var location_type = location_selector[i].value;
}
}
show_markers(location_type);
} // function initialize() {
function show_markers (location_type) {
var temp_markers1 = new Array();
var temp_markers2 = new Array();
var temp_markers3 = new Array();
var temp_markers4 = new Array();
// if the markerClusterer object doesn't exist, create it with empty temp_markers
if (markerCluster1 == null) {
markerCluster1 = new MarkerClusterer(map, temp_markers1, mcOA1);
}
if (markerCluster2 == null) {
markerCluster2 = new MarkerClusterer(map, temp_markers1, mcOA2);
}
if (markerCluster3 == null) {
markerCluster3 = new MarkerClusterer(map, temp_markers1, mcOA3);
}
if (markerCluster4 == null) {
markerCluster4 = new MarkerClusterer(map, temp_markers1, mcOA4);
}
// clear all markers
markerCluster1.clearMarkers();
markerCluster2.clearMarkers();
markerCluster3.clearMarkers();
markerCluster4.clearMarkers();
// iterate through all locations, setting only those in the selected category
for (i = 1; i < locations.length; i++) {
if (typeof(locations[i]) == 'object') {
if (locations[i][0] == location_type) {
markers[i].setVisible(true);
if (locations[i][0] == "A1") {temp_markers1.push(markers[i]);}
if (locations[i][0] == "A2") {temp_markers2.push(markers[i]);}
if (locations[i][0] == "A3") {temp_markers3.push(markers[i]);}
if (locations[i][0] == "A4") {temp_markers4.push(markers[i]);}
} else {
markers[i].setVisible(false);
if (locations[i][0] == "A4") {markers[i].setVisible(true);
temp_markers4.push(markers[i]);}
}
}
} // for
// add all current markers to cluster
markerCluster1.addMarkers(temp_markers1);
markerCluster2.addMarkers(temp_markers2);
markerCluster3.addMarkers(temp_markers3);
markerCluster4.addMarkers(temp_markers4);
} // function show_markers
Thank you all!
One probable solution to this problem may be to fire a query to the SQL DB to fetch all the markers when the map is in the idle state.
google.maps.event.addListener(map, 'idle', function() {
fetchMarkersfromDB();
});
And in the initialize() function pass both this listener and also the showMarker() function call. So that whenever the maps are initialized and displayed the markers at current zoom position would be displaced and during the idle phase the query in the backgroud would fetch remaining markers that can be shown in the next or consequent zoom levels. This way the markers would be ready and performance will be better.
Hope this would help!!
How to each time when click "Create New Poly" button, store last object in array and create a new clean object to draw new separated polyline on the map. I'd like to keep the functionality of the old polylines. Now it is not possible to clean the object. Simplified example presented bellow.
HTML:
<button onclick="create()">Create New Poly</button>
<div id="map" style="width: 500px; height: 400px;"></div>
JS:
var map;
var listener;
var polys = [],
poly = {};
create = function() {
poly = new Poly();
if ( !! listener) google.maps.event.removeListener(listener);
listener = google.maps.event.addListener(map, 'click', function(e) {
poly.addPoint(e.latLng);
});
}
function Poly() {
this.markers = [];
this.setMap(map);
polys.push(this);
}
Poly.prototype = new google.maps.Polyline();
Poly.prototype.addPoint = function(p) {
var m = poly.createMarker(p);
poly.markers.push(m);
poly.getPath().push(p);
}
Poly.prototype.createMarker = function(p) {
var marker = new google.maps.Marker({
position: p
});
marker.setMap(this.getMap());
return marker;
}
$(function() {
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(48.864715, 10.546875),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
});
Demo: JSFIDDLE
Even after doing what Ben Davis suggested http://jsfiddle.net/LxGmR/ it still exhibits the problem.
Which I think is due to all the Ploy objects sharing the same prototype: Poly.prototype = new google.maps.Polyline();. I think the fix is that each new Ploy object needs its own prototype google.maps.Polyline instance.
Which after testing, I have found to be true: http://jsfiddle.net/uhZFE/
Then I looked up how to do this without the wrapper function, I used the method described in the SO answer https://stackoverflow.com/a/6519265/388787 (http://javascript.crockford.com/prototypal.html was also helpful) and produced http://jsfiddle.net/YgSwF/ which is the following; it works as you requested:
var map;
var listener;
var polys = [];
create = function () {
var poly = new Poly();
if ( !! listener) google.maps.event.removeListener(listener);
listener = google.maps.event.addListener(map, 'click', function (e) {
poly.addPoint(e.latLng);
});
polys.push(poly);
}
function Poly() {
google.maps.Polyline.call(this);
this.markers = [];
this.setMap(map);
}
Poly.prototype = Object.create(google.maps.Polyline.prototype);
Poly.prototype.addPoint = function (p) {
var m = this.createMarker(p);
this.markers.push(m);
this.getPath().push(p);
}
Poly.prototype.createMarker = function (p) {
var marker = new google.maps.Marker({
position: p
});
marker.setMap(this.getMap());
return marker;
}
$(function () {
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(48.864715, 10.546875),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
});
I believe your problem has to do with variable scope. You should declare poly inside the create() function. Also, I think it would make more sense to do the pushing of the created object into the array within the create() function to adhere to separation of concerns.
Also, in your addPoint() function, you're referring to the global poly variable when you should be using "this".
Updated code:
var map;
var listener;
var polys = [];
create = function() {
var poly = new Poly();
if ( !! listener) google.maps.event.removeListener(listener);
listener = google.maps.event.addListener(map, 'click', function(e) {
poly.addPoint(e.latLng);
});
polys.push(poly);
}
function Poly() {
this.markers = [];
this.setMap(map);
}
Poly.prototype = new google.maps.Polyline();
Poly.prototype.addPoint = function(p) {
var m = this.createMarker(p);
this.markers.push(m);
this.getPath().push(p);
}
Poly.prototype.createMarker = function(p) {
var marker = new google.maps.Marker({
position: p
});
marker.setMap(this.getMap());
return marker;
}
$(function() {
map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(48.864715, 10.546875),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
});