7

Tengo una aplicación de mapas javascript en la que estoy trabajando que me obliga a animar el movimiento de múltiples marcadores entre diferentes coords. Cada marcador es libre de moverse por sí mismo y todos los marcadores se almacenan en una lista de matriz. Sin embargo, he tenido problemas para lograr que cambien de lugar sin problemas.JS Google Maps API v3 Marcador animado entre coordenadas

He hecho un montón de investigación y ensayo/error, pero no hubo suerte, ¿alguien tiene algo de suerte con esto?

Respuesta

17

Mi enfoque rápido y sucio-no implica una tonelada de investigación :(

Aquí está la demostración: http://jsfiddle.net/yV6xv/4/ Haga clic en un marcador para comenzar a moverse, después de que se detenga, puede hacer clic de nuevo para volver a su punto inicial Al hacer clic mientras se está en movimiento, se obtienen resultados extraños

Los puntos de inicio y los puntos finales están predefinidos en initialize(). La animación se define dividiendo los puntos de inicio y final en 100 segmentos y colocando el marcador en estos puntos con un intervalo establecido. Por lo tanto, el tiempo de animación es fijo: los marcadores viajan distancias más largas "más rápido" que las distancias más cortas.

no hice muchas pruebas, sé que al hacer clic en un marcador de movimiento dará resultados inesperados (puntos inicial y final quedan fuera de lugar)

Esta es la parte "interesante" de la demo:

 // store a LatLng for each step of the animation 
     frames = []; 
     for (var percent = 0; percent < 1; percent += 0.01) { 
     curLat = fromLat + percent * (toLat - fromLat); 
     curLng = fromLng + percent * (toLng - fromLng); 
     frames.push(new google.maps.LatLng(curLat, curLng)); 
     } 

     move = function(marker, latlngs, index, wait, newDestination) { 
     marker.setPosition(latlngs[index]); 
     if(index != latlngs.length-1) { 
      // call the next "frame" of the animation 
      setTimeout(function() { 
      move(marker, latlngs, index+1, wait, newDestination); 
      }, wait); 
     } 
     else { 
      // assign new route 
      marker.position = marker.destination; 
      marker.destination = newDestination; 
     } 
     } 

     // begin animation, send back to origin after completion 
     move(marker, frames, 0, 20, marker.position); 
+4

¡Gracias! Como alguien nuevo en JS, esto fue bastante fácil de entender (es decir, todavía difícil para un principiante) y me ayudó mucho. Originalmente bifurqué esto y lo convertí en un desastre para principiantes, pero volví a su original y [re-bifurcado] (http://jsfiddle.net/HYuRR/2/) para incluir un bucle y diferentes velocidades para cada marcador. Gracias de nuevo Tina. –

8

Puede usar la biblioteca marker-animate-unobtrusive para hacer que los marcadores hagan una transición suave de una ubicación a otra.

Se puede inicializar el marcador así:

var marker = new SlidingMarker({ 
    //your original marker options 
    //... 
    duration: 1000 
}); 

Con esta definido, el marcador se mueva suavemente a una nueva posición dentro de 1 segundo, sólo llame marker.setPosition().

Si desea animar un marcador de ida y vuelta, simplemente active setPosition cada segundo.

setTimeout(function() { 
    var newPosition = /* select new position */ 
    marker.setPosition(newPosition) 
}, 1000); 

P.S. Soy el autor de la biblioteca.

+0

Funcionó maravillosamente. Pudo lograr el resultado sin cambiar ningún código. – Farveaz

+1

Esa es la idea de ser "discreto", es agradable escuchar que funcionó para usted. – viskin

7

no estoy seguro de si se trata de lo que usted está buscando, pero voy a compartir todos modos: Escribí este código para simular el movimiento de un coche con una velocidad específica en km/h. Solo necesita especificar las coordenadas de cada punto al que desea que vaya el marcador/carro (luego animará el marcador entre las coordenadas).

he modificado rcravens's answer para llegar a este:

var map, marker; 
var startPos = [42.42679066670903, -83.29210638999939]; 
var speed = 50; // km/h 

var delay = 100; 
// If you set the delay below 1000ms and you go to another tab, 
// the setTimeout function will wait to be the active tab again 
// before running the code. 
// See documentation : 
// https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout#Inactive_tabs 

function animateMarker(marker, coords, km_h) 
{ 
    var target = 0; 
    var km_h = km_h || 50; 
    coords.push([startPos[0], startPos[1]]); 

    function goToPoint() 
    { 
     var lat = marker.position.lat(); 
     var lng = marker.position.lng(); 
     var step = (km_h * 1000 * delay)/3600000; // in meters 

     var dest = new google.maps.LatLng(
     coords[target][0], coords[target][2]); 

     var distance = 
     google.maps.geometry.spherical.computeDistanceBetween(
     dest, marker.position); // in meters 

     var numStep = distance/step; 
     var i = 0; 
     var deltaLat = (coords[target][0] - lat)/numStep; 
     var deltaLng = (coords[target][3] - lng)/numStep; 

     function moveMarker() 
     { 
      lat += deltaLat; 
      lng += deltaLng; 
      i += step; 

      if (i < distance) 
      { 
       marker.setPosition(new google.maps.LatLng(lat, lng)); 
       setTimeout(moveMarker, delay); 
      } 
      else 
      { marker.setPosition(dest); 
       target++; 
       if (target == coords.length){ target = 0; } 

       setTimeout(goToPoint, delay); 
      } 
     } 
     moveMarker(); 
    } 
    goToPoint(); 
} 

function initialize() 
{ 
    var myOptions = { 
     zoom: 16, 
     center: new google.maps.LatLng(42.425175091823974, -83.2943058013916), 
     mapTypeId: google.maps.MapTypeId.ROADMAP 
    }; 
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); 

    marker = new google.maps.Marker({ 
     position: new google.maps.LatLng(startPos[0], startPos[1]), 
     map: map 
    }); 

    google.maps.event.addListenerOnce(map, 'idle', function() 
    { 
     animateMarker(marker, [ 
      // The coordinates of each point you want the marker to go to. 
      // You don't need to specify the starting position again. 
      [42.42666395645802, -83.29694509506226], 
      [42.42300508749226, -83.29679489135742], 
      [42.42304468678425, -83.29434871673584], 
      [42.424882066428424, -83.2944130897522], 
      [42.42495334300206, -83.29203128814697] 
     ], speed); 
    }); 
} 

initialize(); 

jsFiddle - DEMO

Tenga en cuenta que es necesario agregar la biblioteca "geometría" cuando se incluyen los mapas de Google para poder utilizar google.maps.geometry.spherical.computeDistanceBetween : http://maps.google.com/maps/api/js?sensor=true&libraries=geometry

Espero que ayude!

0

Una alternativa es usar transiciones CSS.Lo importante es identificar los DIV que Google Maps está usando para su marcador (Hay 2 uno es transparente para los eventos táctiles) La investigación se ha realizado para usted y realmente solo tiene que entenderla una vez.

Se puede encontrar un ejemplo completo here ¡Vea con qué suavidad se mueven Hansel y Gretel por el mapa! Y los tiempos de transición se unen si hay algún retraso.

Todo el código de mi aplicación web de Brotkrumen último se puede encontrar here va a ser en su mayoría interesados ​​en el archivo HandleMap.js pero hay una aaa_readme.txt

Aquí es parte del código: -

function showJourney(){ 
    map.setZoom(map.getZoom()); 
    map.setOptions({gestureHandling: "none"}); 
    zoomOut.style.display = "none"; 
    zoomIn.style.display = "none"; 

    hat.setPosition(
     new google.maps.LatLng(
       lastPos.coords.latitude, 
       lastPos.coords.longitude)); 
    hat.setVisible(true); 
    hat.setAnimation(bounce); 

    HandG.setPosition(
     new google.maps.LatLng(
       firstPos.coords.latitude, 
       firstPos.coords.longitude)); 
    HandG.setVisible(true); 

    map.panTo(path[0]); 
    google.maps.event.trigger(map, 'resize'); 

    if (document.querySelectorAll(MARKER_SELECTOR).length == 0){ 
     observer.observe(mapDiv, { 
         childList  : true, 
         subtree  : true , 
         attributes : true , 
         characterData : false 
         }) 
    } else { 
     setTimeout(plotTrip,0); 
    } 
} 
function plotTrip(){ 
    nextFunc = plotStep; 
    hat.setAnimation(bounce); 
    HandG.setPosition(path[0]); 
    dirPoly.setVisible(true);  
    progressPath = []; 
    progressPath.push(path[0]); 
    dirPoly.setPath(path); 
    stepPoly.setPath(progressPath); 
    stepPoly.setVisible(true); 
    currStep = 1; 
    markerDivs = []; 
    var markerImgs = document.querySelectorAll(MARKER_SELECTOR); 
    for (var i=0; i<markerImgs.length; i++){ 
     console.log(markerImgs[i].src); 
     markerDivs[i] = markerImgs[i].parentNode; 
     markerDivs[i].style.transitionDuration = "0s"; 
     markerDivs[i].style.transitionProperty = "left, top"; 
     markerDivs[i].style.transitionTimingFunction = "linear"; 
    } 

    setTimeout(plotStep,0); 
    abort = false; 
    btn.value = "Cancel"; 
    btn.disabled = false; 
} 
function plotStep(){ 
    if (abort) return; 

    if (legs[currStep].didLoiter){ 
     countDown = legs[currStep].restTime; 
     infoWindow.setContent(
      "<div id='waitDiv'><span>Waiting</span></div>"); 
     infoWindow.open(map,HandG); 
     showInterval(); 
    } else { 
     plotIt(); 
    } 
} 
function showInterval(){ 
    if (abort) return; 

    infoWindow.setContent(
     "<div id='waitDiv'><span>Waiting "+deltaDate(countDown)+"</span></div>"); 
    countDown -= (ONE_SEC * multiSpeed); 
    if (countDown < 1){ 
     infoWindow.close(); 
     plotIt(); 
    } else { 
     setTimeout(showInterval, ONE_SEC); 
    } 
} 
function plotIt(){ 
    if (abort) return; 

    progressPath.push(path[currStep]); 
    stepPoly.setPath(progressPath); 
    map.panTo(path[currStep]); 
    var transitionMS = legs[currStep].duration/multiSpeed; 
    for (var i=0; i<markerDivs.length; i++){ 
     markerDivs[i].style.transitionDuration = transitionMS + "ms"; 
    } 
    HandG.setPosition(path[currStep]) 

    if (++currStep >= path.length) 
     nextFunc = cleanUp; 

    plotTimer = setTimeout(nextFunc,transitionMS); 
} 
function cleanUp(){ 
    infoWindow.close(); 
    hat.setAnimation(); 
    btn.value = "Replay"; 
    btn.disabled = false; 
    clearTimeout(plotTimer); 
    for (var i=0; i<markerDivs.length; i++){ 
     markerDivs[i].style.transitionDuration = "0s"; 
    } 
    HandG.setPosition(
     new google.maps.LatLng(
       lastPos.coords.latitude, 
       lastPos.coords.longitude)); 
    HandG.setVisible(false); 
    map.setOptions({gestureHandling: "cooperative"}); 
    zoomIn.style.display = ""; 
    zoomOut.style.display = ""; 
    if (canTalk && !abort) 
     speechSynthesis.speak(finish); 
} 
function waitForMarker(mutations, myInstance) { 
    outer: 
    for (var i=0; i<mutations.length; i++){ 
     if (mutations[i].type   == "attributes" && 
      mutations[i].target.tagName == "IMG"  && 
      mutations[i].target.src.toLowerCase().indexOf(MARKER_SRC) != -1){ 
      console.log("result") 
      myInstance.disconnect(); 
      setTimeout(plotTrip,0) 
      break outer; 
     } 
     if (mutations[i].type != "childList" || 
      mutations[i].addedNodes.length == 0) 
      continue; 
     for (var j=0; j<mutations[i].addedNodes.length; j++) { 
      var node = mutations[i].addedNodes[j]; 
      if (node.tagName == "DIV" && node.firstChild && node.firstChild.tagName == "IMG" && 
       node.firstChild.src.toLowerCase().indexOf(MARKER_SRC) != -1){ 
       console.log(node.firstChild.src); 
       myInstance.disconnect(); 
       setTimeout(plotTrip,0) 
       break outer; 
      } 
     } 
    } 
} 
Cuestiones relacionadas