Related
I tried to create a polyline in google Maps. It's created and polyline also working fine. but I need when to click polyline to get coordinates. My Scenario(I have three markers in google map.so, three markers used to connect the polyline markerA connect to markerB connect to markerC. when I click polyline in between markerA and makrerB. I need that two markers latitude and longitude). How to achieve this scenario.
My Code
<!DOCTYPE html>
<html>
<body>
<h1>My First Google Map</h1>
<div id="googleMap" style="width:100%;height:400px;"></div>
<script>
function myMap() {
var mapProp= {
center:new google.maps.LatLng(51.508742,-0.120850),
zoom:5,
};
var map = new google.maps.Map(document.getElementById("googleMap"),mapProp);
var goldenGatePosition = [{lat: 11.0168,lng: 76.9558},{lat: 11.6643,lng: 78.1460},{lat:11.2189,lng:78.1674}];
for(let i=0;i<goldenGatePosition.length;i++){
var marker = new google.maps.Marker({
position: goldenGatePosition[i],
map: map,
title: 'Golden Gate Bridge'
});
}
var flightPath = new google.maps.Polyline({
path:goldenGatePosition,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2
});
flightPath.setMap(map);
var infowindow = new google.maps.InfoWindow();
var codeStr=''
google.maps.event.addListener(flightPath, 'click', function(event) {
infowindow.setContent("content");
// var pathArr = flightPath.getPath()
// for (var i = 0; i < pathArr.length; i++){
// codeStr = '{lat: ' + pathArr.getAt(i).lat() + ', lng: ' + pathArr.getAt(i).lng() + '}' ;
// console.log(codeStr)
// };
console.log(event.latLng)
var length = this.getLength();
var mid = Math.round( length / 2 );
var pos = this.getAt( mid );
console.log(pos)
// infowindow.position = event.latLng;
infowindow.setPosition(event.latLng);
infowindow.open(map);
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCHmYOxkvd4u3rbHqalUSlGOa-b173lygA&callback=myMap"></script>
</body>
</html>
Google Map
Simplest way:
include the google maps geometry library.
use the poly namespace isLocationOnEdge method to detect which segment of the polyline the click was on. Output the two end coordinates of that segment.
isLocationOnEdge(point, poly[, tolerance])
Parameters:
point: LatLng
poly: Polygon|Polyline
tolerance: number optional
Return Value: boolean
Computes whether the given point lies on or near to a polyline, or the edge of a polygon, within a specified tolerance. Returns true when the difference between the latitude and longitude of the supplied point, and the closest point on the edge, is less than the tolerance. The tolerance defaults to 10-9 degrees.
google.maps.event.addListener(flightPath, 'click', function(event) {
// make polyline for each segment of the input line
for (var i = 0; i < this.getPath().getLength() - 1; i++) {
var segmentPolyline = new google.maps.Polyline({
path: [this.getPath().getAt(i), this.getPath().getAt(i + 1)]
});
// check to see if the clicked point is along that segment
if (google.maps.geometry.poly.isLocationOnEdge(event.latLng, segmentPolyline,10e-3)) {
// output the segment number and endpoints in the InfoWindow
var content = "segment "+i+"<br>";
content += "start of segment=" + segmentPolyline.getPath().getAt(0).toUrlValue(6) + "<br>";
content += "end of segment=" + segmentPolyline.getPath().getAt(1).toUrlValue(6) + "<br>";
infowindow.setContent(content);
infowindow.setPosition(event.latLng);
infowindow.open(map);
}
}
});
proof of concept fiddle
code snippet:
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#googleMap {
height: 80%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<h1>My First Google Map</h1>
<div id="googleMap"></div>
<script>
function myMap() {
var mapProp = {
center: new google.maps.LatLng(51.508742, -0.120850),
zoom: 5,
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var goldenGatePosition = [{
lat: 11.0168,
lng: 76.9558
}, {
lat: 11.6643,
lng: 78.1460
}, {
lat: 11.2189,
lng: 78.1674
}];
var bounds = new google.maps.LatLngBounds();
for (let i = 0; i < goldenGatePosition.length; i++) {
var marker = new google.maps.Marker({
position: goldenGatePosition[i],
map: map,
title: 'Golden Gate Bridge'
});
bounds.extend(goldenGatePosition[i]);
}
var flightPath = new google.maps.Polyline({
path: goldenGatePosition,
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2
});
flightPath.setMap(map);
map.fitBounds(bounds);
var infowindow = new google.maps.InfoWindow();
var codeStr = ''
google.maps.event.addListener(flightPath, 'click', function(event) {
// make polyline for each segment of the input line
for (var i = 0; i < this.getPath().getLength() - 1; i++) {
var segmentPolyline = new google.maps.Polyline({
path: [this.getPath().getAt(i), this.getPath().getAt(i + 1)]
});
// check to see if the clicked point is along that segment
if (google.maps.geometry.poly.isLocationOnEdge(event.latLng, segmentPolyline, 10e-3)) {
// output the segment number and endpoints in the InfoWindow
var content = "segment " + i + "<br>";
content += "start of segment=" + segmentPolyline.getPath().getAt(0).toUrlValue(6) + "<br>";
content += "end of segment=" + segmentPolyline.getPath().getAt(1).toUrlValue(6) + "<br>";
infowindow.setContent(content);
infowindow.setPosition(event.latLng);
infowindow.open(map);
}
}
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=myMap"></script>
I want to add custom background image to my draggable polygons in google Map. I've already used the Polygon class to make a draggable polygon that can also rotate. I want to add background image to it. I've read other posts and they mentioned "custom overlay" but that is a fixed image on the map which doesn't support dragging/rotation. How should I go about doing this?
Update:
I created a custom layer with my image and added it to the map with the same coordinates as the polygon. Whenever the bounds of my polygon change, I will also update my custom layer so they always overlap. However, as shown in the gif, https://imgur.com/3oaktIY, the polygon and the image are not in sync and there's a delay.
Is there any other way to do it?
Did not find solutions online so I figured it out myself with this working demo: draggable polygon with image. I made it with a combination of custom overlay and normal polygon library. You can click on the polygon to rotate and drag it around.
plz see jsfiddle
code snippet:
// This example adds hide() and show() methods to a custom overlay's prototype.
// These methods toggle the visibility of the container <div>.
// Additionally, we add a toggleDOM() method, which attaches or detaches the
// overlay to or from the map.
var overlay;
USGSOverlay.prototype = new google.maps.OverlayView();
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 20,
center: {
lat: 33.678,
lng: -116.243
},
mapTypeId: google.maps.MapTypeId.TERRAIN
});
var rectangle = new google.maps.Rectangle({
strokeColor: 'red',
strokeOpacity: 0,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0,
map: map,
bounds: calcBounds(map.getCenter(), new google.maps.Size(2.7, 20))
});
var rectPoly = createPolygonFromRectangle(rectangle); //create a polygom from a rectangle
rectPoly.addListener('click', function(e) {
rotatePolygon(rectPoly, 10);
rectPoly.rotation += 10;
console.log(rectPoly.rotation)
overlay.div_.style.transform = 'rotate(' + rectPoly.rotation + 'deg)';
});
rectPoly.addListener('drag', function() {
console.log('Drag end!');
let bounds = new google.maps.LatLngBounds();
var i;
// The Bermuda Triangle
let polygonCoords = rectPoly.getPath().getArray();
for (i = 0; i < polygonCoords.length; i++) {
bounds.extend(polygonCoords[i]);
}
// The Center of the Bermuda Triangle - (25.3939245, -72.473816)
center = bounds.getCenter();
overlay.bounds_ = calcBounds(center, new google.maps.Size(2.7, 20))
overlay.draw();
});
function calcBounds(center, size) {
var n = google.maps.geometry.spherical.computeOffset(center, size.height / 2, 0).lat(),
s = google.maps.geometry.spherical.computeOffset(center, size.height / 2, 180).lat(),
e = google.maps.geometry.spherical.computeOffset(center, size.width / 2, 90).lng(),
w = google.maps.geometry.spherical.computeOffset(center, size.width / 2, 270).lng();
return new google.maps.LatLngBounds(new google.maps.LatLng(s, w),
new google.maps.LatLng(n, e))
}
var srcImage = 'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png';
overlay = new USGSOverlay(rectangle.bounds, srcImage, map, rectPoly);
// The custom USGSOverlay object contains the USGS image,
// the bounds of the image, and a reference to the map.
}
/** #constructor */
function USGSOverlay(bounds, image, map, rectPoly) {
// Now initialize all properties.
this.bounds_ = bounds;
this.image_ = image;
this.map_ = map;
this.rectPoly_ = rectPoly
// Define a property to hold the image's div. We'll
// actually create this div upon receipt of the onAdd()
// method so we'll leave it null for now.
this.div_ = null;
// Explicitly call setMap on this overlay
this.setMap(map);
}
/**
* onAdd is called when the map's panes are ready and the overlay has been
* added to the map.
*/
USGSOverlay.prototype.onAdd = function() {
var div = document.createElement('div');
div.style.border = 'none';
div.style.borderWidth = '0px';
div.style.position = 'absolute';
rectPoly = this.rectPoly_;
// Create the img element and attach it to the div.
var img = document.createElement('img');
img.src = this.image_;
img.style.width = '100%';
img.style.height = '100%';
div.appendChild(img);
this.div_ = div;
// Add the element to the "overlayImage" pane.
var panes = this.getPanes();
panes.overlayImage.appendChild(this.div_);
};
USGSOverlay.prototype.draw = function() {
// We use the south-west and north-east
// coordinates of the overlay to peg it to the correct position and size.
// To do this, we need to retrieve the projection from the overlay.
var overlayProjection = this.getProjection();
// Retrieve the south-west and north-east coordinates of this overlay
// in LatLngs and convert them to pixel coordinates.
// We'll use these coordinates to resize the div.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's div to fit the indicated dimensions.
var div = this.div_;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
};
USGSOverlay.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
};
// Set the visibility to 'hidden' or 'visible'.
function createPolygonFromRectangle(rectangle) {
var map = rectangle.getMap();
var coords = [{
lat: rectangle.getBounds().getNorthEast().lat(),
lng: rectangle.getBounds().getNorthEast().lng()
},
{
lat: rectangle.getBounds().getNorthEast().lat(),
lng: rectangle.getBounds().getSouthWest().lng()
},
{
lat: rectangle.getBounds().getSouthWest().lat(),
lng: rectangle.getBounds().getSouthWest().lng()
},
{
lat: rectangle.getBounds().getSouthWest().lat(),
lng: rectangle.getBounds().getNorthEast().lng()
}
];
// Construct the polygon.
var rectPoly = new google.maps.Polygon({
path: coords,
draggable: true,
rotation: 0
});
var properties = ["strokeColor", "strokeOpacity", "strokeWeight", "fillOpacity", "fillColor"];
//inherit rectangle properties
var options = {};
properties.forEach(function(property) {
if (rectangle.hasOwnProperty(property)) {
options[property] = rectangle[property];
}
});
rectPoly.setOptions(options);
rectangle.setMap(null);
rectPoly.setMap(map);
return rectPoly;
}
function rotatePolygon(polygon, angle) {
var map = polygon.getMap();
var prj = map.getProjection();
var bounds = new google.maps.LatLngBounds();
var i;
// The Bermuda Triangle
var polygonCoords = polygon.getPath().getArray();
for (i = 0; i < polygonCoords.length; i++) {
bounds.extend(polygonCoords[i]);
}
// The Center of the Bermuda Triangle - (25.3939245, -72.473816)
console.log(bounds.getCenter());
var origin = prj.fromLatLngToPoint(bounds.getCenter()); //rotate around first point
//var origin2 = prj.fromLatLngToPoint(polygon.getPath().getAt(1)); //rotate around first point
var coords = polygon.getPath().getArray().map(function(latLng) {
var point = prj.fromLatLngToPoint(latLng);
var rotatedLatLng = prj.fromPointToLatLng(rotatePoint(point, origin, angle));
return {
lat: rotatedLatLng.lat(),
lng: rotatedLatLng.lng()
};
});
polygon.setPath(coords);
}
function rotatePoint(point, origin, angle) {
var angleRad = angle * Math.PI / 180.0;
return {
x: Math.cos(angleRad) * (point.x - origin.x) - Math.sin(angleRad) * (point.y - origin.y) + origin.x,
y: Math.sin(angleRad) * (point.x - origin.x) + Math.cos(angleRad) * (point.y - origin.y) + origin.y
};
}
google.maps.event.addDomListener(window, 'load', initMap);
/* 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;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto', 'sans-serif';
line-height: 30px;
padding-left: 10px;
}
<!-- Add an input button to initiate the toggle method on the overlay. -->
<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=geometry"></script>
http://web3o.blogspot.in/2010/05/google-maps-dynamically-movable-and.html
From the above link i got V2 google maps code which is working fine, but not able to import V3 beach markers so i convert the draw circle, circle resize and circle center marker function to V3 and i am not getting the circle in the maps where as i am getting all the marker, beach marker flags etc.
Following is the code, Kindly help me in fixing this, save the code as HTML file and execute in the browser.
I am having issue in the drawCircle function were the circle is not drawn on the Map.
<!--<script src="http://maps.google.com/maps?file=api&v=2&key=AIzaSyDAAkI8Q59oV68_F8r8hL66vlhCu9cWNQM&sensor=true" type="text/javascript"></script>-->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"></script>
<script type="text/javascript">
/* Developed by: Abhinay Rathore [web3o.blogspot.com] */
//Global variables
var map;
var circle = [];
//circle[0] = {map_center: new GLatLng(38.903843, -94.680096),
// };
var Cobj = [];//{'mp_center':
var frndmap = [];
var bounds = new google.maps.LatLngBounds; //Circle Bounds
var map_center = new google.maps.LatLng(12.9735597, 77.6410402);
frndmap = [['Mahesh Pusala', 12.9735521, 77.6410431, 1], ['Bala Sundar', 12.9735567, 77.6410489, 2]];
var Circle=[];//null,null];//Circle object
var CirclePoints = []; //Circle drawing points
var CircleCenterMarker, CircleResizeMarker = [];//null,null];
var circle_moving = false; //To track Circle moving
var circle_resizing = false; //To track Circle resizing
var radius = []; //1 km
//var min_radius = 0.5; //0.5km
//var max_radius = 50; //5km
//Circle Marker/Node icons
/*var redpin = new google.maps.MarkerImage(); //Red Pushpin Icon
redpin.image = "http://maps.google.com/mapfiles/ms/icons/red-pushpin.png";
redpin.iconSize = new google.maps.Size(32, 32);
redpin.iconAnchor = new google.maps.Point(10, 32);*/
var redpin = new google.maps.MarkerImage('http://maps.google.com/mapfiles/ms/icons/red-pushpin.png',
// This marker is 20 pixels wide by 32 pixels tall.
new google.maps.Size(32, 32),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 0,32.
new google.maps.Point(10, 32));
/*var bluepin = new google.maps.MarkerImage(); //Blue Pushpin Icon
bluepin.image = "http://maps.google.com/mapfiles/ms/icons/blue-pushpin.png";
bluepin.iconSize = new google.maps.Size(32, 32);
bluepin.iconAnchor = new google.maps.Point(10, 32);*/
var bluepin = new google.maps.MarkerImage('http://maps.google.com/mapfiles/ms/icons/blue-pushpin.png',
// This marker is 20 pixels wide by 32 pixels tall.
new google.maps.Size(32, 32),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 0,32.
new google.maps.Point(10, 32));
function initialize() { //Initialize Google Map
//for(c in circle) {
//map = new GMap2(document.getElementById("map_canvas")); //New GMap object
var myOptions = {
zoom: 14,
center: map_center,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
/*addCircleResizeMarker(map_center[0], '0');
addCircleCenterMarker(map_center[0],'0');
drawCircle(map_center[0], radius, '0');
addCircleCenterMarker(map_center[1],'1');
addCircleResizeMarker(map_center[1], '1');
drawCircle(map_center[1], radius, '1');
*/
for(i=0; i<3; i++) {
Cobj[i] = {'map_center':new google.maps.LatLng(12.9735597+i, 77.6410402+i),
'Circle':null,
'CircleResizeMarker':null,
'radius':24+i
};
addCircleCenterMarker(i);
addCircleResizeMarker(i);
drawCircle(Cobj[i].map_center,Cobj[i].radius, i);
}
map.setCenter(map_center);
setMarkers(map, frndmap);
}
// Adds Circle Center marker
//radius
function addCircleCenterMarker(iii) {
point = Cobj[iii].map_center;
var markerOptions = { icon: bluepin, draggable: true };
CircleCenterMarker = new google.maps.Marker(point, markerOptions);
CircleCenterMarker.setMap(map); //Add marker on the map
//X= new google.maps.event();
google.maps.event.addListener(CircleCenterMarker, 'dragstart', function() { //Add drag start event
circle_moving = true;
});
google.maps.event.addListener(CircleCenterMarker, 'drag', function(point) { //Add drag event
drawCircle(point,Cobj[iii].radius, iii);
});
google.maps.event.addListener(CircleCenterMarker, 'dragend', function(point) { //Add drag end event
console.log(point.lng());
circle_moving = false;
drawCircle(point, Cobj[iii].radius, iii);
});
}
// Adds Circle Resize marker
// map_center
function addCircleResizeMarker(iii) {
point = Cobj[iii].map_center;
var resize_icon = new google.maps.MarkerImage(redpin);
resize_icon.maxHeight = 0;
var markerOptions = { icon: resize_icon, draggable: true };
Cobj[iii].CircleResizeMarker = new google.maps.Marker(point, markerOptions);
Cobj[iii].CircleResizeMarker.setMap(map); //Add marker on the map
google.maps.event.addListener(Cobj[iii].CircleResizeMarker, 'dragstart', function() { //Add drag start event
circle_resizing = true;
});
google.maps.event.addListener(Cobj[iii].CircleResizeMarker, 'drag', function(point) { //Add drag event
var new_point = new google.maps.LatLng(Cobj[iii].map_center.lat(), point.lng()); //to keep resize marker on horizontal line
var new_radius = new_point.distanceFrom(Cobj[iii].map_center) / 1000; //calculate new radius
//if (new_radius < min_radius) new_radius = min_radius;
//if (new_radius > max_radius) new_radius = max_radius;
drawCircle(Cobj[iii].map_center, new_radius, iii);
});
google.maps.event.addListener(Cobj[iii].CircleResizeMarker, 'dragend', function(point) { //Add drag end event
circle_resizing = false;
var new_point = new google.maps.LatLng(Cobj[iii].map_center.lat(), point.lng()); //to keep resize marker on horizontal line
var new_radius = new_point.distanceFrom(Cobj[iii].map_center) / 1000; //calculate new radius
//if (new_radius < min_radius) new_radius = min_radius;
//if (new_radius > max_radius) new_radius = max_radius;
console.log(new_radius);
drawCircle(Cobj[iii].map_center, new_radius, iii);
});
}
//Draw Circle with given radius and center
function drawCircle(center,new_radius, iii) {
//Circle = Circle[iii];
//Circle Drawing Algorithm from: http://koti.mbnet.fi/ojalesa/googlepages/circle.htm
//Number of nodes to form the circle
var nodes = new_radius * 40;
if(new_radius < 1) nodes = 40;
//calculating km/degree
xx = new google.maps.LatLng(center.lat() + 0.1, center.lng());
yy = new google.maps.LatLng(center.lat() , center.lng()+0.1);
var latConv = google.maps.geometry.spherical.computeDistanceBetween(center,xx)/100;//center.distanceFrom(new google.maps.LatLng(center.lat() + 0.1, center.lng())) / 100;
var lngConv = google.maps.geometry.spherical.computeDistanceBetween(center,yy)/100;//center.distanceFrom(new google.maps.LatLng(center.lat(), center.lng() + 0.1)) / 100;
CirclePoints = [];
var step = parseInt(360 / nodes) || 10;
var counter = 0;
for (var i = 0; i <= 360; i += step) {
var cLat = center.lat() + (new_radius / latConv * Math.cos(i * Math.PI / 180));
var cLng = center.lng() + (new_radius / lngConv * Math.sin(i * Math.PI / 180));
var point = new google.maps.LatLng(cLat, cLng);
CirclePoints.push(point);
counter++;
}
Cobj[iii].CircleResizeMarker.setPosition(CirclePoints[Math.floor(counter / 4)]); //place circle resize marker
CirclePoints.push(CirclePoints[0]); //close the circle polygon
if (Cobj[iii].Circle) {
//map.removeOverlay(Cobj[iii].Circle);
marker.setMap(null);
} //Remove existing Circle from Map
var fillColor = (circle_resizing || circle_moving) ? 'red' : 'blue'; //Set Circle Fill Color
console.log(CirclePoints);
Cobj[iii].Circle = new google.maps.Polygon(CirclePoints, '#FF0000', 2, 1, fillColor, 0.2); //New GPolygon object for Circle
//Cobj[iii].Circle.setMap(map); //Add Circle Overlay on the Map
//radius = new_radius; //Set global radius
//Cobj[iii].map_center = center; //Set global map_center
//if (!circle_resizing && !circle_moving)
//{
//Fit the circle if it is nor moving or resizing
// fitCircle(Cobj[iii].Circle);
//Circle drawing complete trigger function goes here
//}
}
//Fits the Map to Circle bounds
function fitCircle(Circle) {
bounds = Circle.getBounds();
map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
}
function setMarkers(map, locations) {
// Add markers to the map
// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.
// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var image = {
url: 'images/beachflag.png',
// This marker is 20 pixels wide by 32 pixels tall.
size: new google.maps.Size(20, 32),
// The origin for this image is 0,0.
origin: new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 0,32.
anchor: new google.maps.Point(0, 32)
};
var shadow = {
url: 'images/beachflag_shadow.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
size: new google.maps.Size(37, 32),
origin: new google.maps.Point(0,0),
anchor: new google.maps.Point(0, 32)
};
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var shape = {
coord: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
for (var i = 0; i < locations.length; i++) {
var beach = locations[i];
var myLatLng = new google.maps.LatLng(beach[1], beach[2]);
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
shadow: shadow,
icon: image,
shape: shape,
title: beach[0],
zIndex: beach[3]
});
}
}
</script>
<body onload="initialize()">
<div id="map_canvas" style="width:100%; height:450px"></div>
</body>
Your drawCircle function has
Cobj[iii].Circle = new google.maps.Polygon(CirclePoints, '#FF0000', 2, 1, fillColor, 0.2); //New GPolygon object for Circle
Personally I'd rather use google.maps.Circle instead, much simpler
https://developers.google.com/maps/documentation/javascript/reference#Circle
I have a google map using api version 3. I want to create markers with a custom icon and numbered labels. I've been trying to use what seems to be the most accepted method for this, the "labels.js" solution that I've provided below. However, no matter what I try, all the numbered overlays overlap all of the markers (despite me setting the marker and the label with the same zIndex). See the screenshot provided to see what I'm talking about. If you take a look at markers 14 and 15 in the screen, you'll see that the 15 label overlaps the 14 marker, but it shouldn't, it should be underneath the 14 marker.
http://i.imgur.com/QoYqcHJ.jpg
Many discussions about properly overlapping with custom overlays revolve around the line of code:
var pane = this.getPanes().overlayImage;
However, I have this in place. I'm setting each label overlay and marker pair to the same zIndex, and the properly overlapping markers proves that this zIndex increment is working. I've provided all of my code below, and have run into a brick wall. I've tried everything possible with no luck. Assume all variables have been properly declared.
label.js:
/* START label.js */
// Define the overlay, derived from google.maps.OverlayView
function Label(opt_options) {
// Initialization
this.setValues(opt_options);
// Here go the label styles
var span = this.span_ = document.createElement('span');
span.style.cssText = 'position: relative;' +
'white-space: nowrap;color:#666666;' +
'font-family: Arial; font-weight: bold;' +
'font-size: 11px;';
var div = this.div_ = document.createElement('div');
div.appendChild(span);
div.style.cssText = 'position: absolute; display: none;';
};
Label.prototype = new google.maps.OverlayView;
Label.prototype.onAdd = function () {
var pane = this.getPanes().overlayImage;
pane.appendChild(this.div_);
// Ensures the label is redrawn if the text or position is changed.
var me = this;
this.listeners_ = [
google.maps.event.addListener(this, 'position_changed',
function () { me.draw(); }),
google.maps.event.addListener(this, 'text_changed',
function () { me.draw(); }),
google.maps.event.addListener(this, 'zindex_changed',
function () { me.draw(); })
];
};
// Implement onRemove
Label.prototype.onRemove = function () {
this.div_.parentNode.removeChild(this.div_);
// Label is removed from the map, stop updating its position/text.
for (var i = 0, I = this.listeners_.length; i < I; ++i) {
google.maps.event.removeListener(this.listeners_[i]);
}
};
// Implement draw
Label.prototype.draw = function () {
var projection = this.getProjection();
var div = this.div_;
// Some custom code to properly get the offset for the numbered label for each marker
var labelOffset;
if (parseInt(this.get('text').toString()) < 10) labelOffset = new google.maps.Point(6, -35);
else labelOffset = new google.maps.Point(9, -35);
var point1 = this.map.getProjection().fromLatLngToPoint(
(this.get('position') instanceof google.maps.LatLng) ? this.get('position') : this.map.getCenter()
);
var point2 = new google.maps.Point(
((typeof (labelOffset.x) == 'number' ? labelOffset.x : 0) / Math.pow(2, map.getZoom())) || 0,
((typeof (labelOffset.y) == 'number' ? labelOffset.y : 0) / Math.pow(2, map.getZoom())) || 0
);
var offSetPosition = this.map.getProjection().fromPointToLatLng(new google.maps.Point(
point1.x - point2.x,
point1.y + point2.y
));
var position = projection.fromLatLngToDivPixel(offSetPosition);
// End custom code
div.style.left = position.x + 'px';
div.style.top = position.y + 'px';
div.style.display = 'block';
div.style.zIndex = this.get('zIndex'); //ALLOW LABEL TO OVERLAY MARKER
this.span_.innerHTML = this.get('text').toString();
};
/* END label.js */
Code to create map with markers:
var mapOptions = {
zoom: myZoom,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false
};
map = new google.maps.Map(document.getElementById("gmap"), mapOptions);
/* Insert logic here to iterate and add each marker */
// This function is called for every marker, i increases by 1 each call
function addMarker(latlng, mylabel, isShowroom, data, type, i) {
var markerImage;
var labelColor = '#666666';
if (isShowroom) {
markerImage = 'http://www.subzero-wolf.com/common/images/locator/pin-showroom.png';
} else {
if (type == 'service') {
markerImage = '/common/images/locator/pin-dealer.png';
} else if (type == 'parts') {
markerImage = '/common/images/locator/pin-parts.png';
} else {
markerImage = '/common/images/locator/pin-dealer.png';
}
}
var myMarker = new google.maps.Marker({
position: latlng,
draggable: false,
clickable: true,
map: map,
icon: markerImage,
zIndex: isShowroom ? 9999 : i
});
var html = "test content"
myMarker['isShowroom'] = isShowroom;
myMarker['infowindow'] = new google.maps.InfoWindow({
content: html
});
google.maps.event.addListener(myMarker, 'click', function() {
this['infowindow'].open(map, this);
});
// Dont show a label for the showroom because this is the marker with the star icon, no number needed
if (!isShowroom) {
var label = new Label({
map: map
});
label.set('zIndex', i);
label.bindTo('position', myMarker, 'position');
label.set('text', mylabel);
}
markerArray.push(myMarker);
}
I'm using this example to set up a route with more then 8 markers.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Google Maps JavaScript API v3 Example: Directions Waypoints</title>
<style>
#map{
width: 100%;
height: 450px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script>
jQuery(function() {
var stops = [
{"Geometry":{"Latitude":52.1615470947258,"Longitude":20.80514430999756}},
{"Geometry":{"Latitude":52.15991486090931,"Longitude":20.804049968719482}},
{"Geometry":{"Latitude":52.15772967999426,"Longitude":20.805788040161133}},
{"Geometry":{"Latitude":52.15586034371232,"Longitude":20.80460786819458}},
{"Geometry":{"Latitude":52.15923693975469,"Longitude":20.80113172531128}},
{"Geometry":{"Latitude":52.159849043774074, "Longitude":20.791990756988525}},
{"Geometry":{"Latitude":52.15986220720892,"Longitude":20.790467262268066}},
{"Geometry":{"Latitude":52.16202095784738,"Longitude":20.7806396484375}},
{"Geometry":{"Latitude":52.16088894313116,"Longitude":20.77737808227539}},
{"Geometry":{"Latitude":52.15255590234335,"Longitude":20.784244537353516}},
{"Geometry":{"Latitude":52.14747369312591,"Longitude":20.791218280792236}},
{"Geometry":{"Latitude":52.14963304460396,"Longitude":20.79387903213501}}
] ;
var map = new window.google.maps.Map(document.getElementById("map"));
// new up complex objects before passing them around
var directionsDisplay = new window.google.maps.DirectionsRenderer();
var directionsService = new window.google.maps.DirectionsService();
Tour_startUp(stops);
window.tour.loadMap(map, directionsDisplay);
window.tour.fitBounds(map);
if (stops.length > 1)
window.tour.calcRoute(directionsService, directionsDisplay);
});
function Tour_startUp(stops) {
if (!window.tour) window.tour = {
updateStops: function (newStops) {
stops = newStops;
},
// map: google map object
// directionsDisplay: google directionsDisplay object (comes in empty)
loadMap: function (map, directionsDisplay) {
var myOptions = {
zoom: 13,
center: new window.google.maps.LatLng(51.507937, -0.076188), // default to London
mapTypeId: window.google.maps.MapTypeId.ROADMAP
};
map.setOptions(myOptions);
directionsDisplay.setMap(map);
},
fitBounds: function (map) {
var bounds = new window.google.maps.LatLngBounds();
// extend bounds for each record
jQuery.each(stops, function (key, val) {
var myLatlng = new window.google.maps.LatLng(val.Geometry.Latitude, val.Geometry.Longitude);
bounds.extend(myLatlng);
});
map.fitBounds(bounds);
},
calcRoute: function (directionsService, directionsDisplay) {
var batches = [];
var itemsPerBatch = 10; // google API max = 10 - 1 start, 1 stop, and 8 waypoints
var itemsCounter = 0;
var wayptsExist = stops.length > 0;
while (wayptsExist) {
var subBatch = [];
var subitemsCounter = 0;
for (var j = itemsCounter; j < stops.length; j++) {
subitemsCounter++;
subBatch.push({
location: new window.google.maps.LatLng(stops[j].Geometry.Latitude, stops[j].Geometry.Longitude),
stopover: true
});
if (subitemsCounter == itemsPerBatch)
break;
}
itemsCounter += subitemsCounter;
batches.push(subBatch);
wayptsExist = itemsCounter < stops.length;
// If it runs again there are still points. Minus 1 before continuing to
// start up with end of previous tour leg
itemsCounter--;
}
// now we should have a 2 dimensional array with a list of a list of waypoints
var combinedResults;
var unsortedResults = [{}]; // to hold the counter and the results themselves as they come back, to later sort
var directionsResultsReturned = 0;
for (var k = 0; k < batches.length; k++) {
var lastIndex = batches[k].length - 1;
var start = batches[k][0].location;
var end = batches[k][lastIndex].location;
// trim first and last entry from array
var waypts = [];
waypts = batches[k];
waypts.splice(0, 1);
waypts.splice(waypts.length - 1, 1);
var request = {
origin: start,
destination: end,
waypoints: waypts,
travelMode: window.google.maps.TravelMode.WALKING
};
(function (kk) {
directionsService.route(request, function (result, status) {
if (status == window.google.maps.DirectionsStatus.OK) {
var unsortedResult = { order: kk, result: result };
unsortedResults.push(unsortedResult);
directionsResultsReturned++;
if (directionsResultsReturned == batches.length) // we've received all the results. put to map
{
// sort the returned values into their correct order
unsortedResults.sort(function (a, b) { return parseFloat(a.order) - parseFloat(b.order); });
var count = 0;
for (var key in unsortedResults) {
if (unsortedResults[key].result != null) {
if (unsortedResults.hasOwnProperty(key)) {
if (count == 0) // first results. new up the combinedResults object
combinedResults = unsortedResults[key].result;
else {
// only building up legs, overview_path, and bounds in my consolidated object. This is not a complete
// directionResults object, but enough to draw a path on the map, which is all I need
combinedResults.routes[0].legs = combinedResults.routes[0].legs.concat(unsortedResults[key].result.routes[0].legs);
combinedResults.routes[0].overview_path = combinedResults.routes[0].overview_path.concat(unsortedResults[key].result.routes[0].overview_path);
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getNorthEast());
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getSouthWest());
}
count++;
}
}
}
directionsDisplay.setDirections(combinedResults);
}
}
});
})(k);
}
}
};
}
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>
It works like a charm but I have problem to setup an infowindow for each waypoint. I would like to leave markers names like A , B ,C or generate it in otherway but to keep A,B,C or 1,2,3 pattern and I want to add infowindow to each marker which contains title text and link.
I was trying to find any info or examples but nothing works. Maybe someone have and idea how to easily add infowindow to this code.
Here is an example that draws the directions from scratch with custom markers and infowindows:
Example
If you use the suppressInfoWindows option on the DirectionsRenderer, you can just use the part of it that creates the markers and their associated infowindows.
Working example based on your code
Code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Google Maps JavaScript API v3 Example: Directions Waypoints</title>
<style>
#map{
width: 100%;
height: 450px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script>
jQuery(function() {
var stops = [
{"Geometry":{"Latitude":52.1615470947258,"Longitude":20.80514430999756}},
{"Geometry":{"Latitude":52.15991486090931,"Longitude":20.804049968719482}},
{"Geometry":{"Latitude":52.15772967999426,"Longitude":20.805788040161133}},
{"Geometry":{"Latitude":52.15586034371232,"Longitude":20.80460786819458}},
{"Geometry":{"Latitude":52.15923693975469,"Longitude":20.80113172531128}},
{"Geometry":{"Latitude":52.159849043774074, "Longitude":20.791990756988525}},
{"Geometry":{"Latitude":52.15986220720892,"Longitude":20.790467262268066}},
{"Geometry":{"Latitude":52.16202095784738,"Longitude":20.7806396484375}},
{"Geometry":{"Latitude":52.16088894313116,"Longitude":20.77737808227539}},
{"Geometry":{"Latitude":52.15255590234335,"Longitude":20.784244537353516}},
{"Geometry":{"Latitude":52.14747369312591,"Longitude":20.791218280792236}},
{"Geometry":{"Latitude":52.14963304460396,"Longitude":20.79387903213501}}
] ;
var map = new window.google.maps.Map(document.getElementById("map"));
// new up complex objects before passing them around
var directionsDisplay = new window.google.maps.DirectionsRenderer({suppressMarkers: true});
var directionsService = new window.google.maps.DirectionsService();
Tour_startUp(stops);
window.tour.loadMap(map, directionsDisplay);
window.tour.fitBounds(map);
if (stops.length > 1)
window.tour.calcRoute(directionsService, directionsDisplay);
});
function Tour_startUp(stops) {
if (!window.tour) window.tour = {
updateStops: function (newStops) {
stops = newStops;
},
// map: google map object
// directionsDisplay: google directionsDisplay object (comes in empty)
loadMap: function (map, directionsDisplay) {
var myOptions = {
zoom: 13,
center: new window.google.maps.LatLng(51.507937, -0.076188), // default to London
mapTypeId: window.google.maps.MapTypeId.ROADMAP
};
map.setOptions(myOptions);
directionsDisplay.setMap(map);
},
fitBounds: function (map) {
var bounds = new window.google.maps.LatLngBounds();
// extend bounds for each record
jQuery.each(stops, function (key, val) {
var myLatlng = new window.google.maps.LatLng(val.Geometry.Latitude, val.Geometry.Longitude);
bounds.extend(myLatlng);
});
map.fitBounds(bounds);
},
calcRoute: function (directionsService, directionsDisplay) {
var batches = [];
var itemsPerBatch = 10; // google API max = 10 - 1 start, 1 stop, and 8 waypoints
var itemsCounter = 0;
var wayptsExist = stops.length > 0;
while (wayptsExist) {
var subBatch = [];
var subitemsCounter = 0;
for (var j = itemsCounter; j < stops.length; j++) {
subitemsCounter++;
subBatch.push({
location: new window.google.maps.LatLng(stops[j].Geometry.Latitude, stops[j].Geometry.Longitude),
stopover: true
});
if (subitemsCounter == itemsPerBatch)
break;
}
itemsCounter += subitemsCounter;
batches.push(subBatch);
wayptsExist = itemsCounter < stops.length;
// If it runs again there are still points. Minus 1 before continuing to
// start up with end of previous tour leg
itemsCounter--;
}
// now we should have a 2 dimensional array with a list of a list of waypoints
var combinedResults;
var unsortedResults = [{}]; // to hold the counter and the results themselves as they come back, to later sort
var directionsResultsReturned = 0;
for (var k = 0; k < batches.length; k++) {
var lastIndex = batches[k].length - 1;
var start = batches[k][0].location;
var end = batches[k][lastIndex].location;
// trim first and last entry from array
var waypts = [];
waypts = batches[k];
waypts.splice(0, 1);
waypts.splice(waypts.length - 1, 1);
var request = {
origin: start,
destination: end,
waypoints: waypts,
travelMode: window.google.maps.TravelMode.WALKING
};
(function (kk) {
directionsService.route(request, function (result, status) {
if (status == window.google.maps.DirectionsStatus.OK) {
var unsortedResult = { order: kk, result: result };
unsortedResults.push(unsortedResult);
directionsResultsReturned++;
if (directionsResultsReturned == batches.length) // we've received all the results. put to map
{
// sort the returned values into their correct order
unsortedResults.sort(function (a, b) { return parseFloat(a.order) - parseFloat(b.order); });
var count = 0;
for (var key in unsortedResults) {
if (unsortedResults[key].result != null) {
if (unsortedResults.hasOwnProperty(key)) {
if (count == 0) // first results. new up the combinedResults object
combinedResults = unsortedResults[key].result;
else {
// only building up legs, overview_path, and bounds in my consolidated object. This is not a complete
// directionResults object, but enough to draw a path on the map, which is all I need
combinedResults.routes[0].legs = combinedResults.routes[0].legs.concat(unsortedResults[key].result.routes[0].legs);
combinedResults.routes[0].overview_path = combinedResults.routes[0].overview_path.concat(unsortedResults[key].result.routes[0].overview_path);
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getNorthEast());
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getSouthWest());
}
count++;
}
}
}
directionsDisplay.setDirections(combinedResults);
var legs = combinedResults.routes[0].legs;
// alert(legs.length);
for (var i=0; i < legs.length;i++){
var markerletter = "A".charCodeAt(0);
markerletter += i;
markerletter = String.fromCharCode(markerletter);
createMarker(directionsDisplay.getMap(),legs[i].start_location,"marker"+i,"some text for marker "+i+"<br>"+legs[i].start_address,markerletter);
}
var i=legs.length;
var markerletter = "A".charCodeAt(0);
markerletter += i;
markerletter = String.fromCharCode(markerletter);
createMarker(directionsDisplay.getMap(),legs[legs.length-1].end_location,"marker"+i,"some text for the "+i+"marker<br>"+legs[legs.length-1].end_address,markerletter);
}
}
});
})(k);
}
}
};
}
var infowindow = new google.maps.InfoWindow(
{
size: new google.maps.Size(150,50)
});
var icons = new Array();
icons["red"] = new google.maps.MarkerImage("mapIcons/marker_red.png",
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(20, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 9,34.
new google.maps.Point(9, 34));
function getMarkerImage(iconStr) {
if ((typeof(iconStr)=="undefined") || (iconStr==null)) {
iconStr = "red";
}
if (!icons[iconStr]) {
icons[iconStr] = new google.maps.MarkerImage("http://www.google.com/mapfiles/marker"+ iconStr +".png",
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(20, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 6,20.
new google.maps.Point(9, 34));
}
return icons[iconStr];
}
// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.
// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var iconImage = new google.maps.MarkerImage('mapIcons/marker_red.png',
// This marker is 20 pixels wide by 34 pixels tall.
new google.maps.Size(20, 34),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is at 9,34.
new google.maps.Point(9, 34));
var iconShadow = new google.maps.MarkerImage('http://www.google.com/mapfiles/shadow50.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
new google.maps.Size(37, 34),
new google.maps.Point(0,0),
new google.maps.Point(9, 34));
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var iconShape = {
coord: [9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0],
type: 'poly'
};
function createMarker(map, latlng, label, html, color) {
// alert("createMarker("+latlng+","+label+","+html+","+color+")");
var contentString = '<b>'+label+'</b><br>'+html;
var marker = new google.maps.Marker({
position: latlng,
map: map,
shadow: iconShadow,
icon: getMarkerImage(color),
shape: iconShape,
title: label,
zIndex: Math.round(latlng.lat()*-100000)<<5
});
marker.myname = label;
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
return marker;
}
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>