openlayers-16-添加一组轨迹动画

实现一组动画,即根据一组只有起止点坐标的线段,实现点在这些线段上较为平滑的移动,移动速度和平滑程度均可控制。

下面的代码仅作为思路参考,还欠缺很多细节,比如在进行插值计算时,还需要判断经纬度坐标差,选择差值大的作为已知项计算插值,这样会避免一些bug并让计算的插值数据更平滑。还有如何把示例中的圆点改为箭头,并计算箭头的方向与线的走向一致等等一些问题。如果有时间,后期会整理一个更加具体的,可以直接移植使用的demo。

运行结果

在这里插入图片描述

代码如下

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>添加箭头动画</title><link href="ol/ol.css" rel="stylesheet" type="text/css"/><script src="ol/ol.js" type="text/javascript"></script><style type="text/css">#mapCon {width: 100%;height: 100%;}</style>
</head>
<body>
<!-- 地图容器 -->
<div id="mapCon"></div>
<div style="position: absolute;top: 20px;left: 50%;">运动速度:<input id="speed" type="range" min="1" max="10" step="1" value="5"/><button id="start-animation">开始</button>
</div>
<script type="text/javascript">var key = "4689fc6b9bc0fdc8c48298f751ebfb41";//天地图密钥//ol.layer.Tile:是一个瓦片图层类,用于显示瓦片资源。//source是必填项,用于为图层设置来源。//ol.source.XYZ://创建天地图矢量图层var TiandiMap_vec = new ol.layer.Tile({title: "天地图矢量图层",source: new ol.source.XYZ({url: "http://t{0-7}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=" + key,wrapX: false})});//创建天地图矢量注记图层var TiandiMap_cva = new ol.layer.Tile({title: "天地图矢量注记图层",source: new ol.source.XYZ({url: "http://t{0-7}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=" + key,})});//实例化Map对象加载地图var map = new ol.Map({//地图容器div的IDtarget: 'mapCon',//地图容器中加载的图层layers: [TiandiMap_vec, TiandiMap_cva],//地图视图设置view: new ol.View({//地图初始中心点(经纬度)center: [118.37, 37.14],//地图初始显示级别zoom: 12,projection: "EPSG:4326"})});/*** 线性插值* @param start 线段开始点的坐标* @param end 结束点坐标* @param step 步长* @returns {*[]}*/function interpolate(start, end, step) {const x = start[0] + step * (end[0] - start[0]);let num = Math.ceil(Math.abs(end[0] - start[0]) / step);let xArr = [];setp = end[0] > start[0] ? step : 0 - step;for (let i = 1; i < num; i++) {xArr.push(start[0] + setp * i);}//插入起点let lonlat = [start];for (let i = 0; i < xArr.length; i++) {let y = start[1] + (end[1] - start[1]) / (end[0] - start[0]) * (xArr[i] - start[0]);lonlat.push([xArr[i], y]);}//加入终点lonlat.push(end);return lonlat;}//构建一组离散化的点(一组线段的起止点)var Coordinates = [{lonlat: [[118.37, 37.14], [118.48, 37.05]]},{lonlat: [[118.46, 37.04], [118.51, 37.06]]}];//遍历线段,并根据起止点,计算插值数据,用于动画let routes = [];//路径对象数组for (let i = 0; i < Coordinates.length; i++) {const item = Coordinates[i];//获取插值数据let lonlatArr = interpolate(item.lonlat[0], item.lonlat[1], 0.01);//将插值数据构建为Line对象let route = new ol.geom.LineString(lonlatArr);//获取直线的坐标let routeCoords = route.getCoordinates();let routeLength = routeCoords.length;let routeFeature = new ol.Feature({type: 'route',geometry: route});let geoMarker = new ol.Feature({type: 'geoMarker',geometry: new ol.geom.Point(routeCoords[0])});routes.push({route: route,routeCoords: routeCoords,routeLength: routeLength,routeFeature: routeFeature,geoMarker, geoMarker,index: 0})}var styles = {'route': new ol.style.Style({stroke: new ol.style.Stroke({width: 6,color: [237, 212, 0, 0.8]})}),'icon': new ol.style.Style({image: new ol.style.Icon({anchor: [0.5, 1],src: "../../images/stationicon.png"})}),'geoMarker': new ol.style.Style({image: new ol.style.Circle({radius: 7,snapToPixel: false,fill: new ol.style.Fill({color: 'black'}),stroke: new ol.style.Stroke({color: 'white',width: 2})})})};var animating = false;var speed, now;var speedInput = document.getElementById('speed');var startButton = document.getElementById('start-animation');//添加用于展示动画的层var vectorSource = new ol.source.Vector();var vectorLayer = new ol.layer.Vector({source: vectorSource,style: function (feature) {//如果动画是激活的就隐藏geoMarkerif (animating && feature.get('type') === 'geoMarker') {return null;}return styles[feature.get('type')];}});map.addLayer(vectorLayer);for (let i = 0; i < routes.length; i++) {let item = routes[i];vectorSource.addFeature(item.routeFeature);vectorSource.addFeature(item.geoMarker);}var moveFeature = function (event) {var vectorContext = event.vectorContext;var frameState = event.frameState;if (animating) {//通过增加速度,来获得lineString坐标for (let i = 0; i < routes.length; i++) {const item = routes[i];var elapsedTime = frameState.time - item.now;item.index = Math.round(speed * elapsedTime / 1000);if (item.index >= item.routeLength) {//重置时间和各个线段的下标,用于循环item.now = new Date().getTime();item.index = 0;//执行下面两行代码 自动结束动画//stopAnimation(true);//return;}var currentPoint = new ol.geom.Point(item.routeCoords[item.index]);var feature = new ol.Feature(currentPoint);vectorContext.drawFeature(feature, styles.geoMarker);}}//继续动画效果map.render();};function startAnimation() {if (animating) {stopAnimation(false);} else {animating = true;speed = speedInput.value;startButton.textContent = '结束运动';//隐藏geoMarkerfor (let i = 0; i < routes.length; i++) {const item = routes[i];item.geoMarker.setStyle(null);item.now = new Date().getTime();}//设置显示范围// map.getView().setCenter(center);map.on('postcompose', moveFeature);map.render();}}/*** @param {boolean}结束动画*/function stopAnimation(ended) {animating = false;startButton.textContent = '开始运动';for (let i = 0; i < routes.length; i++) {const item = routes[i];//如果动画取消就开始动画var coord = ended ? item.routeCoords[item.routeLength - 1] : item.routeCoords[0];//将各个线段上的点重新定位到起始位置(item.geoMarker.getGeometry()).setCoordinates(coord);}//移除监听map.un('postcompose', moveFeature);}startButton.addEventListener('click', startAnimation, false);
</script>
</body>
</html>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

