I'm trying to draw a bezier curve in google maps by using a SVG path in a Polyline. At first I used a Marker instead similar to Curved line between two near points in google maps, which gave the results that I'm after. However, since it's not possible to drag the map under the marker, I can't use this method.
So I switched to a Polyline instead of a marker. Now I get the same good results when I zoom out, but when I zoom in the curve becomes "cropped".
Here is the code:
function initialize() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var bounds = new google.maps.LatLngBounds();
bounds.extend(coord1);
bounds.extend(coord2);
map.fitBounds(bounds);
pLineOpt = {
path: [coord1, coord2],
strokeWeight: 4,
strokeOpacity: 0,
map: map,
}
pLine = new google.maps.Polyline(pLineOpt);
var markers = [
new google.maps.Marker({
position: coord1,
map: map
}),
new google.maps.Marker({
position: coord2,
map: map
})
];
google.maps.event.addListener(map, 'zoom_changed', function () {
//points
var p1 = map.getProjection().fromLatLngToPoint(coord1);
var p2 = map.getProjection().fromLatLngToPoint(coord2);
//distance between points
var d = new google.maps.Point(p2.x - p1.x, p2.y - p1.y);
var lengthSqr = d.x * d.x + d.y * d.y;
//middle point
var m = new google.maps.Point(d.x / 2, d.y / 2);
//slope of perpendicular line
var perpK = -d.x / d.y;
//distance to control point
var ratioDistanceControlLengthSqr = 9;
var controlDSqr = lengthSqr / ratioDistanceControlLengthSqr;
var p3dX = Math.sqrt(controlDSqr / (Math.pow(perpK, 2) + 1));
var p3dY = perpK * p3dX;
//control point
var p3 = new google.maps.Point(m.x - p3dX, m.y - p3dY);
//curve path
var path = "M 0 0 q " + p3.x + " " + p3.y + " " + d.x + " " + d.y;
//calc scale
var zoom = map.getZoom();
var scale = 1 / (Math.pow(2, -zoom));
var icon = {
path: path,
scale: scale,
strokeWeight: 3,
strokeOpacity: 1,
};
pLineOpt.icons = [{
fixedRotation: true,
icon: icon,
offset: '0'
}];
pLine.setOptions(pLineOpt);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
I have made a jsfiddle with the code: http://jsfiddle.net/s7djLzyd/3/
Does anyone know why the Polyline is cropped when zooming, and if there is a way around this?
Thanks
You need to fix your Polyline Options :
pLineOpt = {
path: [coord1, coord2],
geodesic: true,
strokeColor: '#000',
strokeOpacity: 1.0,
strokeWeight: 4
}
Please try this code snippet : May be this is what you want... :)
function initialize() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var bounds = new google.maps.LatLngBounds();
bounds.extend(coord1);
bounds.extend(coord2);
map.fitBounds(bounds);
pLineOpt = {
path: [coord1, coord2],
geodesic: true,
strokeColor: '#000',
strokeOpacity: 1.0,
strokeWeight: 4
}
pLine = new google.maps.Polyline(pLineOpt);
var markers = [
new google.maps.Marker({
position: coord1,
map: map
}),
new google.maps.Marker({
position: coord2,
map: map
})];
pLine.setMap(map);
google.maps.event.addListener(map, 'zoom_changed', function () {
});
}
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?sensor=false&libraries=geometry,places&ext=.js"></script>
<div id="map-canvas"></div>
From this related question: Google Maps API: Bézier curve polyline wrap
var curvedLine = new GmapsCubicBezier(
49.165876, -123.152446,
33.811192,-115.032444,
30.820807,-123.749998,
25.786328, -80.193694,
0.01, map);
example fiddle
code snippet:
var map;
var origLoc = new google.maps.LatLng(45, -85);
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(33.811192, -115.032444),
zoom: 3
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var marker1 = new google.maps.Marker({
position: coord1,
title: "marker 1",
map: map
});
var marker2 = new google.maps.Marker({
position: coord2,
title: "marker 2",
map: map
});
var curvedLine = new GmapsCubicBezier(
49.165876, -123.152446,
33.811192, -115.032444,
30.820807, -123.749998,
25.786328, -80.193694,
0.01, map);
}
google.maps.event.addDomListener(window, 'load', initialize);
var GmapsCubicBezier = function(lat1, long1, lat2, long2, lat3, long3, lat4, long4, resolution, map) {
var points = [];
for (it = 0; it <= 1; it += resolution) {
points.push(this.getBezier({
x: lat1,
y: long1
}, {
x: lat2,
y: long2
}, {
x: lat3,
y: long3
}, {
x: lat4,
y: long4
}, it));
}
for (var i = 0; i < points.length - 1; i++) {
var Line = new google.maps.Polyline({
path: [new google.maps.LatLng(points[i].x, points[i].y), new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false)],
geodesic: true,
strokeOpacity: 1,
strokeColor: 'black',
/* icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'violet',
strokeOpacity: 1,
strokeWeight: 4
},
repeat: '36px'
}, {
icon: {
path: 'M -1,-2 -1,2',
strokeColor: 'black',
strokeOpacity: 1,
strokeWeight: 2
},
repeat: '36px'
}] */
});
Line.setMap(map);
}
// connect end of line to first point
var Line = new google.maps.Polyline({
path: [new google.maps.LatLng(lat1,long1),new google.maps.LatLng(points[points.length-1].x, points[points.length-1].y)],
geodesic: true,
strokeOpacity: 1,
strokeColor: 'black',
/* icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'violet',
strokeOpacity: 1,
strokeWeight: 4
},
repeat: '36px'
}, {
icon: {
path: 'M -1,-2 -1,2',
strokeColor: 'black',
strokeOpacity: 1,
strokeWeight: 2
},
repeat: '36px'
}] */
});
Line.setMap(map);
return Line;
};
GmapsCubicBezier.prototype = {
B1: function(t) {
return t * t * t;
},
B2: function(t) {
return 3 * t * t * (1 - t);
},
B3: function(t) {
return 3 * t * (1 - t) * (1 - t);
},
B4: function(t) {
return (1 - t) * (1 - t) * (1 - t);
},
getBezier: function(C1, C2, C3, C4, percent) {
var pos = {};
pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
return pos;
}
};
html,
body,
#map {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
<div id="map" style="float:left;width:100%;height:100%;"></div>
Related
I am trying to make a figure here. But the browser is giving the following error. I am trying to use the google maps api with conjunction to geometry library. But not able to run it.
Error:curve.html:79 Uncaught TypeError: Cannot read property 'computeOffset' of undefined
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 50%;
}
</style>
</head>
<body>
<div id="map"></div>
<div>
</br>
<input type="number" name="" id="Radius" placeholder="FrontFace" style="margin:30px" onchange="initMap()">
</br>
<input type="number" name="" id="Backface" placeholder="BackFace" style="margin:30px" onchange="initMap()">
</div>
<script>
var map;
function initMap() {
debugger;
var radius=parseInt(document.getElementById("Radius").value);
var radius2=parseInt(document.getElementById("Backface").value);
var cen= {lat: -34.397, lng: 150.644}
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
google.maps.event.addListener(map,"click",function(event){
var lat=event.latLng.lat();
var lng=event.latLng.lng();
cen={lat:lat,lng:lng};
});
map.addListener('click', function(e) {
debugger;
placeMarkerAndPanTo(e.latLng, map);
// drawCircle(map,cen,radius);
drawBlastClearance(map,cen,radius,radius2)
});
}
function convertLat(r,angle,cen)
{
debugger;
sin=Math.sin(Math.PI*(angle/180))
dy=((r*sin)/ (110540) );
return cen.lat+dy;
}
function convertLng(r,angle,cen)
{
debugger;
cos=Math.cos(Math.PI*(angle/180))
dx=((r*cos)/ (11320*Math.cos(Math.PI*(angle/180))) );
return cen.lng+dx;
}
function drawBlastClearance(map,cen,r1,r2){
debugger;
LatLng=google.maps.LatLng
spherical=google.maps.spherical;
//CODE TO GENERATE BLAST CLEARANCE ZONE POINTS
Apos=spherical.computeOffset(cen, 158, -45);
Bpos= spherical.computeOffset(cen, 156, 45);
CPos=spherical.computeOffset(cen, 80, 237);
DPos=spherical.computeOffset(cen, 80, 113);
///LINE 1
var pos1 = new LatLng(Apos.lat, Apos.lng);
var pos2 = new LatLng(Bpos.lat, Bpos.lng);
var pos3 = new LatLng(CPos.lat, CPos.lng);
var pos4 = new LatLng(DPos.lat, DPos.lng);
var marker = new google.maps.Marker({
position: Apos,
map: map,
label:'A',
title: 'Hello World!'
});
var marker1 = new google.maps.Marker({
position: Bpos,
map: map,
label:'B',
dragable:true,
});
var marker2 = new google.maps.Marker({
position: CPos,
label:'C',
map: map,
});
var marker3 = new google.maps.Marker({
position: DPos,
map: map,
label:'D',
});
var line = new google.maps.Polyline({
path: [
DPos,Bpos
],
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
var line1 = new google.maps.Polyline({
path: [
CPos,Apos
],
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
function updateCurveMarker() {
Point=google.maps.Point;
curvature=-.45;
var curveMarker;
var pos1 = marker.getPosition(), // latlng
pos2 = marker1.getPosition(),
projection = map.getProjection(),
p1 = projection.fromLatLngToPoint(pos1), // xy
p2 = projection.fromLatLngToPoint(pos2);
// Calculate the arc.
// To simplify the math, these points
// are all relative to p1:
var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint (p2 relative to p1)
m = new Point(e.x / 2, e.y / 2), // midpoint
o = new Point(e.y, -e.x), // orthogonal
c = new Point( // curve control point
m.x + curvature * o.x,
m.y + curvature * o.y);
var pathDef = 'M 0,0 ' +
'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
var zoom = map.getZoom(),
scale = 1 / (Math.pow(2, -zoom));
var symbol = {
path: pathDef,
scale: scale,
strokeWeight: 2,
fillColor: '#FF0000'
};
if (!curveMarker) {
curveMarker = new google.maps.Marker({
position: pos1,
clickable: false,
icon: symbol,
zIndex: 0, // behind the other markers
map: map
});
} else {
curveMarker.setOptions({
position: pos1,
icon: symbol,
});
}
}
google.maps.event.addListener(map, 'projection_changed', updateCurveMarker);
google.maps.event.addListener(map, 'zoom_changed', updateCurveMarker);
google.maps.event.addListener(marker1, 'position_changed', updateCurveMarker);
google.maps.event.addListener(marker2, 'position_changed', updateCurveMarker);
function updateCurveMarker1() {
Point=google.maps.Point;
curvature=.45;
var curveMarker;
var pos1 = marker2.getPosition(), // latlng
pos2 = marker3.getPosition(),
projection = map.getProjection(),
p1 = projection.fromLatLngToPoint(pos1), // xy
p2 = projection.fromLatLngToPoint(pos2);
// Calculate the arc.
// To simplify the math, these points
// are all relative to p1:
var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint (p2 relative to p1)
m = new Point(e.x / 2, e.y / 2), // midpoint
o = new Point(e.y, -e.x), // orthogonal
c = new Point( // curve control point
m.x + curvature * o.x,
m.y + curvature * o.y);
var pathDef = 'M 0,0 ' +
'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
var zoom = map.getZoom(),
scale = 1 / (Math.pow(2, -zoom));
var symbol = {
path: pathDef,
scale: scale,
strokeWeight: 2,
fillColor: '#FF0000'
};
if (!curveMarker) {
curveMarker = new google.maps.Marker({
position: pos1,
clickable: false,
icon: symbol,
zIndex: 0, // behind the other markers
map: map
});
} else {
curveMarker.setOptions({
position: pos1,
icon: symbol,
});
}
}
google.maps.event.addListener(map, 'projection_changed', updateCurveMarker1);
google.maps.event.addListener(map, 'zoom_changed', updateCurveMarker1);
google.maps.event.addListener(marker1, 'position_changed', updateCurveMarker1);
google.maps.event.addListener(marker2, 'position_changed', updateCurveMarker1);
}
var markersArray=[];
var circleArray=[];
function placeMarkerAndPanTo(latLng, map) {
while(markersArray.length) { markersArray.pop().setMap(null); }
var marker = new google.maps.Marker({
position: latLng,
map: map
});
markersArray.push(marker) ;
}
function drawCircle(map,cen,radii)
{
while(circleArray.length){circleArray.pop().setMap(null);}
var cityCircle = new google.maps.Circle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: map,
center:cen,
radius: radii
});
circleArray.push(cityCircle);
}
</script>
<!-- <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCVhit3Aj--xP28zBUyThLQ7bAHOt72B1c&cal async defer></script> -->
<!-- lback=initMap libraries=geometry"&sensor=false
-->
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCVhit3Aj--xP28zBUyThLQ7bAHOt72B1c&libraries=geometry,places">
</script>
</body>
</html>
You have a typo in your code. This is incorrect:
spherical=google.maps.spherical;
It should be
spherical=google.maps.geometry.spherical;
fiddle
Can anyone please help me in connecting specified points with an arc or parabola or any curve line in my google map? It is currently connected with a straight line. I have tried using the other stack overflow question where this was asked but those codes only connects two points, I might have multiple markers in the future so i need something that can be resused over and over... Please see the codes below...
<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
var x=new google.maps.LatLng(14.560774500000008,121.02631410000006);
var rcbc=new google.maps.LatLng(14.560648, 121.016781);
var powerplant=new google.maps.LatLng(14.565066, 121.036184);
var trafalgar=new google.maps.LatLng(14.560774500000008,121.02631410000006);
var mapua=new google.maps.LatLng(14.562883, 121.022039);
function initialize()
{
var mapProp = {
center:x,
zoom:15,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
var myTrip=[trafalgar,rcbc];
var myTrip2=[rcbc,powerplant];
var flightPath2=new google.maps.Polyline({
path:myTrip2,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
var flightPath=new google.maps.Polyline({
path:myTrip,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
var marker=new google.maps.Marker({
position:x,
});
var marker2=new google.maps.Marker({
position:london,
});
var marker3=new google.maps.Marker({
position:rcbc,
});
var marker4=new google.maps.Marker({
position:powerplant,
});
marker4.setMap(map);
marker3.setMap(map);
marker2.setMap(map);
marker.setMap(map);
flightPath.setMap(map);
flightPath2.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="googleMap" style="width:1000px;height:680px;"></div>
</body>
</html>
One option would be to use the code from this related question: How to display curved polyline on one side of a straight line? (a Bezier curve).
proof of concept fiddle
code snippet:
function drawCurve(P1, P2, map) {
var lineLength = google.maps.geometry.spherical.computeDistanceBetween(P1, P2);
var lineHeading = google.maps.geometry.spherical.computeHeading(P1, P2);
if (lineHeading < 0) {
var lineHeading1 = lineHeading + 45;
var lineHeading2 = lineHeading + 135;
} else {
var lineHeading1 = lineHeading + -45;
var lineHeading2 = lineHeading + -135;
}
var pA = google.maps.geometry.spherical.computeOffset(P1, lineLength / 2.2, lineHeading1);
var pB = google.maps.geometry.spherical.computeOffset(P2, lineLength / 2.2, lineHeading2);
var curvedLine = new GmapsCubicBezier(P1, pA, pB, P2, 0.01, map);
}
var x = new google.maps.LatLng(14.560774500000008, 121.02631410000006);
var london = new google.maps.LatLng(51.5073509, -0.12775829999998223);
var rcbc = new google.maps.LatLng(14.560648, 121.016781);
var powerplant = new google.maps.LatLng(14.565066, 121.036184);
var trafalgar = new google.maps.LatLng(14.560774500000008, 121.02631410000006);
var mapua = new google.maps.LatLng(14.562883, 121.022039);
function initialize() {
var mapProp = {
center: x,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var myTrip = [trafalgar, rcbc];
var myTrip2 = [rcbc, powerplant];
drawCurve(trafalgar, rcbc, map);
drawCurve(rcbc, powerplant, map);
var marker = new google.maps.Marker({
position: x,
});
var marker2 = new google.maps.Marker({
position: london,
});
var marker3 = new google.maps.Marker({
position: rcbc,
});
var marker4 = new google.maps.Marker({
position: powerplant,
});
marker4.setMap(map);
marker3.setMap(map);
marker2.setMap(map);
marker.setMap(map);
flightPath.setMap(map);
flightPath2.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
// original Belzier Curve code from nicoabie's answer to this question on StackOverflow:
// https://stackoverflow.com/questions/5347984/letting-users-draw-curved-lines-on-a-google-map
var GmapsCubicBezier = function(latlong1, latlong2, latlong3, latlong4, resolution, map) {
var lat1 = latlong1.lat();
var long1 = latlong1.lng();
var lat2 = latlong2.lat();
var long2 = latlong2.lng();
var lat3 = latlong3.lat();
var long3 = latlong3.lng();
var lat4 = latlong4.lat();
var long4 = latlong4.lng();
var points = [];
for (it = 0; it <= 1; it += resolution) {
points.push(this.getBezier({
x: lat1,
y: long1
}, {
x: lat2,
y: long2
}, {
x: lat3,
y: long3
}, {
x: lat4,
y: long4
}, it));
}
var path = [];
for (var i = 0; i < points.length - 1; i++) {
path.push(new google.maps.LatLng(points[i].x, points[i].y));
path.push(new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false));
}
var Line = new google.maps.Polyline({
path: path,
geodesic: true,
strokeColor: "##35495e",
strokeOpacity: 0.8,
strokeWeight: 3
/* dashed line:
icons: [{
icon: {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 4
},
offset: '0',
repeat: '20px'
}], */
});
Line.setMap(map);
return Line;
};
GmapsCubicBezier.prototype = {
B1: function(t) {
return t * t * t;
},
B2: function(t) {
return 3 * t * t * (1 - t);
},
B3: function(t) {
return 3 * t * (1 - t) * (1 - t);
},
B4: function(t) {
return (1 - t) * (1 - t) * (1 - t);
},
getBezier: function(C1, C2, C3, C4, percent) {
var pos = {};
pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
return pos;
}
};
html,
body,
#googleMap {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="googleMap"></div>
When you load the Google Maps JS, specify the geometry library:
<script src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
This means you can then add the geodesic attribute when you create the polylines, e.g.
var flightPath2=new google.maps.Polyline({
path:myTrip2,
geodesic: true,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
"When true, edges of the polygon are interpreted as geodesic and will
follow the curvature of the Earth. When false, edges of the polygon
are rendered as straight lines in screen space."
See Google's examples and documentation:
https://developers.google.com/maps/documentation/javascript/geometry#Navigation
https://developers.google.com/maps/documentation/javascript/examples/geometry-headings
https://developers.google.com/maps/documentation/javascript/3.exp/reference#PolylineOptions
I've been playing with Google Map API for a few days now and it's pretty straight forward for the most part, but one thing that we need to do, I can't figure out. I've played with the labels as you can see in the example below, but I'm unable to give them to look that I have in the image below. Can someone point me to a reference so I can achieve my requirements?
If your looking for the makerwithlable.js, you can get it from here.. Its where I got it:
https://code.google.com/p/google-maps-utility-library-v3/source/browse/trunk/markerwithlabel/src/markerwithlabel.js?r=288
<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script src="markerwithlabel.js" type="text/javascript"></script>
<script>
{
var showOnStartInfoWindows = true;
//create locations..
var arrayAll = [];
var marker = [];
var jax = new google.maps.LatLng(30.318028, -81.674474);
var leesburg = new google.maps.LatLng(28.810750, -81.880056);
var map = null;
arrayAll[0] = {loc: jax, size: 5000, info: "Jacksonville, FL 32204"};
arrayAll[1] = {loc: leesburg, size: 1000, info: "Leesburg, FL"};
//EO create locations..
}
function initialize()
{
//center the map on Jacksonville
var mapProp = {
center:arrayAll[0].loc,
zoom:6,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
//set google's API and pass the DIV by ID.
map = new google.maps.Map(document.getElementById("googleMap"),mapProp);
var bounds = new google.maps.LatLngBounds(leesburg, jax);
map.fitBounds(bounds);
var maxSize = 0;
for(var i = 0; i < arrayAll.length; i++)
{
if(maxSize<arrayAll[i].size)
maxSize = arrayAll[i].size;
}
for(var i = 0; i < arrayAll.length; i++)
{
var size = Math.round((arrayAll[i].size/maxSize)*100);
//create marker
marker[i] = new google.maps.Marker({
position:arrayAll[i].loc,
map: map,
title: 'Right-Click to zoom all the way in.\nLeft-Click to zoom to a state level.',
draggable: false,
raiseOnDrag: false,
labelAnchor: new google.maps.Point(22, 0),
labelClass: "googleLabel", // the CSS class for the label
labelContent: arrayAll[i].info,
icon: {
path: google.maps.SymbolPath.CIRCLE, //BACKWARD_CLOSED_ARROW
fillOpacity: 0.3,
fillColor: '#0000ff',
strokeOpacity: 1.0,
strokeColor: '#0000ff',
strokeWeight: 1.0,
scale: size, //pixels
}
});
marker[i].setMap(map);
//EO create marker
marker_onclick(marker[i]);
marker_info(marker[i]);
}
}
function marker_onclick(marker) {
google.maps.event.addListener(marker, 'dblclick', function(o) {
map.setZoom(18);
map.setCenter(marker.position);
});
google.maps.event.addListener(marker, 'click', function(o) {
map.setZoom(7);
map.setCenter(marker.position);
});
google.maps.event.addListener(marker, 'rightclick', function(o) {
alert('Could route to different URL:\n' + marker.position);
});
}
function marker_info(marker) {
//create popup notice..
var infowindow = new google.maps.InfoWindow({
content:marker.labelContent
});
if(showOnStartInfoWindows)
infowindow.open(map, marker);
google.maps.event.addListener(marker, 'mouseover', function (o) {
//alert('over');
infowindow.open(map, marker);
});
google.maps.event.addListener(marker, 'mouseout', function (o) {
//alert('out');
infowindow.close(map, marker);
});
//EO create popup notice..
}
{
google.maps.event.addDomListener(window, 'load', initialize);
}
</script>
</head>
<body>
<div id="googleMap" style="width:640px;height:640px;"></div>
</body>
</html>
Example of what I'm trying to do.
Based on the value of size you may set the style(fontSize,width,height etc.) and the labelAnchor
{
var showOnStartInfoWindows = true;
//create locations..
var arrayAll = [];
var marker = [];
var jax = new google.maps.LatLng(30.318028, -81.674474);
var leesburg = new google.maps.LatLng(28.810750, -81.880056);
var map = null;
arrayAll[0] = {
loc: jax,
size: 5000,
info: "Jacksonville, FL 32204"
};
arrayAll[1] = {
loc: leesburg,
size: 1000,
info: "Leesburg, FL"
};
//EO create locations..
}
function initialize() {
//center the map on Jacksonville
var mapProp = {
center: arrayAll[0].loc,
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
//set google's API and pass the DIV by ID.
map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var bounds = new google.maps.LatLngBounds(leesburg, jax);
map.fitBounds(bounds);
var maxSize = 0;
for (var i = 0; i < arrayAll.length; i++) {
if (maxSize < arrayAll[i].size)
maxSize = arrayAll[i].size;
}
for (var i = 0; i < arrayAll.length; i++) {
var size = Math.round((arrayAll[i].size / maxSize) * 100);
//create MarkerWithLabel
marker[i] = new MarkerWithLabel({
labelInBackground:false,
position: arrayAll[i].loc,
map: map,
title: 'Right-Click to zoom all the way in.\nLeft-Click to zoom to a state level.',
labelAnchor: new google.maps.Point((size * 1.8) / 2, (size / 3)),
labelClass: "googleLabel", // the CSS class for the label
labelStyle: {
width: (size * 1.8) + 'px',
height: (size / 1.5) + 'px',
lineHeight: (size / 1.5) + 'px',
fontSize: (size / 1.5) + 'px'
},
labelContent: arrayAll[i].size,
icon: {
path: google.maps.SymbolPath.CIRCLE,
fillOpacity: 0.6,
fillColor: 'gold',
strokeOpacity: 1.0,
strokeColor: '#0000ff',
strokeWeight: 1.0,
scale: size, //pixels
}
});
marker[i].setMap(map);
}
}
{
google.maps.event.addDomListener(window, 'load', initialize);
}
html,
body,
#googleMap {
margin: 0;
padding: 0;
height: 100%;
}
.googleLabel {
color: #000;
font-weight: bold;
text-align: center;
}
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerwithlabel/src/markerwithlabel.js" type="text/javascript"></script>
<div id="googleMap"></div>
I am trying to render shapes on Google Maps (using V3 of the API), which contain the same shape, just smaller inside. Basically a box within a box or a polygon within a polygon.
For the rectangle I have the following code, which works:
var drawEdgesRectangle = function (shape) {
// shape is the original, parent rectangle
var NE, SW, childNE, childSW, padding, diagonal, inner;
// set padding constant to 1 (i.e. 1m distance all around)
padding = 1;
// get diagonal distance from corner
diagonal = Math.sqrt(2) * padding;
// get NE of parent
NE = shape.bounds.getNorthEast();
// get SW of parent
SW = shape.bounds.getSouthWest();
// get child NE, SW
childNE = google.maps.geometry.spherical.computeOffset(NE, diagonal, 225);
childSW = google.maps.geometry.spherical.computeOffset(SW, diagonal, 45);
// render inner shape
inner = new google.maps.Rectangle({
strokeColor: 'white',
strokeOpacity: 0.8,
strokeWeight: 1,
fillColor: 'black',
fillOpacity: 0.35,
map: map,
bounds: new google.maps.LatLngBounds(
childSW,
childNE
)
});
}
Of course, doing this for a polygon is a different kettle of fish. I know I can use getPaths() to get the attributes of each line, but working out how to place the inner lines, and indeed, work out where 'inside' is is proving to be conceptually quite difficult for me.
I would like to know if what I want to achieve is possible given the Google API.
One option if you polygons are "simple" (the center is "inside" the polygon and there are no concave sides), would be to do something similar to what you did with the rectangle (which is a four sided polygon that meets those criteria):
Using the geometry library:
To include it:
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
Code (assumes global "poly" and others):
var drawEdgesPoly = function() {
// shape is the original, parent polygon
var shape = poly;
// set padding constant to 1 (i.e. 1m distance all around)
padding = 50;
var vertices = shape.getPath();
var polybounds = new google.maps.LatLngBounds();
for (var i = 0; i < vertices.getLength(); i++) {
polybounds.extend(vertices.getAt(i));
}
var center = polybounds.getCenter();
if (centerMarker && centerMarker.setMap) {
centerMarker.setMap(null);
}
centerMarker = new google.maps.Marker({
position: center,
map: map,
icon: {
url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
size: new google.maps.Size(7, 7),
anchor: new google.maps.Point(4, 4)
}
});
if (polylines && (polylines.length > 0)) {
for (var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
}
polylines = [];
var newPath = [];
for (var i = 0; i < vertices.getLength(); i++) {
polylines.push(new google.maps.Polyline({
path: [center, vertices.getAt(i)],
map: map,
strokeWidth: 2,
strokeColor: 'red'
}));
newPath[i] = google.maps.geometry.spherical.computeOffset(vertices.getAt(i),
padding,
google.maps.geometry.spherical.computeHeading(vertices.getAt(i), center));
}
if (inner && inner.setMap)
inner.setMap(null);
// render inner shape
inner = new google.maps.Polygon({
strokeColor: 'white',
strokeOpacity: 0.8,
strokeWeight: 1,
fillColor: 'black',
fillOpacity: 0.35,
map: map,
editable: false,
path: newPath
});
};
proof of concept fiddle
Play with the polygon in the code snippet or the jsfiddle to see the constraints.
var map;
var infoWindow;
var poly;
var inner;
var polylines = [];
var centerMarker;
var paths = [
[
new google.maps.LatLng(38.872886, -77.054720),
new google.maps.LatLng(38.872602, -77.058046),
new google.maps.LatLng(38.870080, -77.058604),
new google.maps.LatLng(38.868894, -77.055664),
new google.maps.LatLng(38.870598, -77.053346)
]
];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(38.8714, -77.0556),
zoom: 15
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
poly = new google.maps.Polygon({
paths: paths,
strokeWeight: 3,
fillColor: '#55FF55',
fillOpacity: 0.5,
editable: true
});
poly.setMap(map);
drawEdgesPoly();
google.maps.event.addListener(poly.getPath(), 'insert_at', drawEdgesPoly);
google.maps.event.addListener(poly.getPath(), 'remove_at', drawEdgesPoly);
google.maps.event.addListener(poly.getPath(), 'set_at', drawEdgesPoly);
// Define an info window on the map.
infoWindow = new google.maps.InfoWindow();
}
google.maps.event.addDomListener(window, 'load', initialize);
var drawEdgesPoly = function() {
// shape is the original, parent polygon
var shape = poly;
// set padding constant to 1 (i.e. 1m distance all around)
padding = 50;
var vertices = shape.getPath();
var polybounds = new google.maps.LatLngBounds();
for (var i = 0; i < vertices.getLength(); i++) {
polybounds.extend(vertices.getAt(i));
}
var center = polybounds.getCenter();
if (centerMarker && centerMarker.setMap) {
centerMarker.setMap(null);
}
centerMarker = new google.maps.Marker({
position: center,
map: map,
icon: {
url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle.png",
size: new google.maps.Size(7, 7),
anchor: new google.maps.Point(4, 4)
}
});
if (polylines && (polylines.length > 0)) {
for (var i = 0; i < polylines.length; i++) {
polylines[i].setMap(null);
}
}
polylines = [];
var newPath = [];
for (var i = 0; i < vertices.getLength(); i++) {
polylines.push(new google.maps.Polyline({
path: [center, vertices.getAt(i)],
map: map,
strokeWidth: 2,
strokeColor: 'red'
}));
newPath[i] = google.maps.geometry.spherical.computeOffset(vertices.getAt(i),
padding,
google.maps.geometry.spherical.computeHeading(vertices.getAt(i), center));
}
if (inner && inner.setMap)
inner.setMap(null);
// render inner shape
inner = new google.maps.Polygon({
strokeColor: 'white',
strokeOpacity: 0.8,
strokeWeight: 1,
fillColor: 'black',
fillOpacity: 0.35,
map: map,
editable: false,
path: newPath
});
};
html,
body,
#map-canvas {
height: 100%;
width: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
<div id="map-canvas" style="height:100%; width:100%;"></div>
I am trying to create a flight route using google maps with animation. Is it possible to create a polyline path with custom symbol of airplane as in the demo site of http://www.morethanamap.com/demos/visualization/flights
I am able to create a dashed path with animation. The problem is I have am stuck with creating SVG path. I did try to render a Bezier Curves from https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths with path given as "M10 10 C 20 20, 40 20, 50 10" but to no avail.
new google.maps.Polyline({
path: [
new google.maps.LatLng(40, -80),
new google.maps.LatLng(-50, 80)
],
geodesic: true,
strokeOpacity: 0.0,
strokeColor: 'yellow',
icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'red',
strokeOpacity: 1.0,
},
repeat: '24px'
}],
map: map,
});
The SVG path used on that demo is:
M362.985,430.724l-10.248,51.234l62.332,57.969l-3.293,26.145 l-71.345-23.599l-2.001,13.069l-2.057-13.529l-71.278,22.928l-5.762-23.984l64.097-59.271l-8.913-51.359l0.858-114.43 l-21.945-11.338l-189.358,88.76l-1.18-3 2.262l213.344-180.08l0.875-107.436l7.973-32.005l7.642-12.054l7.377-3.958l9.238,3.65 l6.367,14.925l7.369,30.363v106.375l211.592,182.082l-1.496,32.247l-188.479-90.61l-21.616,10.087l-0.094,115.684
I pasted that into this demo online svg editor, scaled to fit.
var planeSymbol = {
path: 'M362.985,430.724l-10.248,51.234l62.332,57.969l-3.293,26.145 l-71.345-23.599l-2.001,13.069l-2.057-13.529l-71.278,22.928l-5.762-23.984l64.097-59.271l-8.913-51.359l0.858-114.43 l-21.945-11.338l-189.358,88.76l-1.18-32.262l213.344-180.08l0.875-107.436l7.973-32.005l7.642-12.054l7.377-3.958l9.238,3.65 l6.367,14.925l7.369,30.363v106.375l211.592,182.082l-1.496,32.247l-188.479-90.61l-21.616,10.087l-0.094,115.684',
scale: 0.0333,
strokeOpacity: 1,
color: 'black',
strokeWeight: 1
};
working example
proof of concept fiddle
code snippet:
function initialize() {
var mapOptions = {
zoom: 6,
center: new google.maps.LatLng(20.291, 153.027),
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
// [START region_polyline]
// Define a symbol using SVG path notation, with an opacity of 1.
var planeSymbol = {
path: 'M362.985,430.724l-10.248,51.234l62.332,57.969l-3.293,26.145 l-71.345-23.599l-2.001,13.069l-2.057-13.529l-71.278,22.928l-5.762-23.984l64.097-59.271l-8.913-51.359l0.858-114.43 l-21.945-11.338l-189.358,88.76l-1.18-32.262l213.344-180.08l0.875-107.436l7.973-32.005l7.642-12.054l7.377-3.958l9.238,3.65 l6.367,14.925l7.369,30.363v106.375l211.592,182.082l-1.496,32.247l-188.479-90.61l-21.616,10.087l-0.094,115.684',
scale: 0.0333,
strokeOpacity: 1,
color: 'black',
strokeWeight: 1,
anchor: new google.maps.Point(300, 300)
};
var lineCoordinates = [
new google.maps.LatLng(22.291, 154.027),
new google.maps.LatLng(21.291, 155.027),
new google.maps.LatLng(20.291, 156.027),
new google.maps.LatLng(45.291, 158.027),
new google.maps.LatLng(51.47238, -0.45093999999994594)
];
var visibleLine = new google.maps.Polyline({
path: lineCoordinates,
strokeOpacity: 0.3,
map: map
});
var staticMark = new google.maps.Marker({
map: map,
position: lineCoordinates[0],
icon: planeSymbol,
visible: false // hide the static marker
});
var bounds = new google.maps.LatLngBounds();
bounds.extend(lineCoordinates[0]);
bounds.extend(lineCoordinates[4]);
// Create the polyline, passing the symbol in the 'icons' property.
// Give the line an opacity of 0.
var line = new google.maps.Polyline({
path: lineCoordinates,
strokeOpacity: 0,
icons: [{
icon: planeSymbol,
offset: '0'
}],
map: map
});
map.fitBounds(bounds);
animatePlane(line);
// [END region_polyline]
}
// Use the DOM setInterval() function to change the offset of the symbol
// at fixed intervals.
function animatePlane(line) {
var count = 0;
window.setInterval(function() {
count = (count + 1) % 2000;
var icons = line.get('icons');
icons[0].offset = (count / 20) + '%';
line.set('icons', icons);
}, 20);
}
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"></div>
You may use a program like Inkscape to draw the image, export is as SVG and copy the path from the source.
Here an example(it takes 3 minutes)
M 8.1326447,0.80527736 C 8.5471666,0.063577346 9.742752,0.030177346 10.052431,0.82497736 C 10.093464,3.0114774 10.134497,5.1980774 10.17553,7.3845774 C 12.760407,8.9653774 15.345284,10.546179 17.930161,12.127079 C 17.930161,12.881779 17.930161,13.636479 17.930161,14.391179 C 15.373077,13.579479 12.815993,12.767779 10.258908,11.956179 C 10.27281,13.280479 10.286713,14.604879 10.300615,15.929279 C 10.8565,16.555879 11.412385,17.182479 11.96827,17.809079 C 12.25527,18.269479 12.437605,19.641079 11.59784,19.085079 C 10.804104,18.802179 10.010367,18.519179 9.21663,18.236279 C 8.3133108,18.620779 7.4099916,19.005279 6.5066724,19.389779 C 6.3952441,18.705879 6.2272708,17.857479 6.8519879,17.359679 C 7.2927717,16.882879 7.7335555,16.406079 8.1743393,15.929279 C 8.1465467,14.604879 8.1187541,13.280479 8.0909615,11.956179 C 5.5894706,12.824879 3.0879797,13.693479 0.58648883,14.562179 C 0.54479393,13.821679 0.50309893,13.081079 0.46140403,12.340579 C 3.0184842,10.717079 5.5755645,9.0935778 8.1326447,7.4700774 C 8.1326447,5.2484774 8.1326447,3.0268774 8.1326447,0.80527736 z