2013-01-24 174 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