您现在的位置是:网站首页 > <canvas>-图形绘制画布文章详情
<canvas>-图形绘制画布
陈川
【
HTML
】
53638人已围观
5847字
<canvas>
是 HTML5 引入的一个原生标签,用于通过 JavaScript 动态绘制图形、动画或交互式可视化内容。它提供了一块空白画布,开发者可以通过 API 直接操作像素,实现从简单几何图形到复杂游戏场景的渲染。
<canvas>
的基本用法
<canvas>
标签本身只是一个容器,需要通过 JavaScript 获取其上下文(context)才能进行绘制。基本语法如下:
<canvas id="myCanvas" width="500" height="300"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d'); // 获取 2D 渲染上下文
</script>
如果不设置 width
和 height
属性,画布默认大小为 300px × 150px。通过 CSS 设置尺寸会导致画布内容拉伸,建议始终使用属性定义画布大小。
绘制基础图形
矩形绘制
<canvas>
提供了三种矩形绘制方法:
ctx.fillRect(50, 50, 100, 80); // 绘制填充矩形 (x, y, width, height)
ctx.strokeRect(200, 50, 100, 80); // 绘制描边矩形
ctx.clearRect(75, 75, 50, 30); // 清除矩形区域
路径绘制
复杂图形需要通过路径 API 构建:
ctx.beginPath(); // 开始新路径
ctx.moveTo(100, 100); // 移动笔触到起点
ctx.lineTo(200, 100); // 绘制直线
ctx.arc(150, 150, 50, 0, Math.PI); // 绘制半圆
ctx.closePath(); // 闭合路径
ctx.stroke(); // 描边路径
样式与颜色控制
填充与描边样式
ctx.fillStyle = '#FF5733'; // 设置填充色
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)'; // 半透明描边色
ctx.lineWidth = 5; // 线宽
ctx.lineCap = 'round'; // 线端样式 (butt|round|square)
渐变与图案
// 线性渐变
const gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
// 图案填充
const img = new Image();
img.src = 'texture.png';
img.onload = () => {
const pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
};
文本渲染
<canvas>
支持基础文本绘制:
ctx.font = 'bold 24px Arial'; // 字体设置
ctx.fillText('Hello Canvas', 50, 50); // 填充文本
ctx.strokeText('Outline Text', 50, 100); // 描边文本
// 文本对齐方式
ctx.textAlign = 'center'; // start|end|left|right|center
ctx.textBaseline = 'middle'; // top|hanging|middle|alphabetic|ideographic|bottom
图像操作
可以在画布上绘制图像并处理:
const img = new Image();
img.src = 'photo.jpg';
img.onload = () => {
// 基本绘制
ctx.drawImage(img, 0, 0);
// 缩放绘制
ctx.drawImage(img, 100, 100, 200, 150);
// 切片绘制
ctx.drawImage(img,
10, 10, 100, 100, // 源图像切片区域
200, 200, 150, 150 // 画布目标区域
);
};
变形与合成
坐标变换
ctx.save(); // 保存当前状态
ctx.translate(100, 100); // 移动原点
ctx.rotate(Math.PI/4); // 旋转45度
ctx.scale(1.5, 0.8); // 缩放
ctx.fillRect(0, 0, 50, 50); // 绘制变形后的矩形
ctx.restore(); // 恢复之前状态
图像合成
ctx.globalAlpha = 0.7; // 全局透明度
ctx.globalCompositeOperation = 'xor'; // 合成模式
// 常见模式: source-over, destination-over, multiply, screen, overlay等
动画实现
通过 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) {
requestAnimationFrame(animate);
}
}
animate();
性能优化技巧
-
离屏渲染:复杂图形先在内存中的 canvas 绘制
const offscreen = document.createElement('canvas'); const offCtx = offscreen.getContext('2d'); // ...在offscreen上绘制... ctx.drawImage(offscreen, 0, 0);
-
批量操作:减少状态变更
// 不好:频繁改变样式 ctx.fillStyle = 'red'; ctx.fillRect(0,0,50,50); ctx.fillStyle = 'blue'; ctx.fillRect(60,0,50,50); // 好:批量绘制同样式图形 ctx.fillStyle = 'red'; ctx.fillRect(0,0,50,50); ctx.fillRect(100,0,50,50);
-
分层渲染:静态内容与动态内容分开绘制
交互实现
通过事件监听实现画布交互:
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI*2);
ctx.fill();
});
高级特性
像素级操作
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 修改像素数据 (RGBA格式)
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // 红色通道反相
data[i+1] = 255 - data[i+1]; // 绿色通道反相
}
ctx.putImageData(imageData, 0, 0);
WebGL 集成
<canvas>
还支持 3D 渲染上下文:
const gl = canvas.getContext('webgl');
if (gl) {
// WebGL 代码...
}
实际应用示例
绘制图表
function drawBarChart(data) {
const barWidth = 40;
const maxValue = Math.max(...data);
data.forEach((value, i) => {
const barHeight = (value / maxValue) * canvas.height;
ctx.fillStyle = `hsl(${i * 360 / data.length}, 70%, 50%)`;
ctx.fillRect(
i * (barWidth + 10),
canvas.height - barHeight,
barWidth,
barHeight
);
});
}
签名板实现
let isDrawing = false;
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', endDrawing);
function startDrawing(e) {
isDrawing = true;
const {x, y} = getCanvasPosition(e);
ctx.beginPath();
ctx.moveTo(x, y);
}
function draw(e) {
if (!isDrawing) return;
const {x, y} = getCanvasPosition(e);
ctx.lineTo(x, y);
ctx.stroke();
}
function endDrawing() {
isDrawing = false;
}
function getCanvasPosition(e) {
const rect = canvas.getBoundingClientRect();
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
}
浏览器兼容性注意事项
-
始终检查上下文获取是否成功
if (!ctx) { alert('您的浏览器不支持Canvas'); }
-
对于不支持
<canvas>
的旧浏览器:<canvas> <!-- 后备内容 --> <p>您的浏览器不支持HTML5 Canvas</p> </canvas>
-
移动端需要考虑触控事件和高DPI屏幕适配:
// 高DPI适配 const dpr = window.devicePixelRatio || 1; canvas.width = canvas.clientWidth * dpr; canvas.height = canvas.clientHeight * dpr; ctx.scale(dpr, dpr);
上一篇: <svg>-SVG矢量图形
下一篇: <map>-图像映射