前言
大家好,我是汪小成。最近在学习Canvas
。这篇文章是我学习Canvas变形操作
时记的笔记,欢迎大家审阅。
简介
在Canvas
中有如下三个基本变形操作:
- 图形平移:
translate(x, y)
- 图形缩放:
scale(x, y)
- 图形旋转:
rotate(deg)
图形平移
在Canvas
中,我们使用translate()
方法来平移图形。图形平移
指的是将图形沿x轴或y轴进行直线运行。平移不会改变图形的形状和大小。
语法
ctx.translate(x, y);
说明
x
表示图形在x轴
方向移动的距离,默认单位为px
。当x
为正数时,图形沿x轴
正方向移动;当x
为负数时,图形沿x轴
反方向移动。
y
表示图形在y轴
方向移动的距离,默认单位为px
。当y
为正数时,图形沿y轴
正方向移动;当y
为负数时,图形沿y轴
反方向移动。
示例一:简单示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>平移图形</title>
</head>
<body>
<canvas width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(30, 30, 50, 40);
ctx.translate(50, 50);
ctx.fillStyle = "yellow";
ctx.fillRect(30, 30, 50, 40);
};
</script>
</body>
</html>
效果图:
说明:
上面的示例中,我们先绘制了一个红色的矩形,然后调用translate()
方法将矩形在x
轴方向和y
轴方向分别平移50px,即黄色矩形的位置。平移操作,本质上来讲,是平移坐标系。
还有一点需要注意的是,translate()
方法必须在fillRect()
方法之前调用才有效。
先进行平移操作,然后绘制需要平移的图形。
示例二:连续平移
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>连续平移</title>
</head>
<body>
<canvas width="300" height="250"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(30, 30, 50, 40);
ctx.save();
ctx.translate(50, 50);
ctx.fillStyle = "yellow";
ctx.fillRect(30, 30, 50, 40);
ctx.restore();
ctx.save();
ctx.translate(100, 100);
ctx.fillStyle = "blue";
ctx.fillRect(30, 30, 50, 40);
ctx.restore();
};
</script>
</body>
</html>
效果图:
说明:
在平移图形前,我们调用了context.save()
方法保存当前状态;在平移操作完成后,我们调用context.restore()
方法恢复之前保存的状态`。这么做的目的是让每一次平移操作都以最初的状态为最根本的参照物。
图形缩放
在Canvas
中,我们使用scale()
方法对图形进行缩放操作。这里的“缩放”包含“缩小”和“放大”两层含义。
语法
ctx.scale(x, y);
说明
x
表示图形在x轴
方向的缩放倍数。y
表示图形在y轴
方向的缩放倍数。x和y一般情况下都是正数。
当x或y取值为0~1之间时,图形会缩小;当x或y取值大于1时,图形会被放大。
示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形缩放</title>
</head>
<body>
<canvas width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
// 1、获取 Canvas 对象
var canvas = document.getElementById("canvas");
// 2、获取上下文环境对象
var ctx = canvas.getContext("2d");
// 绘制图形
ctx.fillStyle = "#faeab3";
ctx.fillRect(30, 30, 60, 60);
// 缩放操作:将图形放大1.5倍
ctx.scale(1.5, 1.5);
ctx.fillStyle = "#ff0000";
ctx.fillRect(30, 30, 60, 60);
};
</script>
</body>
</html>
效果图:
本示例中,我们使用scale(1.5, 1.5)将图形放大了1.5倍。从效果图中,我们可以看出,图形左上角的坐标也放大了1.5位。是因为scale()方法除了会改变图形的大小之外,还会改变诸如线条宽度、左上角坐标等其他属性。
图形旋转
在Canvas
中,我们使用rotate()
方法旋转图形。
语法
ctx.rotate(angle);
说明
参数angle
表示图形的旋转角度。取值范围为 -Math.PI * 2 ~ Math.PI * 2。当angle
小于0时,图形顺时针旋转;当angle
大小0时,图形逆时针旋转。
示例一:图形旋转简单示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形旋转</title>
</head>
<body>
<canvas width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
// 1、获取 Canvas 对象
var canvas = document.getElementById("canvas");
// 2、获取上下文环境对象
var ctx = canvas.getContext("2d");
// 绘制图形
ctx.fillStyle = "#ff0000";
ctx.fillRect(100, 30, 50, 20);
ctx.rotate(30 * Math.PI /180);
// 为了方便比较,我们重新绘制了原来图形
ctx.fillStyle = "#faeab3";
ctx.fillRect(50, 30, 50, 20);
};
</script>
</body>
</html>
效果图:
默认情况下,图形旋转时是以Canvas
坐标原点为旋转中心的。如果我们想要以(x, y)
为中心旋转,需要先使用translate(x, y)
平移图形,然后旋转图形就是以(x, y)
为中心旋转了。
示例二:旋转的半圆
这个示例相对来说有点复杂,我们先来看下效果图。
实现步骤:
- 绘制半圆;
- 让半圆旋转起来;
- 选取不同的圆心;
- 绘制多个半圆,并让这些半圆旋转起来。
步骤1、绘制半圆
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 4, 0, Math.PI, true);
ctx.strokeStyle = "white";
ctx.stroke();
步骤2、让半圆旋转起来
// 画布尺寸
let size = 800;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
// 半圆开始绘制的角度,用于控制半圆旋转
let angle = 0;
function draw() {
window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, size, size);
console.log("angle: " + angle);
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 4, angle, Math.PI + angle, true);
ctx.strokeStyle = "white";
ctx.stroke();
angle += 0.02;
}
window.requestAnimationFrame(draw);
步骤3、选取不同的圆心
let size = 800;
// 圆心的数量
let num = 8;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
// 画布*位置
var center = {
x: canvas.width / 2,
y: canvas.height / 2,
};
// 半径
let radius = 200;
// 初始角度
let angle = 0;
(function frame() {
ctx.fillStyle = "#ff0000";
for (let i = 0; i < num; i++) {
const x = center.x + radius * Math.cos(Math.PI * 0.25 * i);
const y = center.y + radius * Math.sin(Math.PI * 0.25 * i);
// 圆心没有必要绘制出来,这里只是为了便于展示。
ctx.beginPath();
ctx.arc(x, y, 12, 0, 2 * Math.PI, true);
ctx.fill();
}
})();
步骤4、绘制多个半圆,并让这些半圆旋转起来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形旋转</title>
</head>
<body>
<canvas ></canvas>
<script>
window.onload = function () {
let size = 800;
let num = 8;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
var center = {
x: canvas.width / 2,
y: canvas.height / 2,
};
// 半径
let radius = 200;
// 初始角度
let angle = 0;
(function frame() {
window.requestAnimationFrame(frame);
// 拖尾效果
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#ff0000";
for (let i = 0; i < num; i++) {
const x = center.x + radius * Math.cos(Math.PI * 0.25 * i);
const y = center.y + radius * Math.sin(Math.PI * 0.25 * i);
// 绘制圆形
ctx.beginPath();
ctx.arc(
x,
y,
size / 4,
angle + Math.PI * 0.25 * i,
Math.PI + angle + Math.PI * 0.25 * i,
false
);
ctx.lineWidth = 3;
ctx.strokeStyle = "hsl(" + angle * 60 + "deg,80%,50%)";
ctx.stroke();
angle += 0.008;
}
})();
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: black;
display: flex;
vertical-align: middle;
justify-content: center;
}
</style>
</body>
</html>
上面的这段代码就是“旋转的半圆”示例程序的完整代码了。
附:清空画布&拖尾效果
清空画布
在Canvas
中,我们使用clearRect()
方法清空整个画布。
语法:
ctx.clearRect(0, 0, canvas.width, canvas.height);
拖尾效果
我们在绘制一些动画效果时有时候可能会需要使用拖尾效果让动画更美观一点。拖尾效果可以通过如下代码实现:
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);