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 ...
随机推荐
- poj1037 [CEOI 2002]A decorative fence 题解
---恢复内容开始--- 题意: t组数据,每组数据给出n个木棒,长度由1到n,除了两端的木棒外,每一根木棒,要么比它左右的两根都长,要么比它左右的两根都短.即要求构成的排列为波浪型.对符合要求的排列 ...
- PHP-02.文件上传、php保存/转移上传的文件、常见的网络传输协议、请求报文及属性、响应报文及属性
关系数组 array("key"=>"value",...) ; get没有数据大小的限制 post上传大小没有限制 不指定上传方式,默认是get 文件上 ...
- pycharm中报ImportError: libcublas.so.9.0错误的解决方法。
前些天不知为啥cuda不能用了,nvidia-smi也没反应.然后我就重新装了一下cuda.后来使用pycharm远程连接时,居然报错了. ImportError: libcublas.so.9.0: ...
- IDEA微服务项目的application.yml没有绿色叶子的解决办法
1.今天在写微服务项目的时候成功入坑,那么问题是啥呢?接下来和我一起走入bug的世界吧,让我们看看究竟是怎么回事. *问题描述 1.application.yml是灰色的小格子 2.实在难看 *需要解 ...
- 脱离脚手架来配置、学习 webpack4.x (二)基础搭建loader 配置 css、scss
序 上一篇已经把基本架子搭起来了,现在来增加css.scss.自动生成html.css 提前等方面的打包.webpack 默认只能处理js模块,所以其他文件类型需要做下转换,而loader 恰恰是做这 ...
- [VB.NET Tips]赋值运算千万要注意
赋值运算符是一个语句,不能在表达式中使用,表达式中的等号表示相等而不是赋值. 上示例: Dim x As Integer Dim y As Object x = 5 y = x = 5 Console ...
- PacMan 01——玩家移动
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- [C++] 类的设计(2)——拷贝控制(1)
1.一个类通过定义五种特殊的成员函数来控制此类型对象的拷贝.移动.赋值和销毁:拷贝构造函数.拷贝赋值运算符.移动构造函数.移动赋值运算符和析构函数.(拷贝.移动.析构) 2.拷贝和移动构造函数定义 ...
- 月光宝盒之时间魔法--java时间的前生今世
月光宝盒花絮 “曾经有一份真诚的爱情摆在我的面前,但是我没有珍惜,等到了失去的时候才后悔莫及,尘世间最痛苦的事莫过于此.如果可以给我一个机会再来一次的话,我会跟那个女孩子说我爱她,如果非要把这份爱加上 ...
- NN and the Optical Illusion-光学幻觉 CodeForce1100C 几何
题目链接:NN and the Optical Illusion 题目原文 NN is an experienced internet user and that means he spends a ...