如何使用JavaScript和HTML5画布绘制条形图

最终产品图片
您将要创造的

在先前的教程中,我们介绍了如何使用HTML5 canvas绘制饼图或甜甜圈图 。 在本教程中,我将向您展示如何使用JavaScript和HTML5 canvas作为使用条形图以图形方式显示数据的方法。

比起从头开始编写图表,有更简便的方法来创建图表,例如,来自CodeCanyon的完整图表库

信息图表和图形HTML标签库
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函数采用六个参数:

  1. ctx :引用绘图上下文
  2. startX :线起点的X坐标
  3. startY :线起点的Y坐标
  4. endX :线终点的X坐标
  5. endY :线终点的Y坐标
  6. 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函数采用六个参数:

  1. ctx :引用绘图上下文
  2. upperLeftCornerX :条形图左上角的X坐标
  3. upperLeftCornerY :栏的左上角的X坐标
  4. width :条的宽度
  5. height :栏的高度
  6. 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()函数,我们可以看到,首先我们计算了数据模型的最大值。 我们需要这个数字,因为我们需要根据该值和画布的大小缩放所有条形。 否则,我们的栏可能会超出显示区域,因此我们不希望这样做。

canvasActualHeightcanvasActualWidth变量存储使用通过options传递的padding值调整的画布的高度和宽度。 padding变量指示画布边缘与内部图表之间的像素数。

然后,我们绘制图表的网格线。 options.gridScale变量设置用于绘制线条的步骤。 所以gridScale为10将意味着每10个单位绘制一条网格线。

要绘制网格线,我们使用辅助函数drawLine() ; 至于网格线的颜色,我们从options.gridColor变量中获取。 请注意,画布坐标从左上角的0,0开始,并向右和向底部递增,而我们的网格值从底部向顶部递增。 这就是为什么我们在计算gridY值的公式中使用1 - gridValue/maxValuegridY

对于每条网格线,我们还在网格线上方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应该会产生如下结果:

使用html5 canvas的简单条形图

添加数据系列名称和图表图例

要在图表下方添加数据系列名称,我们需要在绘制条形的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画布条形图最终结果

恭喜啦

我们已经看到使用HTML5画布绘制图表实际上并不难。 它只需要一点数学和一点JavaScript知识。 现在,您已拥有绘制自己的条形图所需的一切。

如果您想要一种快速简便的解决方案,不仅可以创建条形图,还可以创建其他类型的图表,则可以下载“ 信息图表和图形HTML标签库”或与WordPress插件相对应的“ 图表和图形WordPress Visual Designer”

信息图表和图形HTML标签库
CodeCanyon的信息图表图表库

翻译自: https://code.tutsplus.com/tutorials/how-to-draw-bar-charts-using-javascript-and-html5-canvas--cms-28561

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值