概述
基於Canvas實現的儀表盤及效果。通過配置參數,可以任意修改儀表盤顏色,刻度,動畫過渡時間等,滿足不同場景下的使用。同時使用原生的Canvas,也是學習Canvas的很好的例子。
詳細
一、演示效果
儀表盤效果如下:

二、項目結構截圖

gauge.js文件是canvas儀表盤的主邏輯,demo.html中是使用的方法。
注:本例子只有2個文件,如上圖所示。
三、使用方法
在html中,加入一個canvas的元素,設置寬高為510。
<canvas width=510 height=510 id="gauge"></canvas>
<script src="./gauge.js"></script>
//然后配置儀表盤
var my_canvas_obj= document.getElementById("gauge");
var gauge2 = new Gauge({
"tick_length": 12,
"large_tick_length": 22,
"tick_thickness": 1,
"tick_group_length": 9,
"ticks_groups_begin": 0,
"total_degrees": 250,
"total_tick": 101,
"tick_color": "#666",
"num_font_size": 18,
"percent": 0,
"center_font_size": 172,
tick_on_color: '#f1594e',
cur_score_circle_color: '#ff5e52',
center_font_color: '#ff5e52',
center_text_unit: '%',
animation_duration: 1000,
"canvas": my_canvas_obj2
})
// 繪制初始儀表盤初始值0%
gauge.render()
setTimeout(function(){
//繪制目標值,90%
gauge.updatePercent(90)
}, 1000)
儀表盤通過一系列的配置參數來實現各種顏色,動畫時間,刻度多少等的自定義
* 配置參數
* 顏色配置
tick_color: "#555962", // 未達到的刻度顏色
tick_on_color: "#527d98", // 已達到的刻度顏色
on_color_gradient: // 已達到的刻度顏色,漸變效果,詳細參考demo中,guage1。值為Array
例如:
on_color_gradient: [
{
color: "#50B517",
percent: 0 // 最開始,0%
},
{
color: "#000000",
percent: 100 // 結束,100%
},
]
on_color_gradient 設置之后,tick_on_color則不會生效
center_font_color: '#555962', //中間數字顏色 設置為#fff-#000時,表示從左往右漸變
bg_color: // cavans的背景色
* 尺寸配置:
tick_length: 80, // 短刻度長度
large_tick_length: 110, // 長刻度長度
tick_thickness: 6, //刻度條寬度
tick_group_length: 9, //每組內的短刻度個數
ticks_groups_begin: 0, //起始點
total_degrees: 240, // 刻度的總角度
animation_duration: 550, //達到目標值的動畫時間
total_tick: 101, // 刻度總個數
show_num: true, // 是否展示長刻度下的數字
show_center_num: true, // 是否顯示中間大的數字
center_font_size: 200, //中間數字font-size
center_num_font_family: ,//中間數字font-family
num_gap: 1, // 每個刻度之間的間隔值,計算顯示數字時需要
num_begin: 0, // 起始刻度值
num_font_size: 24, // 刻度值字體大小
num_font_family: 'HanHei SC,PingFang SC,Helvetica Neue Thin, Helvetica, STHeitiSC-Light, Arial, sans-serif' // 刻度數字font-family
* 不建議隨意修改的參數
tickmask_offset: 10 // 刻度值距離刻度的間隔, 單位px,
center_offset: {
x: 0,
y: 0
}, // 中間數字上下位置的偏移
circle_radius: 5, // 刻度指示圓形的半徑
circle_offset: 0 // 刻度指示距離刻度的空隙
gauge_scale: 1, // 縮放比例
四、代碼實現過程
下面介紹canvas儀表盤的實現過程,代碼邏輯位於gauge.js文件中

