canvas - 基础知识 - 仪表盘的绘制
js逻辑代码:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
CENTROID_RADIUS = 10, // 中心半径
CENTROID_STROKE_STYLE = 'rgba(0, 0, 0, 0.5)',
CENTROID_FILL_STYLE = 'rgba(80, 190, 240, 0.6)',
RING_INNER_RADIUS = 35,
RING_OUTER_RADIUS = 55,
ANNOTATIONS_FILL_STYLE = 'rgba(0,0,230,0.9)',
ANNOTATIONS_TEXT_SIZE = 12
TICK_WIDTH = 10,
TICK_LONG_STROKE_STYLE = 'rgba(100,140,230,0.9)',
TICK_SHORT_STROKE_STYLE = 'rgba(100,140,230,0.7)',
TRACKING_DIAL_STROKING_STYLE = 'rgba(100,140,230,0.5)',
GUIDEWIRE_STROKE_STYLE = 'goldenrod',
GUIDEWIRE_FILL_STYLE = 'rgba(250,250,0,0.6)',
circle = {
x: canvas.width/2,
y: canvas.height/2,
radius: 150
}
// function ...........................
function drawGrid(color, stepx, stepy) {
context.save();
context.shadowColor = undefined;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.strokeStyle = color;
context.fillStyle = '#fff';
context.lineWidth = 0.5;
context.fillRect(0,0, context.canvas.width, context.canvas.height);
for(var i = stepx + 0.5; i< context.canvas.width; i+= stepx) {
context.beginPath();
context.moveTo(i , 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for(var i= stepy + 0.5; i<context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}
function drawDial() {
var loc = {x: circle.x, y : circle.y};
drawCentroid();
drawCentroidGuidewire(loc);
drawRing();
drawTickInnerCircle();
drawTicks();
drawAnnotations();
}
function drawCentroid() {
context.beginPath();
context.save();
context.strokeStyle = CENTROID_STROKE_STYLE;
context.fillStyle = CENTROID_FILL_STYLE;
context.arc(circle.x, circle.y,
CENTROID_RADIUS, 0, Math.PI*2, false);
context.stroke();
context.fill();
context.restore();
}
function drawCentroidGuidewire(loc) {
var angle = -Math.PI/4,
radius, endpt;
radius = circle.radius + RING_OUTER_RADIUS;
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, Math.PI*2, false);
context.fill();
context.stroke();
context.restore();
}
function drawRing() {
drawRingOuterCircle();
context.strokeStyle = 'rgba(0,0,0,0.1)';
context.arc(circle.x, circle.y, circle.radius + RING_INNER_RADIUS, 0, Math.PI*2, false);
context.fillStyle = 'rgba(100,140, 230, 0.1)';
context.fill();
context.stroke();
}
function drawRingOuterCircle() {
context.shadowColor = 'rgba(0,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, Math.PI*2, true);
context.stroke();
}
function drawTickInnerCircle() {
context.save();
context.beginPath();
context.strokeStyle = 'rgba(0,0,0,0.1)';
context.arc(circle.x, circle.y, circle.radius+RING_INNER_RADIUS - TICK_WIDTH, 0, Math.PI*2, false);
context.stroke();
context.restore();
}
function drawTick(angle, radius, cnt) {
var tickWidth = cnt % 4 === 0? TICK_WIDTH : TICK_WIDTH/2;
context.beginPath();
context.moveTo(circle.x + Math.cos(angle) * (radius - tickWidth),
circle.y + Math.sin(angle) * (radius - tickWidth));
context.lineTo(circle.x + Math.cos(angle) * radius, circle.y + Math.sin(angle) * radius);
context.strokeStyle = TICK_SHORT_STROKE_STYLE;
context.stroke();
}
function drawTicks() {
var radius = circle.radius + RING_INNER_RADIUS,
ANGLE_MAX = 2*Math.PI,
ANGLE_DELTA = Math.PI/64,
tickWidth;
context.save();
for(var angle=0, cnt=0; angle < ANGLE_MAX; angle += ANGLE_DELTA, cnt++) {
drawTick(angle, radius, cnt++);
}
context.restore();
}
function drawAnnotations() {
var radius = circle.radius + RING_INNER_RADIUS;
context.save();
context.fillStyle = ANNOTATIONS_FILL_STYLE;
context.font = ANNOTATIONS_TEXT_SIZE + 'px Helvetica';
for(var angle=0; angle < 2*Math.PI; angle += Math.PI/8) {
context.beginPath();
context.fillText((angle * 180 / Math.PI).toFixed(0),
circle.x + Math.cos(angle) * (radius - TICK_WIDTH*2),
circle.y - Math.sin(angle) * (radius - TICK_WIDTH*2));
}
context.restore();
}
// Initialization .................................
context.shadowColor = 'rgba(0,0,0,0.4)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;
context.textAlign = 'center';
context.textBaseline = 'middle';
drawGrid('lightgray', 10, 10);
drawDial();
效果图: