leaflet【十】实时增加轨迹点轨迹回放效果实现

实时轨迹回放

在前面有用leaflet-trackplayer实现了一个轨迹回放的效果,单击前往:轨迹回放效果&控制台控制轨迹运动效果

这篇文章主要是实现一下实时增加轨迹点,不改变原来运行轨迹和速度。这里是简易做了一个demo效果,大概讲述一下实现过程和一些注意的点。整个源码会贴在文章最后:

leaflet-trackplayer

插件npm地址,里面有对应API说明 leaflet-trackplayer

首先准备好一个路径的数据,这里简单循环模拟一下

js 复制代码
const path = [];
for (let i = 0; i < 10; i++) {
  path.push(
      {
        lat: 34 + Math.random() * 0.5,
        lng: 108 + Math.random() * 0.5
      }
  );
}

然后创建一个track对象,也就是利用这个插件实例化一个路径回放的对象,里面的配置什么的就根据实际开发改一下就好了,并且在这里我抽离了一个方法出来,后面回来说这个有什么用。

js 复制代码
const createTrack = (path) => {
  // 创建播放器对象并添加至地图
  track = new L.TrackPlayer(path,
      // 轨迹配置,都可以不要,保留markerIcon一个就可以了
      {
        markerIcon,
        speed: 500, // 播放速度
        weight: 10, // 轨迹线宽度
        passedLineColor: '#0eb0c9', // 已行驶轨迹部分的颜色
        notPassedLineColor: '#add5a2', // 未行驶轨迹部分的颜色
        panTo: true, // 地图跟随移动
        markerRotation: true // 是否开启marker的旋转
      }
  ).addTo(map);
  track.start();

  // 监听运动过程走了多少百分比
  track.on('progress', (progress, {lng, lat}, index) => {
    // 把这个值记录下来,然后给el-progress绑定,这样也就是一个进度条的可视化了。
    sliderProgress.value = progress * 100;
    console.log(`progress:${progress.toFixed(2)} - position:${lng.toFixed(2)},${lat.toFixed(2)} - trackIndex:${index}`);
  });
};

在这个里面有一个track.setProgress(0.5);方法用来设置整个运动的进度,取值在0-1之间,那么进度条反向绑定运动的效果就是这样实现的。

js 复制代码
<el-slider v-model="sliderProgress" :format-tooltip="formatTooltip" @input="changeProgress"/>

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

最后实时更新轨迹,因为这个插件并没有什么实现setPath改变路径数据的方法,那么实现的方法也只能是先删除轨迹,然后重新绘制轨迹,这也是为什么我把创建一个track对象抽成一个方法的原因(创建轨迹运动这一大段代码可以复用)。这里重点在于新增了点之后怎么计算他的一个进度值,在下面代码注释有说明可以理解一下。

js 复制代码
// 删除轨迹对象
const deleteTrack = () => {
  track.remove();
};

// 模拟实时更新
const updatePath = () => {
  deleteTrack();
  const oldLength = path.length;
  for (let i = 0; i < 10; i++) {
    path.push(
        {
          lat: 34 + Math.random() * 0.5,
          lng: 108 + Math.random() * 0.5
        }
    );
  }
  createTrack(path);
  // 需要重新设置进度,除100是转成0-1之间的值,再除整个长度和旧数据的长度的比值
  // 相当于最开始一共十个点,运动到了第五个点,现在进度是50%
  // 这个时候实时增加了5个点,现在就是15个点,如果取15的百分之50就变成了运动到7.5这个点,就显然不对了
  // 15 / 10 = 1.5  这个时候再用50% / 1.5 得到的值是 1/3,那么也正好是第五个点相对于现在整个15个点的位置了。
  track.setProgress(sliderProgress.value / 100 / (path.length / oldLength));
};

到这里就是完成了,然后前后端交互就看什么时候调用接口就相当于走上面这个updatePath方法。

存在一个小缺陷就是,在更新数据的时候由于是先删再画就会有一点点闪烁。录制的效果不是很好,可以测试一下在点击增加轨迹点,当前这个图标运动的位置(也就是整体进度)是不会发生改变的

完整源码

vue 复制代码
<script lang="js" setup>
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import CAR from '@/assets/image/car.png';
import 'leaflet-trackplayer';

onMounted(() => {
  initMap();
});

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