1.初始化
首先properties中放置了所有配置的默認值。
然后將傳入的配置值和默認的配置值就行合並。合並完之后進行一下初始化值的設置。
初始化時,設置一下每一個刻度需要旋轉的角度:
總的刻度角度 / (刻度條的個數 - 1) * Math.PI / 180
2.繪制每一幀
// 計算一下最初始的角度,也就開始的刻度線相對於水平線的角度
var starting_deg = (180 - this.total_degrees) / 2;
// 然后將整個畫布旋轉到初始角度。從左下角可是繪制
context.rotate(starting_deg * PIDEG);
// 首先繪制刻度盤上指示刻度的小圓點
this._drawScoreTipCircle(this._halfCanvasWidth - this.circle_radius, this.circle_radius, 0);
// 繪制刻度線,num_ticks 為總刻度線的條數。
for(var i = 1; i <= num_ticks; i++) {
//判斷是刻度線是應該亮起來還是暗的
var is_on = (((i - 1) / num_ticks) * 100 < this._percent);
//判斷是長刻度線還是短刻度線
var _isLargeTick = this._isLargeTick(i)
var tick_length = _isLargeTick ? this.large_tick_length : this.tick_length;
//獲取不同刻度線的顏色
var color = this._getTickColor(is_on, i);
//設置填充色
context.fillStyle = color;
// 繪制刻度線,即一個長方形。 由於刻度線分長刻度線和短刻度線,而長刻度線和短刻度線因為長度不同,所以長方形的起點位置不同。
if (_isLargeTick) {
// 繪制長刻度線,即一個長方形
context.fillRect(-1*this._halfCanvasWidth + this.circle_radius * 2 + this.circle_offset, -this.tick_thickness/2, tick_length, this.tick_thickness);
// 對於整數值的刻度線,旁邊有一個示數,這里繪制示數
if (this.show_num) {
this._drawGaugeNum(tick_length, i);
}
} else {
// 繪制短刻度線
context.fillRect(-1*this._halfCanvasWidth + this.circle_radius * 2 + this.circle_offset + this.delatLength, -this.tick_thickness/2, tick_length, this.tick_thickness);
}
//每畫完一條,就旋轉一下畫布。旋轉的角度 = 總的刻度角度 / (刻度條的個數 - 1) * Math.PI / 180
context.rotate(this._rotation_deg);
}
// 全部繪制完之后,把前一個舊的canvas清除掉
this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
// 繪制新的圖像
this._context.drawImage(this.canvas, 0, 0);
// 每次繪制完成后要回到畫布的原始的狀態
context.restore();
3.動畫
通過上面的 render 函數,我們可以繪制出一個靜態的儀表盤了。接下來我們需要讓儀表盤的示數展示動起來。這里我們利用 requestAnimationFrame 函數,在函數回調中執行 render 函數,繪制出不一樣的刻度亮/暗圖。
var lastUpdate = +new Date();
// 動畫開始時已經亮起來的刻度的百分比
var start = this._percent;
// 目標百分比
var end = this._target_percent;
// 計算一下每毫秒我們需要完成多少百分比,然后后面每次執行時,根據經過了多少時間來計算出應該完成多少,即刻度應該亮起來多少
var change_per_ms = (end - start)/duration;
var increasing = change_per_ms > 0 ? 1 : 0;
// 首先計算一下所有刻度亮起來時應該是什么顏色的,保存到一個數組中。
// 后面動畫過程中直接從數組中取值即可,不需要再次計算。
this.colorArray = this._gradientColorArray();
// 更新邏輯
var update = function () {
// 通過時間來計算應該完成的百分比
var now = +new Date();
var elapsed = now - lastUpdate;
_this._percent += elapsed*change_per_ms;
lastUpdate= now;
//檢測一下是否已經達到我們最終的百分比,如果達到了就停止動畫;如果沒有就繼續繪制
if ((increasing && _this._percent < _this._target_percent)
|| (!increasing && _this._percent > _this._target_percent)) {
_this.render();
_this._requestAnimFrame(update);
}
else {
_this._percent = _this._target_percent;
_this.render();
}
};
_this._requestAnimFrame(update);
這樣我們的儀表盤就有一開始從0到100刻度逐漸變亮的效果。

