美文网首页
Canvas 饼图与动效

Canvas 饼图与动效

作者: HeyDelilah | 来源:发表于2016-08-16 18:07 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Canvas 饼图与动效

          本文链接:https://www.haomeiwen.com/subject/peipsttx.html