2016-09-24 163 views
1

當我使用每個圓的fill()逐個繪製相同顏色的圓。當它們重疊時,常見的是顏色更深(飽和)。參見示例1(左)in JS Bin繪製與公共區域相同顏色的相撞透明圓

如果我創建長路徑,然後使用fill()爲這個公共路徑,它有奇怪的工件(當然,它是困惑的複雜路徑,不知道我想畫什麼) 查看示例2(右)in JS Bin

我怎麼能達到相同顏色的圓圈的公共區域沒有飽和,它應該不會比其他具有相同顏色的圓圈更暗。 (正是我有in JS Bin右側,但沒有瘋狂的文物)

如果具有不同顏色的圓有公共區域,顏色應飽和。

+1

正如你可以看到,一些coliding界具有相同的顏色卻有些不。並且相同顏色的相撞圓圈應該保持相同的顏色,當它們被另一種顏色的圓圈覆蓋時,顏色需要飽和。 – Rantiev

回答

0

我已經解決了使用幫手畫布和畫布圖像數據處理的問題。

有數據數組,其中包含的座標和值用於確定我們需要使用哪種顏色。

我在它自己的圖層中繪製每個圓的顏色,然後用preventSaturation函數處理每個圖層。然後將所有圖層添加到原始畫布中。

請如果有人知道更好的方式讓我知道。

如果有人不明白我需要做的是: 1)我有this 2)我想有this

var canvas = document.getElementById('circles'); 
var ctx = canvas.getContext('2d'); 

var radius = 30; 
var opacity = .7; 

var data = [ 
    { 
     x: 200, 
     y: 200, 
     v: 10 
    }, 
    { 
     x: 230, 
     y: 230, 
     v: 20 
    }, 
    { 
     x: 250, 
     y: 210, 
     v: 30 
    }, 
    { 
     x: 270, 
     y: 190, 
     v: 40 
    }, 
    { 
     x: 300, 
     y: 220, 
     v: 100 
    }, 
    { 
     x: 300, 
     y: 260, 
     v: 200 
    }, 
    { 
     x: 320, 
     y: 210, 
     v: 300 
    }, 
    { 
     x: 300, 
     y: 160, 
     v: 200 
    }, 
    { 
     x: 380, 
     y: 160, 
     v: 3000 
    }, 
    { 
     x: 380, 
     y: 110, 
     v: 3000 
    }, 
    { 
     x: 320, 
     y: 190, 
     v: 3000 
    } 
]; 

var styles = { 
    blue: { 
     edgeValue: 0, 
     color: [0, 0, 255, 0.7] 
    }, 
    green: { 
     edgeValue: 100, 
     color: [0, 255, 0, 0.7] 
    }, 
    red: { 
     edgeValue: 1000, 
     color: [255, 0, 0, 0.7] 
    } 
}; 

var layers = {}; 

for (var prop in styles) { 
    if(styles.hasOwnProperty(prop)) { 

     var c = document.createElement('canvas'); 
     c.width = canvas.width; 
     c.height = canvas.height; 

     var cx = c.getContext('2d'); 

     var cc = document.createElement('canvas'); 
     cc.width = radius * 2; 
     cc.height = radius * 2; 

     var ccx = cc.getContext('2d'); 

     var cColor = styles[prop].color; 

     ccx.fillStyle = 'rgba(' + cColor[0] + ',' + cColor[1] + ',' + cColor[2] + ',' + cColor[3] + ')'; 

     ccx.beginPath(); 
     ccx.arc(radius, radius, radius, 0, Math.PI * 2, true); 
     ccx.closePath(); 
     ccx.fill(); 

     layers[prop] = { 
      color: styles[prop].color, 
      edgeValue: styles[prop].edgeValue, 
      canvas: c, 
      ctx: cx, 
      canvasC: cc, 
      ctxC: ccx, 
      objects: [] 
     }; 

    } 
} 

data.forEach(function(o) { 
    var layer = o.v < styles.green.edgeValue ? layers.blue : o.v < styles.red.edgeValue ? layers.green : layers.red; 
    layer.ctx.drawImage(layer.canvasC, o.x, o.y); 
    layer.objects.push(o); 
}); 

for(prop in layers) { 
    if(layers.hasOwnProperty(prop)) { 
     var image = layers[prop].ctx 
       .getImageData(0, 0, layers[prop].canvas.width, layers[prop].canvas.height); 
     preventColorSaturation(image.data, layers[prop].color); 
     layers[prop].ctx.putImageData(image, 0, 0); 

     ctx.drawImage(layers[prop].canvas, 0, 0); 
    } 
} 

