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
Related
As you can see below, I have two polygons with sides. Basically 2 triangles with their respective coordinates. See:
function initialize() {
// Define the LatLng coordinates for the polygon's path.
var bounds = new google.maps.LatLngBounds();
var i;
var polygonCoords = [
new google.maps.LatLng(25.774252, -80.190262),
new google.maps.LatLng(18.466465, -66.118292),
new google.maps.LatLng(32.321384, -64.757370)
];
for (i = 0; i < polygonCoords.length; i++) {
bounds.extend(polygonCoords[i]);
}
var map = new google.maps.Map(document.getElementById("map_canvas2"), {
zoom: 4,
center: bounds.getCenter(),
mapTypeId: "roadmap"
});
var triangle1 = new google.maps.Polygon({
paths: polygonCoords,
strokeColor: '#0000ff',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#0000ff',
fillOpacity: 0.35
});
triangle1.setMap(map);
var polygonCoords2 = [
new google.maps.LatLng(25.774252, -80.190262),
new google.maps.LatLng(18.466465, -66.118292),
new google.maps.LatLng(14.979063, -83.500871)
];
var triangule2 = new google.maps.Polygon({
paths: polygonCoords2,
strokeColor: '#0000ff',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#0000ff',
fillOpacity: 0.35
});
triangule2.setMap(map);
}
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
<body onload="initialize()">
<div id="map_canvas2" style="height: 100vh; width:100vw"></div>
</body>
I would like to merge the two triangles so that the risk does not appear in the middle between the two, thus making a polygon with 4 sides or 4 coordinates. What would be the best way to do this?
Perhaps you could merge the arrays and remove the duplicates? Something like:
var newPolygon = polygonCoords.concat(polygonCoords2);
And then remove the duplicate coordinates (I took this code from this post):
var sorted_arr = newPolygon.slice().sort(); // You can define the comparing function here.
// JS by default uses a crappy string compare.
// (we use slice to clone the array so the
// original array won't be modified)
var results = [];
for (var i = 0; i < newPolygon.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
Then replace paths: polygonCoords, with paths: results,
I'm making a Google Maps application which has a video camera icon representing the street view and another icon representing any position.
See the Fiddle:
http://jsfiddle.net/uepc2f8n/52/
If I uncomment this "//google.maps.SymbolPath.FORWARD_CLOSED_ARROW", works fine! But when I put the camera path, the position does not get in the right position.
I don't know much about SVG Path, it's complex!
How do I point the lens of the camera in the direction of my marker?
code snippet (from linked fiddle):
function initialize() {
var direction = new google.maps.LatLng(52.376423, 4.887234);
var station = new google.maps.LatLng(52.155401, 5.118824);
var mapProperties = {
center: direction,
zoom: 10
};
var map = new google.maps.Map(document.getElementById("map-canvas"), mapProperties);
var directionMarker = new google.maps.Marker({
position: direction,
map: map,
draggable: true,
title: "test"
});
var heading = google.maps.geometry.spherical.computeHeading(direction, station);
directionMarker.setIcon({
path: "M17 -5.5V-15c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z", //google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 2,
rotation: heading
});
var stationMarker = new google.maps.Marker({
position: station,
map: map,
});
var polyline = new google.maps.Polyline({
path: [direction, station],
geodesic: true,
strokeColor: "#ff0000",
strokeOpacity: 1.0,
strokeWeight: 2
});
polyline.setMap(map);
}
initialize();
html,
body,
#map-canvas {
height: 100%;
margin: 0;
padding: 0
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry"></script>
<div id="map-canvas"></div>
You need to set the anchor and the rotation of the SVG Symbol correctly for your particular symbol. Looks to me like you want an anchor of (3,-10) and a rotation of heading - 90 degrees.
anchor: new google.maps.Point(3, -10),
rotation: heading - 90
updated fiddle
code snippet:
function initialize() {
var direction = new google.maps.LatLng(52.376423, 4.887234);
var station = new google.maps.LatLng(52.155401, 5.118824);
var mapProperties = {
center: direction,
zoom: 10
};
var map = new google.maps.Map(document.getElementById("map-canvas"), mapProperties);
var directionMarker = new google.maps.Marker({
position: direction,
map: map,
draggable: true,
title: "test"
});
var heading = google.maps.geometry.spherical.computeHeading(direction, station);
directionMarker.setIcon({
path: "M17 -5.5V-15c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z",
scale: 2,
anchor: new google.maps.Point(3, -10),
rotation: heading - 90
});
var stationMarker = new google.maps.Marker({
position: station,
map: map,
});
var polyline = new google.maps.Polyline({
path: [direction, station],
geodesic: true,
strokeColor: "#ff0000",
strokeOpacity: 1.0,
strokeWeight: 2
});
polyline.setMap(map);
var bounds = new google.maps.LatLngBounds();
bounds.extend(station);
bounds.extend(direction);
map.fitBounds(bounds);
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0;
padding: 0
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map-canvas"></div>
I use this code to create my markers (TypeScript btw)
The options for the icon allows me to rotate and set a fill color of the marker.
But how can I change the fill color and rotation after creation?
I have found various responses here on SO, but they refer to changing the icon to a bitmap and swap between red and green bitmaps for example.
Which is not what I want.
var icon = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 4,
fillColor: "#ff5050", //<-- I want to change this after creation
fillOpacity: 1,
strokeWeight: 1,
rotation: 0 //<-- I want to change this after creation
};
var markerOptions = <google.maps.MarkerOptions>{
map: this.map,
icon: icon,
};
Anyone know?
Calling .setIcon on the marker works for me:
setInterval(function () {
angle += 30;
cnt++;
icon.rotation = angle;
icon.fillColor = colorArray[cnt % colorArray.length]
marker.setIcon(icon);
}, 1000);
working fiddle
working code snippet:
var map;
var angle = 0;
var marker;
var icon = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
scale: 4,
fillColor: "#ff5050", //<-- I want to change this after creation
fillOpacity: 1,
strokeWeight: 1,
anchor: new google.maps.Point(0, 5),
rotation: 0 //<-- I want to change this after creation
};
var colorArray = ["#ff0000", "#00FF00", "#0000FF", "#FFFF00", "#00FFFF", "#FF00FF"];
var cnt = 0;
function init() {
var startLatLng = new google.maps.LatLng(50.124462, -5.539994);
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: startLatLng,
zoom: 12
});
var ptMarker = new google.maps.Marker({
position: new google.maps.LatLng(50.124462, -5.539994),
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)
}
});
marker = new google.maps.Marker({
position: new google.maps.LatLng(50.124462, -5.539994),
icon: icon
});
marker.setMap(map);
var circleMarker = new google.maps.Marker({
position: new google.maps.LatLng(50.124462, -5.539994),
map: map,
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 24,
strokeWeight: 2,
fillColor: '#009933',
fillOpacity: 0.001,
anchor: new google.maps.Point(0, 0)
}
});
setInterval(function () {
angle += 30;
cnt++;
icon.rotation = angle;
icon.fillColor = colorArray[cnt % colorArray.length]
marker.setIcon(icon);
}, 1000);
}
google.maps.event.addDomListener(window, 'load', init);
html, body, #map-canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map-canvas" style="border: 2px solid #3872ac;"></div>
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>
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>