如何用帆布创建重叠 - 而不是堆叠 - 形状?

时间:2013-08-22 20:06:54

标签: javascript html5 canvas

我正在尝试创建一个重叠的形状数组。但是我很难防止那些形状叠加在另一个上面。

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

以下是代码:

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/

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

4 个答案:

答案 0 :(得分:6)

您无法指定此行为,但可以实现使用复合模式的算法方法。

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;

在循环中,为第一次绘制添加一个条件,这也是更改复合模式的位置。我们还使用 last 矩形清除画布:

/// 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模式,这意味着当我们第一次填充时,一半的线将不可见,这将成为目标的一部分,因此笔划只能填充在描边区域之外(您可以反转strokefill的顺序,但总是会对第一个矩形进行调整。

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

这也是我们最初将它设置为一半的原因,因为第一次绘制整条线 - 否则第一个矩形将具有双倍粗边框。

答案 1 :(得分:1)

唯一的方法是剪切矩形并计算哪个子矩形超过哪一个。但我认为你必须分别绘制边框和内部矩形,因为分离矩形会增加额外的边框。

希望有所帮助

答案 2 :(得分:1)

可悲的是,您想要使用画布在元素的一部分上设置z-index的功能目前不可用。如果您只需要四个矩形对象,您可以执行类似这样的操作,隐藏矩形的一部分以伪造您想要的效果,但这只是硬编码为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,但我不知道如何做到这一点准确

总的来说,你现在无法真正做到你正在寻找的东西

答案 3 :(得分: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