Canvas 饼图与动效

2016-06-24

用 Canvas 绘制一个饼图且实现动效。涉及:canvas 基本 api, requestAnimationFrame, d3.js, Path2D等等。本文是一个思路总结,仍有很多待优化的地方。

前言

在 canvas 上绘制一个饼图,要求动效如下:

pie-animation.gif

canvas 动效的本质:不断绘制每一帧

对动画帧节的控制:

  • 有一个总的 requestAnimationFrame(RAF),
  • 使用 RAF 自提供的 t,来做动画的间隔控制

开始绘制一个静态的饼图

使用 d3.js 来计算生成饼图路径。( d3是什么?

  1. d3.layout.pie() 计算组成饼图的弧的开始和结束的角度
d3-layout-pie.png
  1. d3.svg.arc() 传入内半径、外半径、开始弧度和结束弧等,生成环形路径数据。
pie1.png
生成三段 svg 路径:


```
M4.898587196589413e-15,-80A80,80 0 1,1 -3.06285495914156e-14,80L-2.4502839673132476e-14,64A64,64 0 1,0 3.91886975727153e-15,-64Z

M-3.06285495914156e-14,80A80,80 0 0,1 -56.568542494923825,56.568542494923776L-45.25483399593906,45.25483399593902A64,64 0 0,0 -2.4502839673132476e-14,64Z

M-56.568542494923825,56.568542494923776A80,80 0 0,1 -1.4695761589768237e-14,-80L-1.175660927181459e-14,-64A64,64 0 0,0 -45.25483399593906,45.25483399593902Z
```
  1. new Path2D() 将 SVG 弧线 path 信息转为 canvas 上的路径命令

静态的饼图就画好了。


饼图动画

(一)内部 requestAnimationFrame

记录下动画开始时刻,若超出 duration 后,即停止动画(停止调用 RAF)

(二)Canvas 动画:每一帧都清空画布,重新绘制饼图中的每个环形;

(三)任意时刻下的环形(即“半截”环形如何绘制)

pie2.png

d3.interpolate(startAngle, endAngle) 返回一个介于环形开始角度和结束角度之间的默认插值器;

如以上青色环形的插值起始值为 d3.interpolate(3.14159.., 3.92699...)

然后对区间 [0,1] 任意的参数 y,返回对应的补间值。

根据新的结束角度,生成新的环形路径。

每一帧中:实际上仅有一个扇形处于在变化之中(“半截”状态),在它之前的扇形通通绘制一个完整扇形,而在它之后的扇形不绘制。

如何求出当前处于“半截”状态的是哪一个组的?

以顺时针动画为例:

1. 根据已知的 t(当前时间戳),求出此刻的 y (用时占比)

pie-total.png
pie-detail.png

比例 : y = (t-st) / (et - st);

2. 根据每组数值大小,算出百分比(累加值)

百分比.png

3. 得到 index 值

其实就是算此刻 y 在百分比数组中的排序 ; (往一个有序数组中插入未知值)

(四)调整每组环形绘制的速度

动画总时长已知,每个环形组动画用时均分情况下,要让每一组的动画衔接自然,则要计算出每组动画的速度。

大环形跑的更快,小环形跑的较慢。(待优化:令其整体匀速运动,仅是单组用时不同)

以 index == 2(第二组)为例:

确定各组动画速度.png

最后得出的 y2 ,才是补间动画真正传入的值。(若用 y 作为补间动画传入值的话,只是平均速度,这会使得每个环形组之间动画衔接不上)


总结

写的有点绕。主要是自己对于一些数学概念没有很好地整理清晰,如:

y 是根据时刻来算的。而数值百分比是根据实际数值大小来算的

虽然得到的都是一个比率,但又好像不是同一个层面的东西。有种不知道咋“自圆其说”的尴尬...

BUG

偶发性,最后的环没有闭合起来。这是由于 t 的精度太细,到了 et 时候,偶尔会跳漏了几帧。暂处理:给个offset值,即多画几帧。

再谈 requestAnimationFrame

在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作动画的需求。这个方法接受一个函数为参,该函数会在重绘前调用;
DOMHighResTimeStamp参数,这个参数指示当前被 requestAnimationFrame 序列化的函数队列被触发的时间。单位毫秒,精确度在 10 µs。

把 RAF 看成封装了的 setTimeout,但它做了两个其他事:

  1. !document.hidden
  2. 调用间隔为最合理、尽量小的值

MDN: window.requestAnimationFrame

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,660评论 2 32
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    J_L_L阅读 1,490评论 0 4
  • 一、图形的组合方式 globalAlpha是一个介于0和1之间的值(包括0和1),用于指定所有绘制的透明度。默认值...
    空谷悠阅读 1,248评论 0 0
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    Looog阅读 3,933评论 3 40