D3是如何画饼图的?

290 阅读3分钟

饼图这个功能,就像下面这样,比较常见。想要完成这个功能在如今的社会,不难。因为很多优秀的第三方库都帮我们实现了,只需要调用一下就可以了。比如 echarts、highCharts、d3、plot、antv全家桶等等。

截屏2025-01-21 12.04.54.png

那接下来的系列文章,我们就来看看D3是如何处理饼图的!

在讲解之前,我们还是要说一下图形化里有关于圆的一些内容。

一、计算机如何表示角度?

描述角度有2种方式,一种是角度制、一种是弧度制。

既然有了角度制,为啥还要有弧度制?

计算机认识3度吗?那肯定不认识,它都不认识这个单位。

那计算机认识啥?认识一切实数(0,1,2,3,4,5等等),所以为了能让计算机识别“度数单位”,“弧度制”出现了,它是“角度制”的一种测量方式。

那上面就是从计算机这个角度来理解“角度”与“弧度”。

二、如何理解弧度?

根据百度百科我们知道,“弧度的绝对值 = 弧长 / 半径”。弧度要加绝对值是因为弧长有正负之分,顺时针弧长是正数,逆时针弧长是负数。

一圈的弧长是“2兀*半径”,所以根据公式,一圈对应的弧度就是2兀(单位是rad,表示弧度单位)。

因为360度也可以表示一圈,所以有了下面的等式:

截屏2025-01-24 19.08.55.png

所以30度是多少弧度?左侧✖️30即可得出对应的弧度,因此根据角度求弧度的公式如下:

截屏2025-01-24 16.52.41.png

三、弧度与弧长?

这两个绝对不是一个东西。

刚才我们说了,“弧度的绝对值 = 弧长 / 半径”,那么弧长的公式自然就是 “弧度✖️ 半径”。

所以我们学习跟圆弧、三角函数相关的API的时候,要格外注意入参是什么,是弧度、还是弧长等等。

四、D3是如何画饼图的?

看下面的代码:

<canvas
  id='canvas'
  width='800'
  height='500'
></canvas>

<script>
    import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
    
    const context = document.queryElementById('canvas').getContext('2d');
    const data = [10, 11, 22];
    const colors = ['#1f77b4', '#ff7f0e', '#2ca02c'];
    const pieCreator = d3.pie();
    const arcs = pieCreator(data);
    const drawArc = d3.arc().outerRadius(100).innerRadius(30).context(context)
    context.translate(width / 2, height / 2);
    arcs.forEach(item => {
        context.beginPath();
        drawArc(item);
        context.fillStyle = colors[i];
        context.fill();
        context.globalAlpha = 1;
        context.strokeStyle = '#000';
        context.stroke();
    })
</script>

将上面代码copy运行一下,你应该会得到下图的效果:

截屏2025-01-24 22.17.43.png

咱们可以在arcs打一个断点,此时就会发现,arcs是一个数组,数组里体现的是当前value在总sum里的占比,只不过这个占比他不是百分比,而是采用了弧度的方式,注意,是弧度,不是弧长!

这种方式确实更好,因为 canvas.arc 的参数就是起始弧度、结束弧度。

画饼弧是比较轻松的,我们只需要将画笔moveTo到起始弧度的起点上,然后外圆弧顺时针或者逆时针都可以,但是内圆弧必须是相反的方向去画,最后stroke描边就可以了。

核心代码如下:

// 外圆半径
const outerRadius = 100
// 内圆半径
const innerRadius = 30

function drawArc(obj) {
    const { startAngle, endAngle } = obj;
    const drawDirection = startAngle < endAngle;
    
    const positionXOfStartAngle = outerRadius * Math.cos(startAngle);
    const positionYOfStartAngle = outerRadius * Math.sin(startAngle);
    
    context.moveTo(positionXOfStartAngle, positionYOfStartAngle);
    context.arc(0, 0, outerRadius, startAngle, endAngle, !drawDirection);
    context.arc(0, 0, innerRadius, endAngle, startAngle, drawDirection);
}

五、最后

好啦,本期内容到这里就结束啦,接下来的文章会在此基础上来拆解一下D3是如何实现padAngle、cornRadius。

希望我的分享对你有帮助,我们下期再见~~