怎樣用JavaScript和HTML5 Canvas繪製圖表

你將要創造什麼

原文:https://code.tutsplus.com/zh-...
原做:John Negoita
翻譯:Stypstive javascript

在這篇教程中,我將展現用JavaScript和canvas做爲手段,在餅狀圖和圓環圖上顯示數字信息。html

與從零到一建立圖表相比,其實有更簡便的方式,例如用CodeCanyon上的這個圖表庫html5

圖片描述

可是若是你想知道庫背後的原理,往下讀。java

什麼是餅狀圖?

圖表是用來圖形化展現數據的工具。 餅狀圖將數據用切割成份的圓來展現。 每份的大小表明了數據值所表明的比例大小。canvas

什麼是圓環圖?

簡而言之,圓環圖是餅狀圖的一個變種。 不一樣的是每份切向餅圖的中心,這樣只有輪緣是可見。 就這樣,圖表就如其名一個圓環。數組

開始用Canvas畫

繪製餅圖以前, 咱們先看看它的組成部分。 咱們先看看如何用canvas組件和JavaScript來畫:網絡

  • 一條線ide

  • 一個弧度(一個圓的部分)wordpress

  • 一個顏色填充的圖形函數

要想用HTML canvas畫它,咱們須要先建立幾樣東西:

建立一個項目文件夾,把它命名爲piechart-tutorial
piechart-tutorial文件夾中建立一個HTML文件index.html 這個文件中將是HTML代碼。
一個JS文件scritp.jspiechart-tutorial文件夾中 這個文件中將是JavaScript代碼。

咱們將能簡就簡,而後添加一下代碼到index.html中:

<html>
<body>
    <canvas id="myCanvas"></canvas>
  <script type="text/javascript" src="script.js"></script>
</body>
</html>

咱們有一個ID爲myCanvas<canvas>元素。 而後咱們經過<script>標籤載入JS代碼。

script.js中,JS代碼首先獲取一個canvas的索引,而後設置canvas的寬和高。 要想在canvas上畫,咱們只須要一個2D上下文,哪裏包含着全部的繪圖方法。

var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 300;
myCanvas.height = 300;
 
var ctx = myCanvas.getContext("2d");

如今咱們已經設置了canvas的寬和高,同時也獲取了canvas的索引,接下來咱們定義一些畫餅狀圖時,須要用到的可重用的函數。 咱們將函數添加在script.js文件中。

function drawLine(ctx, startX, startY, endX, endY){
    ctx.beginPath();
    ctx.moveTo(startX,startY);
    ctx.lineTo(endX,endY);
    ctx.stroke();
}

函數drawLine接受5個參數:

  1. ctx: 指向繪圖上下文的索引

  2. startX:線段起始點的X座標

  3. startY:線段起始點的Y座標

  4. endX:線段結束點的X座標

  5. endY:線段結束點的Y座標

咱們經過調用beginPath()來開始劃線。 它通知繪圖上下文,咱們要在canvas上畫一些東西了。 咱們用moveTo()來設置起始點,調用lineTo()來表示結束點,而後調用stoke()來進行真正的繪圖。

如今看看咱們如何畫圓的一部分,也叫作弧度。

function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle){
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, startAngle, endAngle);
    ctx.stroke();
}

函數drawArc接受6個參數:

  1. ctx:指向繪圖上下文的索引

  2. centerX:圓心的X座標

  3. centerY:圓心的Y座標

  4. radius: 圓的半徑

  5. startAngle:部分圓的扇形的開始角度

  6. endAngle: 部分圓的扇形的結束角度

咱們已經知道怎樣畫線和弧度了,如今讓我看看如何畫帶顏色的形狀。 因爲咱們的目標是畫一份份組成的餅狀圖,因此咱們建立一個畫餅形圖的份的函數。

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接受7個參數:

  1. ctx:指向繪圖上下文的索引

  2. centerX:圓心的X座標

  3. centerY:圓心的Y座標

  4. radius:圓的半徑

  5. startAngle:部分圓的扇形的起始角度

  6. endAngle:部分圓的扇形的結束角度

  7. color:填充的顏色

如下是調用這三個函數的例子:

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對象來存儲數據模型,以下:

var myVinyls = {
    "Classical music": 10,
    "Alternative rock": 14,
    "Pop": 2,
    "Jazz": 12
};

餅狀圖的圖形化展現
餅狀圖用圓來顯示數據模型中的信息,經過將圓切分紅一份份。 每份和數據模型中的類別對應,每份的大小與對應類別的值成正比。

個人音樂集有四個類別。 每一個類別在餅形圖中的份數大小,與它的類別對應的值成正比。

可是咱們怎樣度量份數的大小? 簡單--咱們經過每份的角度。 咱們所須要知道的就是它佔360度或者2PI的份數。 那麼半圓就是180deg或者PI,1/4圓90度或PI/2,以此類推。

爲了決定每一個類別的份的角度,咱們用如下公式:

份角度= 2 * PI * 類別值 / 總值

按照這個公式,古典音樂的那份近似獲得以下角度。 0.526 * PI 或者 94度

讓我開始畫吧。 此次咱們將用JavaScript類,將其命名爲 PieChart 構造函數接受options作爲參數,options包含如下:

  • canvas:指向咱們想要畫餅狀圖的索引

  • data:盛放數據模型的對象的索引

  • colors:一個數組,數組中是每份的顏色。