function preventSaturation (d, s) { 
    var rgb255 = raRGBA255(s); 

    for (var i = 0; i < d.length; i += 4) { 
     d[i] = Math.min(d[i], rgb255[0]); 
     d[i + 1] = Math.min(d[i + 1], rgb255[1]); 
     d[i + 2] = Math.min(d[i + 2], rgb255[2]); 
     d[i + 3] = Math.min(d[i + 3], rgb255[3]); 
    } 
} 

function raRGBA255 (s) { 

    return [ 
     s[0], 
     s[1], 
     s[2], 
     255 * s[3] 
    ]; 
} 

function raHexToRGB (s) { 
    var hexREGEXP = /^#([0-9A-Za-z]{3,6})$/; 
    var parsedHEX = s.match(hexREGEXP); 

    if (!parsedHEX) { 
     return [0, 0, 0]; 
    } 

    return [ 
     parseInt(parsedHEX[1].slice(0, 2), 16), 
     parseInt(parsedHEX[1].slice(2, 4), 16), 
     parseInt(parsedHEX[1].slice(4), 16) 
    ]; 
} 
+0

很高興你把它分類。是的,有一個更快(更有效)的方式來實現你的結果 - 見我的答案。 – markE

1

enter image description here

關於你.getImageData解決方案.. 。

使用合成而不是.getImageData來混合顏色會更快。

這裏有一個功能來組合重疊的半透明圓圈而不會使重疊變暗。

  • 在第二個畫布上以不透明顏色繪製所有相同顏色的圓。
  • 設置context.globalCompositeOperation='source-in'這會導致新圖形取代現有像素。
  • 用第二個畫布填充所需的半透明顏色,用於這組圓形彩色圓圈。

結果是一組沒有變暗效果的重疊圓圈。

function uniformColorCircles(circles){ 
    var PI2=Math.PI*2; 
    tempctx.globalCompositeOperation='source-over'; 
    tempctx.clearRect(0,0,cw,ch); 
    tempctx.beginPath(); 
    for(var i=0;i<circles.length;i++){ 
     var c=circles[i]; 
     tempctx.arc(c.x,c.y,c.radius,0,PI2); 
    } 
    tempctx.fillStyle='black'; 
    tempctx.fill(); 
    tempctx.globalCompositeOperation='source-in'; 
    tempctx.fillStyle=circles[0].rgba; 
    tempctx.fill(); 
} 

這裏是示例代碼和涉及多套半透明圓的演示:

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

 
ctx.fillRect(0,0,120,220); 
 

 
var tempCanvas=canvas.cloneNode(); 
 
var tempctx=tempCanvas.getContext('2d'); 
 

 
var c1={x:100,y:200,radius:50,rgba:'rgba(255,0,0,0.5)'}; 
 
var c2={x:100,y:240,radius:35,rgba:'rgba(255,0,0,0.5)'}; 
 
var c3={x:140,y:200,radius:50,rgba:'rgba(0,255,255,0.5)'}; 
 
var c4={x:140,y:240,radius:35,rgba:'rgba(0,255,255,0.5)'}; 
 
var c5={x:120,y:140,radius:50,rgba:'rgba(255,255,0,0.5)'}; 
 
uniformColorCircles([c1,c2]); 
 
ctx.drawImage(tempCanvas,0,0); 
 
uniformColorCircles([c3,c4]); 
 
ctx.drawImage(tempCanvas,0,0); 
 
uniformColorCircles([c5]); 
 
ctx.drawImage(tempCanvas,0,0); 
 

 

 
function uniformColorCircles(circles){ 
 
    var PI2=Math.PI*2; 
 
    tempctx.globalCompositeOperation='source-over'; 
 
    tempctx.clearRect(0,0,cw,ch); 
 
    tempctx.beginPath(); 
 
    for(var i=0;i<circles.length;i++){ 
 
     var c=circles[i]; 
 
     tempctx.arc(c.x,c.y,c.radius,0,PI2); 
 
    } 
 
    tempctx.fillStyle='black'; 
 
    tempctx.fill(); 
 
    tempctx.globalCompositeOperation='source-in'; 
 
    tempctx.fillStyle=circles[0].rgba; 
 
    tempctx.fill(); 
 
}
body{ background-color:white; } 
 
#canvas{border:1px solid red; }
<canvas id="canvas" width=512 height=512></canvas>

相關問題