前言

最近在做自己维护的一个可视化工具的时候,在添加基于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实现平面迁徙图的更多相关文章

  1. three.js实现世界地图城市迁徙图

    概况如下: 1.THREE.CylinderGeometry,THREE.SphereGeometry绘制地图上的标记: 2.THREE.CanvasTexture用于加载canvas绘制的字体: 3 ...

  2. 手把手教你DIY一个春运迁徙图(一)

    换了新工作,也确定了我未来数据可视化的发展方向.新年第一篇博客,又逢春运,这篇技术文章就来交给大家如何做一个酷炫的迁徙图(支持移动哦).(求star 代码点这里) 迁徙图的制作思路分为静态的元素和变换 ...

  3. canvas图表(2) - 折线图

    原文地址:canvas图表(2) - 折线图 话说这天气一冷啊, 就患懒癌, 就不想码代码, 就想着在床上舒舒服服看视频. 那顺便就看blender视频, 学习下3D建模, 如果学会了建3D模型, 那 ...

  4. openlayers4 入门开发系列之迁徙图篇(附源码下载)

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  5. canvas学习之折线图

    接着上一张柱状图讲,我们是使用折线图: import {canvasPoint} from '../../assets/js/canvas';import {basicInfo,histogramMo ...

  6. 第166天:canvas绘制饼状图动画

    canvas绘制饼状图动画 1.HTML <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  7. 封装构造函数,用canvas写饼状图和柱状图

    封装构造函数,用canvas写饼状图和柱状图 封装函数 // 场景 function XDLScence( options ) { this.stage = options.stage; //执行场景 ...

  8. vue中使用 echarts3.0 或 echarts2.0 (模拟迁徙图,折线图)

    一.echarts3.0(官网: http://echarts.baidu.com/) 首先通过npm安装echarts依赖,安装的为3.0版本 npm install echarts -s 也可以使 ...

  9. konva canvas插件写雷达图示例

    最近,做了一个HTML5的项目,里面涉及到了雷达图效果,这里,我将react实战项目中,用到的雷达图单拎出来写一篇博客,供大家学习. 以下内容涉及的代码在我的gitlab仓库中:Konva canva ...

随机推荐

  1. webpack4.0 babel配置遇到的问题

    babel配置 babel版本升级到8.x之后发现出现了很多问题.首先需要安装 "@babel/core": "^7.1.2", "@babel/pl ...

  2. map + filter + reduce

    map 是对 集合 里面的元素一个接一个的进行某种运算,常常与lambda 结合使用   #求平方: items = [1, 2, 3, 4, 5] squared = list(map(lambda ...

  3. FastJson格式化Request对象导致的一次异常思考

    一.问题描述: 近期,在环境中出现一个阻塞性的异常“nested exception is java.lang.IllegalStateException: It is illegal to call ...

  4. 多线程编程学习十一(ThreadPoolExecutor 详解).

    一.ThreadPoolExecutor 参数说明 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keep ...

  5. jsp作用域总结

    我们在定义每一个变量,每一个属性的时候,都会考虑这个变量.属性的作用范围,也就是作用域. JSP的四大作用域 作用域对象 作用域范围 page 只在当前页面有效 request 一次请求的生命周期内有 ...

  6. charles 编辑菜单总结

    本文参考:charles 编辑菜单总结 charles中proxy菜单的介绍:我的是4.1.2版本,mac系统下的菜单大同小异: 如下图: 这里其实都是常用的功能: 大概可以分为5个大块,看下分割线就 ...

  7. [Full-stack] 一切皆在云上 - AWS

    一元课程:https://edu.51cto.com/center/course/lesson/index?id=181407[非常好] Based on AWS Lambda. 包含:DevOps ...

  8. 【linux】【maven】maven及maven私服安装

    前言 系统环境:Centos7.jdk1.8 私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的用户使用.当Maven需要下载构件的时候,它从私服请求,如 ...

  9. 关于json字符串与实体之间的严格验证

    在一个项目中要求严格验证传入的json字符串与定义的 类匹配,否则不记录.感觉这个严格验证找了好多资料才找到,可能用的人比较少,特摘出来给大家分析,直接上代码了:   using Newtonsoft ...

  10. for for in 给已有的li绑定click事件生成新的li也有click事件

    想要给已有的li元素绑定一个click事件,点击生成新的li元素,并且新的li元素也要有click事件 //不能用for循环给每个li绑定click事件 因为这样的话 后面新生成的li就没有click ...