【带着canvas去流浪】 (3)绘制饼图

示例代码托管在:http://www.github.com/dashnowords/blogs
博客园地址:《大史住在大前端》原创博文目录
华为云社区地址:【你要的前端打怪升级指南】
一. 任务说明
使用原生canvasAPI绘制饼图(南丁格尔玫瑰)。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。

二. 重点提示
南丁格尔玫瑰图的画法有很多种,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效果消失时从外圆开始逐帧绘制白色外层扇区即可,最终再将数据扇区绘制为原色。
【带着canvas去流浪】 (3)绘制饼图的更多相关文章
- 【带着canvas去流浪】(2)绘制折线图
目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...
- 带着canvas去流浪系列之二 绘制折线图
[摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之三 绘制饼图
[摘要] 用canvas原生API绘制Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 【带着canvas去流浪(5)】绘制K线图
目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...
- 带着canvas去流浪系列之五 绘制K线图
[摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 【带着canvas去流浪(7)】绘制水球图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 文字淹水效果的实现 五. 关于canvas抗锯齿 六. 小结 示例代码托管在:http://www.github.com/dashnowor ...
- 【带着canvas去流浪(6)】绘制雷达图
目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...
- 【带着canvas去流浪(4)】绘制散点图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四.散点hover交互效果的实现 4.1 基本算法 4.2 参考代码 4.3 Demo中的小问题 示例代码托管在:http://www.githu ...
- 【带着canvas去流浪】(1)绘制柱状图
目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 思考题 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端& ...
随机推荐
- ELK 架构之 Elasticsearch、Kibana、Logstash 和 Filebeat 安装配置汇总(6.2.4 版本)
相关文章: ELK 架构之 Elasticsearch 和 Kibana 安装配置 ELK 架构之 Logstash 和 Filebeat 安装配置 ELK 架构之 Logstash 和 Filebe ...
- H5移动端项目案例、web手机微商城实战开发
自微信生态圈一步步强大后,关于移动端购物的趋势,逐渐成为大众关心的内容,目前市场上关于移动商城的制定就有大量版本,比如.微商城.移动商城.移动webAPP.微信商城各等各种定义层出不穷,这就对于移动端 ...
- Vue中引入bootstrap导致的CSS问题
最近在进行vue.js+webpack进行模块化开发的时候,遇到一个奇怪的问题. 问题是这样的: 1. 在main.js文件中引入bootstrap的js和css. 2. 自己写了一个Header.v ...
- 基于SpringBoot从零构建博客网站 - 整合lombok和mybatis-plus提高开发效率
在上一章节中<技术选型和整合开发环境>,确定了开发的技术,但是如果直接这样用的话,可能开发效率会不高,为了提高开发的效率,这里再整合lombok和mybatis-plus两个组件. 1.l ...
- 广州站长沙龙 MIP 问题及答案
1. mip提交几个月时间了,生效量比较少,是什么原因? 答:提交 MIP 页面后,经过收录.校验.和生效三个步骤,才能在结果页看到闪电标. 1)提交 URL 后,spider 会去抓取收录: 2)页 ...
- MySQL - 扩展性 3 负载均衡:眼花缭乱迷人眼
负载均衡的基本思路很简单: 在一个服务器集群中尽可能地的平均负载量. 基于这个思路,我们通常的做法是在服务器前端设置一个负载均衡器.负载均衡器的作用是将请求的连接路由到最空闲的可用服务器上.如图 1, ...
- RabbitMQ的介绍及使用进阶(Docker+.Net Core)
目录: 一.什么是RabbitMQ 二.RabbitMQ运用场景 三.RabbitMQ优势及特点 四.Centos7中Docker安装RabbitMQ 五..Net Core 中使用RabbitMQ ...
- 前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
一.AMD和CMD规范(了解) 1.1传统的前端开发多个js文件的关系 yuan.js中定义了一个函数 function mianji(r){ return 3.14 * r * r } main.j ...
- Java之品优购课程讲义_day06(7)
商品录入[SKU 商品信息]5.1 需求分析 基于上一步我们完成的规格选择,根据选择的规格录入商品的 SKU 信息,当用户选择相应的规格,下面的 SKU 列表就会自动生成,如下图:实现思路:实现思路: ...
- 适配器模式(Adapter Pattern)
适配器模式概述 定义:将一个类的接口转化成客户希望的另一个接口,适配器模式让那些接口不兼容的类可以一起工作.别名(包装器[Wrapper]模式) 它属于创建型模式的成员,何为创建型模式:就是关注如何将 ...