1

我一直在寻找一个很好的解决方案来使用 Google Maps JavaScript API V3 为标记设置动画。标记将在使用纬度和经度坐标定义的预定路径上进行动画处理。

对于我所做的所有研究,我仍然找不到与 JavaScript Google Maps API 版本 3 兼容的解决方案。查看较早的 StackOverflow 帖子,显然可以使用 API 的第 2 版进行动画处理,使用GRoute计时器将标记的位置设置为沿路线的点。

这是之前建议的代码。我理解它在逻辑上是如何工作的,但我不知道如何将它移植到与 Google Maps API 的第 3 版一起使用:

function moveToStep(yourmarker,yourroute,c) {
    if {yourroute.getNumSteps() > c) {
        yourmarker.setLatLng(yourroute.getStep(c).getLatLng());
        window.setTimeout(function(){
            moveToStep(yourmarker,yourroute,c+1);
        },500);
    }
}

moveToStep(marker,route,0);

没有提到GRoute, getNumSteps(我假设它返回给定路线上定义的坐标数,setLatLng(我相信哪个获得标记的纬度和经度坐标),或者moveToStep(实际上移动标记)在版本 3完整的文档和参考

似乎 Google 已经将 API 从版本 2 完全重写到版本 3,因为这些功能(似乎非常基本)都已被删除或重命名(我不确定是哪个。)

我在 JavaScript API 版本 3 中看到的唯一动画是用于在标记首次出现在地图上时为其设置动画,方法是将它们设置为BOUNCEDROP. 但是,这些实际上并不会移动标记的纬度/经度坐标,而只是移动它们在地图上的放置方式。这两个标记动画在此处的 API 参考中有所提及。

在前面提到的同一篇 StackOverflow 帖子中,提供了一个链接,指向使用 JavaScript API 的标记动画的工作示例。然而,正如评论者指出的那样,动画是使用该库的早期版本完成的(可在此处获得。)

最后,我想我有两个问题:

1:是否可以使用 Google Maps V3 API 沿给定路径设置动画标记?

如果没有,那么

2:我会被迫使用已弃用的库来实现这一点,还是有其他已知的解决方案?

非常感谢您提供的任何可能有助于解决此问题的贡献!

4

2 回答 2

7

是的。在 v3 中,可以从DirectionsService沿路线为标记设置动画。

此示例使用移植到 v3 的 Mike Williams 的 epoly 库版本。

概念证明小提琴

代码片段:

var map;
 var directionDisplay;
 var directionsService;
 var stepDisplay;
 var markerArray = [];
 var position;
 var marker = null;
 var polyline = null;
 var poly2 = null;
 var speed = 0.000005,
   wait = 1;
 var infowindow = null;

 var myPano;
 var panoClient;
 var nextPanoId;
 var timerHandle = null;

 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
   });
   marker.myname = label;
   // gmarkers.push(marker);

   google.maps.event.addListener(marker, 'click', function() {
     infowindow.setContent(contentString);
     infowindow.open(map, marker);
   });
   return marker;
 }


 function initialize() {
   infowindow = new google.maps.InfoWindow({
     size: new google.maps.Size(150, 50)
   });
   // Instantiate a directions service.
   directionsService = new google.maps.DirectionsService();

   // Create a map and center it on Manhattan.
   var myOptions = {
     zoom: 13,
     mapTypeId: google.maps.MapTypeId.ROADMAP
   }
   map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

   address = 'new york'
   geocoder = new google.maps.Geocoder();
   geocoder.geocode({
     'address': address
   }, function(results, status) {
     map.setCenter(results[0].geometry.location);
   });

   // Create a renderer for directions and bind it to the map.
   var rendererOptions = {
     map: map
   }
   directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);

   // Instantiate an info window to hold step text.
   stepDisplay = new google.maps.InfoWindow();

   polyline = new google.maps.Polyline({
     path: [],
     strokeColor: '#FF0000',
     strokeWeight: 3
   });
   poly2 = new google.maps.Polyline({
     path: [],
     strokeColor: '#FF0000',
     strokeWeight: 3
   });
 }



 var steps = []

 function calcRoute() {

   if (timerHandle) {
     clearTimeout(timerHandle);
   }
   if (marker) {
     marker.setMap(null);
   }
   polyline.setMap(null);
   poly2.setMap(null);
   directionsDisplay.setMap(null);
   polyline = new google.maps.Polyline({
     path: [],
     strokeColor: '#FF0000',
     strokeWeight: 3
   });
   poly2 = new google.maps.Polyline({
     path: [],
     strokeColor: '#FF0000',
     strokeWeight: 3
   });
   // Create a renderer for directions and bind it to the map.
   var rendererOptions = {
     map: map
   }
   directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);

   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
   };

   // Route the directions and pass the response to a
   // function to create markers for each step.
   directionsService.route(request, function(response, status) {
     if (status == google.maps.DirectionsStatus.OK) {
       directionsDisplay.setDirections(response);

       var bounds = new google.maps.LatLngBounds();
       var route = response.routes[0];
       startLocation = new Object();
       endLocation = new Object();

       // 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);
       map.fitBounds(bounds);
       //        createMarker(endLocation.latlng,"end",endLocation.address,"red");
       map.setZoom(18);
       startAnimation();
     }
   });
 }



 var step = 50; // 5; // metres
 var tick = 100; // milliseconds
 var eol;
 var k = 0;
 var stepnum = 0;
 var speed = "";
 var lastVertex = 1;


 //=============== animation functions ======================
 function updatePoly(d) {
   // Spawn a new polyline every 20 vertices, because updating a 100-vertex poly is too slow
   if (poly2.getPath().getLength() > 20) {
     poly2 = new google.maps.Polyline([polyline.getPath().getAt(lastVertex - 1)]);
     // map.addOverlay(poly2)
   }

   if (polyline.GetIndexAtDistance(d) < lastVertex + 2) {
     if (poly2.getPath().getLength() > 1) {
       poly2.getPath().removeAt(poly2.getPath().getLength() - 1)
     }
     poly2.getPath().insertAt(poly2.getPath().getLength(), polyline.GetPointAtDistance(d));
   } else {
     poly2.getPath().insertAt(poly2.getPath().getLength(), endLocation.latlng);
   }
 }


 function animate(d) {
   // alert("animate("+d+")");
   if (d > eol) {
     map.panTo(endLocation.latlng);
     marker.setPosition(endLocation.latlng);
     return;
   }
   var p = polyline.GetPointAtDistance(d);
   map.panTo(p);
   marker.setPosition(p);
   updatePoly(d);
   timerHandle = setTimeout("animate(" + (d + step) + ")", tick);
 }


 function startAnimation() {
   eol = google.maps.geometry.spherical.computeLength(polyline.getPath());
   map.setCenter(polyline.getPath().getAt(0));
   // map.addOverlay(new google.maps.Marker(polyline.getAt(0),G_START_ICON));
   // map.addOverlay(new GMarker(polyline.getVertex(polyline.getVertexCount()-1),G_END_ICON));
   // marker = new google.maps.Marker({location:polyline.getPath().getAt(0)} /* ,{icon:car} */);
   // map.addOverlay(marker);
   poly2 = new google.maps.Polyline({
     path: [polyline.getPath().getAt(0)],
     strokeColor: "#0000FF",
     strokeWeight: 10
   });
   // map.addOverlay(poly2);
   setTimeout("animate(50)", 2000); // Allow time for the initial map display
 }


 //=============== ~animation funcitons =====================


 google.maps.event.addDomListener(window, "load", initialize);
 /*********************************************************************\
 *                                                                     *
 * epolys.js                                          by Mike Williams *
 * updated to API v3                                  by Larry Ross    *
 *                                                                     *
 * A Google Maps API Extension                                         *
 *                                                                     *
 * Adds various Methods to google.maps.Polygon and google.maps.Polyline *
 *                                                                     *
 * .Contains(latlng) returns true is the poly contains the specified   *
 *                   GLatLng                                           *
 *                                                                     *
 * .Area()           returns the approximate area of a poly that is    *
 *                   not self-intersecting                             *
 *                                                                     *
 * .Distance()       returns the length of the poly path               *
 *                                                                     *
 * .Bounds()         returns a GLatLngBounds that bounds the poly      *
 *                                                                     *
 * .GetPointAtDistance() returns a GLatLng at the specified distance   *
 *                   along the path.                                   *
 *                   The distance is specified in metres               *
 *                   Reurns null if the path is shorter than that      *
 *                                                                     *
 * .GetPointsAtDistance() returns an array of GLatLngs at the          *
 *                   specified interval along the path.                *
 *                   The distance is specified in metres               *
 *                                                                     *
 * .GetIndexAtDistance() returns the vertex number at the specified    *
 *                   distance along the path.                          *
 *                   The distance is specified in metres               *
 *                   Returns null if the path is shorter than that      *
 *                                                                     *
 * .Bearing(v1?,v2?) returns the bearing between two vertices          *
 *                   if v1 is null, returns bearing from first to last *
 *                   if v2 is null, returns bearing from v1 to next    *
 *                                                                     *
 *                                                                     *
 ***********************************************************************
 *                                                                     *
 *   This Javascript is provided by Mike Williams                      *
 *   Blackpool Community Church Javascript Team                        *
 *   http://www.blackpoolchurch.org/                                   *
 *   http://econym.org.uk/gmap/                                        *
 *                                                                     *
 *   This work is licenced under a Creative Commons Licence            *
 *   http://creativecommons.org/licenses/by/2.0/uk/                    *
 *                                                                     *
 ***********************************************************************
 *                                                                     *
 * Version 1.1       6-Jun-2007                                        *
 * Version 1.2       1-Jul-2007 - fix: Bounds was omitting vertex zero *
 *                                add: Bearing                         *
 * Version 1.3       28-Nov-2008  add: GetPointsAtDistance()           *
 * Version 1.4       12-Jan-2009  fix: GetPointsAtDistance()           *
 * Version 3.0       11-Aug-2010  update to v3                         *
 *                                                                     *
 \*********************************************************************/


 google.maps.LatLng.prototype.latRadians = function() {
   return this.lat() * Math.PI / 180;
 }

 google.maps.LatLng.prototype.lngRadians = function() {
   return this.lng() * Math.PI / 180;
 }


 // === 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);
 }

 // === A method which returns the Vertex number at a given distance along the path ===
 // === Returns null if the path is shorter than the specified distance ===
 google.maps.Polyline.prototype.GetIndexAtDistance = function(metres) {
   // some awkward special cases
   if (metres == 0) return this.getPath().getAt(0);
   if (metres < 0) 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;
   }
   return i;
 }
html {
  height: 100%;
}
body {
  height: 100%;
  margin: 0px;
  font-family: Helvetica, Arial;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="tools">
  start:
  <input type="text" name="start" id="start" value="union square, NY" />end:
  <input type="text" name="end" id="end" value="times square, NY" />
  <input type="submit" onclick="calcRoute();" />
</div>

<div id="map_canvas" style="width:100%;height:100%;"></div>

于 2013-01-24T21:03:52.280 回答
2

一种方法是沿路线生成一系列位置(例如 500 个不同的位置),然后marker.setPosition(nextLocation)每隔 X 毫秒调用一次,例如使用 setTimeout。

Alternatively, you can use a symbol on your polyline, setting the percentage along the path, again in a setTimeout approach. This has the advantage you don't need to compute the locations, you can just slowly move it some tiny percentage along each X milliseconds.

于 2013-01-24T21:11:25.453 回答