在绘制透明形状时覆盖在画布上绘制

时间:2016-08-30 22:07:02

标签: javascript html5 canvas transparency

我无法看到这已经发布了,所以就这样了。

让我说我在画布上画了2个方格。

LinkedHashMap

生成此图像:

enter image description here

如果我将globalAlpha更改为0.5,我会得到:

enter image description here

但是,我希望产生这个:

enter image description here

同样,所有像素都是透明的,其下面的任何图像都会出现,但红色三角形创建的像素将覆盖绘制它的现有蓝色三角形。

并且ctx.globalComposisteOperation在这种情况下似乎没有帮助,因为它还考虑了透明度以及我希望保留两个方块的事实。

有没有办法用现有方法做到这一点?

6 个答案:

答案 0 :(得分:1)

使用合成在绘制之前清除红色三角形。

使用合成比剪辑略好,因为您不必清除剪辑。清除剪辑需要保存整个上下文状态,然后恢复该上下文状态 - 涉及许多属性。合成只需要前后改变1个属性。

enter image description here



var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// fill the blue rect
ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();

// define the red rect path
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(75, 50);
ctx.lineTo(25, 50);
ctx.lineTo(50, 0);

// clear the red rect path using compositing
ctx.globalCompositeOperation='destination-out';
ctx.fillStyle='black';
ctx.fill();
ctx.globalCompositeOperation='source-over';

// fill the red rect
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fill();

body{ background-color:white; }
#canvas{border:1px solid red; }

<canvas id="canvas" width=512 height=512></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

以photoshop的方式进行,并创建图层来为您完成工作。创建图层(第二个画布)并不比加载图像更麻烦。您可以创建数十个并且没有任何问题,这使得这种工作变得简单。

首先创建第二个画布(图层)

// canvas is original canvas 
var layer = document.createElement("canvas");
layer.width = canvas.width;  // same size as original 
layer.height = canvas.height;
var ctx1 = layer.getContext("2d");

然后使用alpha = 1;

在第二个画布上绘制三角形
var tri = (x,c)=>{
    ctx1.fillStyle = c;
    ctx1.beginPath();
    ctx1.moveTo(25 + x, 0);
    ctx1.lineTo(50 + x, 50);
    ctx1.lineTo(0 + x, 50);
    ctx1.closePath();
    ctx1.fill();
}
tri(0,"#00f");
tri(25,"#f00");

然后只需使用您想要的Alpha值在您正在处理的画布上绘制该图层。

ctx.globalAlpha = 0.5;
ctx.drawImage(layer,0,0);

如果您不需要额外的图层,请通过取消引用来删除画布和上下文。

ctx1 = undefined;
layer = undefined; 

或者您可以保留图层,并为背景制作另一个图层并实时混合以使FX恰到好处

    //
    var canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    var ctx = canvas.getContext("2d");

    var layer = document.createElement("canvas");
    layer.width = canvas.width;  // same size as original 
    layer.height = canvas.height;
    var ctx1 = layer.getContext("2d");
    var tri = (x,c)=>{
        ctx1.fillStyle = c;
        ctx1.beginPath();
        ctx1.moveTo(25 + x, 0);
        ctx1.lineTo(50 + x, 50);
        ctx1.lineTo(0 + x, 50);
        ctx1.fill();
    }
    tri(0,"#00f");
    tri(25,"#0f0");
    tri(50,"#f00");
    ctx.globalAlpha = 0.5;
    ctx.drawImage(layer,0,0);
    layer = ctx1 = undefined;

答案 2 :(得分:0)

您可以在绘制之前清除第二个矩形的区域。

&#13;
&#13;
var c = document.getElementById('game'), 
    ctx = c.getContext('2d');
ctx.globalAlpha = 0.5;
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 50, 50);

// Clear the extra bit of the blue rectangle
ctx.clearRect(25, 25, 25, 25);

ctx.fillStyle = "red";
ctx.fillRect(25, 25, 50, 50);
&#13;
<canvas id="game" width="320" height="240"></canvas>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

我诚实地建议只改变颜色并避免使用alpha。

var c = document.getElementById('game'), 
    ctx = c.getContext('2d');
ctx.fillStyle = "#8080FF";
ctx.fillRect(0, 0, 50, 50);
ctx.fillStyle = "#ff8080";
ctx.fillRect(25, 25, 50, 50);
<canvas id="game" width="320" height="240"></canvas>

答案 4 :(得分:0)

saveMyClass(updatedMyClass: MyClass){
        //saving MyClass using http service
        //return the saved MyClass or error
        var savedMyClass : MyClass = someLogicThatReturnsTheSavedObject(updatedMyClass);
        if(isSomeCondition)
            return Promise.reject(new Error('No reason but to reject'));
        else
            return new Promise<MyClass>(resolve => {setTimeout( ()=>resolve(savedMyClass),1500  )}  );
    }

只需使用clip()获取当前路径,使用clearRect清除其中的所有内容,然后正常绘制路径。

答案 5 :(得分:0)

@markE是对的,使用合成而不是剪辑(非常重)。

然而,只有你用rgba颜色绘制所有内容时,他的解决方案才有效。也许我错误地读了你的问题,但是如果你是从一个不透明的形状出发并希望它变得透明,那么你应该使用copy gCO和globalAlpha属性。

由于drawImagefill快,因此性能影响较小,并且可以让您执行淡出效果;但这实际上取决于你的需求。

var ctx = c.getContext('2d');
// initial blue
ctx.fillStyle = "#0000FF";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();

setTimeout(function drawRed() {
  ctx.fillStyle = "#FF0000";
  ctx.beginPath();
  ctx.moveTo(50, 0);
  ctx.lineTo(75, 50);
  ctx.lineTo(25, 50);
  ctx.lineTo(50, 0);
  ctx.fill();
}, 500);

btn.onclick = function makeItTransparent() {
  // if we weere to make this into an animation, we would set it only once
  ctx.globalCompositeOperation = 'copy';
  ctx.globalAlpha = .8;
  // draw the canvas on itself
  ctx.drawImage(c, 0, 0);
  // once again, in an animation we won't reset this to default
  ctx.globalAlpha = 1;
  ctx.globalCompositeOperation = 'source-over';
};
/* checkboard background */
canvas {
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWNgYGBowIKxgqGgcJA5h3yFAOI3GQFqqi5ZAAAAAElFTkSuQmCC");
  }
<canvas id="c"></canvas>
<button id="btn">make it transparent</button>