簡體   English   中英

如果縮放,谷歌地圖標記(使用 epolys.js 計算)不在折線上

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM