14 canvas
loyalvi Lv7

11 canvas

canvas

canvas 是 HTML5 中的一个元素,用于在网页上绘制图形和动画。它提供了一个矩形区域,你可以使用 JavaScript 在这个区域内绘制各种图形,包括线条、形状、文本、图像等。canvas 元素本身没有绘图能力,所有的绘图操作都需要通过 JavaScript 来完成。

基本用法

  1. HTML 部分
    在 HTML 中添加一个 canvas 元素,并为其指定一个 id,以便在 JavaScript 中引用:
    1
    <canvas id="myCanvas" width="200" height="100"></canvas>
    • widthheight 属性定义了 canvas 的尺寸。如果省略这些属性,canvas 的默认尺寸是 300x150 像素。
  2. JavaScript 部分
    使用 JavaScript 获取 canvas 元素,并获取其绘图上下文(通常是 2D 上下文),然后进行绘图操作:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    // 绘制一个矩形
    ctx.fillStyle = 'green'; // 设置填充颜色
    ctx.fillRect(10, 10, 150, 100); // 绘制一个填充的矩形
    // 绘制一条线
    ctx.strokeStyle = 'blue'; // 设置线条颜色
    ctx.beginPath(); // 开始一条路径
    ctx.moveTo(50, 50); // 移动到起点
    ctx.lineTo(150, 50); // 绘制到终点
    ctx.stroke(); // 绘制路径
    // 绘制文本
    ctx.font = '20px Arial'; // 设置字体样式
    ctx.fillStyle = 'red'; // 设置文本颜色
    ctx.fillText('Hello, Canvas!', 50, 80); // 绘制文本

常用方法和属性

  • 绘图上下文getContext('2d') 返回一个 2D 渲染上下文对象,用于在 canvas 上进行绘图。
  • 绘制形状
    • fillRect(x, y, width, height):绘制一个填充的矩形。
    • strokeRect(x, y, width, height):绘制一个矩形边框。
    • beginPath():开始一条新的路径。
    • moveTo(x, y):移动到指定的点。
    • lineTo(x, y):绘制一条线到指定的点。
    • arc(x, y, radius, startAngle, endAngle, anticlockwise):绘制一个圆弧。
  • 绘制文本
    • fillText(text, x, y):绘制填充文本。
    • strokeText(text, x, y):绘制文本边框。
  • 样式和颜色
    • fillStyle:设置填充颜色或渐变。
    • strokeStyle:设置线条颜色或渐变。
  • 图像操作
    • drawImage(image, dx, dy):在指定位置绘制图像。
  • 保存和恢复状态
    • save():保存当前的绘图状态。
    • restore():恢复之前保存的绘图状态。

应用场景

  • 动画:通过不断清除和重绘 canvas 来创建动画效果。
  • 游戏开发:用于绘制游戏界面和动画。
  • 图表和数据可视化:绘制各种图表和图形以展示数据。
  • 图像处理:进行图像的裁剪、缩放、滤镜等操作。
    canvas 提供了强大的绘图功能,使得在网页上进行复杂的图形绘制和动画制作成为可能。

前端截图

前端实现截图需要使⽤ HTML5 的 Canvas 和相关 API,具体步骤如下:

  1. ⾸先在页面中创建⼀个 Canvas 元素,并设置其宽⾼和样式。
  2. 使⽤ Canvas API 在 Canvas 上绘制需要截图的内容,⽐如⻚⾯的某个区域、某个元素、图⽚等。
  3. 调⽤ Canvas API 中的 toDataURL () ⽅法将 Canvas 转化为 base64 编码的图⽚数据。
  4. 将 base64 编码的图⽚数据传递给后端进⾏处理或者直接在前端进⾏显⽰。
    以下是⼀个简单的例⼦,实现了对整个⻚⾯的截图:
1
2
3
4
5
6
7
8
9
10
const canvas = document.getElementById('canvas');
const ctx =canvas.getContext('2d');
const btn = document.getElementById('btn');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
btn.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(document.documentElement, 0, 0);
const imgData = canvas.toDataURL();console.log(imgData);
});

这个例⼦中,在⻚⾯中创建了⼀个 canvas 元素,并设置其宽⾼和样式,将其放在⻚⾯最上⽅。在
点击“截图”按钮时,通过 toDataURL () ⽅法将整个⻚⾯的截图转换为 base64 编码的图⽚数据,
并打印到控制台上。

简单动画

下面是一个简单的 canvas 动画示例,它会在 canvas 上绘制一个不断移动的小球,实现一个简单的动画效果。

HTML 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas 动画示例</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="400" height="300"></canvas>
<script src="animation.js"></script>
</body>
</html>

JavaScript 部分 (animation.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 小球的初始位置和速度
let x = canvas.width / 2;
let y = canvas.height / 2;
let dx = 2; // 水平方向速度
let dy = -2; // 垂直方向速度
const ballRadius = 10;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除之前的画面
drawBall(); // 绘制小球
// 更新小球的位置
x += dx;
y += dy;
// 碰到边界时反弹
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
dy = -dy;
}
requestAnimationFrame(draw); // 请求下一帧动画
}
// 开始动画
draw();

