使用画布 globalAlpha 淡化

Posted

技术标签:

【中文标题】使用画布 globalAlpha 淡化【英文标题】:Using canvas globalAlpha to fade 【发布时间】:2018-12-13 05:06:03 【问题描述】:

我正在尝试将一个画布的内容淡入另一个画布。从脚本here 开始,我有以下工作,但我对为什么褪色发生得如此之快感到困惑 - 为什么 globalAlpha 在仅 0.2 次操作后似乎几乎完全褪色了新图像?脚本如下和here on jsbin。

<canvas id="main"  ></canvas>
<canvas id="test"  ></canvas>

<script>

var width = 500, height = 300;

var main = document.getElementById('main');
var mainctx = main.getContext('2d');

//begin path, create a rect the size of the canvas
mainctx.beginPath();
mainctx.rect(0, 0, width, height);
mainctx.fillStyle = "#ff0000";
mainctx.fill();

var test = document.getElementById('test');
var testctx = test.getContext('2d');

//begin path, create a rect the size of the canvas
testctx.beginPath();
testctx.rect(0, 0, width, height);
testctx.fillStyle = "#00ff00";
testctx.fill();

var op = 1;

function fade()

    op -= 0.001;

    console.log(op);

    //mainctx.clearRect(0, 0, width, height);
    mainctx.globalAlpha = 1 - op;
    mainctx.drawImage(testctx.canvas, 0, 0);

    if (op <= 0.8) setTimeout(function() console.log("done"); , 1);
    else requestAnimationFrame(fade);


fade();

</script>

【问题讨论】:

也许在你的setTimeout 而不是1 中使用更高的值,比如2000 问题不是淡入淡出的速度(尽管我确实需要放慢它),而是淡入淡出从 1.0 到 0.0 的分布。到 0.8 时,新图像几乎完全消失了。 您必须将原始画布状态保持在第三个屏幕外画布中,您将在交叉淡入淡出的每一步中与第二个画布一起绘制 @Kaiido 一个例子可以帮助解释为什么需要第三个画布。目前,我正在使用两幅画布进行此操作,但这并不完全符合我想要的方式。 @garrettlynch 因为 0.1 opacity + 0.1 opacity 不是 0.2 opacity,所以要实现过渡,您需要在每一步都从原始图像开始。我现在没有时间撰写答案,但我明天会尝试。 【参考方案1】:

它看起来好像正在快速褪色,因为您没有清除画布,而是不断覆盖彼此的相同透明图像。

您需要做的就是删除 clearRect 函数前面的 //

<!DOCTYPE html>
<html>

  <head>
  </head>

  <body>

   <canvas id="main"  ></canvas>
   <canvas id="test"  ></canvas>

  <script>

  var width = 500, height = 300;
  var main = document.getElementById('main');
   var mainctx = main.getContext('2d');

  //begin path, create a rect the size of the canvas
  mainctx.beginPath();
   mainctx.rect(0, 0, width, height);
  mainctx.fillStyle = "#ff0000";
   mainctx.fill();

  var test = document.getElementById('test');
  var testctx = test.getContext('2d');

  //begin path, create a rect the size of the canvas
  testctx.beginPath();
  testctx.rect(0, 0, width, height);
  testctx.fillStyle = "#00ff00";
  testctx.fill();

  var op = 1;

  function fade()
  
      op -= 0.001;

      console.log(op);

          //you already had it here, i only had to remove the "//"
      mainctx.clearRect(0, 0, width, height);
      mainctx.globalAlpha = 1 - op;
          mainctx.drawImage(testctx.canvas, 0, 0);

      if (op <= 0.1) setTimeout(function() console.log("done"); , 1);
      else requestAnimationFrame(fade);
  

  fade();

  </script>

  </body>

</html>

https://jsbin.com/yulekoxuza/edit?html

希望对你有帮助;)

【讨论】:

为了澄清我正在将第一个画布从其当前图像淡化到第二个画布上的图像 - 所以从红色到绿色的交叉渐变不是从无到绿色的渐变。 那么我希望它能解释工作的不透明性【参考方案2】:

感谢@Kaiido 对第三张画布的建议以及@Soul_man 在this post 中的回答,我有了一个似乎运作良好的想法。而不是将原始图像保存在第三个画布中(看起来很麻烦,但也许我错了 - 也许这在内存方面更糟糕?)我现在使用 getImageData 存储原始图像,并在我写之前将其写入每个循环的画布中在越来越高的不透明度级别的新图像中。脚本在下面,有一个jsbin here。

<canvas id="main"   style="border: 1px solid #ff0000;"></canvas>
<canvas id="test"   style="border: 1px solid #ff0000;"></canvas>

<script>

var width = 500, height = 300, text = "hello";


var main = document.getElementById('main');
var mainctx = main.getContext('2d');

//begin path, create a rect the size of the canvas
mainctx.beginPath();
mainctx.rect(0, 0, width, height);

//percentage to hex colour and fill canvas rect
mainctx.fillStyle = "#ff0000";
mainctx.fill();

//write text to canvas
mainctx.font = 'Bold 100px Arial';
mainctx.textAlign="center";
mainctx.textBaseline = "middle";
mainctx.fillStyle = '#ffffff';
mainctx.fillText(text, 0 + (width / 2), 0 + (height / 2));


var test = document.getElementById('test');
var testctx = test.getContext('2d');

//begin path, create a rect the size of the canvas
testctx.beginPath();
testctx.rect(0, 0, width, height);

//percentage to hex colour and fill canvas rect
testctx.fillStyle = "#00ff00";
testctx.fill();

//start opacity at 0
var op = 0;

//copy the existing main canvas image into memory
var originalimage = mainctx.getImageData(0, 0, width, height);


//fade canvas
function fade()

    //place the original image
    mainctx.putImageData(originalimage, 0, 0);

    //starting at 0 set the global alpha and then draw the new image
    mainctx.globalAlpha = op;
    mainctx.drawImage(testctx.canvas, 0, 0);

    //increment
    op += 0.01;

    if (op >= 1.0) setTimeout(function() console.log("done"); , 2000);
    else requestAnimationFrame(fade);


fade();

</script>

【讨论】:

是的,第三个屏幕外画布应该比 putImageDataperformant,但显然,这是一个应该,因为它在很大程度上取决于设备和浏览器实现。所以无论哪种方式都很好。

以上是关于使用画布 globalAlpha 淡化的主要内容,如果未能解决你的问题,请参考以下文章

使用画布时的渲染体验不正确。帆布

HTML5中如何设置画布canvas中用drawImage画出来的每个图片不同的透明度?

globalAlpha 示例

canvas图层

使用 JavaScript 淡化文本颜色

使用子视图按钮淡化 UIView