前端有许多做数据可视化的图表插件,但有时候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. Android实现仿微信实时语音对讲功能|与女友游戏开黑

    与亲朋好友一起玩在线游戏,如果游戏中有实时语音对讲能力就可以拉进玩家之间的距离,添加更多乐趣.我们以经典的中国象棋为例,开发在线语音对讲象棋.本文主要涉及如下几个点: 在线游戏的规则,本文以中国象棋为 ...

  2. Cobalt Strike 之: Malleable C2 流量伪造与加密

    郑重声明: 本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关.倡导维护网络安全人人有责,共同维护网络文明和谐. 目录 ...

  3. 简单添加table线条

    <table style="width: 100%; margin: 0 auto; border: 1px solid #BBBBBB; border-collapse: colla ...

  4. div 元素内容超出可通过鼠标滚轮实现横向滚动

    移动端中的元素内容超出时,对容器设置overflow-x: auto就可以通过手势水平移动.但是 PC 端只能通过鼠标滚轮上下滑动,而不能水平移动. 只需要给元素添加一个监听鼠标滚轮事件,上下滑动时修 ...

  5. Postgresql的csv日志设置

    PG的日志系统比较完善,除去系统启动时指定的日志,wal日志等外,下面主要介绍另一个详细的输出日志:csv log. 涉及到的参数文件:$PGDATA/postgresql.conf涉及的主要参数: ...

  6. java数据结构与算法(day2)--简单排序

    模式:设计api实现api 简单排序 举例(商品排序) 1.1Comparable接口介绍(排序算法更有通用性:对象排序) 创建对象,并且生成豆子.创建Comparable接口 1 package c ...

  7. 制造业常用KPI

    1.  质量KPI CA (Capability of Accuracy): 平均值距离期望中心值的距离,值越大,说明平均值越接近期望中心值. Ca=(X-U)/(T/2) CP (Capabilit ...

  8. 使用expect在实现跨机器拿日志

    1.shell脚本 config_file_path=$1 #集群的ip port=$2 #获取集群服务端口中的日志 sjc=$3 #时间戳 user_name="sdbadmin" ...

  9. spring boot 跨域

    spring boot提供了两种跨域配置方式 1.全局跨域 2.局部跨域 全局跨域 package com.tons.config; import org.springframework.contex ...

  10. 1487. 保证文件名唯一 (Medium)

    问题描述 1487. 保证文件名唯一 (Medium) 给你一个长度为 n 的字符串数组 names .你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹. 由 ...