Gia*_*ley 1 html javascript canvas
我有一个画布,当我绘制两个低不透明度重叠的东西时,它们重叠的部分的不透明度会变高。即使两件事重叠,有没有一种方法可以使其具有相同的不透明度。
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle = "rgba(0, 0, 255, 0.2)";
ctx.fillRect(10, 10, 50, 50);
ctx.fillRect(20, 20, 50, 60);
ctx.fillRect(40, 5, 50, 40)Run Code Online (Sandbox Code Playgroud)
canvas {
width: 100vw;
height: 100vh;
}Run Code Online (Sandbox Code Playgroud)
<p>all of it should be the same color but the overlapping parts are darker</p>
<canvas id="canvas"></canvas>Run Code Online (Sandbox Code Playgroud)
对于简单的情况,通常的技巧是使用第二个画布作为图层:在独立的画布上绘制不应与完全不透明混合的部分,然后在可见画布上使用预期的 alpha 绘制此画布:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const detached = canvas.cloneNode();
const ctx2 = detached.getContext("2d");
// draw at full opacity
ctx2.fillStyle = "rgb(0, 0, 255)";
ctx2.fillRect(10, 10, 50, 50);
ctx2.fillRect(20, 20, 50, 60);
ctx2.fillRect(40, 5, 50, 40)
// draw something in the background of the visible canvas
// where we want the blue rects to mix with
ctx.fillStyle = "green";
ctx.fillRect(50, 65, 30, 30);
// now draw the blue rects in a single pass with the expected alpha
ctx.globalAlpha = 0.2
ctx.drawImage(detached, 0, 0);Run Code Online (Sandbox Code Playgroud)
/* CSS checkerboard stolen from https://drafts.csswg.org/css-images-4/#example-2de97f53 */
canvas {
background: repeating-conic-gradient(rgba(0,0,0,0.1) 0deg 25%, white 0deg 50%);
background-size: 2em 2em;
}Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>Run Code Online (Sandbox Code Playgroud)
请注意,这个确切的示例可以使用单个画布完成:如果所有形状确实共享相同的颜色,则可以使它们全部成为同一子路径的一部分,并在一次调用中将它们全部填充。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(50, 65, 30, 30);
ctx.fillStyle = "rgb(0, 0, 255, 0.2)";
ctx.beginPath();
ctx.rect(10, 10, 50, 50);
ctx.rect(20, 20, 50, 60);
ctx.rect(40, 5, 50, 40);
ctx.fill();Run Code Online (Sandbox Code Playgroud)
/* CSS checkerboard stolen from https://drafts.csswg.org/css-images-4/#example-2de97f53 */
canvas {
background: repeating-conic-gradient(rgba(0,0,0,0.1) 0deg 25%, white 0deg 50%);
background-size: 2em 2em;
}Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>Run Code Online (Sandbox Code Playgroud)
现在,只有当所有要绘制的形状的透明度都相同时,这些才起作用。如果多个形状具有不同的 alpha 值,它们仍然会混合。
下面是这种情况的一个例子。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(50, 10, 50, 60);
ctx.fillStyle = "rgba(0, 0, 255, .2)";
ctx.fillRect(40, 50, 70, 60);
ctx.fillStyle = "rgba(0, 0, 255, .8)";
ctx.fillRect(10, 20, 60, 70);Run Code Online (Sandbox Code Playgroud)
/* CSS checkerboard stolen from https://drafts.csswg.org/css-images-4/#example-2de97f53 */
canvas {
background: repeating-conic-gradient(rgba(0,0,0,0.1) 0deg 25%, white 0deg 50%);
background-size: 2em 2em;
}Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>Run Code Online (Sandbox Code Playgroud)
如果我们希望第一个蓝色矩形位于第二个矩形之上而不混合,但仍与绿色矩形混合,我们需要使用第一个解决方案的变体,但使用更多步骤:
不过,我将利用这个新片段的机会来展示,通过对该globalCompositeOperation属性的一些创造性使用,我们可以在一个画布上完成所有这些。
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
// To use a single canvas, we will draw the green "background" later
// target color is rgb(0, 0, 255, 0.2) & max alpha is 0.8
// 0.2 x (1 / 0.8) -> 0.25
ctx.fillStyle = "rgb(0, 0, 255, 0.25)";
ctx.fillRect(40, 50, 70, 60);
ctx.fillStyle = "rgba(0, 0, 255, 1)";
ctx.fillRect(10, 20, 60, 70);
ctx.globalAlpha = 0.8;
// gCO "copy" will clear whatever was on the context before the next paint
ctx.globalCompositeOperation = "copy";
ctx.drawImage(ctx.canvas, 0, 0);
// we could continue over like this if more such opacities were required
ctx.globalAlpha = 1;
// gCO "destination-over" will draw behind what's already painted on the context
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "green";
ctx.fillRect(50, 10, 50, 60);Run Code Online (Sandbox Code Playgroud)
/* CSS checkerboard stolen from https://drafts.csswg.org/css-images-4/#example-2de97f53 */
canvas {
background: repeating-conic-gradient(rgba(0,0,0,0.1) 0deg 25%, white 0deg 50%);
background-size: 2em 2em;
}Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>Run Code Online (Sandbox Code Playgroud)
现在,有些人可能会对此感兴趣,但是在 WHATWG/html 上,我们开始了关于为 canvas2D 启用图层 API 的讨论,虽然还远未达成共识,但我编写了一个相当小的CanvasLayer 接口原型,它将允许我们在画布中使用图层。
这个想法是创建一个CanvasLayer对象,该对象记录绘图操作,当使用上下文的当前设置在上下文中渲染该对象时,将在该对象上执行这些操作。基本上再现了分离的画布技巧,但自动处理分离的画布的大小,并且(如果本地实现),而不分配完整的位图缓冲区。
在我非常有偏见的观点中(我是该提案和原型的作者),当我们必须处理画布上的多个层时,这将允许更清晰的代码。
/* CSS checkerboard stolen from https://drafts.csswg.org/css-images-4/#example-2de97f53 */
canvas {
background: repeating-conic-gradient(rgba(0,0,0,0.1) 0deg 25%, white 0deg 50%);
background-size: 2em 2em;
}Run Code Online (Sandbox Code Playgroud)
<canvas></canvas>
<script type="module">
import CanvasLayer from "https://cdn.jsdelivr.net/gh/Kaiido/CanvasLayer/bundles/CanvasLayer.min.mjs";
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(50, 10, 50, 60);
const backLayer = new CanvasLayer();
backLayer.fillStyle = "rgba(0, 0, 255)"; // fully opaque
backLayer.fillRect(40, 50, 70, 60);
const frontLayer = new CanvasLayer();
frontLayer.fillStyle = "rgba(0, 0, 255)";
frontLayer.fillRect(10, 20, 60, 70);
frontLayer.globalAlpha = 0.2;
frontLayer.renderLayer(backLayer);
ctx.globalAlpha = 0.8;
ctx.renderLayer(frontLayer);
</script>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
754 次 |
| 最近记录: |