带着canvas去流浪系列之三 绘制饼图
【摘要】 用canvas原生API绘制Echarts图表
示例代码托管在:http://www.github.com/dashnowords/blogs
一. 任务说明
使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。
二. 重点提示
南丁格尔玫瑰图的画法有很多种,Echarts中提供的以半径或面积两种不同模式,本文中以面积比例画法为例,绘制算法如下:
确定每个扇区的角度。由于所有扇区的角度加在一起为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高亮的实现思路
绘图过程中,将每个扇区的绘图数据(半径,相对于圆心的起始转角,扇区角度)均挂载在绘图数据上。
在
canvas标签上监听鼠标移动事件mousemove,并在回调函数中将鼠标移动事件event.clientX和event.clientY转换为相对于canvas坐标的数值(mouseX,mouseY)。从圆心坐标
(paintingCenter.x,paintingCenter.y)到(mouseX,mouseY)连接为向量,根据该向量的角度和模即可判断鼠标是否处于某个扇区之上。如果处于扇区之上,则以过渡动画来绘制关键帧使得hover效果表现出来。先修改
context.fillStyle颜色为对应扇区的高亮色,然后让外圆绘图半径以线性的方式逐帧增加至目标大小(例如10%),每一帧中使用canvas绘图上下文重新对绘图区域进行封闭画线,然后填充即可。hover效果出现时绘制高亮色的绘图区域,hover效果消失时从外圆开始逐帧绘制白色外层扇区即可,最终再将数据扇区绘制为原色。
来源:华为云社区 作者:大史不说话
带着canvas去流浪系列之三 绘制饼图的更多相关文章
- 带着canvas去流浪系列之五 绘制K线图
[摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之四 绘制散点图
[摘要] 用原生canvasAPI实现百度Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI ...
- 带着canvas去流浪系列之七 绘制水球图
[摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之六 绘制雷达图
[摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...
- 带着canvas去流浪系列之二 绘制折线图
[摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之八 碰撞
[摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...
- 带着canvas去流浪系列之八 碰撞【华为云技术分享】
[摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...
- 带着canvas去流浪系列之一:绘制柱状图
[摘要] 学习使用canvasAPI来实现数据可视化. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制柱 ...
- 带着canvas去流浪系列之九 粒子动画【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
随机推荐
- CSPS模拟 75
我身边 mikufun:矩阵树学学学 Lrefrain:矩阵题刷刷刷 Dybala:神仙定理康康康 skyh:讨论讨论讨论(most mei face) DeepinC:我过样例了! Mouding: ...
- EffectiveJava-1
最近在看EffectiveJava,记录一下,分享一下自己的心得. 一.将局部变量的作用于最小化 在第一次使用的地方进行声明,过早的声明局部变量,会延长局部变量的生命周期,若在代码块外声明变量,当程序 ...
- python学习之【第五篇】:Python中的元组及其所具有的方法
1.前言 Python的元组(tuple)与列表很相似,不同之处在于元组不能被修改,即元组一旦创建,就不能向元组中的增加新元素,不能删除元素中的元素,更不能修改元组中元素.但是元组可以访问任意元素,可 ...
- 『题解』Codeforces656E Out of Controls
更好的阅读体验 Portal Portal1: Codeforces Portal2: Luogu Description You are given a complete undirected gr ...
- Redis必备面试题《基础篇》
Date:2019-11-12 读前思考: 面试官会问什么样的问题? 所问的问题背后真实的套路是什么? 喜欢问Redis哪些问题? 如何顺畅回答面试问的问题?吊打面试官. 1.什么是Redis? Re ...
- DFS深度优先算法学习
刚开始学习算法,参考大佬博客还是有很多不明白的,于是一步步解析,写下笔记记录. 大佬博客地址: https://blog.csdn.net/fuzekun/article/details/852204 ...
- php的精度计算问题(bcadd和bcsub)
一.前言 我们在进行php开发的时候经常会遇到浮点型的问题,特别是涉及金额的部分,常常需要进行加减运算.当小数点的位数比较多的时候,往往容易犯一些很低级的错误.这里记录一下php的精度计算和封装的小d ...
- nyoj 50-爱摘苹果的小明 (比较)
50-爱摘苹果的小明 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:10 submit:15 题目描述: 小明家的院子里有一棵苹果树,每到秋天树上就 ...
- 力扣(LeetCode)删除排序链表中的重复元素 个人题解
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次. 这题思路比较简单,同样是快慢针的思路. 用一个整数类型val对应最新的只出现过一次的那个值, 如果节点的下一个节点的值和这个对应则不做别 ...
- 朱辉(茶水): Linux Kernel iowait 时间的代码原理
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 朱辉(茶水) 来源: 微信公众号linux阅码场(id: linuxdev) 作者介绍 朱辉,个人主页 htt ...