资讯专栏INFORMATION COLUMN

怎样用JavaScript和HTML5 Canvas绘制图表

doodlewind / 1442人阅读

摘要:饼状图将数据用切割成份的圆来展示。至于半径,我们用宽度的一半与高度的一半的较小值,因为我们不想让饼状图超出。结果看起来如下这样绘制圆环图我们已经看到如何创建饼状图。怎样画洞呢我们可以画一个白色的圆在饼状图上。

原文:https://code.tutsplus.com/zh-...
原作:John Negoita
翻译:Stypstive

在这篇教程中,我将展示用JavaScript和canvas作为手段,在饼状图和圆环图上显示数字信息。

与从零到一创建图表相比,其实有更简便的方式,例如用CodeCanyon上的这个图表库

但是如果你想知道库背后的原理,往下读。

什么是饼状图?

图表是用来图形化展示数据的工具。 饼状图将数据用切割成份的圆来展示。 每份的大小代表了数据值所代表的比例大小。

什么是圆环图?

简而言之,圆环图是饼状图的一个变种。 不同的是每份切向饼图的中心,这样只有轮缘是可见。 就这样,图表就如其名一个圆环。

开始用Canvas画

绘制饼图之前, 我们先看看它的组成部分。 我们先看看如何用canvas组件和JavaScript来画:

一条线

一个弧度(一个圆的部分)

一个颜色填充的图形

要想用HTML canvas画它,我们需要先创建几样东西:

创建一个项目文件夹,把它命名为piechart-tutorial
piechart-tutorial文件夹中创建一个HTML文件index.html 这个文件中将是HTML代码。
一个JS文件scritp.jspiechart-tutorial文件夹中 这个文件中将是JavaScript代码。

我们将能简就简,然后添加一下代码到index.html中:

</>复制代码

我们有一个ID为myCanvas元素。 然后我们通过

现在,我们有了画一个饼形图的所有必要的工具,让我们看看如何一起使用它们。

画饼形图

在概念上,任意图表都有两部分:

包含要展示的数据的数据模型。 这由特定类型的图表进行结构化。

图形化展示是指按照数学公式的规则,将数据模型中的数据通过视觉元素来进行展示。

饼状图数据模型
结构化饼状图数据的方式中,最常用的就是用一系列的类别和对应的值,每个类别的值与饼图的份相关联。

例如,饼图的数据模型展示按照流派进行分组,看起来就是下面这样:

古典音乐:10

另类摇滚:14

流行:2

爵士:12

我们可以在script.js文件中添加一个JS对象来存储数据模型,如下:

</>复制代码

  1. var myVinyls = {
  2. "Classical music": 10,
  3. "Alternative rock": 14,
  4. "Pop": 2,
  5. "Jazz": 12
  6. };

饼状图的图形化展示
饼状图用圆来显示数据模型中的信息,通过将圆切分成一份份。 每份和数据模型中的类别对应,每份的大小与对应类别的值成正比。

我的音乐集有四个类别。 每个类别在饼形图中的份数大小,与它的类别对应的值成正比。

但是我们怎样度量份数的大小? 简单--我们通过每份的角度。 我们所需要知道的就是它占360度或者2PI的份数。 那么半圆就是180deg或者PI,1/4圆90度或PI/2,以此类推。

为了决定每个类别的份的角度,我们用以下公式:

</>复制代码

  1. 份角度= 2 * PI * 类别值 / 总值

按照这个公式,古典音乐的那份近似得到如下角度。 0.526 * PI 或者 94度

让我开始画吧。 这次我们将用JavaScript类,将其命名为 PieChart 构造函数接受options做为参数,options包含以下:

canvas:指向我们想要画饼状图的索引

data:盛放数据模型的对象的索引

colors:一个数组,数组中是每份的颜色。

PieChart类同时也包含一个draw()方法,它来对图表进行实际的绘制。

</>复制代码

  1. var Piechart = function(options){
  2. this.options = options;
  3. this.canvas = options.canvas;
  4. this.ctx = this.canvas.getContext("2d");
  5. this.colors = options.colors;
  6. this.draw = function(){
  7. var total_value = 0;
  8. var color_index = 0;
  9. for (var categ in this.options.data){
  10. var val = this.options.data[categ];
  11. total_value += val;
  12. }
  13. var start_angle = 0;
  14. for (categ in this.options.data){
  15. val = this.options.data[categ];
  16. var slice_angle = 2 * Math.PI * val / total_value;
  17. drawPieSlice(
  18. this.ctx,
  19. this.canvas.width/2,
  20. this.canvas.height/2,
  21. Math.min(this.canvas.width/2,this.canvas.height/2),
  22. start_angle,
  23. start_angle+slice_angle,
  24. this.colors[color_index%this.colors.length]
  25. );
  26. start_angle += slice_angle;
  27. color_index++;
  28. }
  29. }
  30. }

