<canvas>-图形绘制画布
<canvas>
是 HTML5 引入的一个强大标签,用于在网页上动态绘制图形、动画或交互式内容。它通过 JavaScript 提供了一套完整的绘图 API,支持像素级操作,适合游戏开发、数据可视化等场景。
<canvas>
的基本用法
<canvas>
标签本身只是一个容器,需要通过 JavaScript 来绘制内容。它的基本语法如下:
<canvas id="myCanvas" width="500" height="300"></canvas>
width
和 height
属性定义了画布的尺寸。如果不设置,默认宽度为 300px,高度为 150px。建议始终明确设置这些属性,避免 CSS 缩放导致的失真。
获取绘图上下文
要在 <canvas>
上绘图,首先需要获取绘图上下文(rendering context)。2D 绘图上下文是最常用的:
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
getContext('2d')
返回一个 CanvasRenderingContext2D 对象,提供了所有 2D 绘图方法。
绘制基本形状
矩形
Canvas 提供了三种绘制矩形的方法:
// 填充矩形
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 75);
// 描边矩形
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.strokeRect(200, 50, 100, 75);
// 清除矩形区域
ctx.clearRect(80, 80, 40, 20);
路径绘制
复杂形状需要通过路径(path)来创建:
// 绘制三角形
ctx.beginPath();
ctx.moveTo(100, 100); // 起点
ctx.lineTo(150, 50);
ctx.lineTo(200, 100);
ctx.closePath(); // 自动闭合路径
ctx.stroke();
// 绘制圆形
ctx.beginPath();
ctx.arc(300, 200, 50, 0, Math.PI * 2); // x, y, 半径, 起始角, 结束角
ctx.fillStyle = 'green';
ctx.fill();
样式和颜色
Canvas 提供了丰富的样式设置选项:
// 线性渐变
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'yellow');
ctx.fillStyle = gradient;
ctx.fillRect(50, 150, 200, 100);
// 阴影效果
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.shadowBlur = 10;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.fillRect(300, 150, 100, 100);
文本绘制
Canvas 可以绘制文本,并支持各种文本样式:
ctx.font = '30px Arial';
ctx.fillStyle = 'purple';
ctx.textAlign = 'center';
ctx.fillText('Hello Canvas', canvas.width/2, 50);
// 描边文本
ctx.font = 'bold 40px sans-serif';
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.strokeText('Stroke Text', 150, 120);
图像操作
Canvas 可以绘制、缩放和裁剪图像:
const img = new Image();
img.src = 'example.jpg';
img.onload = function() {
// 绘制原始图像
ctx.drawImage(img, 10, 10);
// 缩放绘制
ctx.drawImage(img, 150, 10, 100, 80);
// 裁剪并绘制部分图像
ctx.drawImage(img, 50, 50, 100, 100, 300, 10, 100, 100);
};
动画实现
通过结合 requestAnimationFrame
可以实现流畅的动画:
let x = 0;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x, 100, 50, 50);
x += 2;
if (x > canvas.width) x = 0;
requestAnimationFrame(animate);
}
animate();
高级技巧
保存和恢复状态
Canvas 的状态(样式、变形等)可以通过栈来管理:
ctx.fillStyle = 'red';
ctx.save(); // 保存当前状态
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100);
ctx.restore(); // 恢复之前保存的状态
ctx.fillRect(200, 50, 100, 100); // 将使用红色填充
变形操作
Canvas 支持平移、旋转和缩放等变形操作:
ctx.fillStyle = 'orange';
ctx.translate(150, 150); // 移动原点
ctx.rotate(Math.PI / 4); // 旋转45度
ctx.fillRect(-50, -50, 100, 100); // 以新原点为中心绘制
像素操作
可以直接操作像素数据:
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 反色处理
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // R
data[i+1] = 255 - data[i+1]; // G
data[i+2] = 255 - data[i+2]; // B
}
ctx.putImageData(imageData, 0, 0);
性能优化
对于复杂的 Canvas 应用,性能优化很重要:
- 分层渲染:使用多个重叠的
<canvas>
元素,将静态内容和动态内容分开 - 避免浮点坐标:使用整数坐标可以避免子像素渲染带来的模糊
- 批量操作:尽量减少状态改变(如样式变化)
- 离屏Canvas:预渲染复杂图形到隐藏的Canvas
// 离屏Canvas示例
const offscreenCanvas = document.createElement('canvas');
const offscreenCtx = offscreenCanvas.getContext('2d');
// 在离屏Canvas上预渲染复杂图形
offscreenCtx.fillRect(0, 0, 100, 100);
// 在主Canvas上绘制预渲染的内容
ctx.drawImage(offscreenCanvas, 0, 0);
交互实现
Canvas 本身没有内置的交互功能,但可以通过事件监听实现:
canvas.addEventListener('click', function(event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
if (ctx.isPointInPath(x, y)) {
alert('点击了图形!');
}
});
WebGL 集成
<canvas>
还支持通过 WebGL 进行 3D 图形渲染:
const gl = canvas.getContext('webgl');
if (gl) {
// WebGL 代码
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
实际应用案例
绘制图表
// 简单柱状图
const data = [30, 60, 90, 40, 70];
const barWidth = 50;
const spacing = 20;
ctx.fillStyle = 'steelblue';
data.forEach((value, index) => {
const x = index * (barWidth + spacing);
const height = value * 2;
ctx.fillRect(x, canvas.height - height, barWidth, height);
});
画板应用
let isDrawing = false;
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
function startDrawing(e) {
isDrawing = true;
draw(e);
}
function draw(e) {
if (!isDrawing) return;
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.strokeStyle = '#000';
ctx.lineTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
}
function stopDrawing() {
isDrawing = false;
ctx.beginPath();
}
兼容性和限制
虽然现代浏览器都支持 <canvas>
,但仍需注意:
- 旧版IE(8及以下)不支持
- 画布内容不是DOM的一部分,无法通过CSS选择器访问
- 绘制大量对象时可能出现性能问题
- 高DPI设备上可能出现模糊,需要特殊处理:
// 处理高DPI设备
const dpr = window.devicePixelRatio || 1;
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * dpr;
canvas.height = canvas.height * dpr;
ctx.scale(dpr, dpr);
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:<svg>-SVG矢量图形
下一篇:<map>-图像映射