高缩放级别下Google Maps Marker偏离Polyline问题(基于epolys.js)
问题解决:Google Maps高缩放级别下距离标记偏离折线的问题
问题描述
我开发的脚本在Google Maps中展示多个标记点间的折线,额外的圆形标记用于可视化已行驶距离。脚本可正常运行,但在12-15级高缩放级别时,该距离标记不再贴合折线,而是偏离数米。标记位置由epolys.js的GetPointAtDistance方法计算。
问题原因
当前使用的GetPointAtDistance方法在计算两点间的插值点时,采用了平面线性插值(直接对经纬度值按比例计算),但折线设置了geodesic: true,意味着折线是沿地球球面的最短路径(测地线)绘制的。平面插值的点无法落在这条球面路径上,缩放级别越高,这种偏移的视觉效果就越明显。
解决方案
使用Google Maps Geometry库提供的google.maps.geometry.spherical.interpolate方法替换原有的线性插值逻辑。该方法会沿着球面测地线路径进行插值,确保计算出的点精准贴合折线的geodesic路径。
修改后的完整代码
<div id="container"> <div id="map" style="width:100%; height: 400px;"></div> </div> <script> // 初始化地图 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; // 单位:米 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) { // 特殊情况处理 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 google.maps.geometry.spherical.interpolate(p1, p2, m); } // 定义虚线样式 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 } ] // 创建标记点 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, }); } // 创建折线 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); // 添加距离标记 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"> </script>
内容的提问来源于stack exchange,提问作者flyte321
相关产品推荐
相关产品推荐