类中首先将传入的options参数进行存储。 它保存了canvas的索引,同时也创建一个绘画上下文作为类成员变量。 然后它存储了options中的colors数组。

接下来的部分是最根本的,函数draw()。 它会从数据模型中提取数据。 首先,它计算数据模型中所有数据值的和。 然后对其中每个类别应用上面提到的计算角度的函数。 最后我们调用drawPieSlice()函数,用canvas的中心作为饼状图的中心。 至于半径,我们用canvas宽度的一半与canvas高度的一半的较小值,因为我们不想让饼状图超出canvas。

同样,每次画一个类别时,要偏移每份的起始角度和结束角度,否则会发生重叠。

要想使用类,我们必须先创建一个实例对象,然后在创建的对象上调用draw()方法。

</>复制代码

  1. var myPiechart = new Piechart(
  2. {
  3. canvas:myCanvas,
  4. data:myVinyls,
  5. colors:["#fde23e","#f16e23", "#57d9ff","#937e88"]
  6. }
  7. );
  8. myPiechart.draw();

结果看起来如下这样:

绘制圆环图

我们已经看到如何创建饼状图。 同样我们看到,圆环图与饼状图不同之处仅在于中间多了一个洞。 怎样画洞呢? 我们可以画一个白色的圆在饼状图上。

让我们通过修改PieChart类来做它。

</>复制代码

  1. var Piechart = function(options){
  2. this.options = options;
  3. this.canvas = options.canvas;
  4. this.ctx = this.canvas.getContext("2d");
  5. this.colors = options.colors;
  6. this.draw = function(){
  7. var total_value = 0;
  8. var color_index = 0;
  9. for (var categ in this.options.data){
  10. var val = this.options.data[categ];
  11. total_value += val;
  12. }
  13. var start_angle = 0;
  14. for (categ in this.options.data){
  15. val = this.options.data[categ];
  16. var slice_angle = 2 * Math.PI * val / total_value;
  17. drawPieSlice(
  18. this.ctx,
  19. this.canvas.width/2,
  20. this.canvas.height/2,
  21. Math.min(this.canvas.width/2,this.canvas.height/2),
  22. start_angle,
  23. start_angle+slice_angle,
  24. this.colors[color_index%this.colors.length]
  25. );
  26. start_angle += slice_angle;
  27. color_index++;
  28. }
  29. //drawing a white circle over the chart
  30. //to create the doughnut chart
  31. if (this.options.doughnutHoleSize){
  32. drawPieSlice(
  33. this.ctx,
  34. this.canvas.width/2,
  35. this.canvas.height/2,
  36. this.options.doughnutHoleSize * Math.min(this.canvas.width/2,this.canvas.height/2),
  37. 0,
  38. 2 * Math.PI,
  39. "#ff0000"
  40. );
  41. }
  42. }
  43. }

添加的代码在options参数中,通过一个doughnutHoleSize成员变量。 如果这个参数在options中没有传,代码就按照之前的进行绘制,如果传了,就在饼状图中心画一个白色的圆形。

圆的半径由饼形图的半径和doughnutHoleSize参数的乘积来决定。 它应该是0到1之间的数字,0代表饼形图,大于0时,值越大饼形图中间的洞越大,当值为1时会使图表不可见。

要想画一个图表一半大小的圆环图,我们可以将doughnutHoleSize设置为0.5,然后像下面这样调用:

</>复制代码

  1. var myDougnutChart = new Piechart(
  2. {
  3. canvas:myCanvas,
  4. data:myVinyls,
  5. colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
  6. doughnutHoleSize:0.5
  7. }
  8. );
  9. myDougnutChart.draw();

以下是结果:

添加标签和图表图例

我们的饼状图表和圆环图表看起来挺棒了,但是它会变得更棒,通过添加两样东西:

值标签:显示每份对应的百分比

图表图例:显示图表中每个类别和颜色的对应关系

通常,每份的值用百分比来表示,通过100 * 每份值 / 总的值来计算,整个圆代表100%

例如,在我们的例子数据中,古典音乐可以近似地用26%来表示。 如果能将这个值刚好显示在对应的份上面就太好了。 要想这样,我们可以用绘图上下文的fillText(text, x, y)函数。 这个函数接受三个参数:文本和xy坐标。

怎样计算放置文本的xy坐标呢? 我们必须动用一些几何知识了,一个叫做极坐标的东西。 一般地,极坐标用半径和角度来定义一个点的位置。 我们将要用到的两个公式是:

