网上太多资料代码,抄来抄去,而且版本也是v5.x版本的,部分API已经弃用

基础知识不多说,直接讲重点

  1. 三个关键变量
//  记录开始动画的时间
const startTime = ref(0);
// 轨迹分割的颗粒度,数值越小分的越细
const particle = 20;
// 轨迹动画的速度,数值越大位移越快
const speed = 10;
  1. 根据给定的轨迹线路,确定轨道上每个位移点
  const trackLine = new LineString(coordinates);
// 轨迹在投影平面上的长度
const trackLineLen = trackLine.getLength();
// 当前平面的分辨率
const resolution = map.value.getView().getResolution();
// 点有可能是小数,要到终点需要手动添加最后一个点
const pointCount = trackLineLen / (resolution * particle);
for (let i = 0; i <= pointCount; i++) {
passCoordinates.value.push(trackLine.getCoordinateAt(i / pointCount));
}
passCoordinates.value.push(coordinates.at(-1)!);
  1. 将起点、终点、轨迹、运动小车样式添加到layer上
 // 设置运动小车样式,并添加ID,供后续逻辑找到此geometry
const geoMarker = new Feature({
type: "geoMarker",
geometry: new Point(passCoordinates.value[0]!)
});
geoMarker.setId("point"); featureLayer.value = new VectorLayer({
source: new Vector({
features: [trackFeature, geoMarker, startMarker, endMarker]
}),
style: (feature) => {
return styles[feature.get("type")];
}
}); map.value.addLayer(featureLayer.value);
  1. 绑定事件render监听事件,记录开始时间
  startTime.value = new Date().getTime();
map.value.on("postrender", move);
// 第一次需要手动调用一遍,否则不执行postcompose
map.value.render();
  1. 动画逻辑
const move = (evt: RenderEvent) => {
const frameState = evt.frameState;
// 执行动画已经过了多少时间(秒)
const timeout = (frameState!.time - startTime.value) / 1000;
let count = Math.round(speed * timeout); if (count >= passCoordinates.value.length - 1) {
// 确保到达最后一个点位,并停止移动动画
count = passCoordinates.value.length - 1;
stopMove();
}
const point = featureLayer.value.getSource().getFeatureById("point");
// point.setGeometry(new Point(passCoordinates.value[count]));
point.getGeometry().setCoordinates(passCoordinates.value[count]);
map.value.render();
};

完整代码:

