Skip to content
目录

路况和轨迹播放综合效果

Markdown 官方教程

maptalks体系内不支持对一条线进行分段着色的,如果你需要做这种路况效果需要你自己拆分线路,将其拆成一段段的,且携带自己的 业务信息

总的思想就是:路况数据用一个独立的图层来加载,然后把这些分段数据合并成一个整条路线作为路线播放的数据源

轨迹播放插件

maptalks.routeplayer是个轨迹播放插件,该示例里我们使用它, 其具体的API等请参考其官方仓库里的说明

其事件有:

  • playstart
  • playfinish
  • playing
  • playpause
js
player.on('playing',e=>{

});

关于轨迹的数据结构

json
{
    "path": [
        [
            116.379028,
            39.865042,
            0,
            1694591213642
        ],
        [
            116.379742,
            39.865566,
            0,
            1694591517503.7537
        ],
        ...

    ]
}

[经度,纬度,海拔,时间戳,其他等]

WARNING

这个很重要请要注意,自己的业务如果数据结构不同,需要自己转成改数据结构

准备数据

这里我偷懒了,直接使用了高德的路线规划的数据来进行测试,所以在例子你会看到一些数据转换的代码的,比如坐标转换等,主要是 我也没有测试数据,所以只能找些测试数据,因为数据结构的不同故而导致代码会掺杂这这些无关的代码

json
{
  "status": "1",
  "info": "OK",
  "infocode": "10000",
  "count": "3",
  "route": {
    "origin": "116.379028,39.865042",
    "destination": "116.69569267333372,40.002403206049195",
    "taxi_cost": "125",
    "paths": [
      {
        "distance": "45271",
        "duration": "4677",
        "strategy": "速度最快",
        "tolls": "11",
        "toll_distance": "6797",
        "steps": [
          {
            "instruction": "向东南行驶108米左转",
            "orientation": "东南",
            "distance": "108",
            "tolls": "0",
            "toll_distance": "0",
            "toll_road": [],
            "duration": "92",
            "polyline": "116.379742,39.865566;116.379943,39.865404;116.380056,39.86535;116.380222,39.865173;116.380335,39.865028;116.380475,39.864787",
            "action": "左转",
            "assistant_action": [],
            "tmcs": [
              {
                "lcode": [],
                "distance": "36",
                "status": "拥堵",
                "polyline": "116.379742,39.865566;116.379943,39.865404;116.380056,39.86535"
              },
              {
                "lcode": [],
                "distance": "72",
                "status": "拥堵",
                "polyline": "116.380056,39.86535;116.380222,39.865173;116.380335,39.865028;116.380475,39.864787"
              }
            ],
            "cities": [
              {
                "name": "北京城区",
                "citycode": "010",
                "adcode": "110100",
                "districts": [
                  {
                    "name": "丰台区",
                    "adcode": "110106"
                  }
                ]
              }
            ]
          },
          {
            "instruction": "向东行驶58米靠右",
            "orientation": "",
            "distance": "58",
            "tolls": "0",
            "toll_distance": "0",
            "toll_road": [],
            "duration": "20",
            "polyline": "116.380475,39.864787;116.380576,39.864739;116.380684,39.864728;116.381129,39.864798",
            "action": "靠右",
            "assistant_action": [],
            "tmcs": [
              {
                "lcode": [],
                "distance": "58",
                "status": "严重拥堵",
                "polyline": "116.380475,39.864787;116.380576,39.864739;116.380684,39.864728;116.381129,39.864798"
              }
            ],
            "cities": [
              {
                "name": "北京城区",
                "citycode": "010",
                "adcode": "110100",
                "districts": [
                  {
                    "name": "丰台区",
                    "adcode": "110106"
                  }
                ]
              }
            ]
          },
         ...
        ],
        "restriction": "0",
        "traffic_lights": "7"
      }
    ]
  }
}

数据结构转换的一些工具函数

TIP

这些代码在你的业务不一定需要,这里只是因为测试数据结构的差异导致的额外的工作而已

