如何在自定义Google地图标记上添加动画并沿路线移动?

23

我使用JavaScript和Google Maps API编写了一个小型手持设备应用程序,现在我需要使用计时器函数沿着一条路线在地图上随意移动我的标记图标。 我有一个人的图标,并且需要自动在地图上移动它。 我该如何做到这一点?


我编辑了标题以反映问题的内容。@jyothi:在发布问题时,请花些时间审查其内容。只需额外花费2分钟进行审查,您就可以将质量提高100%,并期望获得更多和更好的答案。 - Aron Rotteveel
谢谢您,先生。您能回答我的问题吗? - jyothi
@jyothi,你解决了这个问题吗?我需要在地图应用程序上完成完全相同的事情。如果你已经实现了它,能否给我们一些提示? - devdar
3个回答

17

该页面使用的是 http://econym.org.uk/gmap/epoly.htm 库的旧版本,其中包含一些实用的工具函数,可用于查找路径上某个位置的纬度和经度。这将使构建动画标记变得更加容易。 - Steve Hiner
仅出于兴趣,我去年在一个我建立的网站上也使用了类似的技术。这些方法可能有点过时,不符合最新的API标准,但它们运行良好。http://www.flushtracker.com/ - Matt
@Matt 看起来域名 flushtracker.com 现在重定向到 domestos.com/uk/home.html - Anthony Walsh

9

很遗憾,官方的GMaps集合中没有自动标记移动功能。

但是,如果您有一个GRoute,那意味着您有一组点。要循环遍历路线步骤,您可以使用类似以下代码:

for (var c = 0; c < yourroute.getNumSteps(); c++) { 
    yourmarker.setLatLng(yourroute.getStep(c).getLatLng());
}

当然,您可能希望使用定时器异步执行此操作:
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);

为了使移动更加流畅,您可以插值已有的点。

这个功能在Google Maps V3中是否可用?DirectionsService返回的“steps”数组似乎只包含指示的步骤(例如,在某处左转),而不是构成渲染线的单个点。 - Kevin
@Puskvor,是否有可能保持增加经纬度坐标以模拟路线,而该路线不一定只在街道上。 - devdar
1
@dev_darin:是的。但并不是所有的路线都是直线;在各个路线点之间,你的方法当然是可行的。 - Piskvor left the building
@Puskvor,您能告诉我如何增加经纬度吗?我知道它是基于角度的,我正在考虑使用随机数生成器来获取值,但我想知道如何递增。 - devdar
@dav_durin:获取一个坐标,增加给定的数量,获取另一个坐标,增加其他数量,使用新坐标创建一个新的LatLng,.setLatLng(yourNewLatLng)。 - Piskvor left the building

8
这是我的解决方案,适用于v3 API。根据计算的路线持续时间,该方案对标记进行动画处理,而不是使用固定速度。有一个速度因素,例如,你可以将路线的行驶速度加快10倍。

我尽可能地简化了它。随意使用。

var autoDriveSteps = new Array();
var speedFactor = 10; // 10x faster animated drive

function setAnimatedRoute(origin, destination, map) {
    // init routing services
    var directionsService = new google.maps.DirectionsService;
    var directionsRenderer = new google.maps.DirectionsRenderer({
        map: map
    });

    //calculate route
    directionsService.route({
            origin: origin,
            destination: destination,
            travelMode: google.maps.TravelMode.DRIVING
        },
        function(response, status) {
            if (status == google.maps.DirectionsStatus.OK) {
                // display the route
                directionsRenderer.setDirections(response);

                // calculate positions for the animation steps
                // the result is an array of LatLng, stored in autoDriveSteps
                autoDriveSteps = new Array();
                var remainingSeconds = 0;
                var leg = response.routes[0].legs[0]; // supporting single route, single legs currently
                leg.steps.forEach(function(step) {
                    var stepSeconds = step.duration.value;
                    var nextStopSeconds = speedFactor - remainingSeconds;
                    while (nextStopSeconds <= stepSeconds) {
                        var nextStopLatLng = getPointBetween(step.start_location, step.end_location, nextStopSeconds / stepSeconds);
                        autoDriveSteps.push(nextStopLatLng);
                        nextStopSeconds += speedFactor;
                    }
                    remainingSeconds = stepSeconds + speedFactor - nextStopSeconds;
                });
                if (remainingSeconds > 0) {
                    autoDriveSteps.push(leg.end_location);
                }
            } else {
                window.alert('Directions request failed due to ' + status);
            }
        });
}

// helper method to calculate a point between A and B at some ratio
function getPointBetween(a, b, ratio) {
    return new google.maps.LatLng(a.lat() + (b.lat() - a.lat()) * ratio, a.lng() + (b.lng() - a.lng()) * ratio);
}

// start the route simulation   
function startRouteAnimation(marker) {
    var autoDriveTimer = setInterval(function () {
            // stop the timer if the route is finished
            if (autoDriveSteps.length === 0) {
                clearInterval(autoDriveTimer);
            } else {
                // move marker to the next position (always the first in the array)
                marker.setPosition(autoDriveSteps[0]);
                // remove the processed position
                autoDriveSteps.shift();
            }
        },
        1000);
}

使用方法:

setAnimatedRoute("source address or LatLng ...", "destination address or LatLng ...", map);
// start simulation on button click...
$("#simulateRouteButton").click(function() {
    startRouteAnimation(agentMarker);
});

一个非常优雅的解决方案。谢谢。 - Wei-jye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接