HTML5 進階系列:canvas 動態圖表

来源:http://www.cnblogs.com/linxin/archive/2017/05/23/6892389.html
-Advertisement-
Play Games

前言 canvas 強大的功能讓它成為了 HTML5 中非常重要的部分,至於它是什麼,這裡就不需要我多作介紹了。而可視化圖表,則是 canvas 強大功能的表現之一。 現在已經有了很多成熟的圖表插件都是用 canvas 實現的,Chart.js、ECharts等可以製作出好看炫酷的圖表,而且幾乎覆蓋 ...


前言

canvas 強大的功能讓它成為了 HTML5 中非常重要的部分,至於它是什麼,這裡就不需要我多作介紹了。而可視化圖表,則是 canvas 強大功能的表現之一。

現在已經有了很多成熟的圖表插件都是用 canvas 實現的,Chart.js、ECharts等可以製作出好看炫酷的圖表,而且幾乎覆蓋了所有圖表的實現。

有時候自己只想畫個柱狀圖,自己寫又覺得麻煩,用別人插件又感覺累贅,最後打開百度,拷段代碼,粘貼上來修修改改。還不如自己擼一個呢。

原文作者:林鑫,作者博客:https://github.com/lin-xin/blog

效果

動畫效果圖片顯示不出來,可以到最下麵找demo地址

image

分析

可以這個圖表由 xy軸、數據條形和標題組成。

  • 軸線:可以使用 moveTo() & lineTo() 實現
  • 文字:可以使用 fillText() 實現
  • 長方形:可以使用 fillRect() 實現

這樣看來,似乎並沒有多難。

實現

定義畫布

<canvas id="canvas" width="600" height="500"></canvas>

canvas 標簽只是個容器,真正實現畫圖的還是 JavaScript。

畫坐標軸

坐標軸就是兩條橫線,也就是canvas里最基礎的知識。

  • 由 ctx.beginPath() 開始一條新的路徑
  • ctx.lineWidth=1 設置線條寬度
  • ctx.strokeStyle='#000000' 設置線條顏色
  • ctx.moveTo(x,y) 定義線條的起點
  • ctx.lineTo(x1,y1) 定義線條的終點
  • 最後 ctx.stroke() 把起點和終點連成一條線
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
var padding = 50;       // 坐標軸到canvas邊框的邊距,留邊距寫文字

ctx.beginPath();
ctx.lineWidth = 1;
// y軸線
ctx.moveTo(padding + 0.5, height - padding + 0.5);
ctx.lineTo(padding + 0.5, padding + 0.5);
ctx.stroke();
// x軸線
ctx.moveTo(padding + 0.5, height - padding + 0.5);
ctx.lineTo(width - padding + 0.5, height - padding + 0.5);
ctx.stroke();

畫坐標點

y軸上多少坐標點由自己來定義,需要獲取到數據的最大值來計算y軸上的坐標值。x軸的點則由傳入的數據長度決定,坐標值由傳入數據的 xAxis 屬性決定。

  • 坐標值就是文字,由 ctx.fillText(value, x, y) 填充文字,value 為文字值,x y 為值的坐標
  • ctx.textAlign='center' 設置文字居中對齊
  • ctx.fillStyle='#000000' 設置文字填充顏色
var yNumber = 5;                                                // y軸的段數
var yLength = Math.floor((height - padding * 2) / yNumber);     // y軸每段的真實長度
var xLength = Math.floor((width - padding * 2) / data.length);  // x軸每段的真實長度

ctx.beginPath();
ctx.textAlign = 'center';
ctx.fillStyle = '#000000';
ctx.strokeStyle = '#000000';
// x軸刻度和值
for (var i = 0; i < data.length; i++) {
    var xAxis = data[i].xAxis;
    var xlen = xLength * (i + 1);
    ctx.moveTo(padding + xlen, height - padding);
    ctx.lineTo(padding + xlen, height - padding + 5);
    ctx.stroke();                                       // 畫軸線上的刻度
    ctx.fillText(xAxis, padding + xlen - xLength / 2, height - padding + 15);   // 填充文字
}
// y軸刻度和值
for (var i = 0; i < yNumber; i++) {
    var y = yFictitious * (i + 1);
    var ylen = yLength * (i + 1);
    ctx.moveTo(padding, height - padding - ylen);
    ctx.lineTo(padding - 5, height - padding - ylen);
    ctx.stroke();
    ctx.fillText(y, padding - 10, height - padding - ylen + 5);
}

柱狀動畫

接下來要把數據通過柱狀的高低顯示出來,這裡有個動畫效果,柱狀會從0升到對應的值。在 canvas 上實現動畫我們可以使用 setInterval、setTimeout 和 requestAnimationFrame。

requestAnimationFrame 不需要自己設置定時時間,而是跟著瀏覽器的繪製走。這樣就不會掉幀,自然就流暢。
requestAnimationFrame 原本只支持IE10以上,不過可以通過相容的寫法實現相容到IE6都行。