js
//简单的经纬度数据处理
        function formatLngLats(str) {
            if (str.indexOf(';') === -1) {
                const lnglat = str.split(',').map(v => {
                    return parseFloat(v);
                });
                lnglat.push(0);
                return lnglat;
            }
            const array = str.split(';');
            return array.map(c => {
                return formatLngLats(c);
            })
        }


        function getColor(status) {
            if (status === '畅通') return;
            if (status === '缓行') return '#FFA700';
            if (status === '拥堵') return '#E94B37';
        }


        //整条路线的坐标数据
        function getWholeCoordinates(route) {
            let str = '';
            const { origin, destination, paths } = route;
            str += origin;
            const path = paths[0];
            const steps = path.steps;
            steps.forEach(step => {
                const { polyline } = step;
                str += ';';
                str += polyline;
            });
            str += ';';
            str += destination;
            return formatLngLats(str);
        }

加载路况路线

代码层面很简单,就是把分段的线路都构造一个LineString即可,根据业务的信息为每条线配置不同的颜色

js
//添加基本的路线
        function addBaseLine(route) {
            const line = new maptalks.LineString(getWholeCoordinates(route), {
                symbol: {
                    lineColor: 'green',
                    lineWidth
                }
            }).addTo(layer);
        }


        //分段路线数据
        function addLines(path) {
            const steps = path.steps;
            steps.forEach(step => {
                const tmcs = step.tmcs || [];
                tmcs.forEach(tmc => {
                    const { polyline, status } = tmc;
                    const lineColor = getColor(status);
                    if (!lineColor) {
                        return;
                    }
                    const coordinates = formatLngLats(polyline);
                    const line = new maptalks.LineString(coordinates, {
                        symbol: {
                            lineColor,
                            lineWidth
                        }
                    });
                    line.addTo(layer);
                });
            });
        }

        //起始点
        function addPoints(route) {
            const { origin, destination } = route;
            const point = new maptalks.Marker(formatLngLats(origin), {
                symbol: {
                    markerFile: './../assets/image/start.png'
                }
            }).addTo(layer);
            const point1 = new maptalks.Marker(formatLngLats(destination), {
                symbol: {
                    markerFile: './../assets/image/end.png'
                }
            }).addTo(layer);

        }

轨迹播放

  • 把所有的分段路线合并成一个整条的路线
  • 为每个坐标点赋值时间戳,这个只是因为是测试数据里没有时间戳导致的,手动计算了下这个值,这个值应该在你的业务数据携带
  • 默认关闭轨迹播放里的路线显示选项,即轨迹播放的线条是隐藏在背后
js
//轨迹播放
        function addRouterLine(route) {
            const coordinates = getWholeCoordinates(route).map(c => {
                return new maptalks.Coordinate(c);
            })
            const coords = [];
            //相邻点重复的去重,如果你的业务不需要可以省去改步骤
            for (let i = 0, len = coordinates.length; i < len; i++) {
                const c = coordinates[i];
                const lastC = coords[coords.length - 1];
                if (!lastC || !c.equals(lastC)) {
                    coords.push(c);
                }
            }
            //给坐标点赋值时间戳,这个值正常应该坐标数据里就携带,这里只是模拟下的
            let time = new Date().getTime();
            const path = [];
            const speed = 1 * 1000 / 3600;
            for (let i = 0, len = coords.length; i < len; i++) {
                if (i === 0) {
                    const lnglat = coords[i].toArray();
                    lnglat.push(time);
                    path.push(lnglat);
                } else {
                    const c2 = coords[i], c1 = coords[i - 1];
                    //两点之间的距离
                    const distance = map.computeLength(c2, c1);
                    //时间差
                    const offsetTime = distance / speed * 1000;
                    time += offsetTime;
                    const lnglat = c2.toArray();
                    lnglat.push(time);
                    path.push(lnglat);
                }
            }

            player = new maptalks.RoutePlayer({ path }, map, {
                maxTrailLine: 100,
                showTrail: false,
                //不显示线路
                showRoutes: false,
                // showMarker: false,
                lineSymbol: {
                    lineColor: '#f0f',
                    lineWidth: lineWidth + 2
                },
                markerSymbol: {
                    markerFile: './../assets/image/car.svg',
                    markerWidth: 40,
                    markerHeight: 40
                }
            });
            unitTime = player.getUnitTime();
        }

        function loadData() {
            fetch('./../assets/data/tripline.json').then(res => res.json()).then(json => {
                const route = json.route;
                const path = route.paths[0];
                addBaseLine(route);
                addLines(path);
                addPoints(route);
                addRouterLine(route);
            })
        }
        loadData();

TIP

maptalks.routeplayer 也支持3D图层的,具体的请参考其仓库

This document is generated by mdpress