在先前的教程中,我们介绍了如何使用HTML5 canvas绘制饼图或甜甜圈图 。 在本教程中,我将向您展示如何使用JavaScript和HTML5 canvas作为使用条形图以图形方式显示数据的方法。
比起从头开始编写图表,有更简便的方法来创建图表,例如,来自CodeCanyon的完整图表库 。
但是,如果您想知道创建这样的库需要什么,本教程适合您。
什么是条形图?
条形图是用于表示数值数据的非常常用的工具。 从财务报告到PowerPoint演示文稿再到信息图表,条形图经常使用,因为它们提供了非常易于理解的数字数据视图。
条形图使用条形图表示数值数据,条形图是宽度或高度与它们表示的数值数据成比例的矩形。
条形图有很多类型:
- 水平和垂直条形图,具体取决于图表方向
- 堆叠的条形图或经典条形图,用于表示多个数据系列
- 2D或3D条形图
- 等等
条形图的组成部分是什么?
让我们看一下构成条形图的各种类型的组件:
- 图表数据:这些是由图表表示的数字集和相关类别。
- 数据系列的名称(1)。
- 图表网格(2):提供参考系统,以便可以轻松理解视觉表示。
- 条形图(3):彩色矩形,其尺寸与所表示的数据成比例。
- 图表图例(4):显示所用颜色与其代表的数据之间的对应关系。
既然我们知道条形图的组成部分,让我们看看如何编写JavaScript代码以绘制这样的图表。
使用JavaScript绘制条形图
设置JS项目
要开始使用JavaScript和HTML5画布进行绘制,我们需要像这样设置项目:
- 创建一个文件夹来保存项目文件; 我们将此文件夹称为
bar-chart-tutorial
。 - 在项目文件夹中,创建一个文件并将其命名为
index.html
。 这将包含我们HTML代码。 - 同样在项目文件夹中,创建一个文件并将其命名为
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
文件中添加以下代码:
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 300;
myCanvas.height = 300;
var ctx = myCanvas.getContext("2d");
这将获得对canvas元素的引用,然后将width和height设置为300px
。 要在画布上绘制,我们只需要引用其2D上下文,其中包含所有绘制方法。
添加一些辅助功能
绘制条形图只需要知道如何绘制两个元素:
- 绘制线:用于绘制网格线
- 绘制一个彩色矩形:用于绘制图表的条形图
让我们为这两个元素创建辅助JS函数。 我们将这些功能添加到我们的script.js
文件中。
function drawLine(ctx, startX, startY, endX, endY,color){
ctx.save();
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
ctx.restore();
}
drawLine
函数采用六个参数:
-
ctx
:引用绘图上下文 -
startX
:线起点的X坐标 -
startY
:线起点的Y坐标
-
endX
:线终点的X坐标
-
endY
:线终点的Y坐标
-
color
:线的颜色
我们正在修改strokeStyle
的颜色设置。 这将确定用于绘制线条的颜色。 我们使用ctx.save()
和ctx.restore()
以便不影响此函数外使用的颜色。
我们通过调用beginPath()
画线。 这通知绘图上下文我们开始在画布上绘制一些新内容。 我们使用moveTo()
设置起点,调用lineTo()
指示终点,然后通过调用stroke()
进行实际绘制。
我们需要的另一个辅助函数是绘制条的函数-这是一个彩色矩形。 让我们将其添加到script.js
:
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
ctx.save();
ctx.fillStyle=color;
ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
ctx.restore();
}
drawBar
函数采用六个参数:
-
ctx
:引用绘图上下文 -
upperLeftCornerX
:条形图左上角的X坐标 -
upperLeftCornerY
:栏的左上角的X坐标 -
width
:条的宽度
-
height
:栏的高度 -
color
:栏的颜色
条形图数据模型
现在我们已经有了辅助功能,让我们继续图表的数据模型。 所有类型的图表(包括条形图)背后都有数据模型。 数据模型是一组结构化的数字数据。 在本教程中,我们将使用一系列数据类别及其关联的数值,这些数值代表我按音乐类型分组的唱片集中的黑胶唱片数量:
- 古典音乐:10
- 替代摇滚:14
- 流行音乐:2
- 爵士乐:12
我们可以用对象形式在JavaScript中表示它。 让我们将其添加到我们的script.js
文件中:
var myVinyls = {
"Classical music": 10,
"Alternative rock": 14,
"Pop": 2,
"Jazz": 12
};
实施条形图组件
让我们实现将实际绘制条形图的组件。 为此,我们将以下JavaScript对象添加到我们的script.js
文件中:
var Barchart = function(options){
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.draw = function(){
var maxValue = 0;
for (var categ in this.options.data){
maxValue = Math.max(maxValue,this.options.data[categ]);
}
var canvasActualHeight = this.canvas.height - this.options.padding * 2;
var canvasActualWidth = this.canvas.width - this.options.padding * 2;
//drawing the grid lines
var gridValue = 0;
while (gridValue <= maxValue){
var gridY = canvasActualHeight * (1 - gridValue/maxValue) + this.options.padding;
drawLine(
this.ctx,
0,
gridY,
this.canvas.width,
gridY,
this.options.gridColor
);
//writing grid markers
this.ctx.save();
this.ctx.fillStyle = this.options.gridColor;
this.ctx.font = "bold 10px Arial";
this.ctx.fillText(gridValue, 10,gridY - 2);
this.ctx.restore();
gridValue+=this.options.gridScale;
}
//drawing the bars
var barIndex = 0;
var numberOfBars = Object.keys(this.options.data).length;
var barSize = (canvasActualWidth)/numberOfBars;
for (categ in this.options.data){
var val = this.options.data[categ];
var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
drawBar(
this.ctx,
this.options.padding + barIndex * barSize,
this.canvas.height - barHeight - this.options.padding,
barSize,
barHeight,
this.colors[barIndex%this.colors.length]
);
barIndex++;
}
}
}
该类首先存储作为参数传递的options
。 它存储canvas
参考,并创建一个也作为类成员存储的图形上下文。 然后,它存储作为选项传递的colors
数组。
下一部分是最一致的draw()
函数。 首先将绘制网格线,网格标记,然后使用通过options
对象传递的参数绘制条形图,从而绘制图表。
查看draw()
函数,我们可以看到,首先我们计算了数据模型的最大值。 我们需要这个数字,因为我们需要根据该值和画布的大小缩放所有条形。 否则,我们的栏可能会超出显示区域,因此我们不希望这样做。
canvasActualHeight
和canvasActualWidth
变量存储使用通过options
传递的padding值调整的画布的高度和宽度。 padding
变量指示画布边缘与内部图表之间的像素数。
然后,我们绘制图表的网格线。 options.gridScale
变量设置用于绘制线条的步骤。 所以gridScale
为10将意味着每10个单位绘制一条网格线。
要绘制网格线,我们使用辅助函数drawLine()
; 至于网格线的颜色,我们从options.gridColor
变量中获取。 请注意,画布坐标从左上角的0,0
开始,并向右和向底部递增,而我们的网格值从底部向顶部递增。 这就是为什么我们在计算gridY
值的公式中使用1 - gridValue/maxValue
的gridY
。
对于每条网格线,我们还在网格线上方2个像素处绘制网格线的值(这就是为什么我们将gridY - 2
作为文本的Y坐标的原因)。
接下来,我们使用辅助函数drawBar()
绘制条形图。 计算每个条形的高度和宽度的数学方法非常简单。 它考虑了图表数据模型中每个类别的填充以及值和颜色。
使用条形图组件
现在让我们看看如何使用上面实现的Barchart
类。 我们需要实例化该类并调用draw()
函数。 将以下代码添加到script.js
文件:
var myBarchart = new Barchart(
{
canvas:myCanvas,
padding:10,
gridScale:5,
gridColor:"#eeeeee",
data:myVinyls,
colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
}
);
myBarchart.draw();
该代码使用所需的选项创建Barchart
类的新实例。 在浏览器中加载index.html
应该会产生如下结果:
添加数据系列名称和图表图例
要在图表下方添加数据系列名称,我们需要在绘制条形的for-loop
之后的script.js
文件中添加以下代码:
...
//drawing series name
this.ctx.save();
this.ctx.textBaseline="bottom";
this.ctx.textAlign="center";
this.ctx.fillStyle = "#000000";
this.ctx.font = "bold 14px Arial";
this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
this.ctx.restore();
...
我们还需要像下面这样更改调用Barchart
组件的方式:
var myBarchart = new Barchart(
{
canvas:myCanvas,
seriesName:"Vinyl records",
padding:20,
gridScale:5,
gridColor:"#eeeeee",
data:myVinyls,
colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
}
);
myBarchart.draw();
结果如下所示:
要添加图例,我们首先需要修改index.html
使其看起来像这样:
<html>
<body>
<canvas id="myCanvas" style="background: white;"></canvas>
<legend for="myCanvas"></legend>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
legend
标签将用作图表图例的占位符。 for
属性将图例链接到保存图表的画布。 现在,我们需要添加创建图例的代码。 我们将在绘制数据系列名称的代码之后的index.js
文件中执行此操作。 该代码标识了与图表相对应的legend
标记,它将添加图表数据模型中的类别列表以及相应的颜色。 生成的index.js
文件将如下所示:
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 300;
myCanvas.height = 300;
var ctx = myCanvas.getContext("2d");
function drawLine(ctx, startX, startY, endX, endY,color){
ctx.save();
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(endX,endY);
ctx.stroke();
ctx.restore();
}
function drawBar(ctx, upperLeftCornerX, upperLeftCornerY, width, height,color){
ctx.save();
ctx.fillStyle=color;
ctx.fillRect(upperLeftCornerX,upperLeftCornerY,width,height);
ctx.restore();
}
var myVinyls = {
"Classical music": 10,
"Alternative rock": 14,
"Pop": 2,
"Jazz": 12
};
var Barchart = function(options){
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.draw = function(){
var maxValue = 0;
for (var categ in this.options.data){
maxValue = Math.max(maxValue,this.options.data[categ]);
}
var canvasActualHeight = this.canvas.height - this.options.padding * 2;
var canvasActualWidth = this.canvas.width - this.options.padding * 2;
//drawing the grid lines
var gridValue = 0;
while (gridValue <= maxValue){
var gridY = canvasActualHeight * (1 - gridValue/maxValue) + this.options.padding;
drawLine(
this.ctx,
0,
gridY,
this.canvas.width,
gridY,
this.options.gridColor
);
//writing grid markers
this.ctx.save();
this.ctx.fillStyle = this.options.gridColor;
this.ctx.textBaseline="bottom";
this.ctx.font = "bold 10px Arial";
this.ctx.fillText(gridValue, 10,gridY - 2);
this.ctx.restore();
gridValue+=this.options.gridScale;
}
//drawing the bars
var barIndex = 0;
var numberOfBars = Object.keys(this.options.data).length;
var barSize = (canvasActualWidth)/numberOfBars;
for (categ in this.options.data){
var val = this.options.data[categ];
var barHeight = Math.round( canvasActualHeight * val/maxValue) ;
drawBar(
this.ctx,
this.options.padding + barIndex * barSize,
this.canvas.height - barHeight - this.options.padding,
barSize,
barHeight,
this.colors[barIndex%this.colors.length]
);
barIndex++;
}
//drawing series name
this.ctx.save();
this.ctx.textBaseline="bottom";
this.ctx.textAlign="center";
this.ctx.fillStyle = "#000000";
this.ctx.font = "bold 14px Arial";
this.ctx.fillText(this.options.seriesName, this.canvas.width/2,this.canvas.height);
this.ctx.restore();
//draw legend
barIndex = 0;
var legend = document.querySelector("legend[for='myCanvas']");
var ul = document.createElement("ul");
legend.append(ul);
for (categ in this.options.data){
var li = document.createElement("li");
li.style.listStyle = "none";
li.style.borderLeft = "20px solid "+this.colors[barIndex%this.colors.length];
li.style.padding = "5px";
li.textContent = categ;
ul.append(li);
barIndex++;
}
}
}
var myBarchart = new Barchart(
{
canvas:myCanvas,
seriesName:"Vinyl records",
padding:20,
gridScale:5,
gridColor:"#eeeeee",
data:myVinyls,
colors:["#a55ca5","#67b6c7", "#bccd7a","#eb9743"]
}
);
这将产生最终结果,如下所示:
恭喜啦
我们已经看到使用HTML5画布绘制图表实际上并不难。 它只需要一点数学和一点JavaScript知识。 现在,您已拥有绘制自己的条形图所需的一切。
如果您想要一种快速简便的解决方案,不仅可以创建条形图,还可以创建其他类型的图表,则可以下载“ 信息图表和图形HTML标签库”或与WordPress插件相对应的“ 图表和图形WordPress Visual Designer” 。