【问题标题】:Overlapping shapes in canvas画布中的重叠形状
【发布时间】:2018-07-21 08:24:50
【问题描述】:

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

形状都在绘制,但形状的交集是空白的。

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

要求: 不能使用CanvasRenderingContext2D.globalCompositeOperation,因为我将其用于其他用途;这需要用作单个形状,因此我可以使用该形状来...剪辑()。

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

看起来应该很容易,但我很难过,我认为缺少一些基本的东西。谢谢!

【问题讨论】:

    标签: javascript html canvas graphics drawing


    【解决方案1】:

    路径方向很重要

    只需删除(或设置为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,然后将它们相加。

    举例说明:

    对于左边的插图,我们可以看到两个第一条线交点的方向之和(如果点位于左侧并且中心位于 y 上)将为 0(“零”),因此中心部分没有填充.如果一个点从中心顶部和向下穿过形状发送一条线,也会发生这种情况。

    然而,在右边的插图中,当我们来到内部部分时,总和是非零的,所以它也被填充了。

    示例: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();
    &lt;canvas id="c" width="500" height="500"&gt;&lt;/canvas&gt;

    不相关但需要记住的一点:您还需要为圆弧创建一个新的子路径,以避免从矩形的一角到圆弧上的起始角点的直线。只需在添加圆弧之前添加此行:

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

    【讨论】:

    • 太棒了!这修复了它。感谢您提供详尽的解释,这是非常有价值的信息,我找不到任何有关如何解决此问题的文章;非常感谢。
    【解决方案2】:
    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();
    

    【讨论】:

    • 您能否详细说明问题是什么以及您是如何解决的?
    • 啊,我明白了 - 你在每个形状之后都画 - 这是我也想出的解决方案,但我在原始帖子中不够清楚 - 我想画两个形状在调用 fill() 之前。 @K3N 上面的帖子解释了如何修复。感谢您的意见!
    【解决方案3】:

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

    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();
    &lt;canvas id='c' height=500 width=500/&gt;

    形状需要在圆形之间填充。或者,在代码 sn-p 中,我将 ctx.rect 更改为 ctx.fillRect。

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

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-03
      • 2017-11-15
      • 2018-07-08
      • 2019-02-24
      • 2020-04-09
      相关资源
      最近更新 更多