You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高缩放级别下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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 12:20:36