4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅]
1.缩放 canvas 对象
在 <canvas>
中缩放对象可以通过 scale
方法来实现。这个方法会根据提供的参数对之后绘制的所有内容进行缩放。下面是两个具体的示例,展示如何使用 scale
方法来缩放 canvas 上的对象。
示例 1: 简单的矩形缩放
这个例子展示了如何使用 scale
方法缩放一个简单的矩形。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Scale Rectangle Example</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>缩放矩形示例</h1>
<canvas id="scaleRectangleCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('scaleRectangleCanvas');
const ctx = canvas.getContext('2d');
// 不缩放时绘制一个矩形
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100);
// 设置缩放因子 (宽度缩放2倍,高度缩放2倍)
ctx.scale(2, 2);
// 绘制缩放后的矩形(注意:坐标和尺寸也会被缩放)
ctx.fillStyle = 'red';
ctx.fillRect(50, 50, 100, 100); // 这个矩形实际位置是 (100, 100),大小为 (200, 200)
</script>
</body>
</html>
在这个例子中:
- 首先我们没有应用任何缩放的情况下绘制了一个蓝色的矩形。
- 然后调用
ctx.scale(2, 2)
来设置缩放因子,这会让之后所有的绘图命令在 X 和 Y 轴上都放大两倍。 - 接着绘制了一个红色的矩形,由于之前设置了缩放,所以它实际上比预期的位置更靠右下,并且也更大。
示例 2: 缩放并旋转图像
此示例展示了如何结合 scale
和 rotate
方法来缩放和旋转一个图像。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Scale and Rotate Image Example</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>缩放并旋转图像示例</h1>
<canvas id="scaleRotateImageCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('scaleRotateImageCanvas');
const ctx = canvas.getContext('2d');
// 创建一个新的 Image 对象
const img = new Image();
// 设置图像源(可以是本地路径或网络链接)
img.src = '2.png'; // 替换为你的图片URL
// 确保图像加载完毕后再执行操作
img.onload = function() {
// 保存当前状态
ctx.save();
// 移动画布中心到画布中间
ctx.translate(canvas.width / 2, canvas.height / 2);
// 设置缩放因子 (宽度缩放1.5倍,高度缩放1.5倍) 和旋转角度 (45度)
ctx.scale(1.5, 1.5);
ctx.rotate(Math.PI / 4); // 45度转换为弧度
// 绘制图像 (以新的原点为中心,需要调整x, y值为负的一半宽高)
ctx.drawImage(img, -img.width / 2, -img.height / 2);
// 恢复到之前的状态
ctx.restore();
};
</script>
</body>
</html>
在这个例子中:
- 我们首先保存了当前的绘图状态,以便稍后恢复。
- 使用
translate
方法将绘图原点移动到画布的中心,这样旋转将会围绕画布中心进行。 - 然后设置了缩放因子和旋转角度,这里我们将图像放大了 1.5 倍,并旋转了 45 度。
- 在绘制图像时,我们需要将其 x 和 y 参数设置为图像宽度和高度的一半的负数,以确保图像的中心位于画布的中心。
- 最后,我们恢复了之前的绘图状态,使得后续的绘图不会受到这次缩放和旋转的影响。
2.canvas 变换
在 <canvas>
中,变换(Transformations)可以用来平移、旋转、缩放和倾斜绘图上下文。下面我将提供两个示例,分别展示如何使用 translate
和 rotate
方法来变换绘图上下文。
示例 1: 使用 translate
平移图形
这个例子展示了如何使用 translate
方法将绘制的坐标系统移动到新的位置,从而实现图形的平移。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Translate Example</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 平移变换示例</h1>
<canvas id="translateCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('translateCanvas');
const ctx = canvas.getContext('2d');
// 绘制一个未平移的矩形
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100);
// 保存当前绘图状态
ctx.save();
// 将原点移动到 (200, 200)
ctx.translate(200, 200);
// 绘制一个平移后的矩形(相对新原点)
ctx.fillStyle = 'red';
ctx.fillRect(-25, -25, 50, 50); // 注意这里的坐标是相对于新的原点
// 恢复之前的绘图状态
ctx.restore();
// 绘制另一个平移的矩形,这次直接指定新位置
ctx.fillStyle = 'green';
ctx.fillRect(350, 350, 100, 100);
</script>
</body>
</html>
在这个例子中:
- 我们首先绘制了一个未经过任何变换的蓝色矩形。
- 使用
ctx.save()
保存了当前的绘图状态,以便稍后恢复。 - 然后调用
ctx.translate(200, 200)
将绘图原点从左上角移动到了(200, 200)
的位置。 - 接着我们绘制了一个红色矩形,它的坐标是相对于新的原点计算的,因此它实际上出现在画布上的
(175, 175)
到(225, 225)
区域内。 - 最后,使用
ctx.restore()
恢复了之前的绘图状态,并绘制了另一个绿色矩形以显示没有被影响的状态。
示例 2: 使用 rotate
旋转变换
此示例展示了如何结合 rotate
方法旋转图形,并通过 translate
来确保旋转是围绕特定点进行的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Rotate Example</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 旋转变换示例</h1>
<canvas id="rotateCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('rotateCanvas');
const ctx = canvas.getContext('2d');
// 绘制一个未旋转的矩形
ctx.fillStyle = 'blue';
ctx.fillRect(150, 150, 100, 100);
// 保存当前绘图状态
ctx.save();
// 将原点移动到旋转中心 (300, 300)
ctx.translate(300, 300);
// 旋转绘图上下文 (45度转换为弧度)
ctx.rotate(Math.PI / 4);
// 绘制一个旋转后的矩形(相对新原点)
ctx.fillStyle = 'red';
ctx.fillRect(-50, -50, 100, 100); // 注意这里的坐标是相对于新的原点
// 恢复之前的绘图状态
ctx.restore();
// 绘制另一个矩形以显示没有被影响的状态
ctx.fillStyle = 'green';
ctx.fillRect(400, 400, 100, 100);
</script>
</body>
</html>
在这个例子中:
- 首先绘制了一个未旋转的蓝色矩形。
- 使用
ctx.save()
保存当前绘图状态。 - 使用
ctx.translate(300, 300)
将绘图原点移到旋转中心的位置(300, 300)
,这样接下来的旋转将会围绕这个点进行。 - 调用
ctx.rotate(Math.PI / 4)
来旋转绘图上下文 45 度(π/4 弧度)。 - 接着绘制了一个红色矩形,其坐标是相对于新的原点计算的,所以它实际上是围绕
(300, 300)
旋转的。 - 使用
ctx.restore()
恢复了之前的绘图状态,并绘制了一个绿色矩形以显示不受旋转影响的状态。
这两个示例展示了如何利用 <canvas>
的变换功能来创建复杂的视觉效果。你可以根据需要调整这些变换的方法和参数,或者探索更多关于变换和其他绘图属性的方法。
3.canvas 文本
在 HTML5 <canvas>
中绘制文本是通过使用 CanvasRenderingContext2D
接口提供的方法来完成的。下面我将给出两个示例,一个展示如何在画布上绘制简单的静态文本,另一个则展示了如何创建更复杂的文本效果,例如旋转和应用样式。
示例 1: 绘制简单文本
这个例子展示了如何设置字体、颜色以及在指定位置绘制文本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Text Example</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 简单文本示例</h1>
<canvas id="textCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('textCanvas');
const ctx = canvas.getContext('2d');
// 设置文本属性
ctx.font = '30px Arial';
ctx.fillStyle = 'blue'; // 文本颜色
// 使用 fillText 方法绘制填充文本
ctx.fillText('Hello Canvas!', 50, 100);
// 改变文本对齐方式
ctx.textAlign = 'center';
ctx.fillText('Centered Text', canvas.width / 2, 200);
// 改变文本基线
ctx.textBaseline = 'bottom';
ctx.fillText('Bottom Aligned Text', 50, 350);
</script>
</body>
</html>
在这个例子中:
- 我们设置了文本的字体为
'30px Arial'
,并且文本的颜色为蓝色。 - 使用
ctx.fillText()
方法在画布上的(50, 100)
位置绘制了字符串'Hello Canvas!'
。 - 修改了文本的水平对齐方式 (
textAlign
) 和垂直基线 (textBaseline
) 来控制文本相对于指定坐标的定位,并分别绘制了居中的文本和底部对齐的文本。
示例 2: 创建复杂文本效果
此示例展示了如何结合变换(如旋转)和其他绘图属性来创建更复杂的文本效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Complex Text Effects</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 复杂文本效果示例</h1>
<canvas id="effectCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('effectCanvas');
const ctx = canvas.getContext('2d');
// 设置初始文本属性
ctx.font = 'bold 40px Georgia';
ctx.fillStyle = 'red';
// 保存当前状态
ctx.save();
// 平移坐标系统到画布中心
ctx.translate(canvas.width / 2, canvas.height / 2);
// 旋转上下文 45 度 (π/4 弧度)
ctx.rotate(Math.PI / 4);
// 绘制旋转后的文本
ctx.fillText('Rotated Text', -100, 0);
// 恢复之前的状态
ctx.restore();
// 绘制带有阴影的文本
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowBlur = 10;
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.fillText('Shadowed Text', 100, 100);
// 绘制描边文本
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.strokeText('Outlined Text', 100, 200);
</script>
</body>
</html>
在这个例子中:
- 首先我们设置了文本的字体为粗体
'40px Georgia'
,并设定了文本颜色为红色。 - 使用
ctx.save()
保存了当前绘图状态,以便稍后恢复。 - 然后使用
ctx.translate()
和ctx.rotate()
方法来平移和旋转绘图上下文,使得文本可以围绕画布中心旋转。 - 调用
ctx.fillText()
方法绘制了旋转后的文本。 - 使用
ctx.restore()
恢复了之前的绘图状态。 - 接着,设置了文本的阴影效果,并使用
ctx.fillText()
方法绘制了带阴影的文本。 - 最后,定义了文本的描边样式,并使用
ctx.strokeText()
方法绘制了具有轮廓的文本。
这两个示例展示了如何在 <canvas>
上绘制文本,并通过调整文本属性和应用变换来创建不同的视觉效果。你可以根据需要进一步探索更多关于文本绘制的方法和属性。
4.应用阴影
在 HTML5 <canvas>
中,可以使用 CanvasRenderingContext2D
接口提供的阴影属性来为绘制的对象添加阴影效果。下面我将给出两个示例,一个展示如何为简单的图形添加阴影,另一个则展示了如何为文本添加阴影。
示例 1: 为简单图形添加阴影
这个例子展示了如何设置阴影属性,并将其应用于矩形和圆形等基本形状。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Shadow on Shapes</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 图形阴影示例</h1>
<canvas id="shapeCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('shapeCanvas');
const ctx = canvas.getContext('2d');
// 设置阴影属性
ctx.shadowOffsetX = 10; // 水平偏移量
ctx.shadowOffsetY = 10; // 垂直偏移量
ctx.shadowBlur = 20; // 阴影的模糊程度
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; // 阴影颜色及透明度
// 绘制带阴影的矩形
ctx.fillStyle = 'blue';
ctx.fillRect(100, 100, 150, 100);
// 绘制带阴影的圆形
ctx.beginPath();
ctx.arc(450, 200, 75, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();
</script>
</body>
</html>
在这个例子中:
- 我们设置了阴影的水平和垂直偏移量 (
shadowOffsetX
,shadowOffsetY
)、模糊程度 (shadowBlur
) 和颜色 (shadowColor
)。 - 使用
ctx.fillRect()
方法绘制了一个带有阴影的蓝色矩形。 - 使用
ctx.arc()
方法定义了一个圆形路径,并用ctx.fill()
方法填充了绿色,同样应用了阴影效果。
示例 2: 为文本添加阴影
此示例展示了如何结合文本样式和阴影属性来创建有吸引力的文本阴影效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Text Shadow</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 文本阴影示例</h1>
<canvas id="textCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('textCanvas');
const ctx = canvas.getContext('2d');
// 设置文本字体
ctx.font = 'bold 60px Georgia';
// 设置文本阴影属性
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowBlur = 10;
ctx.shadowColor = 'rgba(0, 0, 0, 0.7)';
// 设置文本颜色
ctx.fillStyle = 'red';
// 使用 fillText 方法绘制带阴影的文本
ctx.fillText('Shadowed Text', 50, 150);
// 创建更复杂的文本阴影效果
ctx.save(); // 保存当前状态
ctx.translate(300, 200); // 平移到画布中心
// 应用多重阴影效果
ctx.shadowOffsetX = -5;
ctx.shadowOffsetY = -5;
ctx.shadowBlur = 15;
ctx.shadowColor = 'rgba(255, 255, 255, 0.7)'; // 白色阴影
ctx.fillText('Multi-shadow', 0, 0);
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowColor = 'rgba(0, 0, 0, 0.7)'; // 黑色阴影
ctx.fillText('Multi-shadow', 0, 0);
ctx.restore(); // 恢复之前的状态
</script>
</body>
</html>
在这个例子中:
- 首先我们设置了文本的字体为粗体
'60px Georgia'
。 - 然后设置了阴影的偏移量、模糊程度和颜色。
- 使用
ctx.fillText()
方法绘制了带有单一阴影效果的红色文本。 - 接着,为了创建多重阴影效果,我们使用了
ctx.save()
和ctx.restore()
来保存和恢复绘图状态,使得可以在同一文本上应用不同的阴影效果。 - 通过两次调用
ctx.fillText()
方法,一次用于白色阴影,一次用于黑色阴影,实现了对同一个文本的多重阴影效果。
这两个示例展示了如何在 <canvas>
上为图形和文本添加阴影效果,并通过调整阴影属性来创造不同的视觉效果。你可以根据需要进一步探索更多关于阴影和其他绘图属性的应用。
5.像素数据
在 HTML5 <canvas>
中,可以通过 CanvasRenderingContext2D
接口提供的方法来操作像素数据。getImageData()
方法可以获取指定矩形区域的图像数据,而 putImageData()
方法则用于将图像数据绘制回画布。下面我将给出两个示例,一个展示如何读取和修改单个像素的颜色,另一个展示如何创建简单的滤镜效果(如灰度)。
示例 1: 修改单个像素的颜色
这个例子展示了如何使用 getImageData()
获取图像数据,然后修改单个像素的颜色,并用 putImageData()
将更改后的图像数据放回画布。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Modify Single Pixel Color</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 修改单个像素颜色示例</h1>
<canvas id="pixelCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('pixelCanvas');
const ctx = canvas.getContext('2d');
// 创建一个彩色矩形作为背景
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 获取整个画布的图像数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 修改特定位置 (x=300, y=200) 的像素颜色为红色
const x = 300;
const y = 200;
const index = (y * canvas.width + x) * 4;
// 设置新颜色值 (R,G,B,A)
data[index] = 255; // Red
data[index + 1] = 0; // Green
data[index + 2] = 0; // Blue
data[index + 3] = 255; // Alpha (不透明度)
// 将修改后的图像数据放回画布
ctx.putImageData(imageData, 0, 0);
</script>
</body>
</html>
在这个例子中:
- 我们先创建了一个绿色的矩形背景。
- 然后使用
getImageData()
获取了整个画布的图像数据。 - 接着计算出特定位置
(x=300, y=200)
在一维数组中的索引位置,并设置了该位置的 RGB 值为红色(255, 0, 0)
和全不透明度255
。 - 最后,我们使用
putImageData()
方法将修改后的图像数据重新绘制到画布上。
示例 2: 创建灰度滤镜效果
此示例展示了如何遍历所有像素并应用灰度滤镜,即将每个像素的 RGB 值转换为相同的灰度值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Grayscale Filter on Canvas</title>
<style>
body { font-family: Arial, sans-serif; }
canvas { border: 1px solid black; display: block; margin: 20px auto; }
</style>
</head>
<body>
<h1>Canvas 灰度滤镜示例</h1>
<canvas id="filterCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('filterCanvas');
const ctx = canvas.getContext('2d');
// 创建一个渐变背景
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'red');
gradient.addColorStop(0.5, 'green');
gradient.addColorStop(1, 'blue');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 获取图像数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 应用灰度滤镜
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // Red
data[i + 1] = avg; // Green
data[i + 2] = avg; // Blue
// Alpha 保持不变
}
// 将处理过的图像数据放回画布
ctx.putImageData(imageData, 0, 0);
</script>
</body>
</html>
在这个例子中:
- 我们首先创建了一个从左到右由红、绿、蓝组成的线性渐变背景。
- 使用
getImageData()
获取了整个画布的图像数据。 - 遍历所有像素的数据,对于每个像素,计算其红、绿、蓝三个分量的平均值,并将这些分量设置为相同的平均值,从而实现灰度效果。
- 最后,我们再次使用
putImageData()
方法将修改后的图像数据放回画布。
这两个示例展示了如何直接操作 <canvas>
上的像素数据以实现特定的效果。你可以根据需要进一步探索更多关于图像处理的技术。
6.canvas 的安全机制
Canvas 是 HTML5 中的一个元素,允许在网页上通过 JavaScript 进行图形绘制。为了保护用户隐私和确保网站安全,浏览器对 Canvas 实施了一定的安全机制,主要包括同源策略(Same-origin policy)和污染(tainting)概念。
-
同源策略:
- 当一个 Canvas 对象被用来加载图像或其他多媒体内容时,如果这些资源来自与包含该 Canvas 的页面不同的源(协议、域名或端口不同),那么同源策略就会生效。
- 根据同源策略,Canvas 只能操作来源于相同域的数据。这意味着你不能直接从一个 Canvas 中读取或者导出包含了跨域资源的像素数据。
-
污染(Tainting):
- 如果在一个 Canvas 上绘制了来自不同源的图像数据,Canvas 将被标记为“污染”。一旦 Canvas 被污染,尝试调用
toDataURL()
、getImageData()
或者mozGetAsFile()
等方法来获取 Canvas 内容将会抛出安全错误。 - 为了防止敏感信息泄露,浏览器会阻止访问被污染 Canvas 的像素数据,即使后来只在 Canvas 上绘制了同源的内容,它仍然会被认为是污染的。
- 如果在一个 Canvas 上绘制了来自不同源的图像数据,Canvas 将被标记为“污染”。一旦 Canvas 被污染,尝试调用
-
CORS(跨源资源共享):
- 为了合法地使用跨域资源,服务器需要设置适当的 CORS 头部。如果服务器正确配置了 CORS,并且客户端代码明确指定了使用 CORS(例如,通过创建 Image 对象时设置
crossOrigin
属性),那么就可以合法地加载跨域资源到 Canvas 上而不导致其被污染。 - 即使启用了 CORS,开发者也应当谨慎处理,因为这可能会暴露用户的身份验证信息给第三方。
- 为了合法地使用跨域资源,服务器需要设置适当的 CORS 头部。如果服务器正确配置了 CORS,并且客户端代码明确指定了使用 CORS(例如,通过创建 Image 对象时设置
-
用户代理行为:
- 不同的浏览器可能对 Canvas 安全机制有着细微的不同实现,因此开发时应该测试多种浏览器以确保兼容性。
遵循这些安全措施可以有效减少潜在的安全风险,如点击劫持攻击、信息泄露等。对于开发者来说,理解并正确应用这些规则是非常重要的。