【问题标题】:How to reset transparency when drawing overlapping content on HTML canvas?在 HTML 画布上绘制重叠内容时如何重置透明度?
【发布时间】:2016-02-16 20:14:26
【问题描述】:

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

【问题讨论】:

  • @Kaiido。不,这是一个比clearRect 问题更有趣的问题! ;-) 他们想要绘制一个半透明填充,然后部分覆盖另一个半透明填充——但重叠区域应该只有第二个填充(不是 2 个 alpha 填充的混合)。经过短暂的思考,我想不出合成解决方案,因为合成尊重 alpha。它可能归结为.getImageData 解决方案。
  • @markE 但这对我来说似乎违反直觉:如果我用半透明颜色多次绘制,它变得越来越不透明似乎很正常。如果 OP 想要始终相同的 alpha,也许可以考虑 globalAlpha 属性,或者 clearRect() 仅在将要重绘的像素上。但尚不清楚rgba(0,255,0,0.5) + rgba(0,0,255,0.5) 应该返回什么。 rgba(0, 107, 147, 0.5) 好像是 .25 对于两种 alpha 颜色?
  • 是的,这是违反直觉的——通常你需要加法阿尔法,这样你就可以模拟混合水彩之类的东西。我(完全)猜测他们正在为下面的某些图像添加半透明注释,并且他们希望第二个半透明颜色完全覆盖第一个半透明颜色。如果他们只是使用 alpha 来获得某种颜色,他们可以将 rgba --> rgb 转换为完全不透明的颜色,然后使用合成来获得它们的效果。
  • 对自己轻笑! :-)) 在我的最后一条评论中,如果所有颜色都转换为不透明,那么您不需要合成,您只需按顺序绘制,下一种颜色总是会覆盖最后一种颜色。
  • szimek...我们需要您提供更多信息。 您是否需要半透明(如果不需要,将 rgba 转换为 rgb)?你所有的 alpha 值是否都相同(如果是,Blindman67 有你的解决方案)?

标签: javascript html canvas


【解决方案1】:

使用alpha = 1 绘制到屏幕外画布。然后只需将屏幕外画布渲染到显示画布上,并将ctx.globalAlpha 设置为您希望的任何值。这样你就可以一直画到太阳下山,而无需在 alpha 中添加任何内容。如果需要,在绘制后更改 alpha 也很容易。

补充说明

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

浏览器可以轻松处理许多屏幕外画布,我刚刚完成了一项将 60 个全屏画布堆叠在一起的工作(请注意,您的 GPU 需要有 RAM 来保存图像,否则它太慢了)和 Chrome甚至没有眨眼。 Firefox 和 IE 一样有能力。

更新

我添加了一个 sn-p 来说明我的意思。详情在底部相关代码的 cmets 中。只是一个简单的绘图界面。

// 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>

【讨论】:

  • 听起来很有希望……但前提是所有 alpha 值都相同。
  • 60 个同时全屏渲染——哇!只是好奇......需要这么多叠加层的应用是什么?
  • 一些显微镜图像的非常深(层)视差图像视图。
  • 酷!听起来像是一个有趣的项目——有趣的项目让我们不再将编程视为一件苦差事。
  • @Kaiido 将添加一个 sn-p 以澄清。
猜你喜欢
  • 2012-05-07
  • 2017-11-29
  • 2015-10-20
  • 2016-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
相关资源
最近更新 更多