详细讲一下Canvas标签的基础使用和应用场景
最近收到私信,发现很多同学对Canvas标签非常不熟悉,甚至连听都没听过,这篇文章就带大家好好了解一下这个原生标签Canvas。
1.基础设置
<!-- 创建Canvas元素 -->
<!-- width和height设置画布大小,不要用CSS设置,会导致画面模糊 -->
<canvas id="myCanvas" width="500" height="300"></canvas>
<script>
// 获取Canvas元素
const canvas = document.getElementById('myCanvas');
// 获取绘图上下文,'2d'表示二维绘图
const ctx = canvas.getContext('2d');
</script>
2. 基础图形绘制
/**
* 基础图形绘制类
* 包含最常用的绘图方法
*/
class BasicDrawing {
constructor(canvasId) {
// 初始化画布和上下文
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
}
// 绘制矩形
drawRectangle() {
// 设置填充颜色
this.ctx.fillStyle = 'red';
// 绘制填充矩形
// 参数含义:x坐标, y坐标, 宽度, 高度
this.ctx.fillRect(10, 10, 100, 80);
// 设置边框颜色
this.ctx.strokeStyle = 'blue';
// 设置边框宽度
this.ctx.lineWidth = 2;
// 绘制边框矩形
this.ctx.strokeRect(130, 10, 100, 80);
}
// 绘制圆形
drawCircle() {
// 开始一个新的绘制路径
this.ctx.beginPath();
// 绘制圆形
// 参数:圆心x, 圆心y, 半径, 开始角度, 结束角度
this.ctx.arc(50, 50, 30, 0, Math.PI * 2);
// 设置填充颜色
this.ctx.fillStyle = 'green';
// 填充
this.ctx.fill();
}
// 绘制线条
drawLine() {
this.ctx.beginPath();
// 移动到起点
this.ctx.moveTo(10, 10);
// 画线到终点
this.ctx.lineTo(200, 200);
// 设置线条颜色
this.ctx.strokeStyle = 'black';
// 设置线条宽度
this.ctx.lineWidth = 2;
// 绘制线条
this.ctx.stroke();
}
}
// 使用示例
const drawing = new BasicDrawing('myCanvas');
drawing.drawRectangle();
3. 动画效果
/**
* 简单动画示例
* 展示如何制作移动的小球
*/
class SimpleAnimation {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
// 小球的初始位置和速度
this.x = 50;
this.y = 50;
this.speed = 2;
this.radius = 20;
}
// 绘制小球
drawBall() {
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
this.ctx.fillStyle = 'red';
this.ctx.fill();
}
// 更新小球位置
update() {
// 移动小球
this.x += this.speed;
// 如果碰到边界就反弹
if (this.x + this.radius > this.canvas.width || this.x - this.radius < 0) {
this.speed = -this.speed;
}
}
// 开始动画
animate() {
// 清除整个画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制和更新
this.drawBall();
this.update();
// 请求下一帧动画
// requestAnimationFrame比setTimeout更适合动画
requestAnimationFrame(() => this.animate());
}
}
// 使用示例
const animation = new SimpleAnimation('myCanvas');
animation.animate();
4.简单的画板功能
/**
* 简单画板
* 允许用户用鼠标在画布上绘画
*/
class SimpleDrawingBoard {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
// 是否正在绘制
this.isDrawing = false;
// 初始化画板设置
this.initializeBoard();
}
// 初始化画板
initializeBoard() {
// 设置线条样式
this.ctx.strokeStyle = 'black';
this.ctx.lineWidth = 2;
this.ctx.lineCap = 'round'; // 让线条末端圆润
// 添加鼠标事件监听
this.canvas.addEventListener('mousedown', (e) => this.startDrawing(e));
this.canvas.addEventListener('mousemove', (e) => this.draw(e));
this.canvas.addEventListener('mouseup', () => this.stopDrawing());
this.canvas.addEventListener('mouseout', () => this.stopDrawing());
}
// 开始绘制
startDrawing(e) {
this.isDrawing = true;
// 移动到鼠标位置
this.ctx.beginPath();
this.ctx.moveTo(
e.clientX - this.canvas.offsetLeft,
e.clientY - this.canvas.offsetTop
);
}
// 绘制
draw(e) {
if (!this.isDrawing) return;
// 画线到当前鼠标位置j
this.ctx.lineTo(
e.clientX - this.canvas.offsetLeft,
e.clientY - this.canvas.offsetTop
);
this.ctx.stroke();
}
// 停止绘制
stopDrawing() {
this.isDrawing = false;
}
// 清除画布
clear() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
// 使用示例
const drawingBoard = new SimpleDrawingBoard('myCanvas');
// 添加清除按钮
const clearButton = document.createElement('button');
clearButton.textContent = '清除画布';
clearButton.onclick = () => drawingBoard.clear();
document.body.appendChild(clearButton);
5.图片处理
/**
* 图片处理类
* 展示如何在Canvas中处理图片
*/
class ImageProcessor {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
}
// 加载并显示图片
loadImage(imageUrl) {
// 创建新的图片对象
const img = new Image();
// 图片加载完成后的处理
img.onload = () => {
// 将图片绘制到画布上
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
};
// 设置图片源
img.src = imageUrl;
}
// 添加简单的灰度效果
applyGrayscale() {
// 获取画布上的图像数据
const imageData = this.ctx.getImageData(
0, 0,
this.canvas.width,
this.canvas.height
);
const data = imageData.data;
// 处理每个像素
for (let i = 0; i < data.length; i += 4) {
// 计算灰度值
const gray = (data[i] + data[i + 1] + data[i + 2]) / 3;
// 设置RGB值为灰度值
data[i] = gray; // R
data[i + 1] = gray; // G
data[i + 2] = gray; // B
// data[i + 3] 是透明度,保持不变
}
// 将处理后的图像数据放回画布
this.ctx.putImageData(imageData, 0, 0);
}
}
// 使用示例
const processor = new ImageProcessor('myCanvas');
processor.loadImage('path/to/image.jpg');
// 添加灰度效果按钮
const grayscaleButton = document.createElement('button');
grayscaleButton.textContent = '添加灰度效果';
grayscaleButton.onclick = () => processor.applyGrayscale();
document.body.appendChild(grayscaleButton);
使用建议:
1.性能优化
- 避免在循环中重复获取canvas和context
- 使用requestAnimationFrame而不是setInterval
- 适当使用缓存
2.常见问题解决
- 画布模糊:使用正确的尺寸设置
- 图片跨域:确保图片允许跨域访问
- 性能问题:控制重绘频率
3.适用场景
- 简单游戏开发
- 图表绘制
- 图片处理
- 签名板
- 动画效果
4. 初学者注意事项
- 先掌握基础图形绘制
- 理解坐标系统
- 多练习动画效果
- 从简单项目开始
5.进阶方向
- 复杂动画效果
- 碰撞检测
- 粒子效果
- 3D效果(使用WebGL)