【问题标题】:latLng from polyLine PercentagelatLng 从折线百分比
【发布时间】:2013-10-02 02:11:13
【问题描述】:

如何沿折线从给定百分比返回 latLng 值? 我花了一天时间使用插值和单个节点。它们是否有更简单的功能可以让 grunt 工作?

谷歌地图 API v3 谢谢!

【问题讨论】:

    标签: google-maps-api-3


    【解决方案1】:

    http://www.geocodezip.com/scripts/v3_epoly.js

    为移植到 v3 的 Google Maps Javascript API v2 编写。 Documentation for the v2 version

    有这两种方法:

    • .Distance() 返回多边形路径的长度
    • .GetPointAtDistance() 返回指定距离处的 GLatLng
      沿着小路。
      距离以米为单位指定
      如果路径短于该路径,则返回 null

    这应该有效(如果您包含该脚本并且您的折线变量是“折线”):

    var latlng = polyline.GetPointAtDistance(polyline.Distance()*(desired percentage)/100);
    

    当然,如果你的折线长度没有变化,那么每次你想在折线上找到一个点时计算长度会更有效。

    var polylength = polyline.Distance();
    var latlng = polylength*(desired percentage)/100);
    

    live example

    代码 sn-p:

    var directionDisplay;
    var directionsService = new google.maps.DirectionsService();
    var map;
    var polyline = null;
    var marker;
    var infowindow;
    
    function createMarker(latlng, label, html) {
      // alert("createMarker("+latlng+","+label+","+html+","+color+")");
      var contentString = '<b>' + label + '</b><br>' + html;
      var marker = new google.maps.Marker({
        position: latlng,
        map: map,
        title: label,
        zIndex: Math.round(latlng.lat() * -100000) << 5,
        contentString: contentString
      });
      marker.myname = label;
      // gmarkers.push(marker);
    
      google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(this.contentString);
        infowindow.open(map, marker);
      });
      return marker;
    }
    var myLatLng = null;
    var lat;
    var lng;
    var zoom = 2;
    var maptype;
    
    function initialize() {
      infowindow = new google.maps.InfoWindow();
      myLatLng = new google.maps.LatLng(37.422104808, -122.0838851);
      maptype = google.maps.MapTypeId.ROADMAP;
      // If there are any parameters at eh end of the URL, they will be in  location.search
      // looking something like  "?marker=3"
    
      // skip the first character, we are not interested in the "?"
      var query = location.search.substring(1);
    
      // split the rest at each "&" character to give a list of  "argname=value"  pairs
      var pairs = query.split("&");
      for (var i = 0; i < pairs.length; i++) {
        // break each pair at the first "=" to obtain the argname and value
        var pos = pairs[i].indexOf("=");
        var argname = pairs[i].substring(0, pos).toLowerCase();
        var value = pairs[i].substring(pos + 1);
    
        // process each possible argname  -  use unescape() if theres any chance of spaces
        if (argname == "filename") {
          filename = unescape(value);
        }
        if (argname == "lat") {
          lat = parseFloat(value);
        }
        if (argname == "lng") {
          lng = parseFloat(value);
        }
        if (argname == "start") {
          document.getElementById("start").value = decodeURI(value);
        }
        if (argname == "end") {
          document.getElementById("end").value = decodeURI(value);
        }
        if (argname == "time") {
          document.getElementById("time").value = decodeURI(value);
          // putMarkerOnRoute(parseFloat(document.getElementById('time').value));
        }
        if (argname == "zoom") {
          zoom = parseInt(value);
        }
        if (argname == "type") {
          // from the v3 documentation 8/24/2010
          // HYBRID This map type displays a transparent layer of major streets on satellite images. 
          // ROADMAP This map type displays a normal street map. 
          // SATELLITE This map type displays satellite images. 
          // TERRAIN This map type displays maps with physical features such as terrain and vegetation. 
          if (value == "m") {
            maptype = google.maps.MapTypeId.ROADMAP;
          }
          if (value == "k") {
            maptype = google.maps.MapTypeId.SATELLITE;
          }
          if (value == "h") {
            maptype = google.maps.MapTypeId.HYBRID;
          }
          if (value == "t") {
            maptype = google.maps.MapTypeId.TERRAIN;
          }
    
        }
      }
      if (!isNaN(lat) && !isNaN(lng)) {
        myLatLng = new google.maps.LatLng(lat, lng);
      }
      var myOptions = {
        zoom: zoom,
        center: myLatLng,
        mapTypeId: maptype
      };
      directionsDisplay = new google.maps.DirectionsRenderer({
        suppressMarkers: true
      });
    
      map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
      polyline = new google.maps.Polyline({
        path: [],
        strokeColor: '#FF0000',
        strokeWeight: 3
      });
      directionsDisplay.setMap(map);
      calcRoute();
    }
    
    function calcRoute() {
    
      var start = document.getElementById("start").value;
      var end = document.getElementById("end").value;
      var travelMode = google.maps.DirectionsTravelMode.DRIVING
    
      var request = {
        origin: start,
        destination: end,
        travelMode: travelMode
      };
      directionsService.route(request, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
          polyline.setPath([]);
          var bounds = new google.maps.LatLngBounds();
          startLocation = new Object();
          endLocation = new Object();
          directionsDisplay.setDirections(response);
          var route = response.routes[0];
          var summaryPanel = document.getElementById("directions_panel");
          summaryPanel.innerHTML = "";
    
          // For each route, display summary information.
          var path = response.routes[0].overview_path;
          var legs = response.routes[0].legs;
          for (i = 0; i < legs.length; i++) {
            if (i == 0) {
              startLocation.latlng = legs[i].start_location;
              startLocation.address = legs[i].start_address;
              // marker = google.maps.Marker({map:map,position: startLocation.latlng});
              // marker = createMarker(legs[i].start_location,"start",legs[i].start_address,"green");
            }
            endLocation.latlng = legs[i].end_location;
            endLocation.address = legs[i].end_address;
            var steps = legs[i].steps;
            for (j = 0; j < steps.length; j++) {
              var nextSegment = steps[j].path;
              for (k = 0; k < nextSegment.length; k++) {
                polyline.getPath().push(nextSegment[k]);
                bounds.extend(nextSegment[k]);
              }
            }
          }
    
          polyline.setMap(map);
    
          computeTotalDistance(response);
          putMarkerOnRoute(parseFloat(document.getElementById('percent').value));
        } else {
          alert("directions response " + status);
        }
      });
    }
    
    var totalDist = 0;
    var totalTime = 0;
    
    function computeTotalDistance(result) {
      totalDist = 0;
      totalTime = 0;
      var myroute = result.routes[0];
      for (i = 0; i < myroute.legs.length; i++) {
        totalDist += myroute.legs[i].distance.value;
        totalTime += myroute.legs[i].duration.value;
      }
      totalDist = totalDist / 1000.
      document.getElementById("total").innerHTML = "total distance is: " + totalDist + " km<br>total time is: " + (totalTime / 60).toFixed(2) + " minutes<br>average speed is: " + (totalDist / (totalTime / 3600)).toFixed(2) + " kph";
      document.getElementById("totalTime").value = (totalTime / 60.).toFixed(2);
    }
    
    function putMarkerOnRoute(percent) {
      if (percent > 100) {
        percent = 100;
        document.getElementById('percent').value = percent;
      }
    
      var distance = percent / 100 * totalDist * 1000;
      // time = ((percentage/100) * totalTIme/60).toFixed(2);
      // alert("Time:"+time+" totalTime:"+totalTime+" totalDist:"+totalDist+" dist:"+distance);
      if (!marker) {
        marker = createMarker(polyline.GetPointAtDistance(distance), "percent: " + percent, "marker");
      } else {
        marker.setPosition(polyline.GetPointAtDistance(distance));
        marker.setTitle("percent:" + percent);
        marker.contentString = "<b>percent: " + percent + "</b><br>distance: " + (distance / 1000).toFixed(2) + " km<br>marker";
        google.maps.event.trigger(marker, "click");
      }
    }
    google.maps.event.addDomListener(window, 'load', initialize);
    // from epoly_v3.js
    // modified to use geometry library for length of line segments
    // === A method which returns a GLatLng of a point a given distance along the path ===
    // === Returns null if the path is shorter than the specified distance ===
    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 += google.maps.geometry.spherical.computeDistanceBetween(this.getPath().getAt(i), 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);
    }
    html {
      height: 100%
    }
    
    body {
      height: 100%;
      margin: 0px;
      padding: 0px
    }
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
    <div id="tools">
      start:
      <input type="text" name="start" id="start" value="Hyderabad" /> end:
      <input type="text" name="end" id="end" value="Bangalore" />
      <input type="submit" onclick="calcRoute();" /><br /> percentage:
      <input type="text" name="percent" id="percent" value="0" />
      <input type="submit" onclick="putMarkerOnRoute(parseFloat(document.getElementById('percent').value));" /> &nbsp;total time:<input type="text" name="totalTime" id="totalTime" value="0" />
    </div>
    <div id="map_canvas" style="float:left;width:70%;height:100%;"></div>
    <div id="control_panel" style="float:right;width:30%;text-align:left;padding-top:20px">
      <div id="directions_panel" style="margin:20px;background-color:#FFEE77;"></div>
      <div id="total"></div>
    </div>

    【讨论】:

      猜你喜欢
      • 2020-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多