HTML画布标签

在学习画布标签之前,需要对 ”CSS 样式 + JavaScript 行为“ 有一定的了解,这样才具备 Canvas 画布标签 API 的使用能力,Canvas 通过 JavaScript 对其 API 的引用处理
<canvas> 标签用于定义图形容器,容器本身是没有画图能力的,但我们可以使用脚本来绘制图形

创建画布

一个画布在网页中是一个矩形框,通过 <canvas> 元素来绘制,默认情况下 <canvas> 元素没有边框和内容,通过 style 样式定义边框

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
</body>
</html>

尝试通过 style 来给画布定义一个红色背景

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000; background-color: #f00;"></canvas>
</body>
</html>

如果不让画布的背景全部为红色,而是改成四分之一变成红色,这里就需要通过画布填充来实现啦

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.fillStyle="#ff0000";
		contxt.fillRect(0, 0, 100, 50);
	</script>
</body>
</html>
  • fillStyle 设置画布的填充颜色、渐变、图案,默认为 #000000
  • fillRect 设置画布的填充矩形对角坐标,前两个值为起始坐标点,后两个值为对角坐标点

绘制路径

在Canvas上画线,我们将使用以下两种方法:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.moveTo(0, 0);
		contxt.lineTo(200, 100);
		contxt.stroke();
	</script>
</body>
</html>
  • moveTo(x, y) 定义线条开始坐标
  • lineTo(x, y) 定义线条结束坐标
  • stroke() 表示执行划线操作
  • strokeStyle 定义画笔的颜色
  • arc() 定义圆形弧盘
  • arcTo() 自定义弧线走势

通过重复 moveTo 组合 lineTo 绘制多条线条,如下画两条红色的平行线

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.moveTo(0, 0);
		contxt.lineTo(200, 100);
		contxt.moveTo(0, 50);
		contxt.lineTo(200, 150);
		contxt.strokeStyle = '#ff0000';
		contxt.stroke();
	</script>
</body>
</html>

arc 前两个参数值表示圆心坐标,第三个值为圆半径,第四、五个值为起始、结束弧度,第六个值布尔类型值,true 表示逆时针画弧,false 表示顺时针画弧

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.arc(100, 50, 40, 0, 2 * Math.PI);
		contxt.stroke();
	</script>
</body>
</html>

arcTo 前两个表示起始坐标,第三、四个表示结束坐标,第五个值表示画弧半径

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.moveTo(50, 50);
		contxt.arcTo(200, 50, 200, 200, 100);
		contxt.lineTo(200, 200);
		contxt.stroke();
	</script>
</body>
</html>

绘制文本

使用 canvas 绘制文本,重要的属性和方法如下:

  • font - 定义字体
  • fillText(text, x, y) - 在 canvas 上绘制实心的文本
  • strokeText(text, x, y) - 在 canvas 上绘制空心的文本
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		contxt.font = "14px Arial";
		contxt.fillText("好好学习", 10, 20);
		contxt.strokeText("天天向上", 10, 40);
	</script>
</body>
</html>

绘制渐变

渐变可以填充在矩形, 圆形, 线条, 文本等等, 各种形状可以自己定义不同的颜色。

以下有两种不同的方式来设置Canvas渐变:

  • createLinearGradient(x, y, x1, y1) - 创建线条渐变
  • createRadialGradient(x, y, r, x1, y1, r1) - 创建一个径向/圆渐变
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		var gradit = contxt.createLinearGradient(0, 0, 200, 0);
		gradit.addColorStop(0, "#ff0000");
		gradit.addColorStop(1, "#ffffff");
		contxt.fillStyle = gradit;
		contxt.fillRect(10, 10, 150, 80);
	</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<canvas id="canvas" width="200" height="100" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		var gradit = contxt.createRadialGradient(75, 50, 5, 90, 60, 100);
		gradit.addColorStop(0, "#ff0000");
		gradit.addColorStop(1, "#ffffff");
		contxt.fillStyle = gradit;
		contxt.fillRect(10, 10, 150, 80);
	</script>
