2020-04-22

【WEB程式】以 Chartjs 繪製圖表

Chartjs 是一套免費且開放原始碼(採用 MIT 授權) 的網頁圖表繪製套件,可繪製 6 種基本圖表:
line(折線圖/線條圖)、bar(條狀圖,直/橫條)、radar(雷達圖)、doughnut & pie(圓餅圖/甜甜圈圖)、polar area(極座標圖餅圖/南丁格爾玫瑰圖/雞冠花圖/風花圖)、bubble(氣泡圖)

2 種衍伸圖表(不知道這兩種圖表的中文名稱):
scatter(散佈圖)area

還可以上述 8 種圖表混合使用。


chartjs 上傳到您的網站內的指定目錄下,在本例為 /plugin/

PHP 網頁內容
 
...
...
<head>
    <script src="/jquery/jquery-1.11.3.min.js"></script>    <!-- jQuery 不是必需, 但我不熟純 javascript -->
    <script src="/plugin/chartjs/Chart.bundle.min.js"></script>
    <script src="/plugin/chartjs/Chart.min.js"></script>
    <script src="/plugin/chartjs/chartjs-plugin-zoom.min.js"></script>
    <script src="/plugin/chartjs/utils.js"></script>
    <script src="/plugin/chartjs/moment-with-locales.min.js"></script>
</head>
<!-- 設定圖表尺寸 -->
<style>
.chart
{
  height:100; width:45%; margin: 20px;
}
</style>

...
...

<body>
<?php

// 宣告存放數據的陣列
$aExname = array();     // 考試名稱
$aDlday = array();      // 單日下載
$aDlcnt = array();      // 總下載數
$aExamday = array();    // 單日練習
$aExamcnt = array();    // 總練習數

// 建立資料庫連線, 並取得資料
$pdoStat = $pdo->prepare($sql);
$pdoStat->execute();
$rs = $pdoStat->fetchAll();
if(count($rs)>0)
{
    foreach($rs as $row)
    {
        // 將各欄位值存入陣列
        array_push($aExname, $row['exname']);  // 考試名稱
        array_push($aDlday, $row['dlday']);  // 單日下載
        array_push($aDlcnt, $row['dlcnt']);  // 總下載數
        array_push($aExamday, $row['examday']);  // 單日練習
        array_push($aExamcnt, $row['examcnt']);  // 總練習數
    }
    
    // 將陣列自 PHP 轉出變為 javascript 陣列
    // str_pad() 沒什麼作用, 只是讓轉出的 HTML 原始碼易於閱讀而已
    echo str_pad(" ", 28)."<script language='javascript'>\n";
    echo str_pad(" ", 28).'var aExname = '.json_encode($aExname).";\n"; // 考試名稱
    echo str_pad(" ", 28).'var aDlday = '.json_encode($aDlday).";\n";   // 單日下載
    echo str_pad(" ", 28).'var aDlcnt = '.json_encode($aDlcnt).";\n";   // 總下載數
    echo str_pad(" ", 28).'var aExamday = '.json_encode($aExamday).";\n";   // 單日練習
    echo str_pad(" ", 28).'var aExamcnt = '.json_encode($aExamcnt).";\n";   // 總練習數
    echo str_pad(" ", 28)."</script>\n";
}
?>

// 左, 右 放置 2 個直條圖
<div class="chart" style="float:left;">
  <!-- 各考試單日統計 -->
  <canvas id="chartDay" />
</div>

<div class="chart" style="float:right;">
  <!-- 各考試總計 -->
  <canvas id="chartTotal" />
</div>

<script language='javascript'>
var ctx1 = $("#chartDay");
var myChart1 = new Chart(ctx1,
                            {
                                type: 'bar',    // 指定圖表為直條圖
                                data: {
                                        datasets: [{
                                                    data: aExamday,
                                                    label: "單日練習",
                                                    borderColor: window.chartColors.green,    // 有這幾個基本顏色可選:red, orange, yellow, green, blue, purple, grey
                                                    backgroundColor: window.chartColors.green
                                                   },
                                                   {
                                                    data: aDlday,
                                                    label: "單日下載",
                                                    borderColor: window.chartColors.red,      // 折線顏色
                                                    backgroundColor: window.chartColors.red  // legend 色塊顏色
                                                   }
                                                  ],
                                        labels: aExname
                                      },
                                options: {
                                            animation: {
                                                            duration: 0,  // 不以動畫方式畫線
                                                       },
                                            title: {    // 圖表標題
                                                        display: true,
                                                        text: "各考試單日統計",
                                                        fontSize: 18
                                                   },
                                            legend:{    // 各色直條圖所代表的群體
                                                        position: 'top'    // 置於圖表上方, 另可置於 bottom, left, right
                                                   },
                                            scales: {
                                                        yAxes: [{    // Y 軸的樣式
                                                                type: 'linear',
                                                                position: 'left',
                                                                ticks: {    // 加上千位符
            userCallback: function(value, index, values)
           {
               return value.toLocaleString();
           }
         }
                                                               }]
                                                    },
                                            tooltips: { // 直條內的提示數字加上 千位符
                                                        callbacks: {
                                                                        // this callback is used to create the tooltip label
                                                                        label: function(tooltipItem, data)
                                                                                {
                                                                                    var dataLabel = data.labels[tooltipItem.index];
                                                                                    var value = ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();

                                                                                    if (Chart.helpers.isArray(dataLabel))
                                                                                        {
                                                                                            dataLabel = dataLabel.slice();
                                                                                            dataLabel[0] += value;
                                                                                        }
                                                                                    else
                                                                                        {
                                                                                            dataLabel += value;
                                                                                        }
                                                                                    return dataLabel;
                                                                                }
                                                                    }
                                                    },
                                            onClick: function (event, arr)
                                                    {
                                                        // 可以指定點擊某個直條時,跳轉至指定的網頁
                                                        switch(arr[0]._view['label'])
                                                        {
                                                            case '條件1': window.location.href = "下個網頁";
                                                                            break;
                                                            case '條件2': window.location.href = "下個網頁";
                                                                            break;
                                                            ...
                                                            ...
                                                        }
                                                    }
                                        }
                                      });


