[英]Google Maps Marker (calculated with epolys.js) not on polyline if zoom
我的腳本顯示了幾個標記之間的折線。 一個額外的標記(綠色圓圈)應該可視化已經走過的距離。
該腳本有效,但在高縮放級別 (12-15) 上,行進距離的標記不再“坐在”折線上,而是在許多米之外。 (參見屏幕截圖)標記 position 是使用 Epolys.js 腳本中的 GetPointAtDistance 計算的。
在此處查看演示: 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">
´´´
看起來 epoly 代碼中 GetPointAtDistance 中的插值不如(或至少一致)谷歌地圖 JavaScript API v3 幾何庫中的代碼准確。
如果我替換現有的插值:
return new google.maps.LatLng(p1.lat() + (p2.lat() - p1.lat()) * m, p1.lng() + (p2.lng() - p1.lng()) * m);
使用google.maps.geometry.spherical.interpolate
方法:
return google.maps.geometry.spherical.interpolate(p1, p2, m);
標記最終在線上(當該線是geodesic: true
)。
代碼片段:
// 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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.