网上太多资料代码,抄来抄去,而且版本也是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. 如何在Visual Studio新C++项目中调用之前配置过的库?

      本文介绍在Visual Studio软件中调用C++各种配置.编译完毕的第三方库的方法.   在撰写C++代码时,如果需要用到他人撰写的第三方库(例如地理数据处理库GDAL.矩阵运算库Armadi ...

  2. 基于minsit数据集的图像分类任务|CNN简单应用项目

    Github地址 Image-classification-task-based-on-minsit-datasethttps://github.com/Yufccode/CollegeWorks/t ...

  3. 在Java中,对 byte 和 short 类型 进行位操作的时候,严重留意事项

    总结:在java中,对byte和short类型的 右移操作 必须先进行 & 0xff 后再右移,避免byte或short是负数的情况下,导致 右移操作前 自动升为int,前面补了很多1,此时右 ...

  4. SQL中Between And的问题

    使用Between And时需要注意的事项:(1)"between and"是包括边界值的,"not between"不包括边界值.(2)"betwe ...

  5. Power BI 2 DAY

    目录 Power BI零散知识点 M函数 Power BI零散知识点 纵向合并 = 主页-组合-追加查询-追加查询(修改数据源)-将查询追加为信查询(创建新数据源) 横向合并 = 主页-组合-合并查询 ...

  6. JS leetcode 实现strStr()函数 题解分析

    壹 ❀ 引 前几天心情比较浮躁,烦心事太多,偷懒了3天,还是继续刷leetcode.那么今天做的题目为实现 strStr() 函数.,原题如下: 给定一个 haystack 字符串和一个 needle ...

  7. Linux学习资料锦集

    Linux  学习资料链接: (1)Linux常见命令及其用法_STM32李逼的博客-CSDN博客 (2)Linux命令了解_STM32李逼的博客-CSDN博客 3)Linux使用编辑器_STM32李 ...

  8. Apache HTTP Server、IIS反向代理设置

    Apache HTTP Server 在 Apache 中设置反向代理,需要使用 mod_proxy 和相关的模块,如 mod_proxy_http.以下是一个基本的配置示例: 确保已经安装并启用了  ...

  9. GaussDB(for MySQL) Serverless全面商用:无感弹性,极致性价比

    本文分享自华为云社区<GaussDB(for MySQL) Serverless全面商用:无感弹性,极致性价比>,作者: GaussDB 数据库. 技术背景 对于现代企业级IT系统,数据库 ...

  10. react 高效高质量搭建后台系统 系列

    react 高效高质量搭建后台系统 前言 目标:用 react 高效高质量搭建后台系统 如何实现:搞定一个优秀的.通用的.有一定复杂度的react的后台系统.类似项目就可以依葫芦画瓢快速展开. spu ...