echarts symbol 回调函数_【OpenLayer 实战】实现仿Echarts风格的动态迁徙图/航班图

a7749cf58cee907397dcba96c598c2f5.png

使用的数据还是来自echarts,模拟了全国各地到湖南重点景区的客流情况。

32703f19143b57fa3d75dd849bfb1fe6.gif

分析
要实现动态迁徙图的效果,主要需解决两个问题
    曲线的绘制。因为给出的数据只有起点和终点两个点位,所以想要绘制曲线可以参考turf中的bezier曲线生成API。
    点迹的动画播放。仍然要依靠render机制,这里我还是使用比较熟悉的postrender事件回调函数。
实现
首先利用turf做一个利用两个点就可以生成弧线要素的函数,其实这里面调用的是turf的bezierSpline,写死了一个定比例取到的点位,参数列表为要素的自定义属性留了位置。同时在函数里计算出曲线的长度待用。 

function getTurfArcFeature(start, end, opt) {  var line = turf.lineString([    start,    [start[0] + (end[0] - start[0]) * 0.5,    start[1] + (end[1] - start[1]) * 0.65],    end  ]);  var curved = turf.bezierSpline(line);  let length = turf.length(curved, { units: 'meters' });  var bF = turfFormat.readFeature(curved);  bF.getGeometry().transform('EPSG:4326', 'EPSG:3857');  bF.setProperties(opt);  bF.set("length", length);  return bF;}

然后重点分析一下点位动画的实现:

先写出监听postrender事件回调函数的基本框架,并取得VectorContex对象的句柄:

tileLayer.on('postrender', (evt) => {  let veContext = getVectorContext(evt);  })

再写出遍历所有曲线的forEach结构及回调函数,回调函数内先将本次迭代的曲线绘制到地图上:

tileLayer.on('postrender', (evt) => {  let veContext = getVectorContext(evt);   arcLinesFeature.forEach((item,index) => {    veContext.drawFeature(item, arcStyle);   })  })

然后通过frameState获取当前帧的时间戳,计算得到当前帧运动点位的位置百分比,如果百分比超过100%还要进行归零处理

tileLayer.on('postrender', (evt) => {  let veContext = getVectorContext(evt);  arcLinesFeature.forEach((item,index) => {    veContext.drawFeature(item, arcStyle);        let time = (evt.frameState.time - item.get('start')) / 1000;    let frac = time / 5-index/arcLinesFeature.length;    if (!item.get('start')) item.set('start', new Date().getTime());    if (frac>=1) {      item.set('start', new Date().getTime());      frac=0;    }      }) })

最后根据位置百分比,使用getCoordinateAt求得点位的坐标,并且使用VectorContex对象绘制到canvas上,然后显示调用render()函数,请求渲染下一帧。

tileLayer.on('postrender', (evt) => {  let veContext = getVectorContext(evt);  arcLinesFeature.forEach((item,index) => {    veContext.drawFeature(item, arcStyle);    let time = (evt.frameState.time - item.get('start')) / 1000;    let frac = time / 5-index/arcLinesFeature.length;    if (!item.get('start')) item.set('start', new Date().getTime());    if (frac>=1) {      item.set('start', new Date().getTime());      frac=0;    }    let along = item.getGeometry().getCoordinateAt(frac);    let pF=new Feature(new Point(along));    veContext.drawFeature(pF, dotStyle);  })  map.render()})

完整代码

(删掉了我自己的Google开发者Key,黑色主题地图还请自己动手做一个)