</body>
</html>

绘制图像

把一幅图像放置到画布上, 使用以下方法:

  • drawImage(image, x, y)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>画布标签</title>
</head>
<body>
	<p>Image to use:</p>
	<img id="scream" src="https://www.runoob.com/try/demo_source/img_the_scream.jpg" alt="The Scream" width="220" height="277" />
	<p>Canvas:</p>
	<canvas id="canvas" width="250" height="300" style="border:1px solid #000;"></canvas>
	<script type="text/javascript">
		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		var images = document.getElementById("scream");
		images.onload = () => contxt.drawImage(images, 10, 10);
	</script>
</body>
</html>

画布实战

<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8" />
	<title>画布标签</title>
	<style type="text/css">
		body {
			padding: 0;
			margin: 0;
			background-color: rgba(0, 0, 0, 0.1)
		}

		canvas {
			display: block;
			margin: 50px auto;
		}
	</style>
</head>

<body>
	<canvas id="canvas" width="300" height="300"></canvas>
	<script type="text/javascript">
		/*绘制表盘*/
		const drawDial = (ctx) => {
			let pi = Math.PI;

			ctx.clearRect(0, 0, 300, 300); //清除所有内容
			ctx.save();

			ctx.translate(150, 150); //一定坐标原点到原来的中心
			ctx.beginPath();
			ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周
			ctx.stroke();
			ctx.closePath();

			for (let i = 0; i < 60; i++) {//绘制刻度。
				ctx.save();
				ctx.rotate(-pi / 2 + i * pi / 30);  //旋转坐标轴。坐标轴x的正方形从 向上开始算起
				ctx.beginPath();
				ctx.moveTo(110, 0);
				ctx.lineTo(140, 0);
				ctx.lineWidth = i % 5 ? 2 : 4;
				ctx.strokeStyle = i % 5 ? "blue" : "red";
				ctx.stroke();
				ctx.closePath();
				ctx.restore();
			}
			ctx.restore();
		}

		/*绘制时针、或分针、或秒针
		* 参数1:要绘制的针的角度
		* 参数2:要绘制的针的长度
		* 参数3:要绘制的针的宽度
		* 参数4:要绘制的针的颜色
		* 参数4:ctx
		* */
		const drawHand = (angle, len, width, color, ctx) => {
			ctx.save();
			ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心
			ctx.rotate(-Math.PI / 2 + angle);  //旋转坐标轴。 x轴就是针的角度
			ctx.beginPath();
			ctx.moveTo(-4, 0);
			ctx.lineTo(len, 0);  // 沿着x轴绘制针
			ctx.lineWidth = width;
			ctx.strokeStyle = color;
			ctx.lineCap = "round";
			ctx.stroke();
			ctx.closePath();
			ctx.restore();
		}

		/*绘制时分秒针*/
		const drawAllHands = (ctx) => {
			let time = new Date();

			let s = time.getSeconds();
			let m = time.getMinutes();
			let h = time.getHours();

			let pi = Math.PI;
			let secondAngle = pi / 180 * 6 * s;  //计算出来s针的弧度
			let minuteAngle = pi / 180 * 6 * m + secondAngle / 60;  //计算出来分针的弧度
			let hourAngle = pi / 180 * 30 * h + minuteAngle / 12;  //计算出来时针的弧度

			drawHand(hourAngle, 60, 6, "red", ctx);  //绘制时针
			drawHand(minuteAngle, 106, 4, "green", ctx);  //绘制分针
			drawHand(secondAngle, 129, 2, "blue", ctx);  //绘制秒针
		}

		const draw = (ctx) => {
			requestAnimationFrame(function step() {
				drawDial(ctx); //绘制表盘
				drawAllHands(ctx); //绘制时分秒针
				requestAnimationFrame(step);
			});
		}

		var canvas = document.getElementById('canvas');
		var contxt = canvas.getContext('2d');
		draw(contxt);
	</script>
</body>

</html>