/////////////////
var ctx2 = $("#chartTotal");
var myChart2 = new Chart(ctx2,
                            {
                                type: 'bar',
                                data: {
                                        datasets: [{
                                                    data: aExamcnt,
                                                    label: "總練習數",
                                                    borderColor: window.chartColors.green,
                                                    backgroundColor: window.chartColors.yellow
                                                   },
                                                   {
                                                    data: aDlcnt,
                                                    label: "總下載數",
                                                    borderColor: window.chartColors.blue,
                                                    backgroundColor: window.chartColors.blue
                                                   }
                                                  ],
                                        labels: aExname
                                      },
                                options: {
                                            animation: {
                                                            duration: 0,  // 不以動畫方式畫線
                                                       },
                                            title: {
                                                        display: true,
                                                        text: "各考試總計",
                                                        fontSize: 18
                                                   },
                                            legend:{
                                                        position: 'top'
                                                   },
                                            scales: {
                                                        yAxes: [{
                                                                type: 'linear',
                                                                position: 'left',
                                                                ticks: {    // 加上千位符
             userCallback: function(value, index, values)
           {
               return value.toLocaleString();
           }
         }
                                                               }]
                                                    },
                                            tooltips: { // 直條內的提示數字加上 千位符
                                                        callbacks: {
                                                                        // this callback is used to create the tooltip label
                                                                        label: function(tooltipItem, data)
                                                                                {
                                                                                    var dataLabel = data.labels[tooltipItem.index];
                                                                                    var value = ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();

                                                                                    if (Chart.helpers.isArray(dataLabel))
                                                                                        {
                                                                                            dataLabel = dataLabel.slice();
                                                                                            dataLabel[0] += value;
                                                                                        }
                                                                                    else
                                                                                        {
                                                                                            dataLabel += value;
                                                                                        }
                                                                                    return dataLabel;
                                                                                }
                                                                    }
                                                    },
                                            onClick: function (event, arr)
                                                    {
                                                        // 可以指定點擊某個直條時,跳轉至指定的網頁
                                                        switch(arr[0]._view['label'])
                                                        {
                                                            case '條件1': window.location.href = "下個網頁";
                                                                            break;
                                                            case '條件2': window.location.href = "下個網頁";
                                                                            break;
                                                            ...
                                                            ...
                                                        }
                                                    }
                                        }
                        });
</script>

...
...
</body>
</html>
 


圖表成果如下:
* 因圖表寬度較小,因此 chartjs 自動隱藏某些考試名稱,以下圖為例,只顯示單數欄的考試名稱
* 滑鼠至直條內時會顯示相應的數值
* 不知道是不是沒摸索到顏色的配置方法,Chartjs 不會自動幫您配顏色,所以您必須要自己先建立一個顏色陣列,要用時,再到陣列取顏色值;或是自己以亂數產生顏色值,只是以亂數產生,有時會碰到相臨 2 個顏色太相近的窘境。



還有另一套圖表套件 ---- ZingChart,老人家自己覺得蠻好用又功能強大,但下載免費版使用時,圖表會強制顯示該公司的 LOGO 打廣告。

若不在意該公司的 LOGO 老人家倒是蠻推 ZingChart 的,因為好上手,學習曲線低;但如果不想顯示 LOGO......就付費吧(老人家的長官就不希望看到 LOGO,所以後來採用 Chartjs)。


最新發現! Apache 基金會的 Apache ECharts,開放源碼,而且免費,也不難學習,更推!!

 


相關筆記 ----

【WEB程式】以 Apache ECharts 繪製圖表

沒有留言:

張貼留言