import { Map, View } from 'ol';import TileLayer from 'ol/layer/Tile';import XYZ from 'ol/source/XYZ';import Point from 'ol/geom/Point';import VectorSource from 'ol/source/Vector';import VectorLayer from 'ol/layer/Vector';import Feature from 'ol/Feature';import * as turf from '@turf/turf'import GeoJSON from 'ol/format/GeoJSON'import { getVectorContext } from 'ol/render';import Style from 'ol/style/Style';import Stroke from 'ol/style/Stroke';import Fill from 'ol/style/Fill';import CircleStyle from 'ol/style/Circle';import data from './data/t.json' let tileLayer = new TileLayer({  source: new XYZ({    url: 'http://www.google.cn/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i451159038!3m14!2szh-CN!3sUS!5e18!12m1!1e68!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2zcC5oOiNmZjFhMDB8cC5pbDp0cnVlfHAuczotMTAwfHAubDozM3xwLmc6MC41LHMudDo2fHMuZTpnfHAuYzojZmYyRDMzM0M!4e0&key=&token=126219'  })})let map = new Map({  target: 'map',  layers: [    tileLayer  ],  view: new View({    center: [11936406.337013, 3786384.633134],    zoom: 5  })}); var flightSource = new VectorSource()var flightLayer = new VectorLayer(  {    source: flightSource  })var turfFormat = new GeoJSON(); function getTurfArcFeature(start, end, opt) {  var line = turf.lineString([    start,    [start[0] + (end[0] - start[0]) * 0.5,    start[1] + (end[1] - start[1]) * 0.65],    end  ]);  var curved = turf.bezierSpline(line);  let length = turf.length(curved, { units: 'meters' });  var bF = turfFormat.readFeature(curved);  bF.getGeometry().transform('EPSG:4326', 'EPSG:3857');  bF.setProperties(opt);  bF.set("length", length);  return bF;} map.addLayer(flightLayer) var arcStyle = new Style({  stroke: new Stroke({    color: [0, 122, 122, 0.7],    width: 1  })}) var dotStyle = new Style({  image: new CircleStyle({    fill: new Fill({      color: [255, 255, 255,0.7]    }),    radius: 1   })}) var arcLinesFeature = [];data.moveLines.forEach((item, index) => {  let tempF = getTurfArcFeature(item.coords[0], item.coords[1], { 'from': item.fromName, 'to': item.toName });  arcLinesFeature.push(tempF);}) tileLayer.on('postrender', (evt) => {  let veContext = getVectorContext(evt);  arcLinesFeature.forEach((item,index) => {    veContext.drawFeature(item, arcStyle);    let time = (evt.frameState.time - item.get('start')) / 1000;    let frac = time / 5-index/arcLinesFeature.length;    if (!item.get('start')) item.set('start', new Date().getTime());    if (frac>=1) {      item.set('start', new Date().getTime());      frac=0;    }    let along = item.getGeometry().getCoordinateAt(frac);    let pF=new Feature(new Point(along));    veContext.drawFeature(pF, dotStyle);  })  map.render()}) 

【OpenLayers】OpenLayers概述

【OpenLayers】实现简单的地图显示

【OpenLayers】地图控件之缩放控件

【OpenLayers】归属控件与全屏控件

【OpenLayers】地图控件之坐标拾取控件和鹰眼控件

【OpenLayers】地图控件之旋转控件与比例尺控件

【OpenLayers】实现图层切换控件

【OpenLayers】多源数据加载之数据组织

【OpenLayers】多源数据加载之瓦片地图原理一

【OpenLayers】多源数据加载之瓦片地图原理二

【OpenLayers】多源数据加载之用最简单的方式加载瓦片地图

【OpenLayers】多源数据加载之使用XYZ的方式加载瓦片地图

【OpenLayers】多源数据加载之详解OpenLayers的瓦片坐标系

【OpenLayers】多源数据加载之离线瓦片地图

【OpenLayers】多源数据加载之矢量地图

【OpenLayers】多源数据加载之WMS(一)

【OpenLayers】多源数据加载之WMS(二)

【OpenLayers】多源数据加载之矢量切片

【OpenLayers】多源数据加载之WMTS

【OpenLayers】图形绘制之设置图形的样式

【OpenLayers】图形绘制之编辑图形

【OpenLayers】使用GeoJSON数据渲染热力图

【OpenLayers】实现“上一视图”、“下一视图”的视图切换功能

【OpenLayers】图文标注

【OpenLayers】聚合标注

【OpenLayers】图层卷帘(Layer Swipe)

【OpenLayers】Drag-and-Drop Image Vector

【OpenLayer 实战】实现克里金插值渲染图-Kriging