<template>
<div class="map" id="map" ref="myMap"></div>
<button @click="startMove">start animate</button>
</template> <script setup lang="ts">
import { Feature, Map, View } from "ol";
import { Coordinate } from "ol/coordinate";
import { LineString, Point } from "ol/geom";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import { transform } from "ol/proj";
import RenderEvent from "ol/render/Event";
import { Vector, XYZ } from "ol/source";
import { Circle, Fill, Icon, Stroke, Style } from "ol/style";
import { onBeforeUnmount, onMounted, ref } from "vue";
import markIcon from "../assets/mark.png"; const map = ref();
const featureLayer = ref();
const passCoordinates = ref<Coordinate[]>([]); // 记录开始动画的时间
const startTime = ref(0);
// 轨迹分割的颗粒度,数值越小分的越细
const particle = 20;
// 轨迹动画的速度,数值越大位移越快
const speed = 10; onMounted(() => {
initMap();
addTrack();
});
const initMap = () => {
const amap = new TileLayer({
source: new XYZ({
url: "http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
wrapX: false
})
});
map.value = new Map({
target: "map",
layers: [amap],
view: new View({
center: transform([114.3, 30.5], "EPSG:4326", "EPSG:3857"),
zoom: 10,
minZoom: 3
})
});
}; const coordinates = [
transform([114.0, 30.0], "EPSG:4326", "EPSG:3857"),
transform([114.1, 30.1], "EPSG:4326", "EPSG:3857"),
transform([114.2, 30.1], "EPSG:4326", "EPSG:3857"),
transform([114.2, 30.4], "EPSG:4326", "EPSG:3857"),
transform([114.4, 30.4], "EPSG:4326", "EPSG:3857")
]; const addLayer = (trackLine: any) => {
const trackFeature = new Feature({
type: "track",
geometry: trackLine
});
const geoMarker = new Feature({
type: "geoMarker",
geometry: new Point(passCoordinates.value[0]!)
});
geoMarker.setId("point"); const startMarker = new Feature({
type: "icon",
geometry: new Point(passCoordinates.value[0]!)
});
const endMarker = new Feature({
type: "icon",
geometry: new Point(passCoordinates.value.at(-1)!)
}); const styles: { [k in string]: Style } = {
track: new Style({
stroke: new Stroke({
width: 6,
color: [220, 30, 60, 0.9]
})
}),
icon: new Style({
image: new Icon({
anchor: [0.5, 1],
scale: 0.4,
src: markIcon
})
}),
geoMarker: new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: "#333" }),
stroke: new Stroke({
color: "#f00",
width: 2
})
})
})
}; featureLayer.value = new VectorLayer({
source: new Vector({
features: [trackFeature, geoMarker, startMarker, endMarker]
}),
style: (feature) => {
return styles[feature.get("type")];
}
}); map.value.addLayer(featureLayer.value);
}; const move = (evt: RenderEvent) => {
const frameState = evt.frameState;
// 执行动画已经过了多少时间(秒)
const timeout = (frameState!.time - startTime.value) / 1000;
let count = Math.round(speed * timeout); if (count >= passCoordinates.value.length - 1) {
// 确保到达最后一个点位,并停止移动动画
count = passCoordinates.value.length - 1;
stopMove();
}
const point = featureLayer.value.getSource().getFeatureById("point");
// point.setGeometry(new Point(passCoordinates.value[count]));
point.getGeometry().setCoordinates(passCoordinates.value[count]);
map.value.render();
}; const startMove = () => {
startTime.value = new Date().getTime();
map.value.on("postrender", move);
// 第一次需要手动调用一遍,否则不执行postcompose
map.value.render();
}; const stopMove = () => {
map.value.un("postrender", move);
}; const addTrack = () => {
const trackLine = new LineString(coordinates);
// 轨迹在投影平面上的长度
const trackLineLen = trackLine.getLength();
// 当前平面的分辨率
const resolution = map.value.getView().getResolution(); // 点有可能是小数,要到终点需要手动添加最后一个点
const pointCount = trackLineLen / (resolution * particle);
for (let i = 0; i <= pointCount; i++) {
passCoordinates.value.push(trackLine.getCoordinateAt(i / pointCount));
}
passCoordinates.value.push(coordinates.at(-1)!); addLayer(trackLine);
}; onBeforeUnmount(stopMove);
</script> <style lang="scss" scoped>
.map {
width: 100vw;
height: 80vh;
}
</style>
Ï

