目录

* 一. 任务说明 <https://www.cnblogs.com/dashnowords/p/10574646.html#一.-任务说明>
* 二. 重点提示 <https://www.cnblogs.com/dashnowords/p/10574646.html#二.-重点提示>
* 三. 示例代码 <https://www.cnblogs.com/dashnowords/p/10574646.html#三.-示例代码>
* 四. hover高亮的实现思路
<https://www.cnblogs.com/dashnowords/p/10574646.html#四.-hover高亮的实现思路>


示例代码托管在:http://www.github.com/dashnowords/blogs
<https://github.com/dashnowords/blogs/tree/master/Demo/canvas-echarts/pie-chart>

博客园地址:《大史住在大前端》原创博文目录 <https://www.cnblogs.com/dashnowords/p/10127926.html>

华为云社区地址:【你要的前端打怪升级指南】
<https://bbs.huaweicloud.com/blogs/8ae7e6420a4611e9bd5a7ca23e93a891>

一. 任务说明

使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】
<https://echarts.baidu.com/examples/editor.html?c=pie-roseType&theme=light>)。



二. 重点提示

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

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


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


* 再利用上述公式分别计算出每个扇形对应的外圆半径,在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效果消失时从外圆开始逐帧绘制白色外层扇区即可,最终再将数据扇区绘制为原色。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信