高德轨迹更新效果

146 阅读3分钟

高德轨迹更新效果

基于高德地图 JSAPI 2.0 开发的轨迹回放系统,支持实时轨迹点加载、平滑动画播放、轨迹可视化等功能。

主要功能

  • 🎯 轨迹回放动画 - 平滑的移动动画,自动旋转,地图跟随
图片效果

b3ab5f25-768e-4df0-b3d9-3616ba53dd00.png

代码附上:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
    <title>轨迹回放</title>
    <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
    <style>
        html, body, #container {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div id="container"></div>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=YOUR_API_KEY"></script>
<script>
    // JSAPI2.0 使用覆盖物动画必须先加载动画插件
    AMap.plugin('AMap.MoveAnimation', function(){
        // 完整的轨迹点数据(模拟远程数据源)
        var allTrajectoryPoints = [
            [116.478935,39.997761],
            [116.478939,39.997825],
            [116.478912,39.998549],
            [116.478912,39.998549],
            [116.478998,39.998555],
            [116.478998,39.998555],
            [116.479282,39.99856],
            [116.479658,39.998528],
            [116.480151,39.998453],
            [116.480784,39.998302],
            [116.480784,39.998302],
            [116.481149,39.998184],
            [116.481573,39.997997],
            [116.481863,39.997846],
            [116.482072,39.997718],
            [116.482362,39.997718],
            [116.483633,39.998935],
            [116.48367,39.998968],
            [116.484648,39.999861]
        ];

        var marker;
        var currentPath = []; // 当前已加载的轨迹点
        var loadedIndex = 0; // 已加载的轨迹点索引
        var batchSize = 3; // 每次加载的轨迹点数量
        var loadInterval = null; // 定时器
        var isAnimating = false; // 标记是否正在动画中

        var map = new AMap.Map("container", {
            resizeEnable: true,
            center: [116.397428, 39.90923],
            zoom: 17
        });

        marker = new AMap.Marker({
            map: map,
            position: allTrajectoryPoints[0],
            icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
            offset: new AMap.Pixel(-13, -26),
        });

        // 只保留已走过轨迹线
        var passedPolyline = new AMap.Polyline({
            map: map,
            strokeColor: "#FF8000",  //线颜色
            strokeWeight: 6,      //线宽
        });

        // 维护一个累积的已走过路径数组,确保轨迹线一直显示
        var accumulatedPassedPath = [allTrajectoryPoints[0]];
        var lastRecordedPosition = allTrajectoryPoints[0]; // 上次记录的位置

        // 初始化时设置已走过轨迹为起点
        passedPolyline.setPath(accumulatedPassedPath);
        currentPath.push(allTrajectoryPoints[0]);
        loadedIndex = 1;

        marker.on('moving', function (e) {
            // 获取当前marker的位置
            var currentPos = e.target.getPosition();
            var currentPosArray = [currentPos.lng, currentPos.lat];
            
            // 计算与上次记录位置的距离
            var dist = Math.sqrt(
                Math.pow(currentPosArray[0] - lastRecordedPosition[0], 2) + 
                Math.pow(currentPosArray[1] - lastRecordedPosition[1], 2)
            );
            
            // 如果移动距离超过阈值(避免重复添加太近的点),添加到累积路径
            if (dist > 0.00001) {
                accumulatedPassedPath.push(currentPosArray);
                lastRecordedPosition = currentPosArray;
                
                // 更新轨迹线显示
                passedPolyline.setPath(accumulatedPassedPath);
            }
            
            map.setCenter(currentPos, true);
        });

        marker.on('moveend', function(e) {
            isAnimating = false;
            // 确保最后一个位置被记录
            var finalPos = e.target.getPosition();
            var finalPosArray = [finalPos.lng, finalPos.lat];
            
            // 检查最后一个位置是否已经记录
            var lastPoint = accumulatedPassedPath[accumulatedPassedPath.length - 1];
            var dist = Math.sqrt(
                Math.pow(finalPosArray[0] - lastPoint[0], 2) + 
                Math.pow(finalPosArray[1] - lastPoint[1], 2)
            );
            
            if (dist > 0.00001) {
                accumulatedPassedPath.push(finalPosArray);
                passedPolyline.setPath(accumulatedPassedPath);
            }
            
            lastRecordedPosition = finalPosArray;
        });

        // 模拟远程加载轨迹点的函数
        function loadTrajectoryPoints() {
            if (loadedIndex >= allTrajectoryPoints.length) {
                // 所有轨迹点已加载完成,清除定时器
                if (loadInterval) {
                    clearInterval(loadInterval);
                    loadInterval = null;
                }
                console.log('所有轨迹点已加载完成');
                return;
            }

            // 计算本次要加载的轨迹点
            var newPoints = [];
            var endIndex = Math.min(loadedIndex + batchSize, allTrajectoryPoints.length);
            
            for (var i = loadedIndex; i < endIndex; i++) {
                newPoints.push(allTrajectoryPoints[i]);
            }

            console.log('加载新的轨迹点:', newPoints);
            
            // 将新点添加到当前路径
            currentPath = currentPath.concat(newPoints);
            loadedIndex = endIndex;

            // 获取marker当前位置
            var currentPosition = marker.getPosition();
            var currentPosArray = [currentPosition.lng, currentPosition.lat];
            
            // 如果marker正在移动,需要暂停并重新规划路径
            if (isAnimating) {
                marker.pauseMove();
                
                // 找到当前位置在currentPath中最接近的点索引
                var closestIndex = 0;
                var minDist = Infinity;
                for (var k = 0; k < currentPath.length; k++) {
                    var dist = Math.sqrt(
                        Math.pow(currentPath[k][0] - currentPosition.lng, 2) + 
                        Math.pow(currentPath[k][1] - currentPosition.lat, 2)
                    );
                    if (dist < minDist) {
                        minDist = dist;
                        closestIndex = k;
                    }
                }
                
                // 构建从当前位置开始的新路径
                // 如果当前位置不在路径点上,先添加当前位置
                var newPath = [];
                if (minDist > 0.0001) {
                    newPath.push(currentPosArray);
                }
                
                // 添加从最近点之后的所有点(包括新加载的点)
                for (var m = closestIndex + 1; m < currentPath.length; m++) {
                    newPath.push(currentPath[m]);
                }
                
                // 如果还有剩余路径,继续移动
                if (newPath.length > 0) {
                    isAnimating = true;
                    marker.moveAlong(newPath, {
                        duration: 500,
                        autoRotation: true,
                    });
                }
            } else {
                // 如果marker没有在移动,找到当前位置在路径中的位置,从那里继续
                var startPath = [];
                var foundIndex = -1;
                
                // 查找当前位置在路径中的位置
                for (var n = 0; n < currentPath.length; n++) {
                    var dist = Math.sqrt(
                        Math.pow(currentPath[n][0] - currentPosition.lng, 2) + 
                        Math.pow(currentPath[n][1] - currentPosition.lat, 2)
                    );
                    if (dist < 0.0001) {
                        foundIndex = n;
                        break;
                    }
                }
                
                if (foundIndex >= 0 && foundIndex < currentPath.length - 1) {
                    // 从找到的位置之后开始
                    startPath = currentPath.slice(foundIndex + 1);
                } else if (foundIndex === -1) {
                    // 如果没找到,从当前位置开始,包含所有剩余点
                    startPath = [currentPosArray].concat(currentPath.slice(1));
                } else {
                    // 已经在最后一个点,使用新加载的点
                    startPath = currentPath.slice(-newPoints.length);
                }
                
                if (startPath.length > 0) {
                    isAnimating = true;
                    marker.moveAlong(startPath, {
                        duration: 500,
                        autoRotation: true,
                    });
                }
            }
        }

        // 确保地图渲染完成后再开始移动动画
        map.on('complete', function() {
            console.log('地图渲染完成,开始加载轨迹点');
            
            // 加载第一批数据
            var firstBatch = [];
            var firstEndIndex = Math.min(loadedIndex + batchSize, allTrajectoryPoints.length);
            for (var i = loadedIndex; i < firstEndIndex; i++) {
                firstBatch.push(allTrajectoryPoints[i]);
            }
            currentPath = currentPath.concat(firstBatch);
            loadedIndex = firstEndIndex;
            console.log('加载第一批轨迹点:', firstBatch);
            
            // 开始第一次移动
            if (currentPath.length > 1) {
                isAnimating = true;
                marker.moveAlong(currentPath, {
                    duration: 500,
                    autoRotation: true,
                });
            }
            
            // 每3秒加载一次新数据
            loadInterval = setInterval(function() {
                loadTrajectoryPoints();
            }, 3000);
        });

        map.setFitView();
    });
</script>
</body>
</html>