【问题标题】:HTML5: Apply transparency to Canvas after drawing through JavaScriptHTML5:通过 JavaScript 绘制后对 Canvas 应用透明度
【发布时间】:2014-11-22 21:22:32
【问题描述】:

我正在尝试将多个对象绘制到一个画布元素,然后将它们淡出干净。但是,当尝试使用 globalAlpha 来实现这一点时,您可以看到通常会被遮挡的对象片段,因为每个对象都变得单独透明。解释:

考虑以下代码:

context.fillStyle="yellow";
context.fillRect(0,0,100,100);
context.fillStyle="blue";
context.fillRect(50,50,100,100);

这将创建一个像这样的图像:

Y = Yellow, B = Blue

Y Y Y Y
Y Y Y Y
Y Y B B B B
Y Y B B B B
    B B B B
    B B B B

根据需要,蓝色框完全覆盖了黄色框。但是,当我们开始在混合中添加透明度时:

context.globalAlpha=0.5;
context.fillStyle="yellow";
context.fillRect(0,0,100,100);
context.fillStyle="blue";
context.fillRect(50,50,100,100);

我们最终得到了这个:

Y = Yellow, B = Blue, M = Mix of both

Y Y Y Y
Y Y Y Y
Y Y M M B B
Y Y M M B B
    B B B B
    B B B B

由于蓝色矩形在绘制时是透明的,因此之前被遮挡的黄色框的角现在可见。这太丑了。

请记住:正在淡出的画布及其背后的元素都是复杂的、动态的混乱;手动跟踪正在绘制的每个对象以及它们如何重叠会很快失去控制,并且使用纯色叠加层来“伪造”淡出同样不是一个可行的解决方案。

虽然我愿意使用 CSS 透明度来实现这一点,如果它真的是最好的方法的话,我希望使用画布本身来实现这一点。我遇到过canvas pixel manipulation,这可能是一种选择,但我担心我可能忽略了一种更简单、更有效的处理方式。

有什么想法吗?

【问题讨论】:

标签: javascript html canvas


【解决方案1】:

要获得使当前画布淡出的清晰效果,您可以在完全填充任何颜色时使用“destination-out”操作:这会使画布保持不变...除非您将 globalAlpha 降低到 x,然后生成的 alpha 将乘以 1-x。

(http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcout)

jsbin:

http://jsbin.com/cecavojepa/1/edit?js,output

核心衰落功能:

function fadeCanvas() {
  ctx.save();
  ctx.globalAlpha = 0.1;
  ctx.globalCompositeOperation='destination-out';
  ctx.fillStyle= '#FFF';
  ctx.fillRect(0,0,cv.width, cv.height);    
  ctx.restore();   
}

【讨论】:

  • 很有趣,但是当您使用 strokeRect 而不是黑色笔触时,它并没有完全淡出!
【解决方案2】:

我认为最简单的解决方案就是使用 CSS 不透明度:

#mycanvas {opacity: 0.5}

一行,不乱。

【讨论】:

    【解决方案3】:

    我觉得回答自己的问题有点傻,但在试图解释为什么我想避免使用 CSS 时——因为纯画布解决方案还允许将多个画布组合成一个——我意识到该解决方案正盯着我看面对:

    在屏幕外渲染平面版本,然后使用所需的透明度将生成的图像绘制到屏幕画布上。

    示例代码:

    // Create an offscreen canvas large enough to fit our drawing
    var offscreenCanvas = document.createElement('canvas');
    offscreenCanvas.height = 150;
    offscreenCanvas.width = 150;
    
    // Draw to the offscreen canvas
    var offscreenContext = offscreenCanvas.getContext("2d");
    offscreenContext.fillStyle="green";
    offscreenContext.fillRect(0,0,100,100);
    offscreenContext.fillStyle="blue";
    offscreenContext.fillRect(50,50,100,100);
    
    // Draw our offscreen canvas to our visible canvas as an image
    visibleContext.globalAlpha=0.3;
    visibleContext.drawImage(offscreenCanvas, 0, 0);
    

    这可以防止来自多个重叠对象的颜色“混合”,从而实现更清晰的淡入/淡出效果。

    【讨论】:

    • 在显示的画布上绘制要快得多,然后以黑色或白色填充矩形以淡出。 jsbin.com/sizupidipu/2/edit
    • @GameAlchemist 该解决方案创建了“淡入”效果,而这里的目标是创建“淡出”效果。如问题中所述,画布对象背后可见的不仅仅是纯色,而是其自身的动态图像。
    • 好吧,我想知道。那么这只是选择正确的复合模式的问题。 Destination-out 似乎是一个合适的候选人:jsbin.com/sizupidipu/4/edit?js,output(比 drawImage 屏幕外的画布快)
    • 这似乎也是一个可行的解决方案。我可能会尝试组合一个 JSPerf 来测试哪个更快以及多少,但我怀疑你说目的地输出会更快是正确的。
    • 无需基准测试:fillrect 比 drawImage 快。使用屏幕外画布,您会冒在某些设备/浏览器上无法进行硬件加速的风险。
    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2014-12-21
    • 2015-06-26
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 2021-12-31
    相关资源
    最近更新 更多