PieChart類同時也包含一個draw()方法,它來對圖表進行實際的繪製。

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的索引,同時也建立一個繪畫上下文做爲類成員變量。 而後它存儲了options中的colors數組。

接下來的部分是最根本的,函數draw()。 它會從數據模型中提取數據。 首先,它計算數據模型中全部數據值的和。 而後對其中每一個類別應用上面提到的計算角度的函數。 最後咱們調用drawPieSlice()函數,用canvas的中心做爲餅狀圖的中心。 至於半徑,咱們用canvas寬度的一半與canvas高度的一半的較小值,由於咱們不想讓餅狀圖超出canvas。

一樣,每次畫一個類別時,要偏移每份的起始角度和結束角度,不然會發生重疊。

要想使用類,咱們必須先建立一個實例對象,而後在建立的對象上調用draw()方法。

var myPiechart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:["#fde23e","#f16e23", "#57d9ff","#937e88"]
    }
);
myPiechart.draw();

結果看起來以下這樣:

圖片描述

繪製圓環圖

咱們已經看到如何建立餅狀圖。 一樣咱們看到,圓環圖與餅狀圖不一樣之處僅在於中間多了一個洞。 怎樣畫洞呢? 咱們能夠畫一個白色的圓在餅狀圖上。

讓咱們經過修改PieChart類來作它。

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成員變量。 若是這個參數在options中沒有傳,代碼就按照以前的進行繪製,若是傳了,就在餅狀圖中心畫一個白色的圓形。

圓的半徑由餅形圖的半徑和doughnutHoleSize參數的乘積來決定。 它應該是0到1之間的數字,0表明餅形圖,大於0時,值越大餅形圖中間的洞越大,當值爲1時會使圖表不可見。

要想畫一個圖表一半大小的圓環圖,咱們能夠將doughnutHoleSize設置爲0.5,而後像下面這樣調用:

var myDougnutChart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
        doughnutHoleSize:0.5
    }
);
myDougnutChart.draw();

如下是結果:

圖片描述

添加標籤和圖表圖例

咱們的餅狀圖表和圓環圖表看起來挺棒了,可是它會變得更棒,經過添加兩樣東西:

  • 值標籤:顯示每份對應的百分比

  • 圖表圖例:顯示圖表中每一個類別和顏色的對應關係

一般,每份的值用百分比來表示,經過100 * 每份值 / 總的值來計算,整個圓表明100%

例如,在咱們的例子數據中,古典音樂能夠近似地用26%來表示。 若是能將這個值恰好顯示在對應的份上面就太好了。 要想這樣,咱們能夠用繪圖上下文的fillText(text, x, y)函數。 這個函數接受三個參數:文本和xy座標。

怎樣計算放置文本的xy座標呢? 咱們必須動用一些幾何知識了,一個叫作極座標的東西。 通常地,極座標用半徑和角度來定義一個點的位置。 咱們將要用到的兩個公式是:

x = R * cos(angle)

y = R * sin(angle)

咱們將要應用這個公式,將文本放在餅狀圖的半徑的一半位置與每份角度的一半位置處。 要想作它,咱們須要修改咱們的PieChart類,增長以下代碼在if(this.options.doughnutHoleSize){...}代碼塊中。

...
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>標籤用來存儲咱們的圖例元素。

<html>
<body>
    <canvas id="myCanvas"></canvas>
    <div id="myLegend"></div>
    <script type="text/javascript" src="script.js"></script>
</body>
</html>

而後在script.js中,咱們添加建立圖例元素的代碼。 咱們將代碼添加在PieChart類中draw()函數的末尾。

...
        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++]+";'>&nbsp;</span> "+categ+"</div>";
            }
            this.options.legend.innerHTML = legendHTML;
        }
...

代碼經過傳入options參數來尋找legend元素。 若是找到,就在其中填上帶顏色的塊和數據模型類別的名字。

同時,咱們也須要將調用繪值圖表的代碼改爲以下形式:

var myLegend = document.getElementById("myLegend");
 
var myDougnutChart = new Piechart(
    {
        canvas:myCanvas,
        data:myVinyls,
        colors:["#fde23e","#f16e23", "#57d9ff","#937e88"],
        legend:myLegend
    }
);
myDougnutChart.draw();

這就是結果的圖表和圖表圖例:

圖片描述

恭喜

咱們看到用HTML5 canvas繪製圖表,其實也並非那麼困難。 它僅僅須要一點數學和JavaScript知識。 你如今有了要畫一個你本身的餅形圖和圓環圖的所有。

若是你想要一個簡便快捷的解決方案,用來建立餅形圖和圓環圖,同時還有其餘類型的圖表。你能夠下載信息圖表和HTML圖表標籤庫或者WordPress插件對應的Charts and Graphs WordPress Visual Designer

關於Envato藝雲臺

圖片描述

Envato藝雲臺是數據資產和創造性人才匯聚的全球領先市場平臺。全球數百萬人都選擇經過咱們的市場平臺、工做室和課程來購買文件、選聘自由職業者,或者學習建立網站、製做視頻、應用、製圖等所需的技能。咱們的子網站包括Envato藝雲臺Tuts+ 網絡,全球最大的H五、PS、插圖、代碼和攝影教程資源庫,以及Envato藝雲臺市場,其中的900多萬類數字資產均經過如下七大平臺進行銷售 - CodeCanyon、ThemeForest、GraphicRiver、VideoHive、PhotoDune、AudioJungle和3DOcean。

相關文章
相關標籤/搜索