【OpenLayer 实战】请求Geoserver带Filter的WFS查询

【OpenLayer 实战】使用GeoJSON进行行政区划剪裁(clip, not mask or filter)

END

 

请:右下点在看a682a6ff971c2980c48e80620801afb6.gif,右上点【···】分享

2f01b72d1e3c448c6dacf074895594b1.png

关注我

发现更多精彩

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

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

相关文章

校运会计算机科学系大本营,计算机系团总支学生会学期总结大会

(本网讯)时光飞逝,又一个学期即将就此画上了圆满的句号。为推动我系团总支学生会工作更长久的发展,提高学生会干部工作的热情和质量,2016年12月8日晚上19:00在第一教学楼C102课室里,校学生会全体成员齐聚一堂,参加了20…

hexo评论_【前端简历加分】hexo框架搭建个人博客站点,手把手教学

最近,粉丝们在金九银十期间也是不断的面试,有比较多的毕业生说我在这个期间出多一些面试题,上几期都是倾向于面试文章,这期出一次简历加分项操作,使用hexo框架搭建个人博客。作为应届毕业生或者1-3年工作经验的程序员拥…

电脑抓整个路由器的包_网络是电竞游戏体验的命脉 2018年年度电竞路由器功能盘点...

2018年是电竞路由器的元年,从2017年的概念产品诞生开始,电竞路由器很快就确定了品类,随着《绝地求生》、《王者荣耀》等对网络质量敏感的竞技游戏的火爆,电竞路由器迅速被竞技玩家熟知,并在2018年以野火燎原的速度发展…

dos 改某个目录下所有文件的时间_go语言入门学习笔记(2)-DOS操作及go语言变量学习...

API:application program interface:应用程序编程接口。就是我们go的各个包的各个函数。我们想要了解这些函数我们可以通过Go的中文网在线标准库文档:https://studygolang.com/pkgdocDOS介绍:Dos:Disk Operating System 磁盘操作系…

计算机科学与技术专业机遇与挑战,科学网—填报专业大类志愿:机遇与挑战 - 雒运强的博文...

2020年的高考结束了,不久就要出分,接着考生就要选择大学和专业了。可是,有一些大学说按专业大类招生,究竟什么是专业大类、这样招生好不好呢?专业大类有很多,如中国语言文学、历史学、考古学、戏剧影视文学…

es multi match_PHP 的ES搜索操作

原文:https://blog.csdn.net/JineD/article/details/106650695首先从ES的支持的字段说起,ES文档中字段有多种类型 官方文档。这几个比较常用:text,keyword,integer,float,boolean,object,geo_point(地理坐标),geo_shape(描述地理区域),date.注…

美术学考计算机,艺术设计专业能跨专业考计算机研究生吗?

首先说明一下,除了一些专业壁垒比较高的学科和专业强烈不建议跨学科或者跨专业考研,其他的专业原则上都是可以跨专业考的。哪些算是专业壁垒比较高呢:医学、艺术类(包括音乐、美术等和设计类)、体育类、外语类、军事类。其余的对于想要跨理工…

git 怎么还原历史版本_4. Git--修改/回退等操作

》》点赞,收藏关注,理财&技术不迷路《《我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容:Git is a distri…

为什么用python写爬虫_零基础,是怎么开始写Python爬虫的

刚开始接触爬虫的时候,简直惊为天人,十几行代码,就可以将无数网页的信息全部获取下来,自动选取网页元素,自动整理成结构化的文件。利用这些数据,可以做很多领域的分析、市场调研,获得很多有价值…

行列式的计算机应用论文结论,【计算机应用论文】建筑耗能计算机模拟分析(共3654字)...

本文作者:王芙蓉、文亮、王涛 单位:西安建筑科技大学建筑学院、中国建筑设计研究院1(略)利用计算机模拟,能够弥补传统设计方法对建筑能耗分析的不足,帮助建筑师直观地判断方案设计对于建筑能耗的影响,从而将建筑能耗成…

datatable怎么根据两列分组_谈谈怎么做服务隔离

