2016-09-24 2 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.

Здесь вы можете комбинировать перекрывающиеся полупрозрачные круги, не перекрывая наложение.

  • Нарисуйте все одинаково цветные круги на 2-м холсте непрозрачным цветом.
  • Набор context.globalCompositeOperation='source-in', который заставляет новые чертежи заменять существующие пиксели.
  • Заполните 2-й холст желаемым полупрозрачным цветом для этого набора неоткрытых кругов.

В результате получается набор перекрывающихся кругов без эффекта затемнения.

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>

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