纯 canvas 实现漂亮的仪表盘

纯 canvas 实现漂亮的仪表盘_第1张图片
经验:

  1. save-restore-restore-restore 是不行的。用 save 保存的状态只能用一次,最后两个 restore 是回不到第一次 save 的状态的。
  2. oninput 是变了就触发,onchange 是变了且 失去焦点 才触发


<html>

<head>
	<meta charset="UTF-8">
	<style>
		canvas {
			background: linear-gradient(20deg, rgba(255, 152, 0, 0.5) 0, rgba(255, 87, 34, 0.9) 45%, rgba(255, 87, 34, 0.8) 50%, rgba(255, 152, 0, 0.6) 100%);
		}
	style>
head>

<body>

	<canvas id="canvas">canvas>
	
	<input type="range" value="70" oninput="handleInput()" id="inputRange">
	<img src="" style="display:none;" id="beautiful-icon">
	<img src="" style="display:none;" id="beautiful-icon-light">


	<script>
		const width = 500;
		const height = 300;
		let canvas;
		let beautiful_icon_base64;
		let beautiful_icon_light_base64;

		window.onload = function() {
			// 给图片设置src(base64)
			document.getElementById("beautiful-icon").setAttribute("src", beautiful_icon_base64)
			document.getElementById("beautiful-icon-light").setAttribute("src", beautiful_icon_light_base64)
			// 给画布设置宽高
			canvas = document.getElementById("canvas");
			canvas.setAttribute("width", width);
			canvas.setAttribute("height", height);
			// 画一个
			handleInput(60);
		}

		function handleInput() {
			const val = parseInt(document.getElementById("inputRange").value);
			draw(val);
		}

		function draw(value) {
			let startAngle = 17 / 16 * Math.PI, // 和数学上的保持一致
				endAngle = -1 / 16 * Math.PI,
				splitNumber = 25,
				diamondNumber = 10,
				diamondSize = 20,
				center = [width / 2, height / 2 + 32];
			var ctx = canvas.getContext('2d');
			ctx.save();
			ctx.clearRect(0, 0, width, height);
			ctx.translate(center[0], center[1]);
			// 
			ctx.beginPath();
			ctx.strokeStyle = 'white';
			ctx.lineWidth = 5;
			ctx.shadowBlur = 10;
			ctx.shadowColor = "rgba(255, 255, 255, 0.8)";
			ctx.arc(0, 0, 35, 2 * Math.PI - startAngle, 2 * Math.PI - endAngle, false);
			ctx.stroke();
			// 画刻度
			ctx.lineWidth = 2;
			let r1 = 90;
			let r2 = 105;
			ctx.shadowBlur = 0;
			for (let i = 0; i <= splitNumber; i++) {
				let angle = startAngle - (startAngle - endAngle) / splitNumber * i;
				let startX = Math.cos(angle) * r1;
				let startY = -Math.sin(angle) * r1;
				let endX = Math.cos(angle) * r2;
				let endY = -Math.sin(angle) * r2;
				if (i <= value * splitNumber / 100) {
					ctx.strokeStyle = 'white';
				} else {
					ctx.strokeStyle = '#ffa96d';
				}
				ctx.beginPath();
				ctx.moveTo(startX, startY);
				ctx.lineTo(endX, endY);
				ctx.stroke();
			}
			// 画指针
			ctx.strokeStyle = '#fff';
			let r3 = 115;
			let angle = startAngle - (startAngle - endAngle) / splitNumber * value * splitNumber / 100;
			let startX = Math.cos(Math.PI + angle) * 12;
			let startY = -Math.sin(Math.PI + angle) * 12;
			let endX = Math.cos(angle) * r3;
			let endY = -Math.sin(angle) * r3;
			ctx.lineWidth = 3;
			ctx.beginPath();
			ctx.moveTo(startX, startY);
			ctx.lineTo(endX, endY);
			ctx.stroke();
			// 
			// 画指针中心的圈圈
			ctx.beginPath();
			ctx.lineWidth = 2;
			ctx.fillStyle = "pink";
			ctx.arc(0, 0, 4, 0, 2 * Math.PI);
			ctx.fill();
			ctx.stroke();
			// 画钻石
			for (let i = 0; i <= diamondNumber; i++) {
				ctx.restore();
				// 不能连着用 restore(),没有用!
				ctx.save();
				let angle = startAngle - (startAngle - endAngle) / diamondNumber * i;
				let startX = Math.cos(angle) * 130;
				let startY = -Math.sin(angle) * 130;
				ctx.translate(center[0] + startX, center[1] + startY);
				ctx.rotate(Math.PI / 2 - angle);
				let scale = 50;
				if (i < diamondNumber * 0.5) {
					scale = 0.5
				} else if (i < diamondNumber * 0.8) {
					scale = i / diamondNumber
				} else {
					scale = 1;
				}
				ctx.scale(scale, scale);
				let img;
				if (i <= value * diamondNumber / 100) {
					img = document.getElementById('beautiful-icon');
				} else {
					img = document.getElementById('beautiful-icon-light');
				}
				if (value === 0) {
					img = document.getElementById('beautiful-icon-light');
				}
				ctx.drawImage(img, 0, 0, diamondSize * 2, diamondSize * 2, -diamondSize, -diamondSize, diamondSize * 2, diamondSize * 2);
			}
			ctx.restore();
		}
	script>
	<script>
		beautiful_icon_base64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAUCAYAAACJfM0wAAACGklEQVQ4T52VTYiOURTHf/+NomxIPkpZsKEklK+NsCFjQdREksUwG1KancxkpdlgQZIUs0KzMNhIFjQ2ZDEppXxHImIhio7+4zx1553nfce8p5567rn3/u655/mf84jCIqIT6ABWADOBIeABMCDpl5dGxBTgALA5n4fAE2BQ0t0Kp+olInqAk+VBxft9YD/wG7gAbGqy7rCkM54bBUfEALC7WPwNeANMBxak/zPwB5id41fAd2ARMLXYu07SsCJia165mjsl6Uhxk1XARWBJ+q4BJySNZFAGny1u8RRYbXA/cDQ3DUna1njNiFgMXAZeSNpVMz8XeATMy7ntBl8B9qSjQ9LNuvxFxCxJn5rk1unsBY7nfLfB94D16Zgj6WOzza38EWElOWpbn8GngUPpmCHpa5vghcDz3NtpcHcm376Vkh63Ce4Czufe5QZbk3fSMUYRkzmgSOl7S7DS8Y2sOLN2Sro+SWj54fok9VbgUss/gR2Sbv8PPCL2AZdy7TNgg6QPZUm7nF3Wti/AMklvJ1CC1WRVVbZWknvHv5KuLCJuAVty/E7S/GbgiHCpvyzmfcvBajwGbGeDrkckLa2DR0QU/tG8luvGgWvglt9GSW5MPngNMNwKOi4VDWkpK/I1sDc729WJoC3BGZ27lgvI9gOYVkB7JLmB1VptKhoiPwicK3xu9l2SKom1B87I/RPwx3F3O1b+gppF/BdXfsvYA+llAgAAAABJRU5ErkJggg==';
		beautiful_icon_light_base64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAUCAYAAACJfM0wAAAC0klEQVQ4T52VTUgUYRjH//+xhIIIjCiD2PHrUhCRQV8XKZtdIzskBmJEdNCZhYogvEVGJ/GSiburEUF5qvCQmbub0qHQi9JBgiB0/IhEjMKgSNqZJ2Z2V8dtV9P39M7z8Xuf9/88L0N4lhkM1MGWahDlAHaA6CX47k8eu8va+xedUGmuzZ+eW2i0wSoAVSCGxZb3IkpPSWd0MI1jemPq/iYQLd6D0nsB3m4mriRsJkh5IEBltjhFeN0Xid53fC54Qg90k1LvCV6AyDTIbQBUt1LgKwkLgl2puEkAPwApA7hlqVLKCTUUH+KUrp21yV4P9F5ROHZj6SYN2hHm8aEA+1OVPLMs625J18CY8z3TeLrMUpRQ+hYEPvzk4lFOGIFWQm4mQewtCkfPZV5zqrFqn63YjwlMqOHYhUz/ZIO/EHkYEWCP47PEPs8JQ3tC8KJjUESqfZH4y2z6zV6t2lnY3j+fzefYxnWtWSFvp/wGTcP/BkCFq2N+Yndx2+BcruTV7FOGVm6DI06MLXKHZlBrg/CaWzE2FfjCfd83Ap4J+ksTgk9urrCOpq4ZIENJsBz2heOjGwGbhtYAsNPtlCiHOGX4K23gdQq2YiLWc0BaUgJf8q38MneOTSPwApBqt2pKrS8Uf74eqLdxjr4lkXizC86Y5d+0WaN2Rl/9D9zUA5dBeZScVnxkAifVrtis90m3gGhKwb5ZlIOlofjManBTD1SA4kxVkqvwuNoRHU6e4VlmUOuD8IzbWMHn4khsby6wqQdUUMwlKFmjhqI9S9+ZiSvmWmSsOBI/kA1uGn5J29O6euNWVJx2eOEARrdb1qmCroEFxz/ZGDgmigytBv1HihWyeF6k01+x5RIUZRchT9eCrgpOjqHfeThGCvQLwNZlDdmkhqOtuXqQVYqMynUA4eUmISGChqJwLDliOdaaYCdvXNfqSTaTmFfIW76O5V9QLvBfnb8g11oJ5jAAAAAASUVORK5CYII='
	script>

body>

html>

你可能感兴趣的:(写着玩)