canvas实现平面迁徙图
前言
最近在做自己维护的一个可视化工具的时候,在添加基于echart的雷达图的时候,按照echart官网案例写完发现在自己项目中无法正常运行,排查了一番发现是我项目中echart的版本太低。找到问题原因之后就升级echart,但是升级echart之后发现原本正常运行的echart地图组件又无法使用,百度了一番发现echart在最新的版本中地图数据进行了切换,原先的数据由于不符合规范被砍掉,导致2.0以前的echart地图都无法正常使用了。既然出现这样的情况,那就没办法了,项目中使用的echart地图有三种类型,迁徙图、标记图和热力图。思来想去,echart最终还是要升级,所以就决定自己开发项目中需要的基于canvas的迁徙图,标记图和热力图。这篇稳重主要就阐述canvas如何实现类似于echart中的迁徙图。
原理说明
1、轨迹开始位置和结束位置之间的轨迹通过二次贝塞尔曲线quadraticCurveTo来实现,其中绘制贝塞尔曲线的控制点需要根据开始位置和结束位置来确定;
2、轨迹上运行的标记通过二次贝塞尔曲线反推获取贝塞尔曲线不同位置的x,y坐标,然后通过不断设置轨迹上点位置来实现轨迹上点;
3、轨迹上点移动和开始和结束位置动画通过requestAnimationFrame来实现,切换重回canvas的时候需要调用cancelAnimationFrame来实现。
演示示例实例效果图如下:
轨迹绘制方法
function drawTravel (start,end) {
var middleX = 0;
var middleY = 0;
var gnt1 = ctx.createLinearGradient(start.pos[0],start.pos[1],end.pos[0],end.pos[1]);
gnt1.addColorStop(0,start.color);
gnt1.addColorStop(1,end.color);
if (start.pos[0] > end.pos[0] && start.pos[1] > end.pos[1]) {
middleX = (start.pos[0] + end.pos[0]) / 2 * rate;
middleY = (start.pos[1] + end.pos[1]) / 2 * (2 - rate);
}
if (start.pos[0] > end.pos[0] && start.pos[1] < end.pos[1]) {
middleX = (start.pos[0] + end.pos[0]) / 2 * rate;
middleY = (start.pos[1] + end.pos[1]) / 2 * rate;
}
if (start.pos[0] < end.pos[0] && start.pos[1] > end.pos[1]) {
middleX = (start.pos[0] + end.pos[0]) / 2 * (2 - rate);
middleY = (start.pos[1] + end.pos[1]) / 2 * (2 - rate);
}
if (start.pos[0] < end.pos[0] && start.pos[1] < end.pos[1]) {
middleX = (start.pos[0] + end.pos[0]) / 2 * (2 - rate);
middleY = (start.pos[1] + end.pos[1]) / 2 * rate;
}
ctx.strokeStyle = gnt1;
ctx.beginPath();
ctx.moveTo(start.pos[0],start.pos[1]);
ctx.quadraticCurveTo(middleX,middleY,end.pos[0],end.pos[1]);
ctx.stroke();
// 获取贝塞尔曲线上的点
for (var i = 0; i < dotNumber; i++) {
var _t = (t - animationDotSpeed * i * 2) >= 0 ? (t - animationDotSpeed * i * 2) : 1 + (t - animationDotSpeed * i * 2);
var x = Math.pow(1-_t, 2) * start.pos[0] + 2 * _t * (1-_t) * middleX + Math.pow(_t, 2) * end.pos[0];
var y = Math.pow(1-_t, 2) * start.pos[0] + 2 * _t * (1-_t) * middleY + Math.pow(_t, 2) * end.pos[1];
ctx.fillStyle = 'rgba(' + dotColor.split('(')[1].split(')')[0] + ',' + (1 - 1 / dotNumber * i) + ')'
ctx.beginPath();
ctx.arc(x,y,dotRadius,0,2*Math.PI);
ctx.fill();
ctx.closePath()
}
}
开始位置和结束位置标记绘制方法
function drawCoordinate (coordinate) {
ctx.fillStyle = centerColor;
ctx.beginPath();
ctx.arc(coordinate.pos[0], coordinate.pos[1], radiusCenter,0,2*Math.PI);
ctx.closePath();
ctx.fill()
ctx.fillStyle = ringColor.split(',').slice(0,3).join(',') + ',0.5)';
ctx.beginPath();
ctx.arc(coordinate.pos[0], coordinate.pos[1], radiusCenter + 5,0,2*Math.PI);
ctx.closePath();
ctx.fill()
if (radiusRing >= radiusRingMax) {
radiusRing = radiusRingMin;
}
ctx.fillStyle = ringColor;
ctx.beginPath();
ctx.arc(coordinate.pos[0], coordinate.pos[1], radiusRing,0,2*Math.PI);
ctx.closePath();
ctx.fill()
radiusRing += animationSpeed;
ringColor = ringColor.split(',').slice(0,3).join(',') + ',' + (0.5 - (radiusRing - radiusRingMin) * 0.02) + ')';
}
执行canvas绘制方法
function draw () {
cancelAnimationFrame(requestAnimationFrameName);
ctx.clearRect(0,0,width,height)
array.forEach(function (item, index) {
drawCoordinate(item);
if (index > 0) {
drawTravel(array[0],item)
}
})
if (t >= 1) {
t = 0;
}
t += animationDotSpeed;
requestAnimationFrameName = requestAnimationFrame(draw)
}
实例预览地址:canvas实现平面地图迁徙图
希望上述说明能够帮助到您。
canvas实现平面迁徙图的更多相关文章
- three.js实现世界地图城市迁徙图
概况如下: 1.THREE.CylinderGeometry,THREE.SphereGeometry绘制地图上的标记: 2.THREE.CanvasTexture用于加载canvas绘制的字体: 3 ...
- 手把手教你DIY一个春运迁徙图(一)
换了新工作,也确定了我未来数据可视化的发展方向.新年第一篇博客,又逢春运,这篇技术文章就来交给大家如何做一个酷炫的迁徙图(支持移动哦).(求star 代码点这里) 迁徙图的制作思路分为静态的元素和变换 ...
- canvas图表(2) - 折线图
原文地址:canvas图表(2) - 折线图 话说这天气一冷啊, 就患懒癌, 就不想码代码, 就想着在床上舒舒服服看视频. 那顺便就看blender视频, 学习下3D建模, 如果学会了建3D模型, 那 ...
- openlayers4 入门开发系列之迁徙图篇(附源码下载)
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- canvas学习之折线图
接着上一张柱状图讲,我们是使用折线图: import {canvasPoint} from '../../assets/js/canvas';import {basicInfo,histogramMo ...
- 第166天:canvas绘制饼状图动画
canvas绘制饼状图动画 1.HTML <!DOCTYPE html> <html lang="en"> <head> <meta ch ...
- 封装构造函数,用canvas写饼状图和柱状图
封装构造函数,用canvas写饼状图和柱状图 封装函数 // 场景 function XDLScence( options ) { this.stage = options.stage; //执行场景 ...
- vue中使用 echarts3.0 或 echarts2.0 (模拟迁徙图,折线图)
一.echarts3.0(官网: http://echarts.baidu.com/) 首先通过npm安装echarts依赖,安装的为3.0版本 npm install echarts -s 也可以使 ...
- konva canvas插件写雷达图示例
最近,做了一个HTML5的项目,里面涉及到了雷达图效果,这里,我将react实战项目中,用到的雷达图单拎出来写一篇博客,供大家学习. 以下内容涉及的代码在我的gitlab仓库中:Konva canva ...
随机推荐
- 反序列化JSON
本人编程生涯刚刚起步,以下是个人理解,如果有些不对的地方,请各位在评论区指出,如果有更详细的博客也可以推荐给我. 首先要根据JSON创建一个实体类,并且要实现Serializable接口,再创建一个J ...
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战
Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战 Springboot: 2.1.8.RELEASE SpringCloud: Greenwich.SR2 ...
- 增强学习Q-learning分析与演示(入门)
一些说明.参阅 https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/blob/master/contents/1_ ...
- Docker下kafka学习三部曲之二:本地环境搭建
在上一章< Docker下kafka学习,三部曲之一:极速体验kafka>中我们快速体验了kafka的消息分发和订阅功能,但是对环境搭建的印象仅仅是执行了几个命令和脚本,本章我们通过实战来 ...
- 关于spring boot多张表建立外健的讨论
现在有四张表:student(学生表).blogs(博客表).comment(评论表).reply(回复表) 现在说一下这四张表: student(学生表):学生的信息记录表 blogs(博客表):学 ...
- Linux环境下进行分布式压测踩过的坑
背景:公司为了满足大并发的情况,需要测试组配合,就需要分布式压测,这里我把我踩过坑都记录下来: 环境:Linux + jmeter-v.5.1.1;使用3台2核4G的压力机: Q1: Server f ...
- charles 视图菜单总结
本文参考:charles 视图菜单总结 Charles的视图菜单里的东西其实是非常常用的功能: 但是我们一般是不需要从这里点进来的: 里面,无非是查看的视图结构(按照域名和按照访问时间) 然后是一些概 ...
- .Net Standard(.Net Core)实现获取配置信息
一.前言 在.Net Framework框架有专门获取webconfig配置的方法供我们使用,但是在.Net Core或者.Net Standard中没有可以直接使用的方法来获取配置文件信息,下面就来 ...
- 运行pytest,报错"AttributeError: 'module' object has no attribute 'xxx'"
最近学习pytest被此问题困扰,敲脑壳,实在是不该.百度解决方法一大堆,我的问题怎么也解决不了,来看一下,我是怎么解决的,各位大佬勿喷,只是自己做笔记用,谢谢. 报错信息如下: 网上解决方法是这样的 ...
- 管中窥豹——框架下的SQL注入 Java篇
管中窥豹--框架下的SQL注入 Java篇 背景 SQL注入漏洞应该算是很有年代感的漏洞了,但是现在依然活跃在各大漏洞榜单中,究其原因还是数据和代码的问题. SQL 语句在DBMS系统中作为表达式被解 ...