mdn / content

The content behind MDN Web Docs
https://developer.mozilla.org
Other
9.14k stars 22.46k forks source link

globalCompositeOperation = 'xor' Overlapping area problem #35981

Open TongKings opened 1 week ago

TongKings commented 1 week ago

MDN URL

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation

What specific section or headline is this issue about?

CanvasRenderingContext2D: globalCompositeOperation

What information was incorrect, unhelpful, or incomplete?

When drawing two triangles with overlapping hypotenuses on a canvas, when globalCompositeOperation = 'xor' , the hypotenuse part does not become transparent? Is there a way to make it transparent? The following is a code example:

<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas XOR </title>
    <style>
        canvas {
            width: 300px;
            height: 300px;
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <canvas id="myCanvas" ></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');
        const dpr = window.devicePixelRatio;
        canvas.height = 300 *dpr;
        canvas.width = 300 *dpr;
        ctx.fillStyle = 'red';
        ctx.beginPath();
        ctx.moveTo(120, 120);
        ctx.lineTo(220, 120);
        ctx.lineTo(170, 70);
        ctx.closePath();
        ctx.fill();

        ctx.globalCompositeOperation = 'xor';
        ctx.fillStyle = 'blue';
        ctx.beginPath();
        ctx.moveTo(150, 150);
        ctx.lineTo(250, 150);
        ctx.lineTo(200, 100);
        ctx.closePath();
        ctx.fill();
    </script>
</body>
</html>

What did you expect to see?

For the part where the hypotenuses of the two triangles overlap, I hope it can still remain completely transparent.Hope this email finds you well.Thank you so much!

Do you have any supporting links, references, or citations?

image

Do you have anything more you want to share?

No response

MDN metadata

Page report details * Folder: `en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation` * MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation * GitHub URL: https://github.com/mdn/content/blob/main/files/en-us/web/api/canvasrenderingcontext2d/globalcompositeoperation/index.md * Last commit: https://github.com/mdn/content/commit/005cc1fd55aadcdcbd9aabbed7d648a275f8f23a * Document last modified: 2024-01-15T21:58:53.000Z
OnkarRuikar commented 1 week ago

This is happening because of antialiasing. The colors are bleeding 2px out. There is no way to disable antialiasing in Canvas.

You'll have to resort to workarounds. For example, draw over the bleed color:

        ctx.lineWidth=2;
        ctx.strokeStyle = "white";
        ctx.stroke();

Here is the demo.

TongKings commented 1 week ago

This is happening because of antialiasing. The colors are bleeding 2px out. There is no way to disable antialiasing in Canvas.

You'll have to resort to workarounds. For example, draw over the bleed color:

        ctx.lineWidth=2;
        ctx.strokeStyle = "white";
        ctx.stroke();

Here is the demo.

Thank you very much for your answer.it’ok. I am considering whether to use WebGL or WebGPU to achieve overlapping diagonal boundaries of multiple graphics. Because the current case has no problem with two graphic boundaries The following is a code example:

<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas XOR </title>
    <style>
        canvas {
            width: 300px;
            height: 300px;
            border: 1px solid black;
        }
    </style>
</head>

<body>
    <canvas id="myCanvas"></canvas>
    <script>
        const canvas = document.getElementById('myCanvas');
        const ctx = canvas.getContext('2d');
        const dpr = window.devicePixelRatio;
        canvas.height = 300 * dpr;
        canvas.width = 300 * dpr;
        ctx.globalCompositeOperation = 'xor';
        ctx.fillStyle = 'black';
        ctx.beginPath();
        ctx.moveTo(150, 150);
        ctx.lineTo(250, 150);
        ctx.lineTo(250, 250);
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = 'black';
        ctx.beginPath();
        ctx.moveTo(150, 150);
        ctx.lineTo(200, 150);
        ctx.lineTo(200, 200);
        ctx.closePath();
        ctx.fill();

        ctx.fillStyle = 'black';
        ctx.beginPath();
        ctx.moveTo(150, 150);
        ctx.lineTo(200, 150);
        ctx.lineTo(200, 250);
        ctx.lineTo(150, 250);
        ctx.closePath();
        ctx.fill();
    </script>
</body>

</html>

Its effect is as follows: image

Josh-Cena commented 1 week ago

@OnkarRuikar Do you think there's anything we could add to the docs? This seems like a general pitfall that's unrelated to globalCompositeOperation itself.