视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
canvas绘制饼图的方法介绍(代码)
2020-11-03 23:13:04 责编:小采
文档
 本篇文章给大家带来的内容是关于canvas绘制饼图的方法介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一. 任务说明

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

二. 重点提示

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

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

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

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

【相关推荐:HTML5视频教程】

下载本文
显示全文
专题