My script shows a polyline between several markers. An additional marker (green circle) should visualize the distance already travelled.
The script works, but on high zoom-levels (12-15) the marker for the distance travelled do not "sit" on the polyline anymore, but many meters away. (see screengrab) The markers position is calculated with GetPointAtDistance from the Epolys.js-script.
code snippet:
// initialise map
function initMap() {
var options = {
center: {
lat: 51.69869842676892,
lng: 8.188009802432369
},
zoom: 14,
mapId: '1ab596deb8cb9da8',
mapTypeControl: false,
streetViewControl: false,
fullscreenControlOptions: {
position: google.maps.ControlPosition.RIGHT_BOTTOM
},
}
var map = new google.maps.Map(document.getElementById('map'), options);
google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
var EarthRadiusMeters = 6378137.0; // meters
var lat1 = this.lat();
var lon1 = this.lng();
var lat2 = newLatLng.lat();
var lon2 = newLatLng.lng();
var dLat = (lat2 - lat1) * Math.PI / 180;
var dLon = (lon2 - lon1) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = EarthRadiusMeters * c;
return d;
}
google.maps.Polyline.prototype.GetPointAtDistance = function(metres) {
// some awkward special cases
if (metres == 0) return this.getPath().getAt(0);
if (metres < 0) return null;
if (this.getPath().getLength() < 2) return null;
var dist = 0;
var olddist = 0;
for (var i = 1;
(i < this.getPath().getLength() && dist < metres); i ) {
olddist = dist;
dist = this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
}
if (dist < metres) {
return null;
}
var p1 = this.getPath().getAt(i - 2);
var p2 = this.getPath().getAt(i - 1);
var m = (metres - olddist) / (dist - olddist);
// updated to use the geometry library function
return google.maps.geometry.spherical.interpolate(p1, p2, m);
}
// Define a symbol using SVG path notation, with an opacity of 1.
const dashedLine = {
path: "M 0,-1 0,1",
strokeOpacity: 1,
scale: 8,
};
var markerCoordinates = [{
lat: 51.17230192226146,
lng: 7.005455256203302
},
{
lat: 52.017106436819546,
lng: 8.903316299753124
},
{
lat: 52.1521613855702,
lng: 9.972045956234473
},
{
lat: 52.12123086563482,
lng: 11.627830412053509
},
{
lat: 53.6301544474316,
lng: 11.415718027446243
},
{
lat: 54.08291262244958,
lng: 12.191652169789096
},
{
lat: 54.3141629859056,
lng: 13.097095856304708
}
]
// create markers
for (i = 0; i < markerCoordinates.length; i ) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(markerCoordinates[i]['lat'], markerCoordinates[i]['lng']),
map: map,
optimized: true,
});
}
// create polylines
const stepsRoute = new google.maps.Polyline({
path: markerCoordinates,
geodesic: true,
strokeColor: "#c5d899",
strokeOpacity: 0.2,
icons: [{
icon: dashedLine,
offset: "0",
repeat: "35px",
}, ]
});
stepsRoute.setMap(map);
var polylineLength = google.maps.geometry.spherical.computeLength(stepsRoute.getPath());
var groupPosition = stepsRoute.GetPointAtDistance(100600);
// add marker at position of the group
var positionMarker = new google.maps.Marker({
map: map,
position: groupPosition,
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 10,
fillOpacity: 1,
strokeWeight: 2,
fillColor: '#5384ED',
strokeColor: '#ffffff',
},
});
var positionMarker = new google.maps.Marker({
map: map,
position: groupPosition,
});
};
/*
* Always set the map height explicitly to define the size of the div element
* that contains the map.
*/
#map {
height: 100%;
}
/*
* Optional: Makes the sample page fill the window.
*/
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Directions Service</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="map"></div>
<!--
The `defer` attribute causes the callback to execute after the full HTML
document has been parsed. For non-blocking uses, avoiding race conditions,
and consistent behavior across browsers, consider loading using Promises
with https://www.npmjs.com/package/@googlemaps/js-api-loader.
-->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=geometry" defer></script>
</body>
</html>