只有globalAlpha影响画布的一层?

时间:2015-11-04 20:44:59

标签: javascript html canvas

我正在尝试使用globalAlpha'淡出'我的画布的顶层,陶醉中间层图像和纯色背景。我正在使用下面的代码,它成功淡出了黑色层。但是,我似乎无法阻止蓝色背景层也逐渐淡出。

<!DOCTYPE html>
<html>

<body>

<canvas id="myCanvas" width="600" height="500"></canvas>
<script>

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var img;    
img = new Image();
img.src = "img/background4x3.png";

var i = 1;
function test1() {

    ctx.fillStyle = "#4DB8FF";
    ctx.fillRect(0, 0, 600, 500);
    ctx.globalAlpha = 1;
    ctx.drawImage(img, 0, 0, 600, 500);


    if (i > 0) {
        ctx.globalAlpha = i;
        ctx.fillStyle = "#000000";
        ctx.fillRect(0, 0, 600, 500);
        setTimeout(test2, 100);
    }
}

function test2() {
    ctx.clearRect(0, 0, 600, 500);
    i -= 0.01;
    test1();    

}

img.onload = function () {          
    test1();
    }


   </script>

 

有没有人有任何建议?我试图使用基于globalAlpha的if和while语句,但到目前为止还没有运气。

2 个答案:

答案 0 :(得分:1)

希望我做对了。图像从黑色渐变而背景蓝/青色不受影响。

您需要使用ctx.globalCompositeOperation(GCO),这有点直观。

  1. 首先清除画布(必须完成),以便所有像素都不透明。
  2. 将GCO设置为source-over这是默认设置并绘制所有像素 从源(你正在绘制的东西)上的所有像素 当然,目的地(画布)除了透明像素。
  3. globalAlpha设置为淡入淡出级别。
  4. 然后绘制黑色矩形。
  5. globalAlpha设置为1
  6. 将GCO设置为destination-atop,这意味着来自源的所有像素 (图像)不是不透明的,目标像素出现在上面 最佳。因此,图像中只有不透明/半透明像素将具有顶部绘制的最后一个绘制的黑色像素
  7. 绘制图像
  8. 将GCO设置为destination-over,这意味着所有像素来自 画布上的最后一次绘制(黑色渐变的图像) 出现在将要绘制的青色矩形上方。所有其他像素将 获取源像素(青色背景)
  9. 绘制青色背景矩形。
  10. 全部完成。

    fadeIn === 0 GCO destination-atop失败时,因为所有像素在黑色背景中都是透明的。因此,请确保通过代码中演示的第二种方法绘制图像。

    jsFiddle的一个工作示例

    Fiddle of code below

    奇怪的是,如果作为Stack Overflow Snippet

    插入,下面的代码不起作用

    代码。

    // set up canvas and context
    var canvas = document.getElementById("canV");
    var ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height); // why? Just habbit;
    
    // create image
    var img;    
    img = new Image();
    var fadeIn = 1;
    
    function update() {
        if(fadeIn <= 0){  // when fade done draw normally
            ctx.globalAlpha = 1;  // set alpha
            ctx.globalCompositeOperation = "source-over"; // default blend mode
            ctx.fillStyle = "#4DB8FF"; // background
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            // do it all again in 4 secs.
            setTimeout(function(){
              fadeIn = 1;
              window.requestAnimationFrame(update);
            }, 4000); // do it again in four seconds
        }else{
            // first draw the black fading out
            ctx.globalCompositeOperation = "source-over";       
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            ctx.globalAlpha = fadeIn;
            ctx.fillStyle = "#000000";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
    
            // now draw the image with destination-atop
            // this means that for each visible pixel (alpha > 0)
            // draw the destination pixels (what is already on the canvas)
            // over the top
            ctx.globalCompositeOperation = "destination-atop";      
            ctx.globalAlpha = 1; 
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    
            // and last draw the background with destination over.
            // which means only draw pixels where the destination
            // pixels are transparent.
            ctx.globalCompositeOperation = "destination-over";      
            ctx.fillStyle = "#4DB8FF";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
    
            // decrease fade
            fadeIn -= 0.02;
            // call next frame
            window.requestAnimationFrame(update)
        }
    
    }
    
    // start it all happening.
    img.onload = function () {     
        window.requestAnimationFrame(update)
    }
    
    // load the image.
    img.src = "http://i.stack.imgur.com/ysINC.png";
    

    希望这有帮助。

