canvas 环形饼状图_Canvas 饼图与动效

本文介绍了如何使用Canvas绘制环形饼状图并实现动效,包括使用requestAnimationFrame、d3.js和Path2D等技术。通过d3.layout.pie计算角度,d3.svg.arc生成路径,然后利用Path2D将SVG路径转化为Canvas路径。文章详细讲解了动画原理,如何控制动画帧,以及如何调整每个环形的绘制速度,确保动画平滑。最后,提到了可能出现的bug及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2016-06-24

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

前言

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

pie-animation.gif

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

对动画帧节的控制:

有一个总的 requestAnimationFrame(RAF),

使用 RAF 自提供的 t,来做动画的间隔控制

开始绘制一个静态的饼图

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

d3.layout.pie() 计算组成饼图的弧的开始和结束的角度

d3-layout-pie.png

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

```

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,但它做了两个其他事:

!document.hidden

调用间隔为最合理、尽量小的值

### UniApp 中使用 iframe 嵌入 H5 页面 #### 实现 iframe 高度自适应 为了使 `iframe` 的高度能够自动调整以匹配其内容的高度,在 HTML 结构中可以通过 JavaScript 动态计算并设置 `iframe` 的高度。具体做法是在 `iframe` 加载完成后执行一段脚本,该脚本会读取 `iframe` 内部文档的实际高度,并将其应用到 `iframe` 上。 ```html <template> <div class="container"> <!-- 使用 v-bind 绑定动态样式 --> <iframe :style="{ height: iframeHeight + 'px' }" id="iframe_id" src="./static/map.html" frameborder="0" width="100%" scrolling="no" onload="this.style.height = this.contentWindow.document.body.scrollHeight + 'px';"></iframe> </div> </template> <script> export default { data() { return { iframeHeight: 0, // 初始化 iframe 高度为 0 }; }, }; </script> ``` 这种方法确保了即使页面初次加载时无法立即获取到正确的高度,也可以在每次重新加载或更新内容后及时调整大小[^1]。 #### Android 调用 H5 方法 当在一个 Android 应用程序里嵌入了一个由 UniApp 构建的 H5 页面时,可能需要让两者之间互相通信。这通常涉及到允许 Web 视图(WebView)内的 JavaScript 访问本地 Java API 或者反过来。对于这种情况下的集成工作: - **初始化 WebView**: 定义一个名为 `webView` 的私有成员变量用于表示 WebView 控件。 - **配置 WebView 参数**: 在 Activity 创建期间(`onCreate`),除了常规设置外还需要启用 JavaScript 支持以及注册接口以便于 JS 可以调用 Android 提供的功能。 ```java // MainActivity.java (部分代码片段) import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.webview); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // 启用JS支持 // 添加H5调用的类 webView.addJavascriptInterface(new JsBridge(), "android"); ... } } ``` 这里的 `JsBridge` 是一个实现了特定功能的对象实例,它被暴露给网页上的 JavaScript 进行交互操作[^2]。 #### 微信小程序嵌套 H5 页面 如果打算在一个基于 UniApp 开发的小程序环境中嵌入外部 H5 页面,则需要注意一些细节问题。特别是关于安全性和性能方面的要求可能会更加严格。例如,微信平台会对可访问 URL 地址有所限制,因此开发者应该提前确认目标站点已被加入白名单列表之中。另外,由于浏览器缓存机制的存在,有时新发布的版本不会立刻显示出来;此时建议尝试清理缓存后再做测试验证[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值