如何在HTML画布上绘制重叠内容时重置透明度?

时间:2015-11-15 18:33:32

标签: javascript html5 canvas

我在画布上使用半透明颜色(例如rgba(255,0,0,0.5))进行绘制。当我再次在同一区域上绘制时,透明度值似乎相加,导致颜色不透明。有没有办法保持源的透明度值(我用来绘制的半透明颜色)?

1 个答案:

答案 0 :(得分:2)

使用alpha = 1绘制到屏幕外画布。然后将屏幕外画布渲染到显示画布,并将ctx.globalAlpha设置为您想要的任何值。这样你就可以画画直到太阳落下而不会给阿尔法添加任何东西。如果需要,在绘制后也可以轻松更改alpha。

附加说明

如果图像中包含其他内容,则必须将其保留在另一个图层上,因为此方法依赖于屏幕画布重置为每次更新所需的起始状态。在代码段中,这只是一个clearRect电话。但也可以用另一个现有层或其组合替换。

浏览器可以轻松处理许多屏幕外画布,我刚刚完成了一个有60个全屏画布堆叠在一起的作业(注意你的GPU需要有RAM来保存图像,或者它太慢了)和Chrome甚至没有眨眼。 Firefox和IE也同样强大。

更新

我添加了一个片段来演示我的意思。底部相关代码的评论中的详细信息。只是一个简单的绘图界面。

// get canvas set up mouse and do the other things
var canvas = document.getElementById("canV"); 
var ctx = canvas.getContext("2d");
var w = canvas.width;
var h = canvas.height;
var mouse = {
    x:0,
    y:0,
    buttonLastRaw:0, // user modified value 
    buttonRaw:0,
    over:false,
};
function mouseMove(event){
    mouse.x = event.offsetX;  mouse.y = event.offsetY; 
    if(mouse.x === undefined){ mouse.x = event.clientX;  mouse.y = event.clientY;}    
    if(event.type === "mousedown"){ mouse.buttonRaw = 1;
    }else if(event.type === "mouseup"){mouse.buttonRaw = 0;
    }else if(event.type === "mouseout"){ mouse.buttonRaw = 0; mouse.over = false;
    }else if(event.type === "mouseover"){ mouse.over = true; }
    event.preventDefault();
}

canvas.addEventListener('mousemove',mouseMove);
canvas.addEventListener('mousedown',mouseMove);
canvas.addEventListener('mouseup'  ,mouseMove); 
canvas.addEventListener('mouseout'  ,mouseMove); 
canvas.addEventListener('mouseover'  ,mouseMove); 
canvas.addEventListener("contextmenu", function(e){      canvas.preventDefault();}, false);

// create off screen layer that we will draw to
var layer1 = document.createElement("canvas");  
layer1.width = w;   // same size as the onscreen canvas
layer1.height = h; 
layer1.ctx = layer1.getContext("2d"); 
// set up drawing settings
layer1.ctx.lineCap = "round";
layer1.ctx.lineJoin = "round";
layer1.ctx.lineWidth = 16;
layer1.ctx.globalAlpha = 1;  // draw to this layer with alpha set to 1;

// set up onscreen canvas
ctx.globalAlpha = 1;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "24px Arial black";
var instructions = true;

// colours to show that different layer are overwriting each other
var colours = "#F00,#FF0,#0F0,#0FF,#00F,#F0F".split(",");
var currentCol = 0;

// update on animation frame
function update(){
    ctx.clearRect(0,0,w,h);  // clear onscreen
    var c = layer1.ctx;      // short cut to the later1 context
    if(mouse.buttonRaw){    // if mouse down 
        if(mouse.lastx === undefined){   // is this start of drawing stroke
            mouse.lastx = mouse.x;   // set up drawing stroke
            mouse.lasty = mouse.y;
	        c.strokeStyle = colours[currentCol % colours.length];
            currentCol += 1;
            instructions = false;   // tuen of the instructions as they have worked it out
            ctx.globalAlpha = 0.6;  // should do this near layering but lasy
        }
        // draw the dragged stroke to the offscreen layer
        c.beginPath();
        c.moveTo(mouse.lastx,mouse.lasty);
        c.lineTo(mouse.x,mouse.y);
        c.stroke();
        mouse.lastx = mouse.x;
        mouse.lasty = mouse.y;        
    }else{  // if the mouse button up show drawing brush and instructions if
            // nothing has happened yet
        mouse.lastx = undefined;    // using this as a semaphore for drag start
        ctx.fillStyle = colours[currentCol%colours.length];
        ctx.globalAlpha = 0.6;    // the brush will compound the alpha 
                                   // this can be avoided by drawing it onto
                                   // the offscreen layer, but you will need 
                                   // another layer or some temp store to 
                                   // protect the offscreen layer. Again I am
                                   // to lazy to implement that right now.
        ctx.beginPath();
        ctx.arc(mouse.x,mouse.y,8,0,Math.PI*2);
        ctx.fill();
        if(instructions){         // show instructions if needed
          ctx.fillStyle = "blue";
          ctx.globalAlpha = 1;
          ctx.fillText("Click drag mouse to draw",250,60);
        }
    }
    
    // draw the offscreen layer onto the onscreen canvas at the alpha wanted
    ctx.drawImage(layer1,0,0);
    requestAnimationFrame(update);  // do it all again.
}
mouse.lastx;  // needed to draw lines.
mouse.lasty;
update()
body {    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAlUlEQVRYR+2WsQ0EIQwEbXpAopbrAZESUhQ1AAkBXVEDAb6jBRP8B0s+yJpklnvvstYizRMRyjmTtVaD096buNYqzjnVB3NOaq3RGEPFhxBwAAzAAAzAAAz8gYFSijCzqmYH+ngyxqj4k3N+nkduep5Sops9wV+T5abnMUa62RM4AAZgAAZgAAZ+b8B7Lzc9PzW82RMvg0g+JLdy9xIAAAAASUVORK5CYII=');


    background-size: 32px 32px;
    background-repeat: repeat;
}
.canC { width:500px;  height:600px;}
<canvas class="canC" id="canV" width=500 height=600></canvas>