阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > <canvas>-图形绘制画布

<canvas>-图形绘制画布

作者:陈川 阅读数:48124人阅读 分类: HTML

<canvas> 是 HTML5 引入的一个强大标签,用于在网页上动态绘制图形、动画或交互式内容。它通过 JavaScript 提供了一套完整的绘图 API,支持像素级操作,适合游戏开发、数据可视化等场景。

<canvas> 的基本用法

<canvas> 标签本身只是一个容器,需要通过 JavaScript 来绘制内容。它的基本语法如下:

<canvas id="myCanvas" width="500" height="300"></canvas>

widthheight 属性定义了画布的尺寸。如果不设置,默认宽度为 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 应用,性能优化很重要:

  1. 分层渲染:使用多个重叠的 <canvas> 元素,将静态内容和动态内容分开
  2. 避免浮点坐标:使用整数坐标可以避免子像素渲染带来的模糊
  3. 批量操作:尽量减少状态改变(如样式变化)
  4. 离屏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>,但仍需注意:

  1. 旧版IE(8及以下)不支持
  2. 画布内容不是DOM的一部分,无法通过CSS选择器访问
  3. 绘制大量对象时可能出现性能问题
  4. 高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>-图像映射

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