前端有许多做数据可视化的图表插件,但有时候UI设计的图可能用现成的js插件无法定制或者比较麻烦(还不如自己造轮子来的快)。

下面记录下用H5 canvas设计一个仪表盘代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
<script src="tween.umd.min.js"></script>
<style>
.container {
position: absolute;
top: 40px;
left: 100px;
width: 138px;
height: 138px;
display: flex;
align-items: center;
justify-content: center;
} #bg, #ring {
position: absolute;
width: 138px;
height: 138px;
} #bg {
background-color: #fff;
} </style>
</head>
<body style="background-color: #ccc">
<div class="container">
<div id="percent" style="z-index: 100; color: #fff;">0%</div>
<canvas id="bg" width="138" height="138"></canvas>
<canvas id="ring" width="138" height="138"></canvas>
</div>
</body>
<script>
const bgCanvas = document.querySelector('#bg');
const ringCanvas = document.querySelector('#ring');
const bgCtx = bgCanvas.getContext('2d');
const ctx = ringCanvas.getContext('2d');
const percentEl = document.querySelector('#percent'); const pixelRatio = window.devicePixelRatio;
const BG_RING_WIDTH = 6;
const POINTER_BALL_RADIUS = 6;
const CANVAS_WIDTH = 138;
const CANVAS_HEIGHT = 138;
const INNER_CIRCLE_RADIUS = 45; if(pixelRatio > 1) {
bgCanvas.width = CANVAS_WIDTH * 2;
bgCanvas.height = CANVAS_HEIGHT * 2;
ringCanvas.width = CANVAS_WIDTH * 2;
ringCanvas.height = CANVAS_HEIGHT * 2;
bgCanvas.style.width = CANVAS_WIDTH;
bgCanvas.style.height = CANVAS_HEIGHT;
ringCanvas.style.width = CANVAS_WIDTH;
ringCanvas.style.height = CANVAS_HEIGHT;
} function createBgCircle() {
bgCtx.save();
bgCtx.beginPath();
bgCtx.arc(CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2, INNER_CIRCLE_RADIUS, 0, 2 * Math.PI);
let gradient = bgCtx.createLinearGradient(INNER_CIRCLE_RADIUS * 2, 0, 0, INNER_CIRCLE_RADIUS * 2);
gradient.addColorStop(0, '#E69908');
gradient.addColorStop(1, '#FDF27B');
bgCtx.fillStyle = gradient;
bgCtx.fill();
bgCtx.restore();
} function createBgRing() {
bgCtx.save();
bgCtx.beginPath();
const x = CANVAS_WIDTH / 2;
const y = r = x;
bgCtx.arc(x, y, r, 0, 2 * Math.PI, true);
bgCtx.arc(x, y, x - BG_RING_WIDTH, 0, 2 * Math.PI, false);
bgCtx.fillStyle = '#EEF5F5';
bgCtx.fill();
bgCtx.restore();
} let imageLoaded = false;
let img = null; async function createProcessRing(radian) {
const x = CANVAS_WIDTH / 2;
const y = r = x;
//裁剪扇形区域
ctx.save();
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, r, -Math.PI/2, -Math.PI/2 + radian);
ctx.clip(); if(imageLoaded) {
ctx.drawImage(img, 0, 0, img.width, img.height);
ctx.restore();
return;
} return new Promise(resolve => {
const imgUrl = "ring.png";
img = new Image();
img.src = imgUrl;
img.onload = function() {
imageLoaded = true;
ctx.drawImage(img, 0, 0, img.width, img.height);
ctx.restore();
resolve();
}
})
} function createBallPointer(x, y) {
const cx = CANVAS_WIDTH / 2;
const cy = cx;
ctx.save();
ctx.translate(cx, cy);
ctx.beginPath();
ctx.arc(x, y, POINTER_BALL_RADIUS, 0, 2 * Math.PI);
let gradient = ctx.createLinearGradient(0, POINTER_BALL_RADIUS * 2, POINTER_BALL_RADIUS * 2, 0);
gradient.addColorStop(0, '#FF8B00');
gradient.addColorStop(1, '#F2C008');
ctx.fillStyle = gradient;
ctx.fill();
ctx.restore();
} function createAnimation(startAngle = 0, endAngle = 360, callback) {
function animate(time) {
requestAnimationFrame(animate)
TWEEN.update(time)
}
requestAnimationFrame(animate) const p = {angle: startAngle}
const tween = new TWEEN.Tween(p)
.to({angle: endAngle}, 600)
.easing(TWEEN.Easing.Quadratic.Out)
.onUpdate(() => {
let radian = Math.PI / 180 * p.angle;
let x = (CANVAS_WIDTH / 2 - BG_RING_WIDTH) * Math.cos(Math.PI/2 - radian);
let y = -(CANVAS_HEIGHT / 2 - BG_RING_WIDTH) * Math.sin(Math.PI/2 - radian);
ctx.clearRect(0, 0, ringCanvas.width, ringCanvas.height);
createProcessRing(radian);
createBallPointer(x, y);
percentEl.innerText = Math.round(p.angle / 360 * 100) + '%';
})
.start();
} async function setup() {
createBgCircle();
createBgRing();
await createProcessRing();
createBallPointer(0, -(CANVAS_WIDTH / 2 - BG_RING_WIDTH/2));
createAnimation(0, 360);
} setup(); </script>
</html>