提高Python并发性能 - asyncio/aiohttp介绍

在进行大规模数据采集时&#xff0c;如何提高Python爬虫的并发性能是一个关键问题。本文将向您介绍使用asyncio和aiohttp库实现异步网络请求的方法&#xff0c;并通过具体结果和结论展示它们对于优化爬虫效率所带来的效果。 1. 什么是异步编程&#xff1f; 异步编程是一种非阻…

ChatGPT帮助高职院校学生实现个性化自适应学习与对话式学习

一、学习层面&#xff1a;ChatGPT帮助高职院校学生实现个性化自适应学习与对话式学习 1.帮助高职院校学生实现个性化自适应学习 数字技术的飞速发展引起了教育界和学术界对高职院校学生个性化自适应学习的更多关注和支持&#xff0c;其运作机制依赖于人工智能等技术&#xff0…

Open3D 点云均值滤波

目录 一、算法原理1、均值滤波2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、均值滤波 对待处理的当前采样点,选择一个模板,该模板由其邻近的若干个数据点组成,…

传送带下料口堵塞识别检测算法 yolov5

传送带下料口堵塞识别检测算法通过python基于yolov5网络深度学习框架模型&#xff0c;下料口堵塞识别检测算法能够准确判断下料口是否出现堵塞现象&#xff0c;一旦发现下料口堵塞&#xff0c;算法会立即抓拍发出告警信号。Python是一种由Guido van Rossum开发的通用编程语言&a…

SOC总线学习记录之ICB(Internal Chip Bus)

蜂鸟E203总线&#xff1a; 采用自定义总线协议 ICB&#xff08;Internal Chip Bus&#xff09;&#xff0c;该总线用于蜂鸟 E203 内核内部使用&#xff0c;同时也可作为 SoC 中的总线使用。 ICB 总线的初衷是为了能够尽可能地结合 AXI 总线和 AHB 总线的优点&#xff0c;兼具高…

css学习7(盒子模型)

1、盒子模型图&#xff1a; Margin(外边距) - 清除边框外的区域&#xff0c;外边距是透明的。Border(边框) - 围绕在内边距和内容外的边框。Padding(内边距) - 清除内容周围的区域&#xff0c;内边距是透明的。Content(内容) - 盒子的内容&#xff0c;显示文本和图像。 <!DO…

内存四区(个人学习笔记黑马学习)

1、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域&#xff1a; 代码区:存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区:存放全局变量和静态变量以及常量栈区:编译器自动分配释放,存放函数的参数值,局部变量等 堆区:由程序员分配和释放,若程…

服务器上使用screen的学习记录