来源于公众号孤独烟 ,作者孤独烟引言OK,如下图所示那显而易见,做服务隔离的目的就是避免服务之间相互影响。毕竟谁也不能说自己的微服务百分百可用,如果不做隔离,一旦一个服务出现了问题,整个系统的稳定性都…

position: absolute;_前端性能优化--transform与position

上个星期去yy语音面试&#xff0c;就有一个这样问题&#xff1a; transform与position:absolute 有什么区别? 我回家后查资料发现这道题目其实不简单啊&#xff0c;涉及到重排、重绘、硬件加速等网页优化的知识。首先看一个用top、left实现的动画效果<style>html,body {…

台式计算机总是重启,台式电脑经常自动重启怎么修复

当我们的电脑出现了电脑自动重启的时候&#xff0c;我们就要注意了&#xff0c;说明我们的电脑主机出现问题了&#xff0c;怎么解决呢。下面是学习啦小编为大家整理的关于台式电脑经常自动重启的相关资料&#xff0c;希望对您有所帮助!台式电脑经常自动重启的解决方法方法/步骤…

gan处理自己的数据集_用GAN生成差分隐私数据集

说在前面今天看了 Generating Differentially Private Datasets Using GANS&#xff0c;明天要讨论。老师不知道从哪里挖出了这篇被拒了的文&#xff0c;研究的主题和我们最近的工作非常相关&#xff0c;而且证明非常有趣&#xff0c;大致地看了一下文章的结构觉得没啥问题&…

ipython安装成功后用不了_ipython安装避坑指南

python学习笔记03 本来想着继续给大家介绍python的数据类型&#xff0c;但是IDLE编辑器&#xff08;默认的 Python shell 编辑器&#xff09;太难用了&#xff0c;导致小编没水出来&#xff0c;所以小编决定装一个别的python shell编辑器&#xff0c;这就是ipython&#xff1b;…

如果用户计算机已接入,01计算机基础知识题(50道)

7、在Windows2000中&#xff0c;切换到MS&#xff0d;DOS方式后&#xff0c;返回Windows2000的命令是。8、在“我的电脑”窗口中用鼠标双击“软盘A”图标&#xff0c;将会。习题参考答案三、填空题1&#xff0e;启动 2&#xff0e;软键盘 3&#xff0e;硬盘 4&#xff0e;弹出式…

k1658停运_最新通知!福州这些列车停运!

停运列车1.4月1日至4月7日太原开k903次&#xff0c;4月3日至4月9日厦门北开k904次停运。2.4月1日至4月8日广州东开k297次&#xff0c;4月2日至4月9日厦门北开k298次停运。3.4月4、5、7日厦门开D6214次、福州开D6229次、厦门开D6224次&#xff0c;4月5、6、8日福州开D6219次、厦…

线程执行完之后会释放吗_java多线程并发:CAS+AQS+HashMap+volatile+ThreadLocal,乐分享...

CyclicBarrier、CountDownLatch、Semaphore 的用法CountDownLatch(线程计数器 )CountDownLatch 类位于 java.util.concurrent 包下&#xff0c;利用它可以实现类似计数器的功能。比如有一个任务 A&#xff0c;它要等待其他 4 个任务执行完毕之后才能执行&#xff0c;此时就可以…

计算机应用基础考查方案,《计算机应用基础》考查方案

《计算机应用基础》考查方案 《计算机应用基础》考核方案 制订人&#xff1a;刘久红老师 计算机应用基础科任教师 制订部门&#xff1a;基础课与思政课教学部 制订时间&#xff1a;2012年12月 一&#xff1a;考核依据 计算机应用基础是面向全院各专业开设的一门重要的公共基础课…

mongodb 导出到sqlserver_SQLServer数据导入Mongodb

SQLServer数据导入Mongodb一、思路MongoVUE免费版支持MySQL导入Mongo,所以思路是SQLServer导入MySQL,再从MySQL导入Mongo。二、准备1&#xff0c;安装mysql数据库(我用的是WAMP&#xff0c;集成mysql&#xff0c;phpadmin)&#xff0c;如果需要&#xff0c;建立自己的数据库如M…