在leaflet当中提供了几个轨迹回放的插件,该文将用两个插件分别实现一下轨迹回放

leaflet-trackplayer

安装依赖&准备静态资源

轨迹回放使用leaflet-trackplayer插件

npm i leaflet-trackplayer --force

初始化地图,在这里初始化地图可以参考,然后导入了轨迹回放插件和一个图片(用于标记当前轨迹运动点)图片资源

import L from 'leaflet';
import 'leaflet-trackplayer';
import 'leaflet/dist/leaflet.css';
import CAR from '@/assets/image/car.png';

let map = null;
const sourceUrl = 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png';
map = L.map('map').setView([23, 120], 2);
  const tileLayer = L.tileLayer(sourceUrl, {
    maxZoom: 18,
    minZoom: 2,
    attribution: '© modify'
  });
  tileLayer.addTo(map);

准备轨迹数据 轨迹数据

  const path = [
    {
      lat: 34.25615548523744,
      lng: 108.91164044842363
    },
	// ...... 省略了很多点,可以在上面GitHub链接中获取
    {
      lat: 34.29496736180883,
      lng: 108.91578701078069
    }
  ];

轨迹绘制&播放

  • 先定义一个icon,用来标记轨迹运动点
  • 通过new L.TrackPlayer创建轨迹,入参分别是 轨迹数据、轨迹配置。然后直接加到地图当中即可,并且我们保存返回的track对象
  • 最后通过track对象的start方法开启播放,通过pause方法关闭播放
let track = null;
const initPath = () => {
  // 定义沿着轨迹移动的Icon
  let markerIcon = L.icon({
    iconSize: [27, 54],
    iconUrl: CAR, // 前面导入的img资源
    iconAnchor: [13.5, 27]
  });
  // 创建播放器对象并添加至地图
  track = new L.TrackPlayer(path,
  	  // 轨迹配置,都可以不要,保留markerIcon一个就可以了
      {
        markerIcon,
        speed: 500, // 播放速度
        weight: 10, // 轨迹线宽度
        passedLineColor: '#f2cac9', // 已行驶轨迹部分的颜色
        notPassedLineColor: '#fbeee2', // 未行驶轨迹部分的颜色
        panTo: true, // 地图跟随移动
        // 轨迹箭头样式
        polylineDecoratorOptions: {
          patterns: [
            /**
             * offset 第一个图案符号的偏移量,从线的起点开始。默认值:0
             * endOffset 最后一个图案符号的最小偏移量,从线的端点开始。默认值:0
             * repeat 重复间隔。定义每个连续符号的锚点之间的距离
             * symbol 图标样式
             * */
            {
              offset: 0,
              repeat: 20,
              symbol: L.Symbol.arrowHead({
                pixelSize: 10,
                pathOptions: {color: 'red', weight: 2, stroke: true}
              })
            }
          ]
        },
        markerRotation: true // 是否开启marker的旋转
      }
  ).addTo(map);
  track.start();
  // 停止播放
  // track.pause();
  // 清除轨迹
  // track.remove();
};

在这里插入图片描述

通过滑块控制轨迹进度

通过track的progress事件去得到轨迹运动过程当中的值,其中progress就是进度(0-1之间)。只需要去取progress的值去给到el-slider绑定的值就完成了滑块进度对应轨迹进度效果了,同时我们给滑块添加@input事件(使用鼠标拖曳时,活动过程实时触发)。在这个方法当中再通过track.setProgress重新设置值回去也就完成了进度条控制轨迹的效果了

const sliderProgress = ref(0);
// 监听进度 progress 0-1 index 到第几个点
track.on('progress', (progress, {lng, lat}, index) => {
  sliderProgress.value = progress * 100;
  console.log(`progress:${progress.toFixed(2)} - position:${lng.toFixed(2)},${lat.toFixed(2)} - trackIndex:${index}`);
});

const formatTooltip = (val) => {
  return val.toFixed(2);
};

const changeProgress = (val) => {
  track.setProgress(val / 100);
  track.setSpeed(500);
};

