一、Canvas基础
Canvas是HTML5提供的2D绘图API,通过JavaScript动态生成图形、图像及动画。其核心元素是<canvas>
标签,默认尺寸300×150像素,可通过width/height属性自定义。
<canvas id="myCanvas" width="800" height="600"></canvas>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d'); // 获取2D上下文
二、基本图形绘制
1. 矩形
fillRect(x,y,w,h)
:填充矩形strokeRect(x,y,w,h)
:描边矩形clearRect(x,y,w,h)
:清除区域
ctx.fillStyle = "#FF0000"; // 设置填充色(默认黑色)
ctx.fillRect(10, 10, 150, 100); // 红色填充矩形
ctx.strokeStyle = "red"; // 设置边框颜色(默认黑色)
ctx.lineWidth = 3; // 设置边框宽度
ctx.strokeRect(50, 50, 80, 80); // 红色边框矩形
ctx.clearRect(45, 45, 60, 60); // 擦除中心区域
2. 线条与多边形
路径操作需遵循beginPath() → 绘制 → fill/stroke
流程:
ctx.beginPath();
ctx.moveTo(20, 20); // 起点
ctx.lineTo(200, 50); // 直线
ctx.lineTo(20, 100);
ctx.closePath(); // 闭合路径
ctx.stroke(); // 描边三角形
3. 圆与圆弧
arc(x,y,r,s,e)
:圆 / 圆弧
x
和y
(圆心坐标)radius
(半径)startAngle
(起始角度)0
弧度对应三点钟方向(水平向右),这是 Canvas 的默认角度基准点。
endAngle
(结束角度)Math.PI/2
表示 90 度(正上方)。Math.PI
表示 180 度(九点钟方向)。Math.PI * 2
表示 360 度,与startAngle=0
组合时绘制完整圆形。
counterclockwise
(绘制方向):未显式指定false
(默认):顺时针方向绘制(从startAngle
到endAngle
)。true
:逆时针方向绘制。
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI*2); // 圆心(100,100),半径50
ctx.fillStyle = "blue";
ctx.fill(); // 填充圆形
4. 颜色与样式
// 渐变效果
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, "red");
gradient.addColorStop(1, "blue");
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100); // 红到蓝渐变填充
三、贝塞尔曲线
1. 二次贝塞尔曲线
quadraticCurveTo(cpX, cpY, endX, endY)
控制点决定曲线弧度:
ctx.moveTo(50, 200);
ctx.quadraticCurveTo(150, 50, 250, 200);
ctx.stroke(); // 绘制U型曲线
2. 三次贝塞尔曲线
bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, endX, endY)
双控制点实现复杂曲线:
ctx.moveTo(50, 50);
ctx.bezierCurveTo(20,100, 180,100, 150,50);
ctx.stroke(); // S型曲线
四、鼠标操作
1. 事件监听
canvas.addEventListener('mousedown', startDrawing); // 触发绘制开始,记录起始坐标
canvas.addEventListener('mousemove', draw); // 实时跟踪鼠标轨迹,绘制动态路径
canvas.addEventListener('mouseup', stopDrawing); // 结束绘制,重置状态
2. 坐标转换
鼠标事件返回的坐标需转换为 Canvas 坐标系:
function getCanvasPos(e) {
const rect = canvas.getBoundingClientRect();
return {
x: e.clientX - rect.left * (canvas.width/rect.width),
y: e.clientY - rect.top * (canvas.height/rect.height)
};
}
3. 绘制轨迹示例
let isDrawing = false;
function startDrawing(e) {
isDrawing = true;
const pos = getCanvasPos(e);
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
}
function draw(e) {
if (!isDrawing) return;
const pos = getCanvasPos(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}
五、动画实现
1. 动画循环
使用requestAnimationFrame
优化性能:
function animate() {
// 1. 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 2. 更新对象状态(位置、颜色等)
update();
// 3. 绘制新帧
draw();
// 4. 递归调用
requestAnimationFrame(animate);
}
animate(); // 启动动画
2. 控制动画速度
使用时间差(Delta Time)确保动画速度不受帧率影响。
let lastTime = 0;
function animate(timestamp) {
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
update(deltaTime);
draw();
requestAnimationFrame(animate);
}
3. 运动示例(弹跳球)
let x = 100, y = 100, dx = 2, dy = -2;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fill();
}
function update() {
if(x < 0 || x > canvas.width) dx = -dx;
if(y < 0 || y > canvas.height) dy = -dy;
x += dx;
y += dy;
}
function animate() {
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall();
update();
requestAnimationFrame(animate);
}
六、高级技巧
1. 渐变与阴影
// 线性渐变
const gradient = ctx.createLinearGradient(0,0,200,0);
gradient.addColorStop(0, "red");
gradient.addColorStop(1, "white");
ctx.fillStyle = gradient;
// 阴影效果
ctx.shadowColor = "rgba(0,0,0,0.5)";
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 5;
2. 物理效果
重力与反弹:添加重力、碰撞检测等效果。
class Ball {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
this.vy = 0; // 垂直速度
this.gravity = 0.5;
this.bounce = -0.8; // 反弹系数
}
update() {
this.vy += this.gravity;
this.y += this.vy;
// 底部碰撞检测
if (this.y + this.radius > canvas.height) {
this.y = canvas.height - this.radius;
this.vy *= this.bounce;
}
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
}
}
3. 性能优化
- 离屏 Canvas:预渲染复杂图形到离屏 Canvas。
- 减少重绘区域:仅重绘变化的区域。
- 避免频繁操作:减少
ctx.save()
和ctx.restore()
的调用。 - 使用双缓冲:在内存中绘制完成后一次性渲染到主 Canvas。
评论 (0)