2013-08-22 77 views
3

我正尝试创建一个重叠形状的数组。但是我很难阻止那些堆叠在一起的形状。如何使用画布创建重叠 - 不堆叠 - 形状?

我想我想让它们啮合在一起,如果有意义的话?

下面的代码:

var overlap_canvas = document.getElementById("overlap"); 
var overlap_context = overlap_canvas.getContext("2d"); 
var x = 200; 
var y = x; 
var rectQTY = 4 // Number of rectangles 

overlap_context.translate(x,y); 

for (j=0;j<rectQTY;j++){ // Repeat for the number of rectangles 

// Draw a rectangle 
overlap_context.beginPath(); 
overlap_context.rect(-90, -100, 180, 80); 
overlap_context.fillStyle = 'yellow'; 
overlap_context.fill(); 
overlap_context.lineWidth = 7; 
overlap_context.strokeStyle = 'blue'; 
overlap_context.stroke(); 

// Degrees to rotate for next position 
overlap_context.rotate((Math.PI/180)*360/rectQTY); 
} 

而且这里是我的jsfiddle: http://jsfiddle.net/Q8yjP/

这里就是我想要实现:

http://postimg.org/image/iio47kny3/

任何帮助或指导将非常感谢!

回答

7

找什么你不能指定此行为,但你可以实现使用复合模式,在算法上下的方式。

正如this demo the result will be like此图所示:

Squares with overlap

定义线的宽度和你想画(你可以填补这个数组你已经有计算的位置/角度循环矩形 - 为简单起见,我只是在这里使用硬编码的):

var lw = 4, 
    rects = [ 
     [20, 15, 200, 75], 
     [150, 20, 75, 200], 
     [20, 150, 200, 75], 
     [15, 20, 75, 200] 
    ], ... 

我将在下面解释行宽。

/// set line-width to half the size 
ctx.lineWidth = lw * 0.5; 

在循环中为第一次绘制添加一个标准,这也是您更改复合模式的位置。我们还与最后矩形清除画布:

/// loop through the array with rectangles 
for(;r = rects[i]; i++) { 
    ctx.beginPath(); 
    ctx.rect(r[0], r[1], r[2], r[3]); 
    ctx.fill(); 
    ctx.stroke(); 

    /// if first we do a clear with last rectangle and 
    /// then change composite mode and line width 
    if (i === 0) { 
     r = rects[rects.length - 1]; 
     ctx.clearRect(r[0] - lw * 0.5, r[1] - lw * 0.5, r[2] + lw, r[3] + lw); 
     ctx.lineWidth = lw; 
     ctx.globalCompositeOperation = 'destination-over'; 
    } 
} 

这将绘制矩形,你必须灵活地改变大小,而不需要重新计算剪裁。

线宽单独设置为stroke从中间划线。因此,由于我们稍后使用destination-over模式,这意味着一半的线将不可见,因为我们第一次填充它成为目的地的一部分,因此笔画将只能够填充到笔划区域之外(您可以颠倒stroke的顺序和fill,但总是会对第一个矩形进行调整)。

我们还需要它来计算必须包含(一半)外部线条的剪辑。

这也是为什么我们最初将其设置为第一次绘制整条线时的原因 - 否则第一个矩形会有两倍厚边框。

+0

和下投票是为了什么? – K3N

+0

谢谢。这是一个很大的帮助,非常感谢您的意见。 – Mattarn

1

要做到这一点的唯一方法就是剪切矩形并计算哪一个矩形通过哪一个矩形。但我认为你将不得不分别绘制你的边框和内部矩形,因为分隔矩形会添加额外的边框。

希望它帮助

1

可悲的是,你要使用的画布元素的一部分设置的z索引的功能不可用当前。如果你只是需要它的四个矩形对象,你可以做这样的事情,隐藏矩形的一部分来伪造你想要的效果,但是这被硬编码为只有4个矩形。

var overlap_canvas = document.getElementById("overlap"); 
var overlap_context = overlap_canvas.getContext("2d"); 
var x = 200; 
var y = x; 
var rectQTY = 4 // Number of rectangles 

overlap_context.translate(x, y); 

for (j = 0; j < rectQTY; j++) { // Repeat for the number of rectangles 
    // Draw a rectangle 
    overlap_context.beginPath(); 
    overlap_context.rect(-90, -100, 180, 80); 
    overlap_context.fillStyle = 'yellow'; 
    overlap_context.fill(); 
    overlap_context.lineWidth = 7; 
    overlap_context.strokeStyle = 'blue'; 
    overlap_context.stroke(); 
    if (j === 3) { 
     overlap_context.beginPath(); 
     overlap_context.rect(24, -86, 72, 80); 
     overlap_context.fillStyle = 'yellow'; 
     overlap_context.fill(); 
     overlap_context.closePath(); 

     overlap_context.beginPath(); 
     overlap_context.moveTo(20, -89.5); 
     overlap_context.lineTo(100, -89.5); 
     overlap_context.stroke(); 
     overlap_context.closePath(); 

     overlap_context.beginPath(); 
     overlap_context.moveTo(20.5, -93.1); 
     overlap_context.lineTo(20.5, 23); 
     overlap_context.stroke(); 
     overlap_context.closePath(); 
    } 

    // Degrees to rotate for next position 
    overlap_context.rotate((Math.PI/180) * 360/rectQTY); 
} 

Demo here

如果你必须使它的动态,你可以减少像黑暗鸭建议或者你可以尝试创建,当一个对象被重叠检测功能,并重绘每一次的形状矩形(很难做,不知道它是否会工作)。也许你可以拿出一些关于如何让他们现在硬编码的元素定位方程,以便总是根据旋转角度工作,这将是你最好的选择IMO,但我不知道如何做到这一点正是

总的来说你真的不能做你在这个时间点

+0

感谢您发布工作的jsfiddle –

0

使用纯JavaScript ...

<!DOCTYPE html> 
<html> 
    <head></head> 
    <body> 
     <canvas id="mycanvas" width="400px" height="400px"></canvas> 
     <script> 
      window.onload = function(){ 
       var canvas = document.getElementById('mycanvas'); 
       var ctx = canvas.getContext('2d'); 
       //cheat - use a hidden canvas 
       var hidden = document.createElement('canvas'); 
       hidden.width = 400; 
       hidden.height = 400; 
       var hiddenCtx = hidden.getContext('2d'); 
       hiddenCtx.strokeStyle = 'blue'; 
       hiddenCtx.fillStyle = 'yellow'; 
       hiddenCtx.lineWidth = 5; 
       //translate origin to centre of hidden canvas, and draw 3/4 of the image 
       hiddenCtx.translate(200,200); 
       for(var i=0; i<3; i++){ 
        hiddenCtx.fillRect(-170, -150, 300, 120); 
        hiddenCtx.strokeRect(-170, -150, 300, 120); 
        hiddenCtx.rotate(90*(Math.PI/180)); 
        } 
       //reset the hidden canvas to original status 
       hiddenCtx.rotate(90*(Math.PI/180)); 
       hiddenCtx.translate(-200,-200); 
       //translate to middle of visible canvas 
       ctx.translate(200, 200); 
       //repeat trick, this time copying from hidden to visible canvas 
       ctx.drawImage(hidden, 200, 0, 200, 400, 0, -200, 200, 400); 
       ctx.rotate(180*(Math.PI/180)); 
       ctx.drawImage(hidden, 200, 0, 200, 400, 0, -200, 200, 400); 
       }; 
     </script> 
    </body> 
</html> 

Demo on jsFiddle

+0

这个小提琴不起作用,你可以更新吗? –