【问题标题】:How to fill the 'opposite' shape on canvas?如何在画布上填充“相反”的形状?
【发布时间】:2011-09-10 09:57:25
【问题描述】:

假设我在 HTML5 画布上有一个圆(圆弧)。我可以这样填写:

ctx.arc(100, 100, 50, 0, 2 * Math.PI);
ctx.fill();

这是一种享受。但是,一个人怎么能填满对面的区域呢?现在它是带有黑色圆圈的白色,但我希望它沿着下图的线条(白色是背景色,黑色是填充色):

我知道我可以只使用黑色背景并画一个白色圆圈,但背景可以是任何东西(以前在那里画过各种各样的东西,所以只交换颜色是不可能的)。

另一件事是,不应该填充整个画布,而是一个正方形,一个圆圈被取消。

我在考虑globalCompositeOperation,但它似乎不符合我的需求,因为它们都没有按照我的需要行事。

那么,我怎样才能像示例图像中那样填充“对面”区域?

【问题讨论】:

    标签: html5-canvas


    【解决方案1】:

    执行此操作的典型方式是使用“剪辑区域”,您可以在其中制作适用于绘图操作的区域蒙版。 HTML5 画布能够制作一个剪贴蒙版,即圆形本身...

    http://www.html5canvastutorials.com/tutorials/html5-canvas-clipping-region-tutorial/

    ...但它缺少 Google Gears Canvas 中的减法()操作,我发现并声称是“来自 HTML5”...但显然不是。

    有人在这里回答了如何反转clip(),但它涉及到屏幕外的画布:

    Canvas 'Clip' reverse action?

    希望其他人有更好的建议。 :-/

    【讨论】:

      【解决方案2】:

      您可以使用另一个画布作为遮罩:

      // This is the canvas where you want to draw
      var canvas = document.getElementById('your-canvas');
      var ctx = canvas.getContext('2d');
      
      // I'll use a skyblue background that covers everything
      // Just to demonstrate
      ctx.fillStyle = "skyblue";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      
      // Create a canvas that we will use as a mask
      var maskCanvas = document.createElement('canvas');
      // Ensure same dimensions
      maskCanvas.width = canvas.width;
      maskCanvas.height = canvas.height;
      var maskCtx = maskCanvas.getContext('2d');
      
      // This color is the one of the filled shape
      maskCtx.fillStyle = "black";
      // Fill the mask
      maskCtx.fillRect(0, 0, maskCanvas.width, maskCanvas.height);
      // Set xor operation
      maskCtx.globalCompositeOperation = 'xor';
      // Draw the shape you want to take out
      maskCtx.arc(30, 30, 10, 0, 2 * Math.PI);
      maskCtx.fill();
      
      // Draw mask on the image, and done !
      ctx.drawImage(maskCanvas, 0, 0);
      <canvas id="your-canvas">

      Demo here.

      【讨论】:

      • 非常感谢,但在您的演示中,它是青色而不是白色。你是否也有同样的经历?
      • 是的,我特意使用了这种颜色。这是背景颜色。
      • Heandel:哎呀,对不起。那显然是你使用的skyblue...它就像一个魅力,谢谢!
      • 我想强调一下,您在 填充画布之后设置为 xor。我在开始时设置它并填充xor,但这很慢。
      • 对我上一条评论的改进(现已删除):dev.rgraph.net/tests/2012-11-30/clip.html
      【解决方案3】:

      在OP中画出黑色的形状——也就是画一个中间切掉一个圆的矩形。

      首先调用 beginPath();然后顺时针画圆;然后逆时针绘制矩形(反之亦然);最后是 fill()。

      var ctx = $('#cv').get(0).getContext('2d');
      
      ctx.fillStyle = "grey";
      ctx.beginPath();
      ctx.arc(200, 200, 100, 0, 2 * Math.PI);
      ctx.rect(400, 0, -400, 400);
      ctx.fill();
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <canvas width="400" height="400" id="cv"></canvas>

      从那里的大多数文档中可能并不明显,但您可以在单个 fill()、stroke() 或 clip() 操作中组合多个子路径。要在形状上打孔,只需沿相反方向绘制孔的形状。 beginPath() 方法重置当前路径。对于fill() 和clip(),Canvas 使用非零缠绕数规则——如果你仔细阅读它应该会更清楚。

      【讨论】:

      • 谢谢,我没有考虑过这个。对于“逆时针矩形”,我说你的意思是一个负维度是否正确?在阅读了绕组数规则后,我得到的想法是偶数个负维度补偿每一对。我最终得到了这个:jsfiddle.net/eGjak/685.
      • 谢谢,这个答案对 Ejecta 中的 HTML5 画布实现很有帮助,这似乎需要通过“敲出”一个圆圈的路径来执行顺时针/逆时针业务。浏览器要宽容得多。
      • @MichaelWaterfall 我遇到了同样的问题,解决方法是指定奇偶填充,如下所示:ctx.fill("evenodd");
      • 为了更简单,可以使用arc函数的最后一个参数,设置为true。
      • 值得注意的是,如果以后有人遇到这种情况,ctx.arc 中的 200,200 指的是矩形宽度的一半和高度的一半。在矩形中,因为这是一个正方形,所以有点令人困惑,前 400 是外部矩形的宽度,-400 是取反的宽度,最后 400 是高度。
      【解决方案4】:

      在画布蒙版上使用 XOR 函数仅适用于不透明填充(即与 globalAlpha 不兼容)。解决此问题的一种方法是使用 .clip() 函数并用背景中的内容填充剪辑区域。然后,您可以将剪裁区域覆盖在原始画布上,在该画布上执行您需要的任何填充。

      【讨论】:

        猜你喜欢
        • 2014-03-02
        • 2021-11-08
        • 2014-06-21
        • 1970-01-01
        • 1970-01-01
        • 2012-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多