在画布上重叠的形状

时间:2018-02-10 19:50:19

标签: javascript html5 canvas graphics drawing

PEN:https://codepen.io/jaredstanley/pen/gvmNye

    var canvas = document.getElementById('c');
    var ctx = canvas.getContext("2d");
    var centerw = canvas.width/2;
    var centerh = canvas.height/2;
    var sq_w = 80;
    //
    ctx.beginPath();
    //draw rectangle
    ctx.rect(this.centerw-(sq_w/2), 0,sq_w, canvas.height);
    //draw circle
    ctx.arc(this.centerw, this.centerh, 185, 0, Math.PI * 2, true);
    //fill
    ctx.fill();

两个形状都是绘制但形状的交叉是空白的。

希望获得一个单一的填充形状,但得到以下结果:[screenshot of result

要求: 无法使用CanvasRenderingContext2D.globalCompositeOperation,因为我将其用于其他内容;这需要用作单个形状,所以我可以使用形状... clip()。

注意:当使用两个rect()调用时,它可以正常工作,并且在使用两个arc()调用时它可以工作,但混合它们似乎会导致问题。

似乎应该很容易,但我很难过,我想错过一些基本的东西。谢谢!

3 个答案:

答案 0 :(得分:2)

路径方向很重要

只需删除(或设置为falsearc() method上的反时钟标志,否则将定义"反对"的路径。影响用于填充的默认non-zero winding algorithm的方向:

//ctx.arc(this.centerw, this.centerh, 185, 0, Math.PI * 2, true); ->
ctx.arc(this.centerw, this.centerh, 185, 0, Math.PI * 2);

仔细观察"非零绕组"

根据非零缠绕规则,我们将从一个线被发送出来的点开始计算绕组数"。对于点线的每个线交点,我们检查交叉线的方向,并给出一个方向+1,如果方向相反,则为-1,并将它们加在一起。

举例说明:

counter-clockwise clockwise

对于左边的插图,我们可以看到两个第一线交点的方向之和(如果点位于左侧,中间位于y上)将为0("零和#34;)所以没有填写中心部分。如果一个点从中心顶部向下发送一条直线穿过形状,也会发生这种情况。

然而,在右边的插图中,当我们来到内部区域时,总和不为零,因此它也会被填满。

示例:arc()使用顺时针方向



var canvas = document.getElementById('c');
var ctx = canvas.getContext("2d");
var centerw = canvas.width/2;
var centerh = canvas.height/2;
var sq_w = 120;
//
ctx.beginPath();
//draw rectangle
ctx.rect(centerw-(sq_w/2), 0,sq_w, canvas.height);
//draw circle
ctx.moveTo(centerw + 185, centerh); // create new sub-path (is unrelated, see below)
ctx.arc(centerw, centerh, 185, 0, Math.PI * 2); // <- don't use the CCW flag
//fill
ctx.fill();
&#13;
<canvas id="c" width="500" height="500"></canvas>
&#13;
&#13;
&#13;

不相关但需要注意的事项:您还需要为圆弧创建一个新的子路径,以避免冒险从直角的一条直线移动到圆弧上的起始角点。只需在添加弧之前添加此行:

ctx.moveTo(centerw + 185, centerh);
ctx.arc(centerw, centerh, 185, 0, Math.PI * 2);

答案 1 :(得分:1)

ctx.beginPath();
//draw rectangle
ctx.rect(this.centerw - (sq_w / 2), 0, sq_w, canvas.height);
ctx.fill();
//draw circle
ctx.beginPath();
ctx.arc(this.centerw, this.centerh, 185, 0, Math.PI * 2, true);
//fill
ctx.fill();

答案 2 :(得分:1)

您看到的结果是因为交叉路径包含的表面上的标准操作是要忽略的。

&#13;
&#13;
var canvas = document.getElementById('c');
var ctx = canvas.getContext("2d");
var centerw = canvas.width/2;
var centerh = canvas.height/2;
var sq_w = 80;

//draw rectangle
ctx.fillRect(this.centerw-(sq_w/2), 0,sq_w, canvas.height);

//draw circle
ctx.arc(this.centerw, this.centerh, 185, 0, Math.PI * 2, true);

//fill
ctx.fill();
&#13;
<canvas id='c' height=500 width=500/>
&#13;
&#13;
&#13;

需要在两轮之间填充形状。或者,在代码片段中,我将ctx.rect更改为ctx.fillRect。

另一种方法是在弧之前开始一条新路径。