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

实时轨迹回放

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

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

leaflet-trackplayer

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

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

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

然后创建一个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) => {
    // 把这个值记录下来,然后给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之间,那么进度条反向绑定运动的效果就是这样实现的。

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

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

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

// 删除轨迹对象
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方法。

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

在这里插入图片描述

完整源码

<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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/877509.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3透传、注入

属性透传 传递给子组件时&#xff0c;没有被子组件消费的属性或事件&#xff0c;常见的如id、class 注意1 1.class、style是合并的&#xff0c;style中如果出现重复的样式&#xff0c;以透传属性为准2.id属性是以透传属性为准&#xff0c;其他情况透传属性名相同&#xff0c…

【AI视频】复刻抖音爆款AI数字人作品初体验

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI视频 | AI数字人 文章目录 &#x1f4af;前言&#x1f4af;抖音上的爆火AI数字人视频&#x1f4af;注册HeyGen账号&#x1f4af;复刻抖音爆款AI数字人&#x1f4af;最终生成效果&#x1f4af;小结 对比原视频效果&#xff1a;…

【算法篇】哈希类(笔记)

目录 一、常见的三种哈希结构 二、LeetCode 练习 1. 有效的字母异位词 2. 两个数组的交集 3. 快乐数 4. 两数之和 5. 四数相加II 6. 赎金信 7. 三数之和 8. 四数之和 一、常见的三种哈希结构 当想使用哈希法来解决问题的时候&#xff0c;一般会选择如下三种数据…

Java--String类

前言&#xff1a; 在之前的学习中&#xff0c;学习了和了解了一些类的基本使用&#xff0c;例如object类等等&#xff0c;但是我们用String这个引用或者说这个类其实我们已经用了好久&#xff0c;只不过没有具体分析过&#xff01; 对于String类&#xff0c;它可以引用一个字符…

JavaScript web API part3

web API DOM 日期对象 > 得到当前系统的时间 new这个操作就是实例化 语法 const date new Date() or const date new Date(2004-11-3 08:00:00) 可以指定时间 > 可应用于通过系统时间和指定时间实现倒计时的操作 //得到当前时间const date new Date()console.lo…

【Python小知识 - 2】:在VSCode中切换Python解释器版本

文章目录 在VSCode中切换Python解释器版本 在VSCode中切换Python解释器版本 在VSCode中按下快捷键CtrlShiftP&#xff0c;出现命令框。 输入以下命令&#xff1a; Python: Select Interpreter输入命令回车后即出现不同的Python解释器选项&#xff0c;选择想要切换的Python解释器…

【题解】—— LeetCode一周小结37

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结36 9.合并零之间的节点 题目链接&#xff1a;2181. 合并零之间…

【最新综述】基于深度学习的超声自动无损检测(下)

4.Levels of automation 5.Basic axioms for DL-based ultrasonic NDE 在回顾了最新技术和每个自动化级别的贡献之后&#xff0c;我们不难发现&#xff0c;目前的数字语言方法论在不同论文之间存在着很大的差异。例如&#xff0c;有些作者提出了同时处理不同步骤的模型[121]&…

感知器神经网络

1、原理 感知器是一种前馈人工神经网络&#xff0c;是人工神经网络中的一种典型结构。感知器具有分层结构&#xff0c;信息从输入层进入网络&#xff0c;逐层向前传递至输出层。根据感知器神经元变换函数、隐层数以及权值调整规则的不同&#xff0c;可以形成具有各种功能特点的…

Java并发常见面试题(上)

Java并发常见面试题(上) 什么是线程和进程? 一个 Java 程序的运行是 main 线程和多个其他线程同时运行 进程:程序的一次执行过程&#xff0c;系统运行一个程序就是一个进程从创建&#xff0c;运行到消亡的过程。在Java中启动main函数就是开启一个进程&#xff0c;main函数所…

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统 在产品将要上线之前&#xff0c;需要制作不同类型格式的根文件系统 在产品研发阶段&#xff0c;我们还是需要使用nfs的方式挂载根文件系统 优点&#xff1a;可以直接在上位机中修改文件系统内容&#xff0c;延长EMMC的寿命 【1】重启上位机nfs服…

WPF利用Path自定义画头部导航条(TOP)样式

1;新建两个多值转换器&#xff0c;都有用处&#xff0c;用来动态确定PATH的X,Y州坐标的。 EndPointConverter 该转换器主要用来动态确定X轴&#xff0c;和Y轴。用于画线条的。 internal class EndPointConverter : IMultiValueConverter {public object Convert(object[] val…

wifiip地址可以随便改吗?wifi的ip地址怎么改变

对于普通用户来说&#xff0c;WiFi IP地址的管理和修改往往显得神秘而复杂。本文旨在深入探讨WiFi IP地址是否可以随意更改&#xff0c;以及如何正确地改变WiFi的IP地址。虎观代理小二将详细解释WiFi IP地址的基本概念、作用以及更改时需要注意的事项&#xff0c;帮助用户更好地…

PPT中的图形与图片:插入、调整与格式设置技术详解

目录 引言 一、图形与图片的插入 1. 插入图形 2. 插入图片 二、图形与图片的调整 1. 调整大小与位置 2. 裁剪与旋转 3. 图形与图片的合并与组合 三、图片格式与布局设置 1. 图片格式设置 2. 图片布局设置 示例案例&#xff1a;制作产品展示PPT 四、结论 引言 在现…

Harmony OS DevEco Studio低代码开发流程 - HarmonyOS开发自学5

一. 为什么要用低代码开发&#xff1f; HarmonyOS低代码开发方式&#xff0c;具有丰富的UI界面编辑功能&#xff0c;例如基于图形化的自由拖拽、数据的参数化配置等&#xff0c;通过可视化界面开发方式快速构建布局&#xff0c;可有效降低用户的时间成本和提升用户构建UI界面的…

【JVM】类加载

1. 类加载过程 Java虚拟机&#xff08;JVM&#xff09;的 类加载 过程是将字节码文件&#xff08;.class文件&#xff09;从存储设备加载到内存&#xff0c;并为其创建相应的类对象的过程。类加载是Java程序运行的基础&#xff0c;保证了程序的动态性和安全性。JVM的类加载过程…

Unity 粒子系统参数说明

一、Particle System 1. Duration&#xff08;持续时间&#xff09; 粒子系统运行一次所需的时间。它决定粒子系统持续播放的时间长度。 2. Looping&#xff08;循环播放&#xff09; 如果启用&#xff0c;粒子系统将在播放完一次后自动重新开始播放&#xff0c;直到你停止它…

pgrouting实战应用

1&#xff09;下载地区地区数据&#xff08;下载数据是XYZM 四位数据&#xff09; 2&#xff09;下载裁剪行政区数据 3&#xff09;使用arcgis pro添加路网数据和行政区数据 4&#xff09;裁剪数据&#xff0c;仅历下行政区路网 5&#xff09;arcgis pro要素转线&#xff0…

【数据结构】顺序表和链表经典题目

系列文章目录 单链表 动态顺序表实现通讯录 顺序表 文章目录 系列文章目录前言一、顺序表经典例题1. 移除元素2. 合并两个有序数组 二、链表经典例题1. 移除链表元素2. 反转链表3. 合并两个有序链表4. 链表的中间节点5. 环形链表的约瑟夫问题 总结 前言 我们通过前面对顺序表…

ArrayList 源码解析

ArrayList是Java集合框架中的一个动态数组实现&#xff0c;提供了可变大小的数组功能。它继承自AbstractList并实现了List接口&#xff0c;是顺序容器&#xff0c;即元素存放的数据与放进去的顺序相同&#xff0c;允许放入null元素&#xff0c;底层通过数组实现。除该类未实现同…