let track = null;
const path = [];
for (let i = 0; i < 10; i++) {
  path.push(
      {
        lat: 34 + Math.random() * 0.5,
        lng: 108 + Math.random() * 0.5
      }
  );
}

// 进度条,这个值在0-100之间
const sliderProgress = ref(0);

// 定义沿着轨迹移动的Icon
const markerIcon = L.icon({
  iconSize: [27, 54],
  iconUrl: CAR, // 前面导入的img资源
  iconAnchor: [13.5, 27]
});

const initPath = () => {
  createTrack(path);
};

// 创建track对象
const createTrack = (path) => {
  // 创建播放器对象并添加至地图
  track = new L.TrackPlayer(path,
      // 轨迹配置,都可以不要,保留markerIcon一个就可以了
      {
        markerIcon,
        speed: 500, // 播放速度
        weight: 10, // 轨迹线宽度
        passedLineColor: '#0eb0c9', // 已行驶轨迹部分的颜色
        notPassedLineColor: '#add5a2', // 未行驶轨迹部分的颜色
        panTo: true, // 地图跟随移动
        markerRotation: true // 是否开启marker的旋转
      }
  ).addTo(map);
  track.start();

  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 deleteTrack = () => {
  track.remove();
};

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

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

// 模拟实时更新
const updatePath = () => {
  deleteTrack();
  const oldLength = path.length;
  for (let i = 0; i < 10; i++) {
    path.push(
        {
          lat: 34 + Math.random() * 0.5,
          lng: 108 + Math.random() * 0.5
        }
    );
  }
  createTrack(path);
  track.setProgress(sliderProgress.value / 100 / (path.length / oldLength));
  // 如果速度也变了记得也一起更新
  track.setSpeed(500 * selectSpeed.value);
};

/**------------------------改变速度---------------------------------------*/
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);
};
</script>

<template>
  <div id="map" ref="mapContainer" class="w-full h-4/6"></div>
  <div class="m-2">
    <el-button type="primary" @click="initPath">查询轨迹</el-button>
    <el-button type="primary" @click="track.start()">开始</el-button>
    <el-button type="primary" @click="track.pause()">暂停</el-button>
    <el-button type="primary" @click="deleteTrack">删除轨迹</el-button>
    <el-button type="primary" @click="updatePath">模拟接口更新</el-button>
  </div>

  <br/>
  <div class="m-2 bg-blue-200 p-2 rounded-md">
    <div class="font-bold">控制台</div>
    <div>进度条</div>
    <div class="w-[400px] ml-2">
      <el-slider v-model="sliderProgress" :format-tooltip="formatTooltip" @input="changeProgress"/>
    </div>
    <div>
      运动速度:
      <el-select
          v-model="selectSpeed"
          style="width: 140px"
          @change="changeSpeed"
      >
        <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
        />
      </el-select>
    </div>
  </div>
</template>

leaflet-plugin-trackplayback

然后还有这个轨迹回放的插件,这个插件就可以根据时间来进行控制,这个功能后续实现在更新一下这个文章,

相关推荐
SL-staff2 天前
Vue3私有化AI白板落地实战|解决政企项目智能绘图合规难题(可直接复用源码)
人工智能·低代码·开源·vue3·白板·jvs规则引擎·jvs-draw
雨季mo浅忆2 天前
Cursor快速实现上传Excel功能
前端·vue3·ai编程
ANnianStriver4 天前
PetLumina-AI 驱动的宠物生活管理平台
java·生活·vue3·springboot·ai编程·宠物·全栈开发
雨季mo浅忆5 天前
记录Vue3项目中的各类问题
前端·bug·vue3
八目蛛8 天前
八目蛛网络(免费工具网站导航)
css·vue.js·开源·vue3·html5·ai编程
颂love8 天前
Vue3基础入门
前端·学习·vue3
海市公约9 天前
Vue3组合式API中watch传值生命周期与自定义Hook实战
vue3·生命周期·watch·props·组件通信·defineexpose·自定义hook
海市公约10 天前
Vue3组合式API与响应式系统核心机制详解
vue3·computed·reactive·ref·响应式系统·composition api·script setup
小茴香35311 天前
Vue3路由权限动态管理
前端·前端框架·vue3
暗冰ཏོ15 天前
《2026 Vue2 + Vue3 完整学习指南:基础语法、路由缓存、登录拦截、项目实战与面试题》
前端·vue.js·vue·vue3·vue2