彻底理解 Canvas/SVG 圆弧算法

如果你想在一个网页中绘制一条弧线,那么你就需要用到 Canvas 或者 SVG 技术。

准确地说,一条弧线是椭圆的一部分。因此,我们可以想象,为了唯一确定一条椭圆弧,我们至少需要以下参数:

圆心位置,这里我们记为 (x, y);长轴和短轴半径 rx, ry;旋转角度 rotation;起始角度 startAngle;终止角度 endAngle。

这听起来很简单对不对?

Canvas 有两个相关的 API,arc 可以用来画正圆的圆弧,所以 x 和 y 的半径是相同的,也没有轴的旋转角度。而 ellipse 是用来画椭圆弧的。

值得注意的是,这两个 API 的最后一个参数,anticlockwise,也就是一个布尔类型的表示是否是逆时针的值。

这是什么意思呢?

想象一下,当我们决定了起始角度和终止角度,其实可以有两段圆弧满足这一点。

所以,anticlockwise 为 true 的时候,表示取逆时针方向的那条圆弧,为 false 的时候,取顺时针的圆弧。


SVG 表达圆弧的方式有点特殊,你需要给定起始坐标 (x0, y0),然后给定一些列参数之后,还要给定终止坐标 (x1, y1)。不得不说,相比 Canvas 给定圆心和起始终止角度的方式,SVG 的这种参数设计实在麻烦很多。

这里还有两个我们还不了解,一个叫 large-arc-flag,另一个叫 sweep-flag。

large-arc-flag,字面意思就是,它是一个表示是否是大圆弧的标志位。

什么是大圆弧呢?之前我们知道,给定角度之后,有两个弧线符合要求。所以,SVG 的逻辑是,你告诉我,你要画的是大的那个圆弧,还是小的那个圆弧。这听起来更直观更好理解,但其实在计算的时候,Canvas 的那种方法要简单得多。理由是,起始角度和终止角度可能不是在 0 到 2π 之间的,这就会给判断是大圆弧还是小圆弧带来很多麻烦。

但还没完,还有一个更难理解的 sweep-flag。sweep-flag 的意思是,是否交换的标记位。

在我们给定半径、轴的旋转角、起始左边、终止坐标之后,其实可以得到两个满足条件的椭圆。这两个椭圆由交点切割为四段圆弧。

根据 large-arc-flag,我们可以排除掉两条不符合大圆弧标志位的圆弧。比如,当 large-arc-flag 是 true 的时候,我们可以排除两条小圆弧。

根据 sweep-flag 的定义,当这个标志位是 1 的时候,绘制的圆弧是“正角度”方向的,也就是顺时针方向的,这样我们就可以唯一确定一条圆弧。


上面讲了这么多细节,可能已经把一些小伙伴绕晕了,为什么我们要对画圆弧这样一个简单的需求了解得这么彻底呢?

ECharts 是一个支持 Canvas 和 SVG 双引擎渲染的可视化工具,用户只需要在初始化的时候指定使用的渲染方式。为了实现这点,我们就需要对 Canvas 和 SVG 的绘制方式有深入的理解。

上面讲的还只是基础知识,实际在绘制圆弧的时候,还会碰到很多细节问题需要考虑。

但正是有了之前介绍的这些看起来很枯燥晦涩的知识,我们才能最终做成 ECharts 这样强大酷炫的可视化工具。

https://www.bilibili.com/video/av70653194/www.bilibili.com

这是本文的视频教程,在滚城一团 ECharts 小课堂系列,我们还会介绍更多的可视化相关算法,所以大家一定要记得关注哦!

发布于 2019-10-10

文章被以下专栏收录