效果:

用H5 Canvas绘制一个仪表盘笔记的更多相关文章

  1. H5 canvas绘制出现模糊的问题

    在之前做移动端小游戏幸运转盘.九宫格转盘,使用到了 canvas ,也是第一次在项目中使用 canvas 来实现. 近期测试人员反应 canvas 绘制的内容太模糊,心想着用 canvas 绘制出来的 ...

  2. 使用canvas绘制一个时钟

    周末学习canvas的一些基础功能,顺带写了一个基础的时钟.现在加工一下,做的更好看一点,先放上效果图: 谈一些自己的理解: (1).要绘制一个新的样式(不想被其他样式影响,或者影响到其他样式),那么 ...

  3. HTML5 在canvas绘制一个矩形

    笔者:本笃庆军 原文地址:http://blog.csdn.net/qingdujun/article/details/32930501 一.绘制矩形 canvas使用原点(0,0)在左上角的坐标系统 ...

  4. Canvas绘制一个大鱼喂小鱼的游戏

    Canvas是HTML5中的一部分,强大的API足以让我们绘制我们任意想绘制的东西.利用Canvas的基础学习以及JavaScript面向对象的思想绘制一个小游戏,下面是源码地址https://git ...

  5. 用canvas绘制一个简易时钟

    在见识了html5中canvas的强大,笔者准备制作一个简易时钟. 下面就是成果啦,制作之前我们先分析一下,绘制一个时钟需要做哪些准备. 一 . 1.首先这个时钟分为表盘,指针(时针,分针,秒针)和数 ...

  6. 用canvas绘制一个时钟

    实现一个时钟的绘制和时间的显示 一,首先是页面的搭建html部分以及一点点的css代码,因为css这块用的比较少,所以就没有单独出来: <!DOCTYPE html> <html l ...

  7. 使用H5 canvas画一个坦克

      具体步骤如下:   1. 首先做出绘图区,作为坦克的战场   <canvas id="floor" width="800px" height=&quo ...

  8. Canvas 绘制一个像素风电子时钟

    想法是在 Canvas 上绘制由小方块组成的数字. 第一步是实现绘制小方块的方法,先画出一个边长为 5 的 10x10 个方块,使用两个 for 循环很简单就能完成. for (let i = 0; ...

  9. 没事用html5 canvas画一个仪表盘自用,自适应的哦

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Canvas绘制图形

    1.Canvas绘制一个蓝色的矩形 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...

随机推荐

  1. 【KAWAKO】docker暴力上手

    目录 从docker hub拉取镜像 根据镜像创建容器,同时把本地目录挂载到容器 进入容器 停止容器 删除停止的容器 从docker hub拉取镜像 进入docker hub,搜索自己喜欢的镜像. 复 ...

  2. HACKNOS: RECONFORCE (V1.1)

    HACKNOS: RECONFORCE (V1.1) 目录 HACKNOS: RECONFORCE (V1.1) 1 信息收集 1.1 端口扫描 1.2 ftp分析 1.3 后台目录扫描 1.2.1 ...

  3. Nacos集群搭建(三个节点)

    Nacos集群安装 一,在每台服务器上安装nacos 1,准备安装包 ​ github下载点 2,在/usr/local/目录下创建一个文件夹用于上传和解压Nacos cd /usr/local/ # ...

  4. vue 组件通信方式 ,父子、隔代、兄弟 三类通信,六种方法

    (1)props / $emit 适用 父子组件通信 (2) ref 与 $parent / $children 适用 父子组件通信 (3)$attrs / $listeners 适用于 隔代组件通信 ...

  5. QFileDialog实现同时选择文件和文件夹,确认取消按钮英文问题解决方法

    如下图所示,需求是同时能够选择文件或者文件夹,但是QFileDialog文件窗口类要么只能选文件,要么只能选文件夹,无法同时去选择文件和文件夹: 要实现这样的需求,封装了一个类,实现同时选择文件和文件 ...

  6. AOP 编程

    1.静态代理 定义一个接口,用以规定执行方法 public interface IOrderProcessor { void Submit(); } 实现执行方法 public class Order ...

  7. C#判断useragent是pc还是手机端

    public static bool CheckAgent(string userAgent) { bool flag = false; string[] keywords = { "And ...

  8. Vue-cli创建的项目结构分析,各初始化文件解释说明

    结构图: 一.项目结构说明  1..gitignore :git的忽略文件(哪些文件或文件夹不想接受git管理的,可在此文件配置) 2.babel.config.js:babel控制文件,ES6=&g ...

  9. 这里记录一下我个人对AXI4主从模块的理解(这些理解主要来自阅读 Xilinx AXI_FULL_M_module 源码)

    先只考虑读请求: 以取指模块和内存模块为例,取指模块是发出请求的模块,因此为 Master,属于AXI4MasterModule:内存模块是响应请求的模块,因此为 Slave,属于AXI4SlaveM ...

  10. Mysql数据库基础第五章:(一)事务

    Mysql数据库基础系列 软件下载地址 提取码:7v7u 数据下载地址 提取码:e6p9 mysql数据库基础第一章:(一)数据库基本概念 mysql数据库基础第一章:(二)mysql环境搭建 mys ...