在vue3中使用openlayers3实现track轨迹动画的更多相关文章

  1. Vue3中的响应式对象Reactive源码分析

    Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...

  2. 从matlab中导出下载到的轨迹数据

    我从该网址(http://www.ee.cuhk.edu.hk/~xgwang/MITtrajsingle.html)下载到了一些轨迹数据. 网页中简单说明了轨迹数据的由来:原始数据是在一个停车场上方 ...

  3. vue3中使用axios如何去请求数据

    在vue2中一般放在created中,但是在vue3中取消了created生命周期,请求方式有两种 直接在setup中去获取数据 setup(props) { const data = reactiv ...

  4. vue3中watch函数

    watch 监听普通类型 let count = ref(1); const changeCount = () => { count.value+=1 }; watch(count, (newV ...

  5. 端午总结Vue3中computed和watch的使用

    1使用计算属性 computed 实现按钮是否禁用 我们在有些业务场景的时候,需要将按钮禁用. 这个时候,我们需要使用(disabled)属性来实现. disabled的值是true表示禁用.fals ...

  6. vue 3 学习笔记 (七)——vue3 中 computed 新用法

    vue3 中 的 computed 的使用,由于 vue3 兼容 vue2 的选项式API,所以可以直接使用 vue2的写法,这篇文章主要介绍 vue3 中 computed 的新用法,对比 vue2 ...

  7. 在vue3中使用router-link-active遇到的坑

    在使用 router-link-active 设置链接激活时CSS类名时,发现在例如 /member/order 和 /member/order/:id 这两个都包含 /member/order的路由 ...

  8. Vue3中插槽(slot)用法汇总

    Vue中的插槽相信使用过Vue的小伙伴或多或少的都用过,但是你是否了解它全部用法呢?本篇文章就为大家带来Vue3中插槽的全部用法来帮助大家查漏补缺. 什么是插槽 简单来说就是子组件中的提供给父组件使用 ...

  9. vue3中defineComponent 的作用

    vue3中,新增了 defineComponent ,它并没有实现任何的逻辑,只是把接收的 Object 直接返回,它的存在是完全让传入的整个对象获得对应的类型,它的存在就是完全为了服务 TypeSc ...

  10. Module Federation 模块联邦 在Vue3中使用Vue2搭建的微服务

    前言: 备注:本文基于对webpack Module Federation有一定了解的情况下 一般情况下使用模块联邦都是会使用相同的版本,如Vue2的组件时在Vue2中使用,但我为什么会在Vue3项目 ...

随机推荐

  1. 人工智能LLM模型:奖励模型的训练、PPO 强化学习的训练、RLHF

    人工智能LLM模型:奖励模型的训练.PPO 强化学习的训练.RLHF 1.奖励模型的训练 1.1大语言模型中奖励模型的概念 在大语言模型完成 SFT 监督微调后,下一阶段是构建一个奖励模型来对问答对作 ...

  2. Midjourney|文心一格 Prompt:完整参数列表、风格汇总、文生图词典合集

    Midjourney|文心一格 Prompt:完整参数列表.风格汇总.文生图词典合集 1.Midjourney 完整参数列表 参数名称 调用方法 使用案例 注意事项 V5 V4 V3 niji 版本 ...

  3. C/C++ 发送与接收HTTP/S请求

    HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的协议.它是一种无状态的.应用层的协议,用于在计算机之间传输超文本文档,通常在 Web 浏览器和 Web 服务器之 ...

  4. svg图片引入方式

    第一种直接引入: <svg t="1684280784467" class="icon" viewBox="0 0 1024 1024" ...

  5. 递归锁和死锁(Python)

    一.递归锁 # Lock :互斥锁 效率高 # RLock :递归(recursion)锁 效率相对低 在同一个线程中可以被acquire多次,如果想要释放锁,acquire多少次就要release多 ...

  6. 小知识:grep过滤以#号开头的注释行 和 空行

    xtts的配置文件,有很多注释不想直接去掉的情况下,想清楚的看到目前设置了哪些参数,可以用grep过滤查看: grep -vE '^#|^$' xtt.properties 效果如下: [oracle ...

  7. 针对SpringBoot服务端返回的空对象和空数组问题

    返回的Json会自动过滤掉空指针的对象,但是若遇到非空指针的没有任何内容的对象,举例如下: public class Person { private String name; private Int ...

  8. DHCP中继代理配置与管理

    实验介绍:DHCP中继存在目的 当一台DHCP需要配置不同网段的IP地址时 一:前期准备 1.在DHCP服务器配置页面 右键ipv4,建立多个作用域. 我这里设置了三个可以分配给服务器端的网段,分别是 ...

  9. Hive中Lateral view用法

    1. lateral view 简介   hive函数 lateral view 主要功能是将原本汇总在一条(行)的数据拆分成多条(行)成虚拟表,再与原表进行笛卡尔积,从而得到明细表.配合UDTF函数 ...

  10. [Java]《On Java》阅读记录之 -- 可变参数重载问题

    <On Java>阅读记录之 -- 可变参数重载问题 有下面一段代码: public class OverloadingVarargs2 { static void f(float i , ...