概述
在本教程中,我将向您展示如何使用JavaScript和画布以饼图和甜甜圈图的形式显示数字信息。
比起从头开始编写图表,有更简便的方法来创建图表,但是,如果您想知道像这样的库在幕后发生的事情,请继续阅读。
什么是饼图?
图表是一种统计工具,用于以图形方式表示数字数据。饼形图将数值数据显示为分成多个切片的圆形。每个切片的大小与它所代表的数值成正比。
什么是甜甜圈图?
简单地说,甜甜圈图是饼图的变体。不同之处在于,将切片切成薄片的中心,这样只有边缘可见。这样,图表看起来像一个甜甜圈,因此是名称。
开始使用画布绘图
在绘制饼图之前,我们将看一下绘制饼图的各个部分。我们将看到如何使用canvas组件和JavaScript进行绘制:
- 一条线
- 弧(圆的一部分)
- 颜色填充的形状
要开始使用HTML5画布进行绘制,我们需要创建一些东西:
- 一个文件夹,用于保存项目文件;我们叫这个文件夹
piechart-tutorial
。 - 一个HTML文件
index.html
里面piechart-tutorial
的文件夹。该文件将包含HTML代码。 - 一个JS文件
script.js
里面piechart-tutorial
的文件夹。该文件将包含我们的JavaScript代码。
我们将使事情变得非常简单,并在其中添加以下代码 index.html
:
1个
2
3
4
5
6
|
< html >
< body >
< canvas id = "myCanvas" ></ canvas >
< script type = "text/javascript" src = "script.js" ></ script >
</ body >
</ html >
|
我们具有<canvas>
带有ID的元素,myCanvas
以便我们可以在我们的JS代码中引用它。然后,我们通过<script>
标签加载JS代码。
在内部script.js
,JS代码将首先获取对画布的引用,然后设置其宽度和高度。要在画布上绘制,我们只需要引用包含所有绘制方法的2D上下文即可。
1个
2
3
4
5
|
var myCanvas = document.getElementById( "myCanvas" );
myCanvas.width = 300;
myCanvas.height = 300;
var ctx = myCanvas.getContext( "2d" );
|
现在我们已经设置好画布,并且还引用了绘图画布,让我们定义一些JavaScript函数,这些函数将在绘制饼图时重用。我们将这些功能添加到我们的script.js文件中。
1个
2
3
4
5
6
|
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()
。
现在让我们看看如何绘制圆的一部分,也称为圆弧。
1个
2
3
4
5
|
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
:圆弧部分结束处的弧度结束角
我们已经看到了如何绘制直线和弧线,因此现在让我们看看如何绘制彩色形状。由于我们的目标是绘制由切片组成的饼图,因此我们创建一个绘制饼图的函数。
1个
2
3
4
5
6
7
8
|
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
:用于填充切片的颜色
这是调用三个函数的示例:
1个
2
3
|
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' );
|
它将产生以下结果:
现在,我们拥有绘制饼图所需的所有工具,接下来让我们看看如何一起使用它们。
绘制饼图
从概念上讲,任何图表都包含两个主要部分:
- 数据模型包含要表示的数字数据。它以特定于图表类型的格式组织。
- 图形表示是根据数学公式形式的某些规则,如何通过可视元素表示数据模型中的数字数据的形式。
饼图数据模型
构造饼图数据模型的最常见方法是一系列类别和相应的值,其中每个类别和值都与饼图的一部分相关联。
例如,显示我按类型分组的乙烯基数量的饼图数据模型如下所示:
- 古典音乐:10
- 替代摇滚:14
- 流行音乐:2
- 爵士乐:12
我们可以向script.js
文件中添加一个JS对象, 以存储数据模型,如下所示:
1个
2
3
4
5
6
|
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()
,其确实图表的实际的绘制。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18岁
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
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()
在创建的对象上调用该 方法。
1个
2
3
4
5
6
7
8
|
var myPiechart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:[ "#fde23e" , "#f16e23" , "#57d9ff" , "#937e88" ]
}
);
myPiechart.draw();
|
结果看起来像这样
绘制甜甜圈图
我们已经看到了如何绘制饼图。我们也知道,甜甜圈图的不同之处仅在于在图的中间有一个孔。我们如何绘制孔?我们可以在饼图上绘制一个白色圆圈。
让我们修改Piechart
类的代码 来做到这一点。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18岁
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
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的值都将导致圆孔越来越大的甜甜圈,而1将使图表不可见。
要绘制一个甜甜圈图,其孔的大小是图表的一半,我们需要使用 doughnutHoleSize
0.5的a并进行以下调用:
1个
2
3
4
5
6
7
8
9
|
var myDougnutChart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:[ "#fde23e" , "#f16e23" , "#57d9ff" , "#937e88" ],
doughnutHoleSize:0.5
}
);
myDougnutChart.draw();
|
结果如下:
添加标签和图表图例
我们的饼图和甜甜圈图看起来不错,但是我们可以通过添加以下两项使它们变得更好:
- 值标签:显示每个切片对应的百分比
- 图表图例:在图表中显示类别及其相应的颜色
通常,与切片相关联的值表示为计算为的百分比值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){...}
块之后添加以下代码 :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18岁
19
20
21
22
|
...
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
已设置,则标签将被推向图表的边缘以使其居中于甜甜圈切片。
这是带有值标签的结果图表的外观:
为了完成图表,我们最后要添加的是图表图例。我们的图表图例将显示我们的数据模型的类别以及用于相应切片的颜色。首先,我们必须index.html
通过添加<div>
将存储图例元素的标签来对文件进行一些修改 。
1个
2
3
4
5
6
7
|
< html >
< body >
< canvas id = "myCanvas" ></ canvas >
< div id = "myLegend" ></ div >
< script type = "text/javascript" src = "script.js" ></ script >
</ body >
</ html >
|
然后,在其中script.js
添加创建图例元素内容的代码。我们将此代码添加draw()
到Piechart
类函数 的末尾 :
01
02
03
04
05
06
07
08
09
10
|
...
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;
}
...
|
代码查找legend
通过options
参数传递的 元素。如果提供了一个,则用包含彩色框和数据模型类别名称的HTML代码填充此元素。
我们还需要对调用饼图的方式进行如下更改:
01
02
03
04
05
06
07
08
09
10
11
|
var myLegend = document.getElementById( "myLegend" );
var myDougnutChart = new Piechart(
{
canvas:myCanvas,
data:myVinyls,
colors:[ "#fde23e" , "#f16e23" , "#57d9ff" , "#937e88" ],
legend:myLegend
}
);
myDougnutChart.draw();
|
这是生成的图表和图表图例:
恭喜啦
我们已经看到使用HTML5画布绘制图表实际上并不难。它只需要一点数学和一点JavaScript知识。现在,您拥有绘制自己的饼图和甜甜圈图所需的一切。
最后
以上就是辛勤金鱼为你收集整理的如何使用JavaScript和HTML5画布绘制饼图和甜甜圈图的全部内容,希望文章能够帮你解决如何使用JavaScript和HTML5画布绘制饼图和甜甜圈图所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复