在之前的教程中,我们介绍了如何使用 html5 画布绘制饼图或圆环图。在本教程中,我将向您展示如何使用javascript和html 5 画布作为使用条形图以图形方式显示数据的方法。
但是,如果您想知道创建这样的库需要什么,本教程适合您。
什么是条形图?
条形图是用于表示数值数据的非常常用的工具。从财务报告到 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>
我们拥有 <canvas> 带有 ID 的元素, myCanvas 以便我们可以在 JS 代码中引用它。然后我们通过 <script> 标签加载 JS 代码。
在文件中添加以下代码 script.js :
var myCanvas = document.getElementById("myCanvas"); myCanvas.width = 300; myCanvas.height = 300; var ctx = myCanvas.getContext("2d");
这将获得对 canvas 元素的引用,然后将宽度和高度设置为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()andctx.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 变量表示画布边缘和内部图表之间的像素数。
然后我们绘制图表的网格线。该 options.gridScale变量设置用于绘制线条的步骤。所以 gridScale10 的 a 意味着每 10 个单位绘制一次网格线。
要绘制网格线,我们使用辅助函数 drawLine();至于网格线的颜色,我们从 options.gridColor变量中获取。请注意,画布坐标从 0,0左上角开始,向右和向下增加,而我们的网格值从底部向顶部增加。这就是我们 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应该会产生如下结果:
添加数据系列名称和图表图例
要在图表下方添加数据系列名称,我们需要在 script.js文件 for-loop中绘制条形图之后添加以下代码:
... //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 知识。您现在拥有绘制自己的条形图所需的一切。
- 设置 JS 项目
- 添加一些辅助函数
- 条形图数据模型
- 实现条形图组件
- 使用条形图组件
- 添加数据系列名称和图表图例