在上一节中,我们详细介绍了柱状图的canvas
实现方式,那么在本篇文章中,我将详细介绍一下如何用canvas
实现一个饼图。
如何实现一个饼图?
Step1
首先创建一个叫做piechart.html
的新文件,并且在其中写入如下代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<canvas width="500" height="500" id="canvas"></canvas>
</body>
<script>
//initialize data set
var data = [100, 68, 20, 30, 100];
var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
//draw background
c.fillStyle = "white";
c.fillRect(0, 0, 500, 500);
</script>
</html>
在这里我们创建了一个文件来存放我们的canvas
和数据。
再说回饼图,如果我们想要绘制饼图的话,就会遇到一个核心问题:"角度的计算与绘制。"
Step2
js
//a list of colors
var colors = ["orange", "green", "blue", "yellow", "teal"];
//calculate total of all data
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
如代码所示,我们使用total
和data
的比例来计算角度。
Step3
到了这里,我们就要详细的计算角度了
- 绘制圆弧路径,我们需要用到一个新的
api
=>
CanvasRenderingContext2D.arc(x, y, radius, startAngle, endAngle, anticlockwise)
这里一共有五个参数,第一个参数是圆弧中心(圆心)的 x 轴坐标;第二个参数是圆弧中心(圆心)的 y 轴坐标;第三个参数是圆弧的半径;第四个参数是圆弧的起始点,x 轴方向开始计算,单位以弧度表示;第五个参数是圆弧的终点,单位以弧度表示;第六个参数是可选的Boolean
值,如果为 true
,逆时针绘制圆弧,反之,顺时针绘制。
- 第二个点,是想要说一下弧度的计算公式:2*π*占比
代码如下:
JS
var prevAngle = 0;
for (var i = 0; i < data.length; i++) {
// 占比
var fabrication = data[i] / total;
// 计算当下角度
var angle = prevAngle + fabrication * Math.PI * 2;
c.fillStyle = colors[i];
// 写一个路径
c.beginPath();
c.moveTo(250, 250);
c.arc(250, 250, 100, prevAngle, angle, false);
c.lineTo(250, 250);
c.fill();
c.strokeStyle = "black";
c.stroke();
prevAngle = angle;
}
效果如下:
Step4
在实现了我们的基本功能之后,我们得把相应的描述饼图的文本加上去。
为了实现文本的居中,我们这里又涉及了一个新的api
=>
CanvasRenderingContext2D.measureText()
方法返回一个关于被测量文本TextMetrics
对象包含的信息(例如它的宽度)。
我们这边基本只使用返回对象的宽度:
ts
//draw centered text
c.fillStyle = "black";
c.font = "24pt sans-serif";
var text = "Sales Data from 2025";
var metrics = c.measureText(text);
c.fillText(text, 250 - metrics.width / 2, 400);
我们可以看到fillText
这里我们的第二个参数,也就x
的位置设置为了250 - metrics.width
,这是类似于left: 50%; transform: trnaslateX(-50%)
一样的效果,主要是为了实现居中。
实现效果: