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();

// 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

4 回答 4

6

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

本演示所示,结果将如下所示:

重叠的正方形

定义线宽和要绘制的矩形(您可以使用已经计算位置/角度的循环填充此数组 - 为简单起见,我在这里只使用硬编码的):

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但是将始终对第一个矩形进行调整)。

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

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

于 2013-08-22T21:16:20.403 回答
1

切割矩形并计算哪个子矩形越过哪个矩形的唯一方法。但我认为您必须分别绘制边框和内部矩形,因为分隔矩形会添加额外的边框。

希望它有所帮助

于 2013-08-22T20:31:10.520 回答
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);
}

演示在这里

如果你必须让它动态,你可以像 Dark Duck 建议的那样切割形状,或者你可以尝试创建一个函数来检测对象何时重叠并在每个矩形重绘一次(很难做到,不确定它是否会工作)。也许你可以想出一些方程式来定位元素与我现在如何硬编码它们以始终根据旋转角度工作,这将是你最好的选择 IMO,但我不知道如何做到这一点确切地

总体而言,您目前无法真正做您正在寻找的事情

于 2013-08-22T21:04:55.593 回答
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>

jsFiddle 上的演示

于 2013-08-23T22:54:55.717 回答