HTML5 rotate 做儀錶盤

來源:互聯網
上載者:User

我們的項目中有關於資料倉儲和挖掘,使用者要求UI的介面需要儀錶盤,我網上找了下,沒有發現免費的HTML儀錶盤,餅圖啥圖表的確很多,那就沒有辦法了,我和同事自己做了一個儀錶盤,結果如下。

之後我們就來討論下這個簡單的儀錶盤是怎麼做的。我們先大致有一個想法,設定一個寬高2:1的canvas,儀錶盤的半徑就是canvas的高度,儀錶盤需要的資料有上面分幾個地區(一般是低中高三個地區,為了測試我們準備了四個地區),刻度標記和文字,指標,和指標指向的值。

首先第一步自然是canvas的聲明

<body>    <div>        <canvas id="board" width="800" height="600">        </canvas>    </div></body></html>

之後的工作都在javascript中完成,我們需要定義一些對象

 //儀錶盤面板 var panel = function(id, option) {     this.canvas = document.getElementById(id); //擷取canvas元素     this.cvs = this.canvas.getContext("2d"); //得到繪製上下文     this.width = this.canvas.width; //對象寬度     this.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) {    var p = this;    var cvs = this.cvs;    for (var i = 0; i < level.length; i++) {        p.save(function() {            cvs.translate(p.width / 2, p.height);            cvs.rotate(Math.PI / 180 * level[i].start);            p.save(function() {                cvs.beginPath();                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() {    var p = this;    var cvs = this.cvs;    for (var i = 0; i <= 180; i++) {        p.save(function() {            cvs.translate(p.width / 2, p.height);            cvs.rotate(Math.PI / 180 * i);            p.save(function() {                cvs.beginPath();                cvs.lineTo(-(p.height - p.outsideStyle.lineWidth) + 10, 0);                cvs.lineTo(-(p.height - p.outsideStyle.lineWidth) + 5, 0);                cvs.stroke();                if (i % 10 == 0) {                    p.drawText(i);                }            });        });    }}

不過下面畫文字的代碼我沒有最佳化,你可以自己按上面的方式旋轉下

panel.prototype.drawText = function(val) {    var p = this;    var cvs = this.cvs;    p.save(function() {        cvs.lineWidth = 1;        cvs.strokeText(val, -(p.height - p.outsideStyle.lineWidth) + 5, 0);    });}

最後是畫指標,指標的角度值,是通過我們給的value來計算的。

panel.prototype.drawSpanner = function(value) {    var p = this;    var cvs = this.cvs;    p.save(function() {        cvs.translate(p.width / 2, p.height);        cvs.moveTo(0, 0);        cvs.arc(0, 0, p.height / 30, 0, (Math.PI / 180) * 360);        cvs.lineWidth = 3;        cvs.stroke();    });    p.save(function() {        cvs.translate(p.width / 2, p.height);        cvs.rotate(Math.PI / 180 * -90);        p.save(function() {            cvs.rotate(Math.PI / 180 * value);            cvs.beginPath();            cvs.moveTo(5, -3);            cvs.lineTo(0, -p.height * 0.7);            cvs.lineTo(-5, -3);            cvs.lineTo(5, -3);            cvs.fill();        });    });}

現在主要的方法都完成了,我們實現對使用者的介面

panel.prototype.init = function(value) {    var p = this;    var cvs = this.cvs;    cvs.clearRect(0, 0, this.width, this.height);    p.drawArc();    p.drawLevelArea(p.level);    p.drawLine();    p.drawSpanner(value);}

到此,panel的對象我們都編寫完成,以下是如何調用

window.onload = function() {    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)" }    };    Panel = new panel("board", panelOption);    Panel.init(15);}

大家可以測試這個簡單的儀錶盤了

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.