网上太多资料代码,抄来抄去,而且版本也是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. 希尔伯特变换用于解调系统——以解调调频信号为例,FM Demodulation

    What's The Hilbert Transform 简单地说,希尔伯特变换的物理意义为:把信号的所有频率分量的相位推迟90度,这样原信号和变换后信号可以视为一组IQ正交信号,在数字域正交化,可以 ...

  2. 微信小程序网页嵌入开发

    无脑开发 下载微信开发者工具 新建一个项目找到index开头的进去全选删除粘贴下面代码 <!-- html --> <!-- 指向嵌入外部链接的地址 --> <web-v ...

  3. [1] HEVD 学习笔记:HEVD 环境搭建

    1. HEVD 概述 + 环境搭建 ​ HEVD作为一个优秀的内核漏洞靶场受到大家的喜欢,这里选择x86的驱动来学习内核漏洞,作为学习笔记记录下来 实验环境 环境 备注 调试主机操作系统 Window ...

  4. 因为命名被diss无数次。简单聊聊编程最头疼的事情之一:命名

    本文已经收录进我的 80K+ Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖 ...

  5. 从嘉手札<2023-10-16>

    一.商君书 1)更法 商鞅和甘龙.杜挚同秦孝公商量变法. 后两者认为变法会动移已有的社会结构,"圣人不易民而教,知者不变法而治""法古无过,循礼无邪" 但商鞅( ...

  6. webpack重新打包清空dist文件夹的问题

    1.5.20.0以上版本才支持output属性里的clean:true 5.20.0+ 5.20以下版本清除dist文件内容一般使用插件 clean-webpack-plugin, 5.20版本以后o ...

  7. 同时配置github和gitee秘钥

    1.设置用户名和邮箱 git config --global --list 查看全局配置信息 git config --global --list 删除配置:必须删除该设置 git config -- ...

  8. 开源的ChatGPT项目

    自从 ChatGPT.Stable Diffusion 发布以来,各种相关开源项目百花齐放,着实让人应接不暇. 今天,我将着重挑选几个优质的开源项目,对我们的日常工作.学习生活,都会有很大的帮助. 今 ...

  9. deque的rotate方法

    deque对象支持旋转操作,可以将元素向左或向右循环移动. 例如: from collections import deque dq = deque([1, 2, 3, 4]) dq.rotate(1 ...

  10. DbgridEh 1900-01-01 00:00:00 问题解决

    --------------------------------------------------