动画解释

  • 初始化:定义了小球的初始位置 xy,以及水平和垂直方向的速度 dxdy。还定义了小球的半径 ballRadius
  • 绘制小球drawBall 函数使用 arc 方法绘制一个圆形的小球,并用 fill 方法填充颜色。
  • 动画循环draw 函数首先清除 canvas 上的内容,然后调用 drawBall 绘制小球。接着更新小球的位置,并检查小球是否碰到 canvas 的边界。如果碰到边界,则反转速度,实现反弹效果。最后,使用 requestAnimationFrame(draw) 来请求浏览器在下一次重绘之前调用 draw 函数,从而实现动画效果。
  • 启动动画:在脚本的最后调用 draw 函数来启动动画。
    这个简单的示例展示了如何使用 canvas 和 JavaScript 创建一个基本的动画效果。你可以根据需要调整速度、颜色、形状等属性来创建更复杂的动画。

requestAnimationFrame

requestAnimationFrame 是 Web API 中的一个函数,用于在浏览器的下一次重绘之前执行动画函数。它提供了一种更高效的方式来创建平滑的动画效果,相比传统的 setTimeoutsetInterval 方法,requestAnimationFrame 有以下优点:

优点

  • 性能优化requestAnimationFrame 会在浏览器完成一次屏幕重绘之前执行动画函数,通常与浏览器的刷新率(通常是 60 次/秒)同步。这意味着它可以更高效地利用浏览器的重绘机制,避免不必要的渲染,从而提高性能,减少卡顿和撕裂现象。
  • 节能:当浏览器标签页不是处于活动状态时(例如用户切换到其他标签页),requestAnimationFrame 会暂停执行动画函数,从而节省资源和电量。
  • 更平滑的动画:由于与浏览器的重绘同步,requestAnimationFrame 可以创建更平滑的动画效果,避免出现抖动或不连贯的情况。

使用方法

1
2
3
4
5
6
7
8
function animate() {
// 执行动画相关的操作
// ...
// 请求下一次动画帧
requestAnimationFrame(animate);
}
// 启动动画
requestAnimationFrame(animate);

参数

  • callback:一个函数,它会在浏览器下一次重绘之前被调用。这个函数通常包含动画的更新和渲染逻辑。

返回值

  • 返回一个 ID 值,可以用于 cancelAnimationFrame 函数来取消动画请求。

取消动画

如果你需要在某些情况下停止动画,可以使用 cancelAnimationFrame 函数:

1
2
3
4
5
6
7
8
9
10
11
let animationId;
function animate() {
// 执行动画相关的操作
// ...
// 请求下一次动画帧
animationId = requestAnimationFrame(animate);
}
// 启动动画
animationId = requestAnimationFrame(animate);
// 在需要停止动画时调用
cancelAnimationFrame(animationId);

requestAnimationFrame 和 setInterval

requestAnimationFramesetInterval 都可以用来创建动画或定时执行代码,但它们在实现方式和性能表现上有一些关键区别:

requestAnimationFrame

  • 同步浏览器刷新率requestAnimationFrame 会在浏览器的下一次重绘之前执行回调函数,通常与浏览器的刷新率(通常是 60 次/秒)同步。这意味着它可以在每次屏幕刷新时更新动画,从而创建平滑的动画效果。
  • 性能优化:当浏览器标签页不是处于活动状态时(例如用户切换到其他标签页),requestAnimationFrame 会暂停执行回调函数,从而节省资源和电量。
  • 更平滑的动画:由于与浏览器的重绘同步,requestAnimationFrame 可以创建更平滑的动画效果,避免出现抖动或不连贯的情况。
  • 适用于动画:特别适合用于创建动画效果,因为它可以确保动画的更新与屏幕刷新同步,减少不必要的渲染,提高性能。

setInterval

  • 固定时间间隔setInterval 会按照指定的时间间隔(以毫秒为单位)重复执行回调函数,不考虑浏览器的刷新率。这意味着它可能会在浏览器的两次重绘之间执行多次,或者在浏览器的两次重绘之间不执行,导致动画效果不平滑。
  • 资源消耗:即使浏览器标签页不是处于活动状态,setInterval 仍然会继续执行回调函数,可能会消耗不必要的资源和电量。
  • 不考虑重绘setInterval 不会自动与浏览器的重绘同步,可能导致动画的更新与屏幕刷新不同步,出现抖动或不连贯的情况。
  • 适用于定时任务:更适合用于需要在固定时间间隔执行的定时任务,而不是动画效果。

总结

  • 动画效果:对于创建动画效果,requestAnimationFrame 是更好的选择,因为它可以与浏览器的重绘同步,创建平滑的动画,并且在非活动标签页时暂停执行,节省资源。
  • 定时任务:对于需要在固定时间间隔执行的定时任务,setInterval 可以满足需求,但需要注意它可能会导致动画效果不平滑,并且在非活动标签页时仍然消耗资源。
    通过理解 requestAnimationFramesetInterval 的区别,可以根据具体需求选择合适的函数来实现动画或定时任务。
由 Hexo 驱动 & 主题 Keep
访客数 访问量