需求

实现下图所示的仪表盘的绘制。

分析

我们先来将仪表盘进行图形拆分,并定义尺寸。

我们绘制的逻辑:

  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();

Canvas入门08-绘制仪表盘的更多相关文章

  1. Canvas入门(1):绘制矩形、圆、直线、曲线等基本图形

    来源:http://www.ido321.com/968.html 一.Canvas的基础知识 Canvas是HTML 5中新增的元素,专门用于绘制图形.canvas元素就相当于一块“画布”,一块无色 ...

  2. Canvas入门(2):图形渐变和图像形变换

    来源:http://www.ido321.com/986.html 一.图形渐变(均在最新版Google中测试) 1.绘制线性渐变 1: // 获取canvas 的ID 2: var canvas = ...

  3. HTML5 canvas入门

    HTML5 Canvas入门 <canvas> 标签定义图形,比如图表和其他图像,您必须使用脚本来绘制图形.在画布上(Canvas)画一个红色矩形,渐变矩形,彩色矩形,和一些彩色的文字. ...

  4. canvas入门之时钟的实现

    canvas 入门之作: 三步实现一个时钟: 直接上效果:   step 1  : 背景制作首先制作从1-12的数字: var canvas = document.getElementById('ca ...

  5. canvas学习笔记(中篇) -- canvas入门教程-- 颜色/透明度/渐变色/线宽/线条样式/虚线/文本/阴影/图片/像素处理

    [中篇] -- 建议学习时间4小时  课程共(上中下)三篇 此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例, ...

  6. Canvas 入门案例

    五.  Canvas 入门案例 1.  canvas 圆形绘制 <!DOCTYPE html> <html lang="en"> <head> ...

  7. Canvas入门笔记-实现极简画笔

    今天学习了Html5 Canvas入门,已经有大神写得很详细了http://www.cnblogs.com/tim-li/archive/2012/08/06/2580252.html#8 在学习过后 ...

  8. -_-#【Canvas】导出在<canvas>元素上绘制的图像

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Canvas入门到高级详解(上)

    神奇的 canvas--AICODER 全栈培训 IT 培训专家 一.canvas 简介 1.1 什么是 canvas?(了解) 是 HTML5 提供的一种新标签 <canvas>< ...

随机推荐

  1. windows环境下 RabbitMQ 安装时创建用户流程命令

    https://blog.csdn.net/xiaojieblog/article/details/70332469

  2. SpringMVC POJO入参过程分析

    SpringMVC确定目标方法POJO类型的入参过程 1.确认一个key: (1).若目标方法的POJO类型的参数没有使用@ModelAttribute作为修饰,则key为POJO类名第一个字母的小写 ...

  3. java课堂动手测试

    课堂实验3 一个Java类文件中真的只能有一个公有类吗? 经过测试,当含有两个public  类时会报错,不能执行,假如删除第二个public则可以正常生成,说明一个java文件只能有一个公有类. 课 ...

  4. DB2常用指令

    1. 启动实例(db2inst1): db2start 2. 停止实例(db2inst1): db2stop 3. 列出所有实例(db2inst1) db2ilist 3-1.列出当前实例: db2 ...

  5. 算法复习-a 到 z不完全排列生成

    在网上看到这个题,觉得很有意思,也算是一种方法...但是复杂度同样很高,生成全排列本身需要很大复杂度. 题目:现在有 a 到 z 26 个元素, 编写程序打印 a 到 z 中任取 3 个元素的组合(比 ...

  6. 自己用ul模拟实现下拉多选框,

    模拟实现下拉多选框 效果如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  7. 【shell】awk的next用法

    awk的next相当于循环中continue的作用,next后面的语句将不再执行. 例如,下面的例子中,包含数字3的那行的print语句没有被执行. [root]$ seq | awk '{print ...

  8. CondaHTTPError问题的解决

    我是在配置pytorch时遇到的这个错误,截图如下: 这是某个网址访问失败导致的,我们可以通过添加其他路径解决这个问题,分别添加如下4个镜像路径,解决问题: 1)conda config --add ...

  9. java-dockerfile

    java环境dockefile FROM centos:7 MAINTAINER yon@taexa.com ENV JAVA_HOME /usr/local/jdk ENV JRE_HOME ${J ...

  10. SQLite为何要用C语言来开发?

    SQLite 选择 C 语言的理由是?为什么不选择 Go 或者 Rust? C 语言是最好的 SQLite 在 2000 年 5 月 29 日发布,并一直使用 C 语言实现.C 语言一直是实现 SQL ...