Canvas - gradient flash and mask [duplicate] - javascript

This question already has answers here:
Canvas flashlight effect
(1 answer)
Efficient HTML5 Canvas Glow Effect without shape
(1 answer)
HTML canvas spotlight effect
(3 answers)
Closed 4 years ago.
I want to get the effect "flash/flashlight". But with the ability to merge multiple effects.
I draw one effect like this, but can not merge them.
function createCircle( x, y ) {
var gradient = context.createRadialGradient(x, y, 0, x, y, 100);
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 1)');
context.fillStyle = gradient;
context.fillRect(0, 0, width, height);
}
I tried different types of "globalCompositeOperation". But the result was still bad.
I attached an image (example) with the desired result.

Is this what you need? I've used globalCompositeOperation as you intended. please take a look at this codepen example
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 600,
cx = cw / 2;
let ch = canvas.height = 300,
cy = ch / 2;
let img = document.getElementById("img");
function grd( x, y ) {
let gradient = ctx.createRadialGradient(x, y, 0, x, y, 130);
gradient.addColorStop(.5, 'rgba(0, 0, 0, 1)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
return gradient;
}
let c1={x:220,y:150}
let c2={x:380,y:150}
ctx.fillStyle = grd(c1.x,c1.y);
ctx.beginPath();
ctx.arc(c1.x, c1.y, 220, 0, 2*Math.PI);
ctx.fill();
ctx.fillStyle = grd(c2.x,c2.y);
ctx.beginPath();
ctx.arc(c2.x,c2.y, 220, 0, 2*Math.PI);
ctx.fill();
ctx.globalCompositeOperation = "source-in";
ctx.drawImage( img, -50, -50 ,cw, cw );
body {
overflow: hidden;
}
canvas {
background-color: #000;
display: block;
}
<canvas id="canvas">
<img src="your_image.jpg" id="img" />
</canvas>

Related

Both squares aren't showing up on the canvas

This is my code:
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
function draw() {
context.fillStyle = "rgb(200, 0, 0)";
context.fillRect(50, 50, 0, 0);
};
draw();
When I run it, I get no errors but it doesn't add the squares to the canvas. Can someone tell me why this happens and how to fix it?
Your second Rectangle does not have a height and width.
the function has the parameters x, y, width, height -> fillRect(x, y, width, height).
Your line context.fillRect(50, 50, 0, 0); creates a box with width and height of 0 at 50px from x and y.
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const settings = {x: 50, y: 50, height: 50, width: 50};
function draw() {
if (ctx) {
ctx.fillStyle = "rgb(0, 200, 0)";
ctx.fillRect(settings.x, settings.y, settings.width, settings.height);
ctx.fillStyle = "rgb(200, 0, 0)";
ctx.fillRect(0, 0, 50, 50);
};
};
draw();
<canvas id="myCanvas"></canvas>

How to fully fade out contents in canvas

This question has been asked twice without the caveat of "Fully Fade Out"
Fastest way of fading out entire contents of a canvas to transparency, not other color
HTML5: Apply transparency to Canvas after drawing through JavaScript
Both of the accepted answers only partially fade out the contents. They both suggest something like:
// semi functional code, but doesn't fully work
ctx.save();
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = "destination-in";
ctx.fillStyle = "rgba(0, 0, 0, 0.9)";
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.restore();
This leaves residue everywhere, never fully fading out anything. See example below:
let canvas = document.getElementsByTagName('canvas')[0];
let ctx = canvas.getContext('2d');
let rand = n => Math.floor(Math.random() * n);
setInterval(() => {
ctx.beginPath();
ctx.arc(rand(300), rand(120), rand(60), Math.PI * 2, 0);
ctx.fillStyle = `rgba(${rand(256)}, ${rand(256)}, ${rand(256)}, 1)`;
ctx.globalCompositeOperation = 'source-over';
ctx.fill();
}, 1000);
let fadeOut = () => {
let fadeAmount = 0.05;
// Note that the colour here doesn't matter! Only the alpha matters.
// The colour here is red, but you'll see no red appear
ctx.fillStyle = `rgba(255, 0, 0, ${1 - fadeAmount})`;
ctx.globalCompositeOperation = 'destination-in';
ctx.fillRect(0, 0, 300, 120);
requestAnimationFrame(fadeOut);
};
requestAnimationFrame(fadeOut);
canvas { border: 3px solid #808080; background-color: #000000; }
<canvas width="300" height="120"></canvas>
The question is: How can one fully fade out elements on a canvas, all the way to transparent?
EDIT: I'm searching for a performant solution that works for heavily layered (think visualizer) situations.
Here is a small sample using globalAlpha, looks good to me, no residue...
each FadingCircle will have own fade, that will determine how fast it fades and if it goes to 0 or below we do not draw it, seems like an easy solution.
You can add colors, random positions and change it as much as you like to suit your needs.
const canvas = document.getElementsByTagName('canvas')[0];
const ctx = canvas.getContext('2d');
class FadingCircle {
constructor(x, y, radius, fade) {
this.x = x
this.y = y
this.radius = radius
this.fade = fade
this.globalAlpha = 1
}
draw(ctx) {
if (this.globalAlpha > 0) {
ctx.beginPath()
ctx.globalAlpha = this.globalAlpha
ctx.arc(this.x, this.y, this.radius, Math.PI * 2, 0)
ctx.fill()
this.globalAlpha -= this.fade
}
}
}
let sml = new FadingCircle(40, 50, 20, 0.01)
let med = new FadingCircle(140, 50, 30, 0)
let big = new FadingCircle(100, 50, 50, 0.005)
let animation = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
big.draw(ctx)
med.draw(ctx)
sml.draw(ctx)
requestAnimationFrame(animation);
};
requestAnimationFrame(animation);
<canvas width="300" height="120"></canvas>

transparent circle on opaque canvas

I'm trying to draw a transparent circle on the HTML Canvas. Here is the code:
const canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
canvas.width = 700;
canvas.height = 700;
ctx.beginPath();
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'destination-out';
ctx.clearRect(50, 50, 200, 200);
ctx.beginPath();
ctx.fillRect(50, 50, 200, 200);
ctx.moveTo(350, 150);
ctx.beginPath();
ctx.arc(350, 150, 80, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
I was able to make the rectangle transparent with globalCompositeOperation set to destination-out but it failed to make the circle fully transparent.
Here is what MDN says about destination-out operation,
The existing content is kept where it doesn't overlap the new shape.
The circle has still some opaque color applied to it. How to make it fully transparent?
Here is the live demo.
Unable to understand what's wrong with the code. Any help would be appreciated.
You are using beginpath methods but the directives you use aren't paths.
The fully transparent rectangle is created by the clearRect and not by the fillRect method.
So you should set fillStyle to white and then the code works.
const canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 400;
ctx.fillStyle = 'rgba(0, 0, 0, .5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillRect(25, 25, 150, 150);
ctx.arc(275, 100, 60, 0, 2 * Math.PI, false);
ctx.fill();
body {
background-color: skyblue;
position: relative;
}
img, #canvas {
position: absolute;
}
<body>
<img src="https://images.unsplash.com/photo-1635315850978-44cd0b237006?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1770&q=80" alt="" width=600 height=390>
<canvas id="canvas"></canvas>
</body>

Fill between 2 partial ellipses

I have two half-ellipses and I'm trying fill the space between them. For whatever reason the "fill" is getting "twisted" in the middle:
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = canvas.height = 300;
ctx.ellipse(150, 0, 150, 90, 0, 0, Math.PI);
ctx.ellipse(150, 200, 150, 90, 0, 0, Math.PI);
ctx.fillStyle = "lightgreen";
ctx.fill();
ctx.stroke();
<canvas id="canvas"></canvas>
Any ideas how to make it fill so it's like a cylinder (without far side on top)
I guess all it need was rotate one of the ellipses and draw it in reverse:
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = canvas.height = 300;
ctx.ellipse(150, 0, 150, 90, 0, 0, Math.PI);
ctx.ellipse(150, 200, 150, 90, Math.PI, 0, Math.PI, true); //changed
ctx.fillStyle = "lightgreen";
ctx.fill();
ctx.stroke();
<canvas id="canvas"></canvas>

How to make a rotating gradient (on a circle)?

I create a simple circle with the arc function:
/* ctx is the 2d context */
ctx.beginPath();
var gradient = ctx.createLinearGradient(0, 0, this.radius, this.radius);
gradient.addColorStop(0, '#FF0000');
gradient.addColorStop(1, '#FFFFFF');
ctx.lineWidth = 10;
ctx.arc(this.radius, this.radius, this.radius, 0, 2*Math.PI, true);
ctx.strokeStyle = gradient;
ctx.stroke();
So I want to rotate the gradient, is that possible?
I've tried with ctx.rotate(x) but that rotates the whole circle!
Yes. Your gradient is going from x1,y1 to x2,y2, which are the four last arguments of createLinearGradient
For example, to reverse your gradient do this:
var gradient = ctx.createLinearGradient(this.radius, this.radius, 0, 0);
Or change it up however you please:
var gradient = ctx.createLinearGradient(this.radius, 0, 0, 0);
And so on.

Categories