我們的項目中有關于資料倉庫和挖掘,使用者要求UI的界面需要儀表盤,我網上找了下,沒有發現免費的HTML儀表盤,餅圖啥圖表的确很多,那就沒有辦法了,我和同僚自己做了一個儀表盤,結果如下。
<a target="_blank" href="http://blog.51cto.com/attachment/201205/161746811.png"></a>
之後我們就來讨論下這個簡單的儀表盤是怎麼做的。我們先大緻有一個想法,設定一個寬高2:1的canvas,儀表盤的半徑就是canvas的高度,儀表盤需要的資料有上面分幾個區域(一般是低中高三個區域,為了測試我們準備了四個區域),刻度線和文字,指針,和指針指向的值。
首先第一步自然是canvas的聲明
[html] view plaincopy
<body>
<div>
<canvas id="board" width="800" height="600">
</canvas>
</div>
</body>
</html>
之後的工作都在javascript中完成,我們需要定義一些對象
[javascript] view plaincopy
//儀表盤面闆
var panel = function(id, option) {
this.canvas = document.getElementById(id); //擷取canvas元素
thisthis.cvs = this.canvas.getContext("2d"); //得到繪制上下文
thisthis.width = this.canvas.width; //對象寬度
thisthis.height = this.canvas.height; //對象高度
this.level = option.level;
this.outsideStyle = option.outsideStyle;
}
這個panel就是我們的儀表盤對象,參數的id是canvas元素,option是我們需要送出給儀表盤的一些參數值。這個option的定義如下:option對象可以擴充,你可以通過optin定制更加自由強大的儀表盤對象的。
var panelOption = {
maxLength: 30,
interval: 5,
level: [//儀表盤需要呈現的資料隔離區域
{start: 0, color: "red" },
{ start: 30, color: "yellow" },
{ start: 40, color: "blue" },
{ start: 100, color: "Lime" }
],
outsideStyle: { lineWidth: 4, color: "rgba(100,100,100,1)" }
};
在繪制元素的時候,我們常常需要儲存和恢複現場,特别當我們使用轉移,旋轉等方法的時候,一定要記得先save最後restore。為了友善,我們編寫了一個save函數提供這個方式,這個模式類似C#中的委托,和設計模式中的觀察着模式
panel.prototype.save = function(fn) {
this.cvs.save();
fn();
this.cvs.restore();
上面這個save可以友善的幫助我們儲存和回複現場。
我們定義個用于畫半圓的方法,這個方法中,我們将需要畫半圓時做的translate放到save函數中,這樣畫半圓的變形操作不會對其他操作有影響。
panel.prototype.drawArc = function() {
var p = this;
var cvs = this.cvs;
p.save(function() {
cvs.translate(p.width / 2, p.height); //将坐标點移到矩形的底部的中間
cvs.beginPath();
cvs.lineWidth = p.outsideStyle.lineWidth;
cvs.strokeStyle = p.outsideStyle.color;
cvs.arc(0, 0, p.height - cvs.lineWidth, 0, Math.PI / 180 * 180, true); //畫半圓
cvs.stroke();
});
然後我們繪制中間顔色的填充區域
panel.prototype.drawLevelArea = function(level) {
for (var i = 0; i < level.length; i++) {
cvs.translate(p.width / 2, p.height);
cvs.rotate(Math.PI / 180 * level[i].start);
cvs.arc(0, 0, p.height - p.outsideStyle.lineWidth, Math.PI / 180 * 180, Math.PI / 180 * 360);
cvs.fillStyle = level[i].color;
cvs.fill();
}
上面的代碼中,rotate很重要,我們每次都按level中的值進行旋轉,然後畫180°的顔色。這樣的過程是
第一次旋轉是0,沒有動,用紅色畫了180°的半圓
第二次旋轉了30°,你可以想想目前的畫布放斜了,然後以斜的畫了180°黃,這樣恰恰好吧紅色超過30°的顔色都覆寫了
依次類推,我們不要對arc的起始和結束值做改變,我們隻要再畫之前,rotate就可以了。當然,要放在save中哦。
之後是畫線,道理是一樣的,代碼如下
panel.prototype.drawLine = function() {
for (var i = 0; i <= 180; i++) {
cvs.rotate(Math.PI / 180 * i);
cvs.lineTo(-(p.height - p.outsideStyle.lineWidth) + 10, 0);
cvs.lineTo(-(p.height - p.outsideStyle.lineWidth) + 5, 0);
if (i % 10 == 0) {
p.drawText(i);
不過下面畫文字的代碼我沒有優化,你可以自己按上面的方式旋轉下
panel.prototype.drawText = function(val) {
cvs.lineWidth = 1;
cvs.strokeText(val, -(p.height - p.outsideStyle.lineWidth) + 5, 0);
最後是畫指針,指針的角度值,是通過我們給的value來計算的。
panel.prototype.drawSpanner = function(value) {
cvs.moveTo(0, 0);
cvs.arc(0, 0, p.height / 30, 0, (Math.PI / 180) * 360);
cvs.lineWidth = 3;
cvs.rotate(Math.PI / 180 * -90);
cvs.rotate(Math.PI / 180 * value);
cvs.moveTo(5, -3);
cvs.lineTo(0, -p.height * 0.7);
cvs.lineTo(-5, -3);
cvs.lineTo(5, -3);
現在主要的方法都完成了,我們實作對使用者的接口
panel.prototype.init = function(value) {
cvs.clearRect(0, 0, this.width, this.height);
p.drawArc();
p.drawLevelArea(p.level);
p.drawLine();
p.drawSpanner(value);
到此,panel的對象我們都編寫完成,以下是如何調用
window.onload = function() {
};
Panel = new panel("board", panelOption);
Panel.init(15);
大家可以測試這個簡單的儀表盤了
本文轉自shyleoking 51CTO部落格,原文連結:http://blog.51cto.com/shyleoking/863987