<el-slider v-model="sliderProgress" :format-tooltip="formatTooltip" @input="changeProgress"/>

同理还可以控制speed运动速度,通过track.setSpeed(val)去设置。这里默认取500km/h的速度值,而后切换的时候根据500去乘对应的倍数将速度设置回去即可

const selectSpeed = ref(1);
const options = [
  {
    value: 0.5,
    label: 'X0.5'
  },
  {
    value: 1,
    label: 'X1'
  },
  {
    value: 2,
    label: 'X2'
  },
  {
    value: 3,
    label: 'X3'
  },
  {
    value: 5,
    label: 'X5'
  }
];
const changeSpeed = (val) => {
  track.setSpeed(500 * val);
};

<el-select v-model="selectSpeed" @change="changeSpeed">
  <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>

在这里插入图片描述

leaflet-plugin-trackplayback

npm i leaflet-plugin-trackplayback

使用这个插件还需要注意一下版本,其中leaflet-plugin-trackplayback版本是1.0.5,这个时候leaflet用最新的1.9.4会报错Cannot use 'in' operator to search for '_leaflet_id' in undefined。这个时候将leaflet版本降到1.7.0即可。——20240625记录,后续版本升级可能会修复吧

轨迹运动数据准备&初始化

这里每一个运动轨迹组(相当于一个数组)每个数组包含以下几个字段,

  • lng 经度

  • lat 纬度

  • time 时间戳,表示什么时间到该点

  • dir 偏移 0-360之间

  • info 鼠标移入该点展示的内容(表格),格式是key+value。可以看插件渲染的逻辑,直接遍历取key和value值构建table

      _getTooltipText: function (targetobj) {
        let content = []
        content.push('<table>')
        if (targetobj.info && targetobj.info.length) {
          for (let i = 0, len = targetobj.info.length; i < len; i++) {
            content.push('<tr>')
            content.push('<td>' + targetobj.info[i].key + '</td>')
            content.push('<td>' + targetobj.info[i].value + '</td>')
            content.push('</tr>')
          }
        }
        content.push('</table>')
        content = content.join('')
        return content
      },
    

初始化轨迹

  const data = [
    [
      {
        'lng': 104.93071666666665,
        'lat': 34.679016666666665,
        'time': 1502120041,
        'dir': 16,
        'info': []
      },
      {
        'lng': 105.23038333333334,
        'lat': 35.3806,
        'time': 1502151540,
        'dir': 254,
        'info': []
      },
      {
        'lng': 105.13055,
        'lat': 36.379416666666664,
        'time': 1502158560,
        'dir': 173,
        'info': []
      },
      {
        'lng': 104.12878333333334,
        'lat': 37.37925,
        'time': 1502164364,
        'dir': 235,
        'info': []
      },
      {
        'lng': 103.23196666666665,
        'lat': 38.37178333333333,
        'time': 1502164715,
        'dir': 152,
        'info': []
      },
      {
        'lng': 104.9536,
        'lat': 39.33618333333333,
        'time': 1502165384,
        'dir': 158,
        'info': [
          {key: 'name', value: 'zhang san'},
          {key: 'age', value: '18'},
          {key: 'sex', value: 'men'},
          {key: 'address', value: 'anywhere'}
        ]
      }
    ]
  ];

// 入参 轨迹数据、地图对象、配置。通过start方法开始运动
const trackplayback = L.trackplayback(data, map, {})
trackplayback.start()

配置说明

GitHub地址 options配置的源码位置:node_modules/leaflet-plugin-trackplayback/src/leaflet.trackplayback/draw.js & clock.js

