【问题标题】:JS Google Maps API v3 Animate Marker Between CoordinatesJS Google Maps API v3 坐标之间的动画标记
【发布时间】:2012-06-09 21:27:15
【问题描述】:

我正在开发一个简单的 javascript 地图应用程序,它要求我为不同坐标之间的多个标记的移动设置动画。每个标记都可以自​​由移动,所有标记都存储在数组列表中。但是,我一直无法让他们顺利过渡到位置。

我进行了大量的研究和试验/错误,但没有运气,有人对此有任何运气吗?

【问题讨论】:

    标签: javascript google-maps animation google-maps-api-3 google-maps-markers


    【解决方案1】:

    我的快速而肮脏的方法不涉及大量研究:(

    这里是演示:http://jsfiddle.net/yV6xv/4/ 点击一个标记开始移动它,在它停止后,您可以再次点击回到它的初始点。在运动中单击会产生奇怪的结果。

    initialize() 中预定义了起点和终点。动画是通过将起点和终点分成 100 段来定义的,并以设定的间隔将标记放置在这些点上。所以动画时间是固定的:标记移动更长的距离比移动更短的距离“更快”。

    我没有做太多测试,我知道点击移动标记会产生意想不到的结果(起点和终点错位)

    这是演示的“有趣”部分:

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

    【讨论】:

    • 谢谢!作为一个 JS 新手,这很容易理解(意思是:对于初学者来说仍然很难)并且帮助了我很多。我最初将它分叉并使它成为初学者的混乱,但我回到您的原始和re-forked 它为每个标记包含一个循环和不同的速度。再次感谢蒂娜。
    【解决方案2】:

    您可以使用marker-animate-unobtrusive 库来制作标记 从一个位置平稳过渡到另一个位置。

    你可以像这样初始化你的标记:

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

    有了这个定义,你的标记将在 1 秒内平滑移动到一个新位置,只需调用 marker.setPosition()。

    如果您想来回动画标记,只需每秒切换一次 setPosition。

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

    附:我是图书馆的作者。

    【讨论】:

    • 工作得非常好。无需更改任何代码即可获得结果。
    • 这就是“不引人注目”的想法,很高兴听到它对你有用。
    • 注意:如果您使用覆盖视图,这似乎不起作用
    【解决方案3】:

    我不确定它是否是您正在寻找的东西,但无论如何我都会分享它:我编写了这段代码来模拟汽车的运动,以公里/小时为单位的特定速度。您只需要指定您希望标记/汽车前往的每个点的坐标(然后它将在坐标之间为标记设置动画)。

    我修改了rcravens's answer 来达到这个目的:

    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

    请注意,当您包含谷歌地图以便能够使用 google.maps.geometry.spherical.computeDistanceBetween 时,您需要添加“几何”库: http://maps.google.com/maps/api/js?sensor=true&libraries=geometry

    希望对你有帮助!

    【讨论】:

    • 如何将“animateMarker”方法的“coords”参数设为动态的?我的情况我应该从一个位置(纬度,语言)开始。嵌套点(纬度,语言)应该从数据库中获取。
    • @ChandanKumar 坐标是动态的,标记将从一个坐标动画到下一个坐标。如果您想获取从一个点到另一个点的方向,请使用developers.google.com/maps/documentation/javascript/directions,并在响应中查看response.routes[0].overview_path,这将在此animateMarker 方法中等效于coords。希望对您有所帮助。
    【解决方案4】:

    另一种方法是使用 CSS 过渡。重要的是识别谷歌地图用于标记的 DIV(有 2 个对触摸事件是透明的)调查已经为您完成,您真的只需要了解一次。

    可以找到一个完整的例子here看看Hansel和Gretel在地图上的移动多么流畅!如果有任何延迟,转换时间会合并。

    我的 Brotkrumen Ultimate Web App 的所有代码都可以在 here 找到你最感兴趣的是 HandleMap.js 文件,但有一个 aaa_readme.txt

    这里是部分代码:-

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-20
      • 1970-01-01
      • 2013-01-27
      • 2016-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多