答案 1 :(得分:0)

您可以使用画布来创建图层。

我们的想法是每个图层都是一个离屏画布,您将在主要的屏幕画布上以正确的顺序绘制。

使用您的代码,它会提供类似的内容:

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var img;    
img = new Image();
img.src = "http://i.stack.imgur.com/ysINC.png";
// an array containing our canvases' contexts
var layers = [];
for( var i=0; i<3; i++){
  // we can only save the contexts 
  // since we've got a reference to their canvas in it
  layers.push(canvas.cloneNode(true).getContext('2d'));
  }
// the alpha values for layer2 and layer1
var i = 1;
var k = 1;

function test1() {
    // layer0 is our background
    layers[0].fillStyle = "#4DB8FF";
    layers[0].fillRect(0, 0, 600, 500);
    // the middle image
    layers[1].globalAlpha = k;
    layers[1].drawImage(img, 0, 0, 600, 500);
    if (i > 0) {
        // the top black layer
        layers[2].globalAlpha = i;
        layers[2].fillStyle = "#000000";
        layers[2].fillRect(0, 0, 600, 500);
        setTimeout(test2, 100);
    }
    else{
        test3();
      }
    // draw each of our layers's canvas on the main one
    for(var j=0; j<layers.length; j++){
      ctx.drawImage(layers[j].canvas, 0,0);
      layers[j].clearRect(0,0, canvas.width, canvas.height);
      }
}

function test2() {
    ctx.clearRect(0, 0, 600, 500);
    i -= 0.01;
    test1();    
}
function test3() {
  if(k>0){
    k -= 0.1;
    setTimeout(test2, 100);
    }
  }
img.onload = function () {          
    test1();
    }
<canvas id="myCanvas" width="600" height="500"></canvas>

如果@ Blindman67正确地得到你想要的东西,你仍然可以使用这种层次的想法,只设置你的一个上下文的gCO:

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var img;    
img = new Image();
img.src = "http://i.stack.imgur.com/ysINC.png";
// an array containing our canvases' contexts
var layers = [];
for( var i=0; i<3; i++){
  // we can only save the contexts 
  // since we've got a reference to their canvas in it
  layers.push(canvas.cloneNode(true).getContext('2d'));
  }
// the alpha values for layer2 and layer1
var i = 1;

function test1() {
    // layer0 is our background
    layers[0].fillStyle = "#4DB8FF";
    layers[0].fillRect(0, 0, 600, 500);
    // the middle image
    layers[1].drawImage(img, 0, 0, 600, 500);
    if (i > 0) {
        // the top black layer
        layers[2].globalAlpha = i;
        layers[2].fillStyle = "#000000";
        layers[2].fillRect(0, 0, 600, 500);
        setTimeout(test2, 100);
    }
    // change our image layer's gCO
    layers[1].globalCompositeOperation="source-atop";
    // draw the black layer on it
    layers[1].drawImage(layers[2].canvas, 0,0);
    // reset image layer's gCO
    layers[1].globalCompositeOperation="source-over";
    // draw each of our layers's canvas on the main one
    for(var j=0; j<layers.length; j++){
      // don't draw the black layer since it's already on the image's one
      if(j!==2)
        ctx.drawImage(layers[j].canvas, 0,0);
      layers[j].clearRect(0,0, canvas.width, canvas.height);
      }
}

function test2() {
    ctx.clearRect(0, 0, 600, 500);
    i -= 0.01;
    test1();    
}
img.onload = function () {          
    test1();
    }
<canvas id="myCanvas" width="600" height="500"></canvas>