{
  // 时间运动配置
  clockOptions: {
    // 播放速度
    // 计算方法 fpstime * Math.pow(2, this._speed - 1)
    speed: 12,
    // 最大播放速度
    maxSpeed: 65
  },
  // info弹框配置
  toolTipOptions: {
    offset: [0, 0],
    direction: 'left',
    permanent: false
  },
  // 运动过程中点配置
  targetOptions: {
    useImg: true,             // 使用图片
    imgUrl: './ship.png',     // 图片地址
    color: '#00f',            // 边框色
    fillColor: '#9FD12D'      // 填充色
  },
  // 远动中经过点配置
  trackPointOptions: {
    isDraw: true,             // 是否绘制
    useCanvas: true,          // 使用canvas
    stroke: true,             // 边框
    color: '#ef0300',         // 边框色
    fill: true,               // 填充
    fillColor: '#ef0300',     // 填充色
    opacity: 1,               // 透明度
    radius: 4                 // 半径
  },
  // 轨迹线配置
  trackLineOptions: {
    isDraw: true,             // 是否绘制
    stroke: true,             // 边框
    color: '#ff4',            // 线色
    weight: 2,                // 线宽
    opacity: 1                // 透明度
    // fill: true,            // 轨迹点之间的填充
    // fillColor: '#000'      // 填充色
  }
}

API说明

也就是拿到trackplayback对象之后调用对应的方法获取到对应的值,然后我们可以切换速度去控制运动快慢,以及切换时间控制运动到那个点。

// 设置时间,从这个时间开始运动
// trackplayback.setCursor(1502164364);

// 获取当前时间(运动过程中)、开始时间、结束时间
// trackplayback.getCurTime();
// trackplayback.getStartTime();
// trackplayback.getEndTime();

// 获取速度
// let speed = trackplayback.getSpeed();

// 隐藏、显示轨迹线
// trackplayback.hideTrackLine();
// trackplayback.showTrackLine();

// 隐藏、显示轨迹点
// trackplayback.hideTrackPoint();
// trackplayback.showTrackPoint()

// 改变速度。重绘轨迹 isPlaying 是否在播放 返回boolean类型
// trackplayback.setSpeed(15);
// trackplayback.rePlaying();

// 暂停轨迹
// trackplayback.stop();
// 销毁轨迹
// trackplayback.dispose();

完整实例

最后贴一下完整的代码示例,替换该文件node_modules/leaflet-plugin-trackplayback/examples/1.html运行该html

<html lang="zh-cn">
<head>
    <title>leaflet.trackplayback</title>
    <link rel="stylesheet" href="./lib/leaflet/leaflet.css">
    <script src="./lib/leaflet/leaflet.js"></script>
    <script src="../dist/leaflet.trackplayback.js"></script>
</head>

<body>
<div id='mapId'
     style=" position: absolute; left: 0; top: 0; right: 0; bottom: 0; width: 100%; height: 100%; overflow: hidden;"></div>
<script>
  const data = [];

  const map = L.map('mapId').setView([33.74, 104.38], 6);
  L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png').addTo(map);

  const trackplayback = L.trackplayback(data, map, {
    clockOptions: {
      // 播放速度
      // 计算方法 fpstime * Math.pow(2, this._speed - 1)
      speed: 12,
      // 最大播放速度
      maxSpeed: 65
    },
    toolTipOptions: {
      offset: [0, 0],
      direction: 'left',
      permanent: false
    },
    // 运动过程中点配置
    targetOptions: {
      useImg: true,             // 使用图片
      imgUrl: './ship.png',     // 图片地址
      color: '#00f',            // 边框色
      fillColor: '#9FD12D'      // 填充色
    },
    // 远动中经过点配置
    trackPointOptions: {
      isDraw: true,             // 是否绘制
      useCanvas: true,          // 使用canvas
      stroke: true,             // 边框
      color: '#ef0300',         // 边框色
      fill: true,               // 填充
      fillColor: '#ef0300',     // 填充色
      opacity: 1,               // 透明度
      radius: 4                 // 半径
    },
    // 轨迹线配置
    trackLineOptions: {
      isDraw: true,             // 是否绘制
      stroke: true,             // 边框
      color: '#ff4',            // 线色
      weight: 2,                // 线宽
      opacity: 1                // 透明度
      // fill: true,            // 轨迹点之间的填充
      // fillColor: '#000'      // 填充色
    }
  });

  trackplayback.start();
</script>
</body>
</html>

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