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 ...
随机推荐
- 【转】Android CTS 测试
http://blog.csdn.net/zxm317122667/article/details/8508013 Android-CTS 4.0.3测试基本配置 1. Download CTS CT ...
- SqlServer数据库技巧
1.数值转换失败提供默认值 , )) end
- Fiddler 手机爬虫
Fiddler抓包工具 配置Fiddler 添加证书信任,Tools - Options - HTTPS,勾选 Decrypt Https Traffic 后弹出窗口,一路确认 ...from bro ...
- Java常见面试题-1
问: 1 面向对象的特征有哪些方面? 2 访问修饰符public,private,protected,以及不写(默认)时的区别? 3 String 是最基本的数据类型吗? 对象类型 基本类型 4 ...
- 常用logback.xml配置详解
选择logback的理由 ==logback==与==log4j==的简单对比一下: 1.首先,对于同样的代码路径,==logback==使用起来更快. 2.==logback==原生实现了log4j ...
- java工作流快速开发之授权代办的设计
关键词:工作流快速开发平台 工作流流设计 业务流程管理 Java工作流引擎 asp.net 开源工作流 net开源工作流引擎 开源工作流系统 一.授权代办开发背景 应用需求:项目审批人出差无法及 ...
- C++ 基础中的基础 ---- 引用
C++ 基础中的基础 ---- 引用 引用的概念:引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字.一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量.比如: int n ...
- python+selenium自动化测试——浏览器驱动
selenium控制浏览器需要下载对应版本的驱动,并把下载好的驱动解压然后拷贝到python的安装目录. 1.chrome 驱动对应版本及下载地址;https://npm.taobao.org/mir ...
- mybatis if判断两个值是否相等存在的坑啊
1.使用“==”比较 字符类型 的值 用“==”比较的使用场景: 不管你用的什么类型的变量,只要变量的值是字符类型就用“==” 产生原因: 在mybatis中如果<if>标签用一个“=”判 ...
- php装上sqlserver驱动后仍然显示Call to undefined function sqlsrv_connect()问题
今天老师要求本来的php+mysql改为php+sqlserver,在网上搜索了相应的教程,说是“需要下载安装Microsoft Drivers for PHP for SQL Server驱动”,下 ...