![最终产品图片](https://i-blog.csdnimg.cn/blog_migrate/16a45b710fc8dd478296a3b48bcb4903.png)
在本教程中,我将向您展示如何使用JavaScript和画布以饼图和甜甜圈图的形式显示数字信息。
比起从头开始编写图表,有更简便的方法来创建图表,例如,来自CodeCanyon的完整图表库 。
![信息图表和图形HTML标签库](https://i-blog.csdnimg.cn/blog_migrate/9b6b111964bdee0beb265d87fb88f814.png)
但是,如果您想知道像这样的库在幕后发生的事情,请继续阅读。
什么是饼图?
图表是一种统计工具,用于以图形方式表示数字数据。 饼形图将数值数据显示为分成多个切片的圆形。 每个切片的大小与其所代表的数值成正比。
什么是甜甜圈图?
简单地说,甜甜圈图是饼图的变体。 区别在于,将切片切向馅饼的中心,这样仅边缘可见。 这样,图表看起来像一个甜甜圈,因此是名称。
开始使用画布绘图
在绘制饼图之前,我们将看一下绘制饼图的各个部分。 我们将看到如何使用canvas组件和JavaScript进行绘制:
- 一条线
- 弧(圆的一部分)
- 颜色填充的形状
要开始使用HTML5画布进行绘制,我们需要创建一些东西:
- 一个文件夹,用于保存项目文件; 我们将此文件夹称为
piechart-tutorial
。 -
piechart-tutorial
文件夹中有一个HTML文件index.html
。 该文件将包含HTML代码。 -
piechart-tutorial
文件夹中有一个JS文件script.js
。 该文件将包含我们JavaScript代码。
我们将使事情变得非常简单,并在index.html
添加以下代码:
<html>
<body>
<canvas id="myCanvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
我们具有ID为myCanvas
的<canvas>
元素,以便可以在我们的JS代码中引用它。 然后,我们通过<script>
标记加载JS代码。
在script.js
内部,JS代码将首先获取对画布的引用,然后设置其宽度和高度。 要在画布上绘制,我们只需要引用包含所有绘制方法的2D上下文即可。
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 300;
myCanvas.height = 300;
var ctx = myCanvas.getContext("2d");
现在我们已经设置好画布,并且还引用了绘图画布,让我们定义一些JavaScript函数,这些函数在绘制饼图时将可以重用。 我们将这些功能添加到我们的script.js文件中。
function drawLine(ctx, startX, startY, endX, endY){
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
}
drawLine
函数采用五个参数:
-
ctx
:引用绘图上下文 -
startX
:线起点的X坐标 -
startY
:线起点的Y坐标
-
endX
:线终点的X坐标
-
endY
:线终点的Y坐标
我们通过调用beginPath()
开始画线。 这通知绘图上下文我们开始在画布上绘制一些新内容。 我们使用moveTo()
设置起点,调用lineTo()
指示终点,然后通过调用stroke()
进行实际绘制。
现在让我们看看如何绘制圆的一部分,也称为圆弧。
function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle){
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
}
drawArc
函数具有六个参数:
-
ctx
:引用绘图上下文 -
centerX
:圆心的X坐标 -
centerY
:圆心的Y坐标 -
radius
:线终点的X坐标 -
startAngle
:圆的一部分开始的弧度的起始角度 -
endAngle
:圆弧部分结束处的弧度结束角
我们已经了解了如何绘制直线和弧线,现在让我们看看如何绘制彩色形状。 由于我们的目标是绘制由切片组成的饼图,因此我们创建一个绘制饼图的函数。
function drawPieSlice(ctx,centerX, centerY, radius, startAngle, endAngle, color ){
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(centerX,centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fill();
}
drawPieSlice
函数采用七个参数:
-
ctx
:引用绘图上下文 -
centerX
:圆心的X坐标 -
centerY
:圆心的Y坐标 -
radius
:线终点的X坐标 -
startAngle
:圆的一部分开始的弧度的起始角度 -
endAngle
:圆弧部分结束处的弧度结束角 -
color
:用于填充切片的颜色
这是调用三个函数的示例:
drawLine(_ctx,100,100,200,200);
drawArc(_ctx, 150,150,150, 0, Math.PI/3);
drawPieSlice(_ctx, 150,150,150, Math.PI/2, Math.PI/2 + Math.PI/4, '#ff0000');
它将产生以下结果:
![画布线弧和饼图切片](https://i-blog.csdnimg.cn/blog_migrate/871d5413d2b227fe717b2b1393f49bd1.png)
现在,我们拥有绘制饼图所需的所有工具,接下来让我们看看如何一起使用它们。
绘制饼图
从概念上讲,任何图表都包含两个主要部分:
- 数据模型包含要表示的数字数据。 它以特定于图表类型的格式构成。
- 图形表示法是根据数学公式形式的某些规则,通过可视元素表示数据模型中的数字数据的方式。
饼图数据模型
构造饼图数据模型的最常见方法是一系列类别和相应的值,其中每个类别和值都与饼图的一部分相关联。
例如,一个饼图的数据模型显示了我按类型分组的乙烯基数量,如下所示:
- 古典音乐:10
- 替代摇滚:14
- 流行音乐:2
- 爵士乐:12
我们可以将JS对象添加到script.js
文件中,以存储数据模型,如下所示:
var myVinyls = {
"Classical music": 10,
"Alternative rock": 14,
"Pop": 2,
"Jazz": 12
};
饼图图形表示
饼形图使用圆圈将数据模型划分为多个切片,以显示数据模型中的信息。 每个切片对应于数据模型中的类别,并且切片的大小与类别值成比例。
我的38种乙烯基唱片的小型收藏有四个类别。 每个类别将获得与该类别中的乙烯基数量成比例的饼图切片。
但是,我们如何测量切片的大小? 这很容易-我们通过切片顶端的角度来做到这一点。 我们所需要知道的是,整个圆对应于360 degrees
或2 * PI
的角度。 因此,半圆为180 deg
或PI
,四分之一为90 deg
或PI/2
,依此类推。
为了确定每个类别切片的角度,我们使用以下公式:
slice angle = 2 * PI * category value / total value
根据此公式,十个古典音乐黑胶唱片的切角约为 0.526 * PI或94度
让我们开始绘画。 为此,我们将使用一个JavaScript类,将其命名为Piechart
。 构造函数将接收一个options参数,该参数包含以下内容:
- canvas:引用我们要绘制饼图的画布
- 数据:对持有数据模型的对象的引用
- colors:包含我们要用于每个切片的颜色的数组
Piechart
类还包含一个方法draw()
,它实际绘制图表。
var Piechart = function(options){
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.draw = function(){
var total_value = 0;
var color_index = 0;
for (var categ in this.options.data){
var val = this.options.data[categ];
total_value += val;
}
var start_angle = 0;
for (categ in this.options.data){
val = this.options.data[categ];
var slice_angle = 2 * Math.PI * val / total_value;
drawPieSlice(
this.ctx,
this.canvas.width/2,
this.canvas.height/2,
Math.min(this.canvas.width/2,this.canvas.height/2),
start_angle,
start_angle+slice_angle,
this.colors[color_index%this.colors.length]
);
start_angle += slice_angle;
color_index++;
}
}
}
该类首先存储作为参数传递的options
。 它存储canvas
参考,并创建一个也作为类成员存储的图形上下文。 然后,它存储作为选项传递的colors
数组。
下一部分是最一致的draw()
函数。 这将从数据模型中提取数据。 首先,它计算数据模型中所有值的总和。 然后,对于数据模型中的每个类别,我们应用上述公式来计算饼角。 最后,我们使用drawPieSlice()
函数,将画布的中心作为切片的中心。 由于不希望饼图超出画布,因此我们将半径用作画布宽度的一半和画布高度的一半之间的最小值。
每次绘制类别时,我们还将偏移切片的开始角度和结束角度,否则切片将重叠。
要使用该类,我们必须创建一个实例,然后在创建的对象上调用draw()
方法。
var myPiechart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:["#fde23e","#f16e23", "#57d9ff","#937e88"]
}
);
myPiechart.draw();
结果看起来像这样
![使用HTML5画布绘制饼图](https://i-blog.csdnimg.cn/blog_migrate/781bccc4c0d6c2aa157a5f7047379cc3.png)
绘制甜甜圈图
我们已经看到了如何绘制饼图。 我们还知道,甜甜圈图的不同之处仅在于在图的中间有一个Kong。 我们如何绘制Kong? 我们可以在饼图上绘制一个白色圆圈。
让我们修改Piechart
类的代码来做到这一点。
var Piechart = function(options){
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.draw = function(){
var total_value = 0;
var color_index = 0;
for (var categ in this.options.data){
var val = this.options.data[categ];
total_value += val;
}
var start_angle = 0;
for (categ in this.options.data){
val = this.options.data[categ];
var slice_angle = 2 * Math.PI * val / total_value;
drawPieSlice(
this.ctx,
this.canvas.width/2,
this.canvas.height/2,
Math.min(this.canvas.width/2,this.canvas.height/2),
start_angle,
start_angle+slice_angle,
this.colors[color_index%this.colors.length]
);
start_angle += slice_angle;
color_index++;
}
//drawing a white circle over the chart
//to create the doughnut chart
if (this.options.doughnutHoleSize){
drawPieSlice(
this.ctx,
this.canvas.width/2,
this.canvas.height/2,
this.options.doughnutHoleSize * Math.min(this.canvas.width/2,this.canvas.height/2),
0,
2 * Math.PI,
"#ff0000"
);
}
}
}
添加的代码在options
参数中查找成员变量doughnutHoleSize
。 如果选项中不存在此代码,则代码将像以前一样绘制饼图,但是如果确实存在,则将绘制一个白色圆圈,其中心与饼图相同。
圆的半径是通过将饼图半径乘以doughnutHoleSize
的值确定的。 该数字应为0到1之间的数字,其中0将生成饼图,而任何大于0的值都将导致甜甜圈的Kong越来越大,而1则使图表不可见。
要绘制一个甜甜圈图,其Kong的大小是图表的一半,我们需要使用0.5的doughnutHoleSize
并进行以下调用:
var myDougnutChart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
doughnutHoleSize:0.5
}
);
myDougnutChart.draw();
结果如下:
![用HTML5画布绘制甜甜圈图](https://i-blog.csdnimg.cn/blog_migrate/415b0eb73771aa55bc0afd76a5f2d572.png)
添加标签和图表图例
我们的饼图和甜甜圈图看起来不错,但是我们可以通过添加以下两点使它们变得更好:
- 值标签:显示每个切片对应的百分比
- 图表图例:在图表中显示类别及其相应的颜色
通常,与切片相关联的值表示为百分比值,该百分比值计算为100 * value associated to a slice / total value
,整个圆圈代表100%
。
例如,在我们的样本数据中,带有古典音乐的乙烯基大约占26%
。 能够在相应的分片上正确写入该值将是很好的。 为此,我们将使用绘图上下文的fillText(text,x,y)
函数。 此函数采用三个参数:文本以及x
和y
坐标。
我们如何计算放置文本的x
和y
坐标? 我们必须利用一些几何知识和称为极坐标的东西。 基本上,极坐标使用半径和角度来定义点的位置。 我们将使用的两个公式是:
x = R * cos(angle)
y = R * sin(angle)
我们将应用这两个公式将文本放置在饼形图半径的中间,并围绕每个饼图切片的角度放置一半。 为此,我们需要修改Piechart
类,并在if (this.options.doughnutHoleSize){...}
块之后添加以下代码:
...
start_angle = 0;
for (categ in this.options.data){
val = this.options.data[categ];
slice_angle = 2 * Math.PI * val / total_value;
var pieRadius = Math.min(this.canvas.width/2,this.canvas.height/2);
var labelX = this.canvas.width/2 + (pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
var labelY = this.canvas.height/2 + (pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
if (this.options.doughnutHoleSize){
var offset = (pieRadius * this.options.doughnutHoleSize ) / 2;
labelX = this.canvas.width/2 + (offset + pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
labelY = this.canvas.height/2 + (offset + pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
}
var labelText = Math.round(100 * val / total_value);
this.ctx.fillStyle = "white";
this.ctx.font = "bold 20px Arial";
this.ctx.fillText(labelText+"%", labelX,labelY);
start_angle += slice_angle;
}
...
代码遍历每个切片,计算百分比,计算位置,并使用fillText()
方法在图表上绘制它。 我们使用fillStyle
属性将文本颜色设置为白色,并使用font
属性设置标签的大小,样式和字体系列。 同样重要的是要注意,如果图表是一个甜甜圈图,并且设置了doughnutHoleSize
,则标签将被推向图表的边缘,以使其在甜甜圈切片上居中。
这是带有值标签的结果图表的外观:
![带有值标签的饼图和甜甜圈图](https://i-blog.csdnimg.cn/blog_migrate/1d424618e54353f08a871307ae1ffea5.png)
为了完成图表,我们最后要添加的是图表图例。 我们的图表图例将显示我们的数据模型的类别以及用于相应切片的颜色。 首先,我们必须通过添加用于存储图例元素的<div>
标记对index.html
文件进行一些修改。
<html>
<body>
<canvas id="myCanvas"></canvas>
<div id="myLegend"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
然后在script.js
,添加创建图例元素内容的代码。 我们将此代码添加到Piechart
类的draw()
函数的Piechart
:
...
if (this.options.legend){
color_index = 0;
var legendHTML = "";
for (categ in this.options.data){
legendHTML += "<div><span style='display:inline-block;width:20px;background-color:"+this.colors[color_index++]+";'> </span> "+categ+"</div>";
}
this.options.legend.innerHTML = legendHTML;
}
...
该代码查找通过options
参数传递的legend
元素。 如果提供了一个,则用包含彩色框和数据模型类别名称HTML代码填充此元素。
我们还需要对调用饼图的方式进行如下更改:
var myLegend = document.getElementById("myLegend");
var myDougnutChart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
legend:myLegend
}
);
myDougnutChart.draw();
这是生成的图表和图表图例:
![带有值标签和图表图例的饼图](https://i-blog.csdnimg.cn/blog_migrate/07426b5c7a2483dce5ae4ec9d1d9fa1b.png)
恭喜啦
我们已经看到使用HTML5画布绘制图表实际上并不难。 它只需要一点数学和一点JavaScript知识。 现在,您拥有绘制自己的饼图和甜甜圈图所需的一切。
如果您想要一种快速简便的解决方案,不仅可以创建饼图和甜甜圈图,还可以创建其他类型的图,则可以下载“ 信息图和图形HTML标签库”或与WordPress插件对应的“ 图表和图形WordPress可视设计器” 。