Canvas入門08-繪制儀表盤


需求

實現下圖所示的儀表盤的繪制。

分析

我們先來將儀表盤進行圖形拆分,並定義尺寸。

我們繪制的邏輯:

  1. 繪制中心圓
  2. 繪制環外圈圓
  3. 繪制環內圈圓
  4. 繪制刻度內圈圓
  5. 繪制刻度線
  6. 繪制刻度文字
  7. 繪制指針

定義圓

var circle = {
    x: canvas.width / 2,
    y: canvas.height / 2,
    radius: 150
};

繪制中心圓

中心圓半徑是10,圓心是畫布中心。

const CENTROID_RADIUS = 10;
const CENTROID_STROKE_STYLE = 'rgba(0,0,0,.5)';
const CENTROID_FILL_STYLE = 'rgba(80,190,240,.6)';

// 畫儀表盤中心
function drawCentroid() {
    context.beginPath();
    context.save();
    context.strokeStyle = CENTROID_STROKE_STYLE;
    context.fillStyoe = CENTROID_FILL_STYLE;
    context.arc(circle.x, circle.y, CENTROID_RADIUS, 0, 2 * Math.PI, false);
    context.stroke();
    context.fill();
    context.restore();
}

繪制環

這里應用了剪紙效果技巧,環外圈圓順時針繪制,環內圈圓逆時針順時針繪制,需要注意方向。


const RING_INNER_RADIUS = 35;
const RING_OUTER_RADIUS = 55;

// 繪制環外圈圓
function drawRingOuterCircle() {
    context.shadowColor = 'rgba(0,0,0,.7)';
    context.shadowOffsetX = 3;
    context.shadowOffsetY = 3;
    context.shadowBlur = 6;
    context.strokeStyle = TRACKING_DIAL_STROKING_STYLE;
    context.beginPath();
    context.arc(circle.x, circle.y, circle.radius + RING_OUTER_RADIUS, 0, 2 * Math.PI, true);
    context.stroke();

}


// 繪制環外圈圓
function drawRingInnerCircle() {
    context.strokeStyle = 'rgba(0,0,0,.1)';
    context.arc(circle.x, circle.y, circle.radius + RING_INNER_RADIUS, 0, 2 * Math.PI, false);
    context.fillStyle = 'rgba(100,140,230,.1)';
    context.fill();
    context.stroke();
}

繪制效果:

繪制刻度內圈圓

const TICK_WIDTH = 10;

// 繪制刻度內圓
function drawTickInnerCircle() {
    context.save();
    context.beginPath();
    context.strokeStyle = 'rgba(0,0,0,.1)';
    context.arc(circle.x, circle.y, circle.radius + RING_INNER_RADIUS - TICK_WIDTH, 0, 2 * Math.PI, false);
    context.stroke();
    context.restore();
}

繪制效果:

繪制刻度線

每條刻度線,其實是一個短線段,需要確定Line的起始坐標和終止坐標。

const TICK_WIDTH = 10;

// 繪制刻度
function drawTicks() {
    var radius = circle.radius + RING_INNER_RADIUS;
    var ANGLE_MAX = 2 * Math.PI;
    // var ANGLE_DELTA = Math.PI / 64;
    var ANGLE_DELTA = Math.PI / 24;

    var tickWidth;

    context.save();

    for (var angle = 0, count = 0; angle < ANGLE_MAX; angle += ANGLE_DELTA, count+=15) {
        drawTick(angle, radius, count);
    }
    context.restore();
}

function drawTick(angle, radius, count) {
    var tickWidth = count % 15 === 0 ? TICK_WIDTH : TICK_WIDTH / 2;

    context.beginPath();
    context.moveTo(circle.x + (radius - tickWidth) * Math.cos(angle), circle.y + (radius - tickWidth) * Math.sin(angle));
    context.lineTo(circle.x + (radius) * Math.cos(angle), circle.y + (radius) * Math.sin(angle));
    context.strokeStyle = TICK_SHORT_STROKE_STYLE;
    context.stroke();

}

繪制刻度值

注意刻度值是每個2個刻度線,繪制一個text。

const ANNOTATIONS_FILL_STYLE = 'rgba(0,0,230,.9)';
const ANNOTATIONS_TEXT_SIZE = 12;

function drawAnnotations() {
    var radius = circle.radius + RING_INNER_RADIUS;
    // var deltaAngle = Math.PI /8;
    var deltaAngle = Math.PI / 12;
    context.save();
    context.fillStyle = ANNOTATIONS_FILL_STYLE;
    context.font = ANNOTATIONS_TEXT_SIZE + 'px Helvetica';

    for (var angle = 0; angle < 2 * Math.PI; angle += deltaAngle) {
        context.beginPath();
        var degree = (angle * 180 / Math.PI).toFixed(0);
        var pt = {
            x: circle.x + (radius - TICK_WIDTH * 2) * Math.cos(angle),
            y: circle.x - (radius - TICK_WIDTH * 2) * Math.sin(angle)
        }
        if (degree !== '360') {
            context.fillText(degree, pt.x, pt.y);
        }
    }

    context.restore();
}

效果:

繪制指針

這里沒有動畫,所以給的是固定角度。


// 繪制指針
function drawCentroidGuidewire(loc) {
    var angle = -Math.PI / 4;
    var radius = circle.radius + RING_OUTER_RADIUS;
    var endpt;

    if (loc.x > circle.x) {
        endpt = {
            x: circle.x + radius * Math.cos(angle),
            y: circle.y + radius * Math.sin(angle)
        };
    } else {
        endpt = {
            x: circle.x - radius * Math.cos(angle),
            y: circle.y - radius * Math.sin(angle)
        };
    }

    context.save();

    context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
    context.fillStyle = GUIDEWIRE_FILL_STYLE;

    context.beginPath();
    context.moveTo(circle.x, circle.y);
    context.lineTo(endpt.x, endpt.y);
    context.stroke();

    context.beginPath();
    context.strokeStyle = TICK_LONG_STROKE_STYLE;
    context.arc(endpt.x, endpt.y, 5, 0, 2 * Math.PI, false);
    context.fill();
    context.stroke();

    context.restore();
}

最后調用的時候,先繪制指針,再繪制中心點,這樣可以使指針在中心點下層,好看一些。

function drawDial() {
    var loc = { x: circle.x, y: circle.y };


    drawCentroidGuidewire(loc);
    drawCentroid();
    drawRingOuterCircle();
    drawRingInnerCircle();
    drawTickInnerCircle();
    drawTicks();
    drawAnnotations();
}


// Initialization 
context.shadowColor = 'rgba(0,0,0,.4)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;

context.textAlign = 'center';
context.textBaseline = 'middle';

drawDial();



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM