2015-11-15 4 views
0

Я рисую полупрозрачный цвет (например, rgba(255,0,0,0.5)) над холстом. Когда я снова рисую над той же областью, значение прозрачности, кажется, складывается, что приводит к непрозрачному цвету. Есть ли способ сохранить значение прозрачности источника (полупрозрачный цвет, который я использую для рисования)?Как сбросить прозрачность при рисовании перекрывающегося содержимого на холсте HTML?

+0

'ctx.clearRect (0,0, canvas.width, canvas.height)' затем перерисовывать? – Kaiido

+0

@Kaiido. Нет, ** это гораздо более интересный вопрос **, чем проблема 'clearRect'! ;-) Они хотят нарисовать полупрозрачную заливку, а затем частично наложить еще одну полупрозрачную начинку, но перекрывающаяся область должна иметь только вторую заливку (не смесь двух альфа-заливок). После коротких мыслей я не могу думать о композиционном решении, потому что композиция уважает альфы. Это может привести к решению '.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)', как будто это было '.25' для обоих цветов альфы? – Kaiido

ответ

2

Нарисуйте на заднем экране холст с alpha = 1. Затем просто визуализируйте экранный холст на холст дисплея с помощью ctx.globalAlpha, установленного по любому желаемому значению. Таким образом, вы можете рисовать до тех пор, пока солнце не опустится, не добавив ничего в альфу. Также легко изменить альфу после того, как вы нарисовали, если потребуется.

Дополнительное примечание

Если другие материалы, включенные в изображение, вы должны будете держать это на другом слое, а также потому, что этот метод основан на экранном полотне сбрасывается до желаемого исходного состояния для каждого Обновить. В этом фрагменте это всего лишь звонок clearRect. Но он может быть заменен другим существующим слоем или комбинацией.

Браузер может легко обрабатывать множество экранных холстов, я только что закончил работу, у которой было 60 полноэкранных холстов, уложенных друг на друга (обратите внимание, что вашему графическому процессору необходимо, чтобы оперативная память сохраняла изображения или была слишком медленной) и 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

Звучит многообещающе .. но только если все альфы одинаковы. – markE

+0

60 одновременных полноэкранных рендерингов - ничего себе! Просто любопытно ... что такое приложение, которое требовало много наложений? – markE

+0

Очень глубокие (слои) изображения параллакса изображения некоторых изображений микроскопа. – Blindman67

Смежные вопросы