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

目录

  • 一. 任务说明
  • 二. 重点提示
  • 三. 示例代码
  • 四. hover高亮的实现思路

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

博客园地址:《大史住在大前端》原创博文目录

华为云社区地址:【你要的前端打怪升级指南】

一. 任务说明

使用原生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效果消失时从外圆开始逐帧绘制白色外层扇区即可,最终再将数据扇区绘制为原色。

原文地址:https://www.cnblogs.com/dashnowords/p/10574646.html

时间: 2024-10-12 15:33:33

【带着canvas去流浪】 (3)绘制饼图的相关文章

【带着canvas去流浪(6)】绘制雷达图

目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] 一. 任务说明 使用原生canvasAPI绘制雷达图.(截图以及数据来自于百度Echarts官方示例库[查看示例链接]). 二. 重点提示 雷达图绘制的看起来并不复杂,无非就是一些路径点的连线,其中的难点都在于一些细节. 坐标转换 为了避免在绘制过程中不断根据

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

[摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生API了,那么从这一节开始,我们就开始接触点好玩的东西——动画. 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生API了,那么从这一节开始,我们就开始接触点好玩的东西——动画. 一. canvas的能力 如果你以为canvas只能绘制图表那真的就图样图森破了,且不谈webgl的绘图上

c# 通过.net自带的chart控件绘制饼图pie chart

c# 通过.net自带的chart控件绘制饼图pie chart 需要实现的目标是: 1.将数据绑定到pie的后台数据中,自动生成饼图. 2.生成的饼图有详细文字的说明. 具体的实现步骤: >>前台界面的设置: 1.设置chart1的属性Legends中默认的Legend1的Enable为false: 2.设置Series的ChartType为Pie 3.设置Series显示的文字内容(此处比较关键) 至此,前台的设置完成. >>下面填写后台代码: List<string&g

玩转Android Camera开发(五):基于Google自带算法实时检测人脸并绘制人脸框(网络首发,附完整demo)

本文主要介绍使用Google自带的FaceDetectionListener进行人脸检测,并将检测到的人脸用矩形框绘制出来.本文代码基于PlayCameraV1.0.0,在Camera的open和preview流程上进行了改动.原先是放在单独线程里,这次我又把它放到Surfaceview的生命周期里进行打开和开预览. 首先要反省下,去年就推出了静态图片的人脸检测demo,当时许诺一周内推出Camera预览实时检测并绘制的demo,结果拖到现在才整.哎,屌丝一天又一天,蹉跎啊.在demo制作过程中

陪你去流浪--薛之谦

陪你去流浪 作曲 : 薛之谦 不知道为了什么 忧愁它烦扰着我 有时会借着月光 能带走爱的凄凉 我看着湖面 平平 淡淡 好像还有艘小船 安安 静静的 没人来打扰 这故事挺好 你掀起 远方 漪涟 海浪 慢慢靠近 要我 陪你 流浪 你坚定的模样 我放弃了抵抗 我可以陪你去流浪 也知道下场不怎么样 就快要夜深人静了 反对的只剩下月亮 我会攥着小糖 眺望你方向 快告诉我 你在赶来的路上 我可以陪你去流浪 等你再次粉墨登场 就快要风平浪静了 我避开所有的阻挡 我会带着小伤 眺望你方向 快告诉我 你在赶来的路

Qt之自绘制饼图

1.说明 最近在搞绘图方面的工作,说实话C++的第三方绘图库并不算多,总之我了解的有:qtcharts.ChartDirector.qwt.kdchart和QCustomPlot.这几个库各有利弊. qtcharts:qt5.7之后才开源的模块,支持绘制各种图标,并且功能相当丰富,但是可扩展性差,如果自己想高度定制,比较困难,主要是和qt的源码风格有决定性的关系. ChartDirector:开源的第三方绘图库,使用方便,推荐使用 qwt:主要绘制仪表盘类似的东西(这个库可以编译后加入qt帮助文

2014-6-7 带思杨去西三旗儿童乐园玩-----思杨晕车了

静儿手术,在家静养.我和妈带思杨去西三旗儿童乐园玩. 667,可恶的堵车.其实是在意料之中的,在沙河北大桥那堵车,堵得很厉害,公交一晃一晃的 ,几乎不咋走.结果思杨就华丽丽滴吐了.本来上午就只喝了点奶,结果全吐了.娃娃可怜的萎 在奶奶怀里.睡也不是,不睡也不是.   经过1个多小时的挪动,终于到了西三旗了.(但是回来的路却很顺,一点不堵车,很快就到 宋兰堡了). 以前不知道,去了才知道思杨竟然开始害怕滑滑梯了.不知道啥原因.也可能是有点胖得缘 故吧,总觉得他比其他的孩子缺少点麻利.肚肚上和屁股上

带着感恩的心去开发

带着感恩去开发, 有些人生活的很开心, 有些人过的很纠结, 什么原因呢? 是因为角色没放正, 要有一颗老板的心态, 如果你能站在老板的角度, 去研发新产品, 有一颗匠人的心, 去雕琢产品, 公司的产品肯定优中出精! 抱着老板的心态有几点好处: - 工作更加积极了 - 老板更加欣赏你了, 同事之间更加和谐了. 没有谁不喜欢积极.努力.能够雕琢出精品的你! - 得到大家的认可之后, 薪水自然是低不了的. 带着感恩的心去工作, 改变心态, 感恩老板给了你一份不错的工作, 感恩同事能与你同舟共济, 感恩

UIGraphics 绘制饼图

相关设置没有写成宏定义,需要到里面改.自用版. // //  YJPieModel.h //  绘制饼图 // //  Created by pilgrim on 15/3/3. //  Copyright (c) 2015年 pilgrim. All rights reserved. // #import <Foundation/Foundation.h> @interface YJPieModel : NSObject //饼图数据 @property (nonatomic, strong