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.
See demo here: https://jsfiddle.net/faoq2jbr/1/

<div id="container">
<div id="map" style="width:100%; height: 400px;"></div>
</div>
<script>
// 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);
return new google.maps.LatLng(p1.lat() + (p2.lat() - p1.lat()) * m, p1.lng() + (p2.lng() - p1.lng()) * 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',
},
});
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAvHtXFKU5QUOBQ_gpn2a0DM-3Yjx3H5jQ&callback=initMap&libraries=geometry">
´´´
Looks like the interpolation in GetPointAtDistance in the epoly code is not as accurate as (or at least consistent with) the code in the Google Maps JavaScript API v3 geometry library.
If I replace the existing interpolation:
with the
google.maps.geometry.spherical.interpolatemethod:The marker ends up on the line (when the line is
geodesic: true).proof of concept fiddle
code snippet: