1. 基本概念
1.1 角度与弧度
在讨论旋转之前,首先需要了解角度和弧度的概念:
- 角度:通常用度数表示,一个圆周为360度。
- 弧度:数学上更常用的角度单位,一个圆周为2π弧度。
在JavaScript中,大多数三角函数(如Math.sin()
和Math.cos()
)使用的是弧度而不是度数。因此,在进行旋转计算时,经常需要在两者之间进行转换。
转换公式:
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
function radiansToDegrees(radians) {
return radians * (180 / Math.PI);
}
1.2 旋转矩阵
在二维平面上,旋转可以通过旋转矩阵来描述。给定一个点 (x, y)
和旋转角度 θ
(以弧度表示),新的坐标 (x', y')
可以通过以下公式计算:
x' = x * cos(θ) - y * sin(θ)
y' = x * sin(θ) + y * cos(θ)
在三维空间中,旋转变得更加复杂,通常使用四元数或旋转矩阵来表示旋转。
2. 使用 CSS 实现旋转
2.1 CSS Transform 属性
CSS 提供了 transform
属性来实现元素的旋转。最常用的旋转方式是使用 rotate()
函数。
示例:
.rotate {
transform: rotate(45deg); /* 顺时针旋转45度 */
}
结合JavaScript动态设置:
const element = document.querySelector('.rotate');
element.style.transform = 'rotate(90deg)';
2.2 三维旋转
除了二维旋转,CSS还支持三维旋转,可以使用 rotateX()
, rotateY()
, rotateZ()
或 rotate3d()
函数。
示例:
.rotate3d {
transform: rotateX(45deg) rotateY(45deg) rotateZ(45deg);
}
3. 使用 Canvas 实现旋转
HTML5 的 <canvas>
元素提供了一个强大的绘图API,可以用来绘制和操作图像、形状等。在Canvas中,旋转主要通过 context.rotate()
方法实现。
3.1 基本旋转
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 保存当前状态
ctx.save();
// 平移到画布中心
ctx.translate(canvas.width / 2, canvas.height / 2);
// 旋转45度(弧度)
ctx.rotate(degreesToRadians(45));
// 绘制一个矩形
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
// 恢复到之前的变换状态
ctx.restore();
3.2 复杂变换
结合平移、缩放和旋转,可以实现复杂的变换效果。
示例:
ctx.save();
ctx.translate(100, 100); // 平移到指定位置
ctx.scale(2, 2); // 缩放
ctx.rotate(degreesToRadians(45)); // 旋转
ctx.fillStyle = 'red';
ctx.fillRect(-50, -50, 100, 100); // 绘制一个矩形
ctx.restore();
4. 使用 SVG 实现旋转
SVG(可缩放矢量图形)是一种基于XML的图形格式,广泛用于Web上的矢量图形绘制。SVG支持通过 transform
属性来实现旋转。
4.1 基本旋转
<svg width="200" height="200">
<rect x="50" y="50" width="100" height="100" fill="blue" transform="rotate(45, 100, 100)" />
</svg>
rotate(45, 100, 100)
表示将矩形绕其中心点 (100, 100)
旋转45度。
4.2 动态旋转
通过JavaScript动态修改SVG元素的 transform
属性,可以实现动画效果。
示例:
<svg id="mySvg" width="200" height="200">
<rect id="myRect" x="50" y="50" width="100" height="100" fill="blue" />
</svg>
<script>
const rect = document.getElementById('myRect');
let angle = 0;
function rotateRect() {
angle += 1;
if (angle >= 360) angle -= 360;
rect.setAttribute('transform', `rotate(${angle}, 100, 100)`);
requestAnimationFrame(rotateRect);
}
rotateRect();
</script>
5. 高级技巧
5.1 矩阵变换
在Canvas中,可以使用变换矩阵来实现更复杂的旋转和平移操作。context.setTransform()
和 context.transform()
方法允许你直接操作变换矩阵。
示例:
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 设置变换矩阵
ctx.setTransform(
Math.cos(degreesToRadians(45)), Math.sin(degreesToRadians(45)),
-Math.sin(degreesToRadians(45)), Math.cos(degreesToRadians(45)),
canvas.width / 2, canvas.height / 2
);
// 绘制一个矩形
ctx.fillStyle = 'green';
ctx.fillRect(-50, -50, 100, 100);
5.2 三维旋转
虽然CSS和Canvas支持三维旋转,但在WebGL中可以实现更复杂的三维图形和动画。WebGL是一个低级别的图形API,适用于高性能的3D渲染。
示例:
const vertexShaderSource = `
attribute vec4 a_position;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * a_position;
}
`;
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1); // 红色
}
`;
// 初始化WebGL上下文
const canvas = document.getElementById('myCanvas');
const gl = canvas.getContext('webgl');
// 创建着色器程序
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
}
gl.useProgram(program);
// 设置顶点数据
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
0, 0,
0, 0.5,
0.7, 0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// 创建旋转矩阵
function createRotationMatrix(angleInRadians) {
return [
Math.cos(angleInRadians), Math.sin(angleInRadians),
-Math.sin(angleInRadians), Math.cos(angleInRadians),
];
}
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
function render(time) {
time *= 0.001; // 将时间转换为秒
const angleInRadians = time * Math.PI * 2 / 3; // 三秒一圈
const rotationMatrix = createRotationMatrix(angleInRadians);
gl.uniformMatrix4fv(matrixLocation, false, new Float32Array([
...rotationMatrix, 0, 0,
0, 0, ...rotationMatrix, 0,
0, 0, 0, 0, 1
]));
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(render);
}
requestAnimationFrame(render);