2013-01-24 175 views
1

我一直在寻找一个很好的解决方案,使用Google Maps JavaScript API V3为标记设置动画效果。标记将在使用纬度和经度坐标定义的预定路径上进行动画。Google Maps JavaScript API v3基于标记动画的已知路线

对于我所做的所有研究,我仍然无法找到与JavaScript Google Maps API版本3兼容的解决方案。查看this之前的StackOverflow后,显然可以使用API​​的版本2进行动画制作,使用GRoute并使用计时器将标记的位置设置为沿着路线的点。

这是以前建议的代码。我理解它是如何工作的逻辑,但我不知道这到底是怎么被移植与谷歌地图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); 

没有的GRoutegetNumSteps提(这我假设的回报某一特定航线上定义坐标数,setLatLng(我相信它获取标记的经纬度坐标),在第3版full documentation and reference,或moveToStep(实际上移动Marker)。

看来,谷歌有将API从版本2完全重写到版本3,因为这些函数(这些函数看起来很基本)都具有e ither被删除或重新命名(我不知道是哪个)

我唯一在JavaScript API第3版中见过的动画提到了当他们第一次出现在地图上时通过制作动画,它们可以是BOUNCEDROP。但是,这些标记实际上并不移动标记的纬度/经度坐标,而仅仅是它们放置在地图上的方式。这两个标记动画在API参考文献here中提及。

在上述相同的StackOverflow后,link被提供给使用JavaScript API的标记动画的工作示例。 (可here)但是,作为一个评论者指出的,动画是使用该库的早期版本做

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

1:是否有可能进行动画标记沿着使用谷歌地图V3 API的给定路径?

,如果没有,那么

2:我将被迫使用过时的库来实现这一点,或者还有没有其他已知的解决方案?

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

回答

4

是的。可以沿着v3中DirectionsService的路线设置动画。

This example使用Mike Williams的epoly库的一个版本移植到v3。

proof of concept fiddle

代码片断:

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"></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>

+0

非常感谢!这对我来说是一个很好的起点。至少现在我知道它可以完成! – Charles

2

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

或者,您可以使用一个symbol on your polyline,沿着路径设置百分比,再次使用setTimeout方法。这具有无需计算位置的优点,您可以在每X毫秒缓慢移动一小部分。

+0

我已经拥有数据库中的所有经度坐标。这意味着我应该使用你提到的第一种方法,对吗?谢谢您的帮助! – Charles