【摘要】 用canvas原生API绘制Echarts图表

示例代码托管在:http://www.github.com/dashnowords/blogs

一. 任务说明

使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。

二. 重点提示

南丁格尔玫瑰图的画法有很多种,Echarts中提供的以半径或面积两种不同模式,本文中以面积比例画法为例,绘制算法如下:

  1. 确定每个扇区的角度。由于所有扇区的角度加在一起为2π ,我们先按照数据比例来计算角度:

  2. 每个扇区面积与总面积之间的比例即为数值的比,将给定参数数组options.radius中的最大和最小数值作为数值最大的一块扇形的绘图数据,代入如下公式即可求得总面积S

3. 再利用上述公式分别计算出每个扇形对应的外圆半径,在canvas中绘制路径并填充即可。

三. 示例代码

南丁格尔玫瑰图绘制示例代码:

//绘制饼图
drawPieChart(options); /**
* 绘制饼图
* @param {[type]} options [description]
* @return {[type]} [description]
*/
function drawPieChart(options) {
//记录最大数值以反求面积总和
options.maxValue = 0;
//求数据集总和以在后续计算每个扇形的角度比例
options.totalNum = options.data.reduce((pre,cur)=>{
if (cur.value > options.maxValue) {
options.maxValue = cur.value;
}
return pre+cur.value;
},0);
/*以最大值对应最大半径来计算面积总和,并覆盖原值
*使得最大的一块扇形外圆半径为options.radius[0]
*内圆半径为options.radius[1]
*/
let Rmin = options.radius[0];
let Rmax = options.radius[1];
let r = Math.sqrt((Rmax*Rmax - Rmin*Rmin)*options.totalNum / options.maxValue + Rmin*Rmin);
options.radius[1] = r;
//移动坐标系原点至绘图中心
let paintingCenter={
x:parseInt(options.center[0],10)/100 * (options.chartZone[2] - options.chartZone[0]) + options.chartZone[0],
y:parseInt(options.center[1],10)/100 * (options.chartZone[3] - options.chartZone[1]) + options.chartZone[1]
}
context.translate(paintingCenter.x, paintingCenter.y);
//绘制每个扇形,过程中累加旋转角度
let allAngle = options.data.reduce((prev,cur,index)=>{
context.fillStyle = options.colorPool[index]
let angle = calcPaintingData(cur,options);
return prev + angle;
},0);
//绘制中空白色圆
context.beginPath();
context.fillStyle = 'white';
context.arc(0,0,options.radius[0],0,2*Math.PI,false);
context.fill();
} /**
* 计算每个扇形所需要的绘图参数
*/
function calcPaintingData(data,options) {
let scale = data.value / options.totalNum;
let angle = scale * 2 * Math.PI;
let Rmin = options.radius[0];
let Rmax = options.radius[1];
let r = Math.sqrt(scale * (Rmax*Rmax - Rmin*Rmin) + Rmin*Rmin);
data.r = r;
//绘制扇形
paintFan({
r:r,
angle:angle,
data:data,
options:options
});
return angle;//将角度值返回给外层函数以供累加
} //绘制扇形
function paintFan(opt) {
context.beginPath();
context.lineTo(opt.r,0);
context.arc(0,0,opt.r,0,opt.angle,false);
context.lineTo(0,0);
context.closePath();
context.fill();
context.rotate(opt.angle);
}

浏览器中可查看效果:

四. hover高亮的实现思路

  1. 绘图过程中,将每个扇区的绘图数据(半径,相对于圆心的起始转角,扇区角度)均挂载在绘图数据上。

  2. canvas标签上监听鼠标移动事件mousemove,并在回调函数中将鼠标移动事件event.clientXevent.clientY转换为相对于canvas坐标的数值(mouseX,mouseY)

  3. 从圆心坐标(paintingCenter.x,paintingCenter.y)(mouseX,mouseY)连接为向量,根据该向量的角度和模即可判断鼠标是否处于某个扇区之上。

  4. 如果处于扇区之上,则以过渡动画来绘制关键帧使得hover效果表现出来。先修改context.fillStyle颜色为对应扇区的高亮色,然后让外圆绘图半径以线性的方式逐帧增加至目标大小(例如10%),每一帧中使用canvas绘图上下文重新对绘图区域进行封闭画线,然后填充即可。

  5. hover效果出现时绘制高亮色的绘图区域,hover效果消失时从外圆开始逐帧绘制白色外层扇区即可,最终再将数据扇区绘制为原色。

