在vue3中使用openlayers3实现track轨迹动画
网上太多资料代码,抄来抄去,而且版本也是v5.x版本的,部分API已经弃用
基础知识不多说,直接讲重点
- 三个关键变量
// 记录开始动画的时间
const startTime = ref(0);
// 轨迹分割的颗粒度,数值越小分的越细
const particle = 20;
// 轨迹动画的速度,数值越大位移越快
const speed = 10;
- 根据给定的轨迹线路,确定轨道上每个位移点
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)!);
- 将起点、终点、轨迹、运动小车样式添加到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);
- 绑定事件render监听事件,记录开始时间
startTime.value = new Date().getTime();
map.value.on("postrender", move);
// 第一次需要手动调用一遍,否则不执行postcompose
map.value.render();
- 动画逻辑
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轨迹动画的更多相关文章
- Vue3中的响应式对象Reactive源码分析
Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...
- 从matlab中导出下载到的轨迹数据
我从该网址(http://www.ee.cuhk.edu.hk/~xgwang/MITtrajsingle.html)下载到了一些轨迹数据. 网页中简单说明了轨迹数据的由来:原始数据是在一个停车场上方 ...
- vue3中使用axios如何去请求数据
在vue2中一般放在created中,但是在vue3中取消了created生命周期,请求方式有两种 直接在setup中去获取数据 setup(props) { const data = reactiv ...
- vue3中watch函数
watch 监听普通类型 let count = ref(1); const changeCount = () => { count.value+=1 }; watch(count, (newV ...
- 端午总结Vue3中computed和watch的使用
1使用计算属性 computed 实现按钮是否禁用 我们在有些业务场景的时候,需要将按钮禁用. 这个时候,我们需要使用(disabled)属性来实现. disabled的值是true表示禁用.fals ...
- vue 3 学习笔记 (七)——vue3 中 computed 新用法
vue3 中 的 computed 的使用,由于 vue3 兼容 vue2 的选项式API,所以可以直接使用 vue2的写法,这篇文章主要介绍 vue3 中 computed 的新用法,对比 vue2 ...
- 在vue3中使用router-link-active遇到的坑
在使用 router-link-active 设置链接激活时CSS类名时,发现在例如 /member/order 和 /member/order/:id 这两个都包含 /member/order的路由 ...
- Vue3中插槽(slot)用法汇总
Vue中的插槽相信使用过Vue的小伙伴或多或少的都用过,但是你是否了解它全部用法呢?本篇文章就为大家带来Vue3中插槽的全部用法来帮助大家查漏补缺. 什么是插槽 简单来说就是子组件中的提供给父组件使用 ...
- vue3中defineComponent 的作用
vue3中,新增了 defineComponent ,它并没有实现任何的逻辑,只是把接收的 Object 直接返回,它的存在是完全让传入的整个对象获得对应的类型,它的存在就是完全为了服务 TypeSc ...
- Module Federation 模块联邦 在Vue3中使用Vue2搭建的微服务
前言: 备注:本文基于对webpack Module Federation有一定了解的情况下 一般情况下使用模块联邦都是会使用相同的版本,如Vue2的组件时在Vue2中使用,但我为什么会在Vue3项目 ...
随机推荐
- HarmonyOS 实战小项目开发(一)
HarmonyOS 实战小项目开发(一) 日常逼逼叨 在经过一周多的Harmonyos 开发基础知识的学习后,自己通过对于Harmonyos基础知识的学习之后,结合自己的一些想法,独自完成了利用Ark ...
- (C语言)每日代码||2023.12.25||strcpy()函数两个参数中的'\0'
#include <stdio.h> #include <string.h> #define MAX 500 void test() { char arr1[] = { '1' ...
- 神经网络优化篇:详解如何训练一个 Softmax 分类器(Training a Softmax classifier)
如何训练一个 Softmax 分类器 回忆一下之前举的的例子,输出层计算出的\(z^{[l]}\)如下,\(z^{[l]} = \begin{bmatrix} 5 \\ 2 \\ - 1 \\ 3 \ ...
- Go语言核心36讲(Go语言实战与应用十)--学习笔记
32 | context.Context类型 我们在上篇文章中讲到了sync.WaitGroup类型:一个可以帮我们实现一对多 goroutine 协作流程的同步工具. 在使用WaitGroup值的时 ...
- 使用HttpServletResponse实现curl接口时控制台输出(续)
上一篇文章的问题 在上一篇文章 Spring Boot RestController接口如何输出到终端 中讨论了如何使用 HttpSerlvetResponse 写入输出流,使应急接口通过 curl ...
- JS Leetcode 179. 最大数 题解分析,sort a-b与b-a的区别,sort排序原理解析
壹 ❀ 引 今天的题目来自LeetCode179. 最大数,题目描述如下: 给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数. 注意:输出结果可能非常大,所以你 ...
- Sunnyui画曲线溢出错误
之前用sunnyui做展示数据库数据曲线的时候.偶然会报溢出错误,也不报错错误在哪,就是直接程序都跑不动了. 后面发现 设置曲线上下限的时候,当上下限一样的时候就会导致溢出错误.sunnyui的曲线也 ...
- NC13230 合并回文子串
题目链接 题目 题目描述 输入两个字符串A和B,合并成一个串C,属于A和B的字符在C中顺序保持不变.如"abc"和"xyz"可以被组合成"axbycz ...
- Python 写入文件、读取文件内容——open函数/readLines/Write/find函数用法
1.读取.txt整个文件 ww.txt文件在程序文件所在的目录,在文件存储在其他地方,ww.txt需要添加文件路径,如:E:\book1\ww.txt:读取后希望返回的是列表类型,将read改为rea ...
- AIR32F103(二) Linux环境和LibOpenCM3项目模板
目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...