2015-11-15 123 views
0

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

+0

'ctx.clearRect(0,0,canvas.width,canvas.height)'然后重绘? – Kaiido

+0

@Kaiido。不,**这是一个比'clearRect'问题更有趣的问题**! ;-)他们想绘制半透明填充,然后部分覆盖另一个半透明填充 - 但重叠区域应该只有第二个填充(不是2个alpha填充的混合)。经过短暂的思考,我想不出合成解决方案,因为合成尊重alpha。它可能归结为'.getImageData'解决方案。 – markE

+0

@markE,但它对我来说似乎是违反直觉的:如果我用半透明颜色绘制多次,它变得越来越不透明似乎是正常的。如果OP要始终使用相同的字母,可能会考虑'globalAlpha'属性,或仅在将要重绘的像素上使用'clearRect()'。但不清楚'rgba(0,255,0,0.5)'+'rgba(0,0,255,0.5)'应该返回什么。 'rgba(0,107,147,0.5)'就好像两个alpha颜色都是'.25'一样? – Kaiido

回答

2

使用alpha = 1绘制到屏幕外画布。然后,将屏幕画布呈现在显示画布上,并将ctx.globalAlpha设置为您希望的值。这样,你可以绘制,直到太阳下山,而不需要添加任何东西到阿尔法。如果需要绘制,在绘制后也很容易。

附记

如果已经包括在图像中的其他内容,你将不得不继续其在另一层,以及因为这种方法依赖屏幕上的画布上被复位到期望的起始状态为每个更新。在这段代码中,这只是一个clearRect调用。但也可以用另一个现有图层或其组合替换。

浏览器可以很容易地处理很多屏幕画布,我刚刚完成了一个有60个全屏幕帆布堆叠在一起的作业(注意你的GPU需要RAM来存放图像或它太慢)和Chrome甚至没有眨眼。 Firefox和IE的功能一样。

UPDATE

我添加了一个片断来证明我的意思。底部有关代码的评论详情。只是一个简单的绘图界面。

// 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; 
 
\t   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>

+1

听起来很有希望..但只有所有的alpha都相同。 – markE

+0

60个同步全屏效果图 - 哇!只是好奇...什么是需要这么多覆盖的应用程序? – markE

+0

某些显微镜图像的非常深的(层)视差图像视图。 – Blindman67