demo.rar

来源:华为云社区  作者:大史不说话

带着canvas去流浪系列之三 绘制饼图的更多相关文章

  1. 带着canvas去流浪系列之五 绘制K线图

    [摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  2. 带着canvas去流浪系列之四 绘制散点图

    [摘要] 用原生canvasAPI实现百度Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI ...

  3. 带着canvas去流浪系列之七 绘制水球图

    [摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  4. 带着canvas去流浪系列之六 绘制雷达图

    [摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...

  5. 带着canvas去流浪系列之二 绘制折线图

    [摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  6. 带着canvas去流浪系列之八 碰撞

    [摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...

  7. 带着canvas去流浪系列之八 碰撞【华为云技术分享】

    [摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...

  8. 带着canvas去流浪系列之一:绘制柱状图

    [摘要] 学习使用canvasAPI来实现数据可视化. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制柱 ...

  9. 带着canvas去流浪系列之九 粒子动画【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

随机推荐

  1. NOI导刊总结

    NOI导刊总结 前两天去郑州,参加了什么NOI导刊的培训,然后就发现大佬是真的多,还十分意外的发现了一个事,清华北大是不是发笔记本和耳机,为啥三个老师的都一模一样... 这几天主要以讲.NOIP知识点 ...

  2. 大数据之路day01_3--JAVA语言基础(1)

    从这里开始,正式进入正轨 1.关键字  2.main main是关键字吗? 不是,他只是一个标识符,只不过有点特殊,虚拟机可以识别. main(主函数)的作用 1:可以保证程序的独立运行 2:是程序的 ...

  3. JQuery弹出菜单时禁止页面(body)滚动

    最近在做手机端的弹出菜单,但是菜单弹出来后滑动手机屏幕的话页面滚动总是会将菜单滑上去,体验非常不好,所以查了一下弹出菜单时禁止页面滚动的方法,整理如下: 方法一:弹出菜单时给body和html添加一个 ...

  4. layaair和egret的区别

    egret缺点1 编译速度非常慢 2 就是强类型转换非常的麻烦 3 只能用ts 所以只能用他们的IDE 不能用sublime layaair唯一不足的就是 insepct太垃圾 占用游戏界面 所以建议 ...

  5. 从 DevOps 到 Serverless:通过“不用做”的方式解决“如何更高效做”的问题

    作者 | 徐进茂(罗离) JAVA 开发工程师  导读:近年来,Serverless 一词越来越热,它已经逐渐成为了一种新型的软件设计架构.和 DevOps 概念提倡的是通过一系列工具和自动化的技术来 ...

  6. docker项目——上线tomcat网站

    项目: 1.使用docker部署tomcat环境 2.上线网站 3.完成访问使用等 第一步.启动基于tomcat镜像的容器 a.导入镜像 [root@localhost ~]# docker load ...

  7. C语言I博客作业08

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 作业 我在这个课程的目标是 熟悉使用while和do-while结构解决问题 这个作业在那个具体方面帮助我实现目标 pta题目及查找的资料 ...

  8. 008.Kubernetes二进制部署Nginx实现高可用

    一 Nginx代理实现kube-apiserver高可用 1.1 Nginx实现高可用 基于 nginx 代理的 kube-apiserver 高可用方案. 控制节点的 kube-controller ...

  9. python 基础之 模块

    Python 基础之模块 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 就是一个python文件中定义好了类和方法,实现了一些功能,可以被别的python文 ...

  10. html部分知识点(待完善)

    html部分知识点 跳转 在A页面某链接处`<a href="#aa" target="_blank"></a> 在B页面指定的标题处定 ...