需求

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

分析

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

我们绘制的逻辑:

  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. PrimeFaces ab function

    The PrimeFaces.ab function is a shortcut function for PrimeFaces.ajax.AjaxRequest. //ajax shortcut a ...

  2. H5开发获取微信系统的地址列表

    前段时间做了H5开发的项目,需要是要把微信系统自带的地址也给添加进来,意识也就是说用户可以选择项目的地址和微信自带的地址  效果图是这样的: 对就是这个需求 下面给出H5 页面下的微信添加HTML 然 ...

  3. shell练习--PAT题目1005:继续(3n+1)猜想(全绿失败喜加一)

    卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数.例如对 n=3 进行验证的时 ...

  4. docker-compose简单使用

    1,下载安装docker-compose # http://get.daocloud.io/ curl -L https://get.daocloud.io/docker/compose/releas ...

  5. web上传文件夹

    文件夹数据库处理逻辑 publicclass DbFolder { JSONObject root; public DbFolder() { this.root = new JSONObject(); ...

  6. HOG行人目标检测

    行人检测是自动驾驶中重要的内容,对于驾驶安全具有重要意义. HOG特征提取: (1)灰度化处理 (2)Gamma变换和梯度计算 (3)Cell划分 (4)Cell组成block,归一化处理 (5)bl ...

  7. 【技术分享:python 应用之一】如何使用 Python 对 Excel 做一份数据透视表

    客户这边,其中有一张如同上图所示的数据汇总表,然而需求是,需要将这张表数据做一个数据透视表,最后通过数据透视表中的数据,填写至系统数据库.拿到需求,首先就想到肯定不能直接用设计器去操作 Excel,通 ...

  8. Mybatis 一对多 关联查询查询

    一对多 与 一对一 查询有许多相似之处. 最主要的区别是 查询结果是list,与之对应的标签为collection. 班级和学生,一个班有多个学生,而每个学生只能属于一个班. 此时班级编号作为学生表的 ...

  9. 项目三、文件上传器v1.1

    /** * 自定义文件上传工具 v1.1 * @param url 路径 */ function fileUploader(url) { var _date = new Date(); //日期 th ...

  10. csdn专家主页

    百度张瑞琪: http://blog.csdn.net/abcjennifer 深度学习系列教程: http://suanfazu.com/t/caffe/9479