function looping() {
    looped = requestAnimationFrame(looping);
    if(current < 100){      
    // current 用來計算當前柱狀的高度占最終高度的百分之幾,通過不斷迴圈實現柱狀上升的動畫
        current = (current + 3) > 100 ? 100 : (current + 3);
        drawAnimation();
    }else{
        window.cancelAnimationFrame(looped);
        looped = null;
    }
}
function drawAnimation() {
    for(var i = 0; i < data.length; i++) {
        var x = Math.ceil(data[i].value * current / 100 * yRatio);
        var y = height - padding - x;
        ctx.fillRect(padding + xLength * (i + 0.25), y, xLength/2, x);
        // 保存每個柱狀的信息
        data[i].left = padding + xLength / 4 + xLength * i;
        data[i].top = y;
        data[i].right = padding + 3 * xLength / 4 + xLength * i;
        data[i].bottom = height - padding;
    }
}
looping();
  • 柱狀即是畫矩形,由 ctx.fillRect(x, y, width, height) 實現,x y 為矩形左上角的坐標,width height 為矩形的寬高,單位為像素
  • ctx.fillStyle='#1E9FFF' 設置填充顏色

到這裡,一個最基本的柱狀圖就完成了。接下來,我們可以為他添加標題。

標題

要放置標題,就會發現我們一大早定義的 padding 內邊距確實有用,總不能把標題給覆蓋到柱狀圖上吧。但是標題有的是在頂部,有的在底部,那麼就不能寫死了。定一個變數 position 來判斷位置去畫出來。這個簡單。

// 標題
if(title){                      // 也不一定有標題
    ctx.textAlign = 'center';
    ctx.fillStyle = '#000000';  // 顏色,也可以不用寫死,個性化嘛
    ctx.font = '16px Microsoft YaHei'
    if(titlePosition === 'bottom' && padding >= 40){
        ctx.fillText(title,width/2,height-5)
    }else{
        ctx.fillText(title,width/2,padding/2)
    }
}

監聽滑鼠移動事件

我們看到,有些圖表,把滑鼠移上去,當前的柱狀就變色了,移開之後又變回原來的顏色。這裡就需要監聽 mouseover 事件,當滑鼠的位置位於柱狀的面積內,觸發事件。

那我怎麼知道在柱狀里啊,發現在 drawAnimation() 里會有每個柱狀的坐標,那我乾脆把坐標給保存到 data 里。那麼滑鼠在柱狀里的條件應該是:

  • ev.offsetX > data[i].left
  • ev.offsetX < data[i].right
  • ev.offsetY > data[i].top
  • ev.offsetY < data[i].bottom
canvas.addEventListener('mousemove',function(ev){
    var ev = ev||window.event;
    for (var i=0;i<data.length;i++){
    for (var i=0;i<data.length;i++){
        if(ev.offsetX > data[i].left &&
        ev.offsetX < data[i].right &&
        ev.offsetY > data[i].top &&
        ev.offsetY < data[i].bottom){
            console.log('我在第'+i+'個柱狀里。');
        }
    }
})

總結

為了更方便的使用,封裝成構造函數。通過

var chart = new sBarChart('canvas',data,{
    title: 'xxx公司年度盈利',   // 標題
    titleColor: '#000000',      // 標題顏色
    titlePosition: 'top',       // 標題位置
    bgColor: '#ffffff',         // 背景色
    fillColor: '#1E9FFF',       // 柱狀填充色
    axisColor: '#666666',       // 坐標軸顏色
    contentColor: '#a5f0f6'     // 內容橫線顏色
});

參數可配置,很簡單就生成一個個性化的柱狀圖。代碼地址:canvas-demo

更多文章:lin-xin/blog


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 設計模式三—抽象工廠模式 一、定義 抽象工廠模式是工廠方法模式的進一步抽象。如果產品簇中只有一種產品,則退化為工廠方法模式。 二、原理圖 三、代碼實例 * 蘋果和土豆是園丁1的傑作 * 葡萄和西紅柿是園丁2的傑作 1、Fruit.java 2、Apple.java 3、Grape.java 4、Ve ...
  • 設計模式二—工廠方法模式 一、工廠方法模式優點 良好的封裝性 優秀的可擴展性 屏蔽產品類 典型的解耦架構 二、實例 三、實例代碼 1、Fruit.java public interface Fruit { /* * 生長 * 收穫 * 栽種 */ public void grow(); public ...
  • 1 [root@ ~/learn_code/design_pattern/19_order]$ cat order.cpp 2 #include 3 #include 4 #include 5 #include 6 #include 7 8 using namespace std; 9 10 cla... ...
  • 參考: http://www.cnblogs.com/jiese/p/3164940.html http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html ...
  • 一、什麼是模板方法模式 概念:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。 通俗的講,模板方法模式是通過把不變行為搬到超類,去除子類裡面的重覆代碼提現它的優勢,它提供了一個很好的代碼復用平臺。當不可變和可變的方法在子類 ...
  • 很多時候,在我們的網站中因為頁面內容過長,用戶瀏覽網頁時若想返回頂部菜單需要滾動滑鼠才能到達,很不方便,為了提高用戶體驗度,我們會在網頁中加入返回頂部功能,以下是php中文網推薦的5款簡潔的返回頂部特效代碼,很值得收藏哦!歡迎分享下載! 1.簡單實用jQuery返回頂部代碼 效果預覽和下載地址:ht ...
  • console.log(typeof 'abc') // "string" console.log(typeof true )// "boolean" console.log(typeof {a:1}) // "object" console.log(typeof function foo(){}) ...
  • 趕工趕工。。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...