</>复制代码

  1. x = R * cos(angle)
  2. y = R * sin(angle)

我们将要应用这个公式,将文本放在饼状图的半径的一半位置与每份角度的一半位置处。 要想做它,我们需要修改我们的PieChart类,增加如下代码在if(this.options.doughnutHoleSize){...}代码块中。

</>复制代码

  1. ...
  2. start_angle = 0;
  3. for (categ in this.options.data){
  4. val = this.options.data[categ];
  5. slice_angle = 2 * Math.PI * val / total_value;
  6. var pieRadius = Math.min(this.canvas.width/2,this.canvas.height/2);
  7. var labelX = this.canvas.width/2 + (pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
  8. var labelY = this.canvas.height/2 + (pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
  9. if (this.options.doughnutHoleSize){
  10. var offset = (pieRadius * this.options.doughnutHoleSize ) / 2;
  11. labelX = this.canvas.width/2 + (offset + pieRadius / 2) * Math.cos(start_angle + slice_angle/2);
  12. labelY = this.canvas.height/2 + (offset + pieRadius / 2) * Math.sin(start_angle + slice_angle/2);
  13. }
  14. var labelText = Math.round(100 * val / total_value);
  15. this.ctx.fillStyle = "white";
  16. this.ctx.font = "bold 20px Arial";
  17. this.ctx.fillText(labelText+"%", labelX,labelY);
  18. start_angle += slice_angle;
  19. }
  20. ...

上面代码遍历每份,计算百分比和位置,然后调用fillText()方法将之绘制到图表上。 我们用了fillStyle属性来设置文本颜色为白色,font属性来设置标签文本的字体、样式和大小。 同样重要,需要注意的是圆环图的doughnutHoleSize设置后,标签会被往边沿推,以使文本能处于圆环图每份的中央。

以下就是带值标签的图表看起来的样子:

要想完成图表,最后一件事就是为图表添加图例。 我们的图表图例将会显示数据模型中数据的类别和对应每份的颜色。 首先,我们需要对index.html文件做些修改,添加一个

标签用来存储我们的图例元素。

</>复制代码

然后在script.js中,我们添加创建图例元素的代码。 我们将代码添加在PieChart类中draw()函数的末尾。

</>复制代码

  1. ...
  2. if (this.options.legend){
  3. color_index = 0;
  4. var legendHTML = "";
  5. for (categ in this.options.data){
  6. legendHTML += "
      "+categ+"
    ";
  7. }
  8. this.options.legend.innerHTML = legendHTML;
  9. }
  10. ...

代码通过传入options参数来寻找legend元素。 如果找到,就在其中填上带颜色的块和数据模型类别的名字。

同时,我们也需要将调用绘值图表的代码改成如下形式:

</>复制代码

  1. var myLegend = document.getElementById("myLegend");
  2. var myDougnutChart = new Piechart(
  3. {
  4. canvas:myCanvas,
  5. data:myVinyls,
  6. colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
  7. legend:myLegend
  8. }
  9. );
  10. myDougnutChart.draw();

这就是结果的图表和图表图例:

恭喜

我们看到用HTML5 canvas绘制图表,其实也并不是那么困难。 它仅仅需要一点数学和JavaScript知识。 你现在有了要画一个你自己的饼形图和圆环图的全部。

如果你想要一个简便快捷的解决方案,用来创建饼形图和圆环图,同时还有其他类型的图表。你可以下载信息图表和HTML图表标签库或者WordPress插件对应的Charts and Graphs WordPress Visual Designer。

关于Envato艺云台

Envato艺云台是数据资产和创造性人才汇聚的全球领先市场平台。全球数百万人都选择通过我们的市场平台、工作室和课程来购买文件、选聘自由职业者,或者学习创建网站、制作视频、应用、制图等所需的技能。我们的子网站包括Envato艺云台Tuts+ 网络,全球最大的H5、PS、插图、代码和摄影教程资源库,以及Envato艺云台市场,其中的900多万类数字资产均通过以下七大平台进行销售 - CodeCanyon、ThemeForest、GraphicRiver、VideoHive、PhotoDune、AudioJungle和3DOcean。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88277.html

相关文章

  • 14个最好的 JavaScript 数据可视化库

    摘要:适用于,演示这是开发的一个简单的可视化库,它允许你创建所有常用的图表类型条形图,树形图,折线图,面积图等。可以轻松地对折线图和条形图进行混合和匹配以组合不同的数据集,这是非常棒的功能。 翻译:疯狂的技术宅原文:https://www.monterail.com/blo... 本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 你的程序有多...

    Mertens 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<