服务器上使用screen 训练模型的时候&#xff0c;花费时间是很长的&#xff0c;不可能一直挂在桌面上。所以就想到用screen了。 记录一下简单的操作指令。 创建screen screen -S roof # 新建一个名字为name的窗口&#xff0c;并进入到该窗口中进入后打开环境&#xff0c;运…

Java项目-苍穹外卖-Day07-redis缓存应用-SpringCache/购物车功能

文章目录 前言缓存菜品问题分析和实现思路缓存菜品数据清理缓存数据功能测试 SpringCache介绍入门案例 缓存套餐购物车功能添加购物车需求分析和产品原型测试 查看购物车清空购物车 前言 本章节主要是进行用户端的购物车功能开发 和redis作为mysql缓存的应用以及SpringCache的…

Python基础知识学习与回顾

Python学习 Python基本语法 标识符 标识符由数字、字符串、下划线构成。 注意事项&#xff1a; 标识符不以数字开头区分大小写下划线开头的标识符具有特殊意义保留字&#xff0c;Python保留了一些关键字&#xff0c;这些关键字都是通过小写字母进行保存。 下划线开头的特…

在k8s中用label控制Pod部署到指定的node上

案例-标注k8s-node1是配置了SSD的节点 kubectl label node k8s-node1 disktypessd 查看标记 测试 将pod部署到disktypessd的节点上&#xff08;这里设置了k8s-node1为ssd&#xff09; 部署后查看结果-副本全都运行在了k8s-node1上—符合预期 删除标记 kubectl label node k8…

Camera | 12.瑞芯微摄像头自动焦距马达驱动移植

本为你主要讲解如何让摄像头ov13850支持自动对焦功能。 摄像头的对角主要通过VCM马达驱动芯片DW9714来实现的。 一、环境 soc : rk3568 board: EVB1-DDR4-V10 软 件&#xff1a;Android 11 Linux&#xff1a;4.19.232 Camera:ov13850二、DW9714 1.DW9714简介 DW9714专…

【已解决+吐槽】pip install cn2an报错 Cannot uninstall ‘ruamel_yaml‘

我需要用cn2an模块将中文的数字转化为阿拉伯数字&#xff0c;但在安装cn2an的过程中出现了以下报错&#xff1a; 于是乎&#xff0c;我跟着CSDN上诸如此类的教程开始跟nodejs死磕&#xff0c;折腾了大半天&#xff0c;以下是各种尝试。这不是重点&#xff0c;我主要是吐槽&…

中文完形填空

本文通过ChnSentiCorp数据集介绍了完型填空任务过程&#xff0c;主要使用预训练语言模型bert-base-chinese直接在测试集上进行测试&#xff0c;也简要介绍了模型训练流程&#xff0c;不过最后没有保存训练好的模型。 一.完形填空 完形填空应该大家都比较熟悉&#xff0c;就是把…

Spring Cloud Alibaba-Sentinel规则

1 流控规则 流量控制&#xff0c;其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标&#xff0c;当达到指定的阈值时 对流量进行控制&#xff0c;以避免被瞬时的流量高峰冲垮&#xff0c;从而保障应用的高可用性。 第1步: 点击簇点链路&#xff0c;我们就可以看到访…

现代化畜牧业行业分析 - 商品猪养殖

改革开放以来&#xff0c;中国畜牧业生产基础条件不断改善、生产方式快速转变&#xff0c;畜牧业综合生产能力和保障市场有效供应能力不断加强。中国肉类、禽蛋产量均居世界第一位&#xff0c;奶类产量居世界第三位。随着产量的增长&#xff0c;中国人均畜产品占有量也持续上升…

联网智能实时监控静电离子风机的工作流程

联网智能实时监控静电离子风机是通过将静电离子风机与互联网连接&#xff0c;实现对其状态和性能的远程监控和管理。 具体实现该功能的方法可以包括以下几个步骤&#xff1a; 1. 传感器安装&#xff1a;在静电离子风机上安装适当的传感器&#xff0c;用于感知相关的参数&…

微信开发之一键创建标签的技术实现

简要描述&#xff1a; 添加标签 请求URL&#xff1a; http://域名地址/addContactLabel 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明…

Python面试:什么是GIL

1. GIL (Global Interpreter lock)可以避免多个线程同时执行字节码。 import threadinglock threading.Lock()n [0]def foo():with lock:n[0] n[0] 1n[0] n[0] 1threads [] for i in range(5000):t threading.Thread(targetfoo)threads.append(t)for t in threads:t.s…

python conda实践 sanic框架gitee webhook实践

import subprocess import hmac import hashlib import base64 from sanic.response import text from sanic import Blueprint from git import Repo# 路由蓝图 hook_blue Blueprint(hook_blue)hook_blue.route(/hook/kaifa, methods["POST"]) async def kaifa(req…