Home > Software engineering >  Is it possible to add shadowblur with clip in canvas?
Is it possible to add shadowblur with clip in canvas?

Time:06-20

I am drawing a canvas.

I simplified my code.

There is a transparent circle.

The background is rgba 0,0,0,0.5.

I'd like to add "shadowblur" for the transparent circle. However, it's fail.

Is it possible?

I have another logic:

  1. Create one circle with linear-gradient (rgba 0,0,0,0.5, transparent)

However, it seems no good.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div >
        <canvas id="myCanvas"></canvas>
    </div>

    <style>
        .Preloader {
            background-color: #7bf;
        }
    </style>

    <script>
        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");

        c.width = window.innerWidth;
        c.height = window.innerHeight;

        class ball {
            constructor(x, y) {
                this.position = {
                    x: x,
                    y: y
                }
                this.r = 100

            }
            draw() {
                ctx.beginPath();
                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
                ctx.fillRect(0, 0, c.width, c.height);
                ctx.fill();
                ctx.closePath();

                ctx.save();
                ctx.beginPath();
                ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);

                ctx.clip();
                ctx.clearRect(0, 0, c.width, c.height);
                ctx.shadowBlur = 0;
                ctx.closePath();
                ctx.restore();
            }
            update() {
                this.draw()
                this.position.x  
                this.position.y  
            }
        }

        var Ball = new ball(c.width / 2, c.height / 2)

        function animate() {
            requestAnimationFrame(animate);
            ctx.clearRect(0, 0, c.width, c.height);
            Ball.update();
        };

        animate();
    </script>
</body>

</html>

CodePudding user response:

If you mean that you want the edges of the clipping-area to be smoother, then you can use compositing to use any bitmap as a mask:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

c.width = window.innerWidth;
c.height = window.innerHeight;

class ball {
    constructor(x, y) {
        this.position = {
            x: x,
            y: y
        }
        this.r = 100

    }
    draw() {
        // fillRect doesn't need beginPath(), and it does fill()
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, c.width, c.height);
        // closePath encloses the current subpath
        // it doesn't "end" the path declaration
        // beginPath does that

        ctx.beginPath();
        ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);

        // we use compositing to create our hole, with shadow:
        ctx.globalCompositeOperation = "destination-out";        
        ctx.shadowBlur = 30;
        ctx.shadowColor = "black";
        ctx.fillStyle = 'black';
        ctx.fill();

        // restore
        ctx.shadowBlur = 0;
        ctx.globalCompositeOperation = "source-over";

    }
    update() {
        this.draw()
        this.position.x  
        this.position.y  
    }
}

var Ball = new ball(c.width / 2, c.height / 2)

function animate() {
    requestAnimationFrame(animate);
    ctx.clearRect(0, 0, c.width, c.height);
    Ball.update();
};

animate();
.Preloader {
    background-color: #7bf;
}
<div >
    <canvas id="myCanvas"></canvas>
</div>

This would also work with CanvasGradient instead of shadowBlur:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

c.width = window.innerWidth;
c.height = window.innerHeight;

class ball {
    constructor(x, y) {
        this.position = {
            x: x,
            y: y
        }
        this.r = 100

    }
    draw() {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, c.width, c.height);

        ctx.globalCompositeOperation = "destination-out";
        ctx.fillStyle = ctx.createRadialGradient(this.position.x, this.position.y, this.r, this.position.x, this.position.y, 0);
        ctx.fillStyle.addColorStop(0, "transparent");
        ctx.fillStyle.addColorStop(.25, "black");
        ctx.fillRect(0, 0, c.width, c.height);

        // restore
        ctx.globalCompositeOperation = "source-over";
    }
    update() {
        this.draw()
        this.position.x  
        this.position.y  
    }
}

var Ball = new ball(c.width / 2, c.height / 2)

function animate() {
    requestAnimationFrame(animate);
    ctx.clearRect(0, 0, c.width, c.height);
    Ball.update();
};

animate();
.Preloader {
    background-color: #7bf;
}
<div >
    <canvas id="myCanvas"></canvas>
</div>

Or even in Chrome and Firefox by using CSS blur filters:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

c.width = window.innerWidth;
c.height = window.innerHeight;

class ball {
    constructor(x, y) {
        this.position = {
            x: x,
            y: y
        }
        this.r = 100

    }
    draw() {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, c.width, c.height);

        ctx.beginPath();
        ctx.arc(this.position.x, this.position.y, this.r, 0, 2 * Math.PI, false);

        // we use compositing to create our hole, with shadow:
        ctx.globalCompositeOperation = "destination-out";        
        ctx.filter = "blur(15px)";
        ctx.fill();

        // restore
        ctx.filter = "none";
        ctx.globalCompositeOperation = "source-over";

    }
    update() {
        this.draw()
        this.position.x  
        this.position.y  
    }
}

var Ball = new ball(c.width / 2, c.height / 2)

function animate() {
    requestAnimationFrame(animate);
    ctx.clearRect(0, 0, c.width, c.height);
    Ball.update();
};

animate();
.Preloader {
    background-color: #7bf;
}
<div >
    <canvas id="myCanvas"></canvas>
</div>

  • Related