JS Class based Object instantiation to React Functional based approach - javascript

Trying to refactor Class based approach to Functional based approach in React on canvas animation. I managed to display the animation but the update doesn't seem to work. Any help of the use of hooks/functional paradigm is welcome.
startDrawing function is class based approach
startDrawingAlt function is what I need help with
Basically, how to rewrite Circle class into the so called modern react functional programming paradigm if it is possible ofc.
The code is below:
import React, {useRef, useEffect, useState} from "react"
export default function CanvasManipulation() {
const canvasRef = useRef(null)
const contextRef = useRef(null)
useEffect(() => {
const canvas = canvasRef?.current
canvas.width = window.innerWidth
canvas.height = window.innerHeight
const context = canvas.getContext("2d")
contextRef.current = context
}, [])
const colors = ["purple"]
const startDrawingAlt = () => {
const context = contextRef.current
const drawUpdate = (x, y, xVelocity, yVelocity, circleRadius) => {
if (x + circleRadius > window.innerWidth || x - circleRadius < 0) {
xVelocity = -xVelocity
}
if (y + circleRadius > window.innerHeight || y - circleRadius < 0) {
yVelocity = -yVelocity
}
x += xVelocity;
y += yVelocity
context.beginPath()
context.arc(x, y, circleRadius, 0, 2 * Math.PI, false);
context.strokeStyle = colors[Math.floor(Math.random() * colors.length)];
context.stroke()
}
let circleArray = []
for (let i = 0; i < 100; i++) {
let circleRadius = Math.random() * 60
let x = Math.random() * window.innerWidth - circleRadius * 2
let xVelocity = (Math.random() - 0.5) * 10
let y = Math.random() * window.innerHeight - circleRadius * 2
let yVelocity = (Math.random() - 0.5) * 10
circleArray.push({x, y, xVelocity, yVelocity, circleRadius})
}
const animateCircle = () => {
requestAnimationFrame(animateCircle)
context.clearRect(0, 0, window.innerWidth, window.innerHeight)
for (let i = 0; i < circleArray.length; i++) {
drawUpdate(circleArray[i]?.x, circleArray[i]?.y, circleArray[i]?.xVelocity, circleArray[i].yVelocity, circleArray[i].circleRadius)
}
}
animateCircle()
}
const startDrawing = () => {
const context = contextRef.current
class Circle {
constructor(x, y, xVelocity, yVelocity, circleRadius) {
this.x = x
this.y = y
this.xVelocity = xVelocity
this.yVelocity = yVelocity
this.circleRadius = circleRadius
this.draw = function () {
context.beginPath()
context.arc(this.x, this.y, this.circleRadius, 0, 2 * Math.PI, false);
context.strokeStyle = colors[Math.floor(Math.random() * colors.length)];
context.stroke()
}
this.update = function () {
if (this.x + this.circleRadius > window.innerWidth || this.x - this.circleRadius < 0) {
this.xVelocity = -this.xVelocity
}
if (this.y + this.circleRadius > window.innerHeight || this.y - this.circleRadius < 0) {
this.yVelocity = -this.yVelocity
}
this.x += this.xVelocity;
this.y += this.yVelocity
this.draw()
}
}
}
let circleArray = []
for (let i = 0; i < 100; i++) {
let circleRadius = Math.random() * 60
let x = Math.random() * window.innerWidth - circleRadius * 2
let xVelocity = (Math.random() - 0.5) * 10
let y = Math.random() * window.innerHeight - circleRadius * 2
let yVelocity = (Math.random() - 0.5) * 10
circleArray.push(new Circle(x, y, xVelocity, yVelocity, circleRadius))
}
const animateCircle = () => {
requestAnimationFrame(animateCircle)
context.clearRect(0, 0, window.innerWidth, window.innerHeight)
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update()
}
}
animateCircle()
}
return (
<canvas ref={canvasRef} onClick={startDrawing}></canvas>
)
}

Related

How to remove black background from this JS coding?

I'm trying to make this particle text be on a transparent background to add onto a slideshow. Can someone assist? I cannot seem to find where it is stated within the code.
Here is the JS code. Sorry I can't seem to get it to fit properly within the code section of the post.
class Particles { constructor(x, y, texture, size) {
this.x = x;
this.y = y;
this.sprite = new PIXI.Sprite(new PIXI.Texture.from(texture));
this.sprite.texture.frame = new PIXI.Rectangle(x, y, size, size);
this.sprite.x = x;
this.sprite.y = y;
this.speedX = 0;
this.speedY = 0;
this.radius = 100;
this.gravity = 0.1;
this.maxGravity = 0.01 + Math.random() * 0.03;
this.friction = 0.9;
this.dirX = Math.random() - 0.5;
this.dirY = Math.random() - 0.5; }
update(mouse) {
const distanceX = mouse.x - this.sprite.x;
const distanceY = mouse.y - this.sprite.y;
const distanceSqrd = distanceX * distanceX + distanceY * distanceY;
if (distanceSqrd < this.radius * this.radius && distanceSqrd > 0) {
const distance = Math.sqrt(distanceSqrd);
let normalX = distanceX / distance;
let normalY = distanceY / distance;
this.speedX -= normalX;
this.speedY -= normalY;
this.gravity *= this.friction;
} else {
this.gravity += 0.1 * (this.maxGravity - this.gravity);
}
let oDistX = this.x - this.sprite.x;
let oDistY = this.y - this.sprite.y;
this.speedX += oDistX * this.gravity;
this.speedY += oDistY * this.gravity;
this.speedX *= this.friction;
this.speedY *= this.friction;
this.sprite.x += this.speedX;
this.sprite.y += this.speedY; } }
class ParticlesText { constructor({ text, size }) {
this.app = new PIXI.Application({ width: innerWidth, height: innerHeight });
document.querySelector("#content-canvas").append(this.app.view);
this.text = text;
this.size = size;
this.cols = 500;
this.rows = 200;
this.pSize = 2;
this.particles = [];
this.mouse = {x: 0, y: 0}
this.container = new PIXI.particles.ParticleContainer(50000);
this.app.stage.addChild(this.container);
this.onResize = this.onResize.bind(this); }
init() {
const that = this;
opentype.load(
"https://raw.githack.com/AlainBarrios/Fonts/master/LeagueSpartan-Bold.otf",
function(err, font) {
if (err) {
alert("Font could not be loaded: " + err);
} else {
const canvas = document.createElement("canvas");
// Now let's display it on a canvas with id "canvas"
const ctx = canvas.getContext("2d");
// Construct a Path object containing the letter shapes of the given text.
// The other parameters are x, y and fontSize.
// Note that y is the position of the baseline.
const path = font.getPath(that.text, 0, that.size, that.size);
const width = font.getAdvanceWidth(that.text, that.size);
that.cols = width;
that.rows = that.size;
canvas.width = width;
canvas.height = that.size;
path.fill = "rgba(255,255,255,1)";
// If you just want to draw the text you can also use font.draw(ctx, text, x, y, fontSize).
path.draw(ctx);
that.addObjects(canvas, ctx);
}
}
); }
isEmpty(x, y, ctx) {
const image = ctx.getImageData(x, y, this.pSize, this.pSize);
let emptyCounter = 0;
for (let i = 0; (length = image.data.length), i < length; i += 4) {
if (image.data[i + 3] !== 0) {
continue;
}
emptyCounter++;
}
return emptyCounter === this.pSize * this.pSize; }
addObjects(canvas, ctx) {
this.container.x = this.app.renderer.width / 2 - this.cols / 2;
this.container.y = this.app.renderer.height / 2 - this.rows / 2;
for (let i = 0; i < this.cols; i += 1) {
for (let j = 0; j < this.rows; j += 1) {
const x = i * this.pSize;
const y = j * this.pSize;
if (this.isEmpty(x, y, ctx)) continue;
const p = new Particles(x, y, canvas, this.pSize);
this.particles.push(p);
this.container.addChild(p.sprite);
}
}
this.container.interactive = true;
this.onResize();
window.addEventListener("resize", this.onResize);
this.container.on("mousemove", e => {
this.mouse = e.data.getLocalPosition(this.container);
});
this.animate(); }
onResize() {
const { innerWidth, innerHeight } = window;
const size = [innerWidth, innerHeight];
const ratio = size[0] / size[1];
if (innerWidth / innerHeight >= ratio) {
var w = innerHeight * ratio;
var h = innerHeight;
} else {
var w = innerWidth;
var h = innerWidth / ratio;
}
//this.app.renderer.view.style.width = w + "px";
//this.app.renderer.view.style.height = h + "px"; }
animate() {
this.app.ticker.add(() => {
stats.begin();
this.particles.forEach(p => {
p.update(this.mouse);
});
stats.end();
}); } }
const particles = new ParticlesText({ text: "KILL THE ROBOTS", size:
150 }); particles.init();

Change color of Paticle(circle) when collision detected in canvas

// Initial Setup
const canvas = document.querySelector('canvas');
const c = canvas.getContext('2d');
// Canvas size
canvas.width = innerWidth;
canvas.height = innerHeight;
//Color
const colors = [
{r: 51, g: 99, b: 252}
//{r: 77, g: 57, b: 206},
// {r: 0, g: 189, b: 255},
];
// Utility Functions
function randomIntFromRange(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function randomColor(colors) {
return colors[Math.floor(Math.random() * colors.length)];
}
function distance(x1, y1, x2, y2) {
const xDist = x2 - x1;
const yDist = y2 - y1;
return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
}
function rotateVelocities(velocity, theta) {
const rotatedVelocity = {
x: velocity.x * Math.cos(theta) - velocity.y * Math.sin(theta),
y: velocity.x * Math.sin(theta) + velocity.y * Math.cos(theta)
};
return rotatedVelocity;
}
// Objects
function Particle(x, y, radius, rgb) {
this.x = x;
this.y = y;
this.velocity = {
x: (Math.random() - 0.5) * 3,
y: (Math.random() - 0.5) * 3
};
this.radius = radius;
this.mass = 1;
this.opacity = 0;
this.r = rgb.r;
this.g = rgb.g;
this.b = rgb.b;
this.update = particles => {
this.draw();
for (let i = 0; i < particles.length; i++) {
const otherParticle = particles[i];
if (this.x === otherParticle.x) continue;
if (distance(this.x, this.y, otherParticle.x, otherParticle.y) - this.radius * 2 < 0) {
const res = {
x: this.velocity.x - otherParticle.velocity.x,
y: this.velocity.y - otherParticle.velocity.y
};
if (res.x * (otherParticle.x - this.x) + res.y * (otherParticle.y - this.y) >= 0) {
const m1 = this.mass;
const m2 = otherParticle.mass;
const theta = -Math.atan2(otherParticle.y - this.y, otherParticle.x - this.x);
const rotatedVelocity1 = rotateVelocities(this.velocity, theta);
const rotatedVelocity2 = rotateVelocities(otherParticle.velocity, theta);
const swapVelocity1 = { x: rotatedVelocity1.x * (m1 - m2) / (m1 + m2) + rotatedVelocity2.x * 2 * m2 / (m1 + m2), y: rotatedVelocity1.y };
const swapVelocity2 = { x: rotatedVelocity2.x * (m1 - m2) / (m1 + m2) + rotatedVelocity1.x * 2 * m2 / (m1 + m2), y: rotatedVelocity2.y };
const u1 = rotateVelocities(swapVelocity1, -theta);
const u2 = rotateVelocities(swapVelocity2, -theta);
this.velocity.x = u1.x;
this.velocity.y = u1.y;
otherParticle.velocity.x = u2.x;
otherParticle.velocity.y = u2.y;
}
}
if (distance(this.x, this.y, otherParticle.x, otherParticle.y) - this.radius * 2 < 0 ) {
this.opacity = 0.1;
}
}
if (this.x + this.radius >= canvas.width || this.x - this.radius <= 0)
this.velocity.x = -this.velocity.x;
if (this.y + this.radius >= canvas.height || this.y - this.radius <= 0)
this.velocity.y = -this.velocity.y;
this.x += this.velocity.x;
this.y += this.velocity.y;
};
this.draw = () => {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = `rgba(${this.r}, ${this.g}, ${this.b}, 1)`;
c.stroke();
c.fillStyle = `rgba(${this.r}, ${this.g}, ${this.b}, ${this.opacity}`;
c.fill();
c.closePath();
};
}
// Implementation
let particles;
function init() {
particles = [];
let radius = 80
for (let i = 0; i < 10; i++) {
let x = randomIntFromRange(radius, innerWidth - radius);
let y = randomIntFromRange(radius, innerHeight - radius);
if (particles.length >= 1) {
for (let j = 0; j < particles.length; j++) {
if (distance(x, y, particles[j].x, particles[j].y) - radius * 2 < 0) {
x = randomIntFromRange(radius, innerWidth - radius);
y = randomIntFromRange(radius, innerHeight - radius);
j = -1;
continue;
}
}
}
particles.push(new Particle(x, y, radius, randomColor(colors)));
}
}
//I would like to initiate one circle out of all as red and whenever the red circle collide with other circle, other circle got red and at last all circle become red. but when two white circle collide it should not become red. basically one infected circle making other circle infected by touching.

Javascript won't draw the animation taking value from HTML input element

I wanted to create physics simulation with dropping ball. To have more fun I wanted to give to user an access to input his values of dropping ball radius and count. If you would run this code on browser, you could click button 'CREATE' to display animation with default values and it would have worked. When I enter balls count in html input element, it recognises the count and executes the code and the animation appears. When I enter radius value in html input element, nothing appears on canvas. I find this as very strange problem. I've already tried renaming variables and element id names. When I I would appreciate if anyone could help.
The html file called index.html
const canvas = document.getElementById('ball-platform');
const createBtn = document.getElementById('createAnimation');
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext('2d');
const gravity = 0.15;
const friction = 0.9;
let balls = [];
function FillCircle(x0, y0, bRadius, theColor) {
let circle = {
x: x0,
y: y0,
color: theColor
};
let xVel = 5,
yVel = 1;
this.movement = () => {
if (Math.round(circle.x + bRadius + xVel) > W || Math.round(circle.x - bRadius + xVel) < 0) {
xVel = -xVel * friction;
yVel *= friction;
} else if (Math.round(circle.y + bRadius + yVel) > H) {
yVel = -yVel * friction;
xVel *= friction;
} else {
yVel += gravity;
}
circle.x += xVel;
circle.y += yVel;
}
this.draw = () => {
ctx.beginPath();
ctx.fillStyle = circle.color;
ctx.ellipse(circle.x, circle.y, bRadius, bRadius, -90 * Math.PI / 180, 360 * Math.PI / 180, false);
ctx.fill();
ctx.stroke();
}
}
createBtn.addEventListener('mousedown', () => {
balls = [];
let bRadius = document.getElementById('bRadius').value;
let count = document.getElementById('count').value;
if (bRadius == "" || bRadius <= 0) {
bRadius = 5;
}
if (count == "" || count < 0) {
count = 5;
}
initialize(count, bRadius);
});
function initialize(count, bRadius) {
for (let i = 0; i < count; i++) {
let xpos = (Math.random() * (W - bRadius - 10)) + bRadius;
let ypos = (Math.random() * (H - bRadius - 10)) + bRadius;
balls.push(new FillCircle(xpos, ypos, bRadius, 'red'));
}
}
function animation() {
requestAnimationFrame(animation);
ctx.clearRect(0, 0, W, H);
for (let a = 0; a < balls.length; a++) {
let circle = balls[a];
circle.movement();
circle.draw();
}
}
animation();
<nav style='display: block;'>
<button id='createAnimation'>CREATE</button>
<input placeholder='Radius' , id='bRadius'>
<input placeholder='Count' id='count'>
</nav>
<canvas id="ball-platform" width="500" height="500" style="border: 1px solid black"></canvas>
I think you need to convert the input values to numbers,
const canvas = document.getElementById('ball-platform');
const createBtn = document.getElementById('createAnimation');
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext('2d');
const gravity = 0.15;
const friction = 0.9;
let balls = [];
function FillCircle(x0, y0, bRadius, theColor) {
let circle = {
x: x0,
y: y0,
color: theColor
};
let xVel = 5,
yVel = 1;
this.movement = () => {
if (Math.round(circle.x + bRadius + xVel) > W || Math.round(circle.x - bRadius + xVel) < 0) {
xVel = -xVel * friction;
yVel *= friction;
} else if (Math.round(circle.y + bRadius + yVel) > H) {
yVel = -yVel * friction;
xVel *= friction;
} else {
yVel += gravity;
}
circle.x += xVel;
circle.y += yVel;
}
this.draw = () => {
ctx.beginPath();
ctx.fillStyle = circle.color;
ctx.ellipse(circle.x, circle.y, bRadius, bRadius, -90 * Math.PI / 180, 360 * Math.PI / 180, false);
ctx.fill();
ctx.stroke();
}
}
createBtn.addEventListener('mousedown', () => {
balls = [];
let bRadius = parseInt(document.getElementById('bRadius').value);
let count = parseInt(document.getElementById('count').value);
if (bRadius == "" || bRadius <= 0) {
bRadius = 5;
}
if (count == "" || count < 0) {
count = 5;
}
initialize(count, bRadius);
});
function initialize(count, bRadius) {
for (let i = 0; i < count; i++) {
let xpos = (Math.random() * (W - bRadius - 10)) + bRadius;
let ypos = (Math.random() * (H - bRadius - 10)) + bRadius;
balls.push(new FillCircle(xpos, ypos, bRadius, 'red'));
}
}
function animation() {
requestAnimationFrame(animation);
ctx.clearRect(0, 0, W, H);
for (let a = 0; a < balls.length; a++) {
let circle = balls[a];
circle.movement();
circle.draw();
}
}
animation();
<nav style='display: block;'>
<button id='createAnimation'>CREATE</button>
<input placeholder='Radius' , id='bRadius'>
<input placeholder='Count' id='count'>
</nav>
<canvas id="ball-platform" width="500" height="500" style="border: 1px solid black"></canvas>

How to add css in text in jquery please give me refrence

How to add css in text in jquery I have try but no way found it please help me.
let particles = [];
let frequency = 20;
// Popolate particles
setInterval(
function () {
popolate();
}.bind(this),
frequency);
let c1 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let c2 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let c3 = createCanvas({ width: jQuery(window).width(), height: jQuery(window).height() });
let tela = c1.canvas;
let canvas = c1.context;
// jQuery("body").append(tela);
jQuery("#text").append(c3.canvas);
writeText(c2.canvas, c2.context, "Create\nPublish\nDeliver")
jQuery("#text").css("background-color", "grey");
class Particle {
constructor(canvas, options) {
let random = Math.random();
this.canvas = canvas;
this.x = options.x;
this.y = options.y;
this.s = 3 + Math.random();
this.a = 0;
this.w = jQuery(window).width();
this.h = jQuery(window).height();
this.radius = 0.5 + Math.random() * 20;
this.color = this.radius > 5 ? "#FF5E4C" : "#ED413C"; //this.randomColor()
}
randomColor() {
let colors = ["#FF5E4C", "#FFFFFF"];
return colors[this.randomIntFromInterval(0, colors.length - 1)];
}
randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
render() {
this.canvas.beginPath();
this.canvas.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
this.canvas.lineWidth = 2;
this.canvas.fillStyle = this.color;
this.canvas.fill();
this.canvas.closePath();
}
move() {
//this.swapColor()
this.x += Math.cos(this.a) * this.s;
this.y += Math.sin(this.a) * this.s;
this.a += Math.random() * 0.8 - 0.4;
if (this.x < 0 || this.x > this.w - this.radius) {
return false;
}
if (this.y < 0 || this.y > this.h - this.radius) {
return false;
}
this.render();
return true;
}}
function createCanvas(properties) {
let canvas = document.createElement('canvas');
canvas.width = properties.width;
canvas.height = properties.height;
let context = canvas.getContext('2d');
return {
canvas: canvas,
context: context };
}
function writeText(canvas, context, text) {
let size = 100;
context.font = size + "px Montserrat";
context.fillStyle = "#111111";
context.textAlign = "center";
let lineheight = 70;
let lines = text.split('\n');
for (let i = 0; i < lines.length; i++) {
context.fillText(lines[i], canvas.width / 2, canvas.height / 2 + lineheight * i - lineheight * (lines.length - 1) / 3);
}
}
function maskCanvas() {
c3.context.drawImage(c2.canvas, 0, 0, c2.canvas.width, c2.canvas.height);
c3.context.globalCompositeOperation = 'source-atop';
c3.context.drawImage(c1.canvas, 0, 0);
blur(c1.context, c1.canvas, 2);
}
function blur(ctx, canvas, amt) {
ctx.filter = `blur(jQuery{amt}px)`;
ctx.drawImage(canvas, 0, 0);
ctx.filter = 'none';
}
/*
* Function to clear layer canvas
* #num:number number of particles
*/
function popolate() {
particles.push(
new Particle(canvas, {
x: jQuery(window).width() / 2,
y: jQuery(window).height() / 2 }));
return particles.length;
}
function clear() {
canvas.globalAlpha = 0.03;
canvas.fillStyle = '#111111';
canvas.fillRect(0, 0, tela.width, tela.height);
canvas.globalAlpha = 1;
}
function update() {
clear();
particles = particles.filter(function (p) {
return p.move();
});
maskCanvas();`enter code here`
requestAnimationFrame(update.bind(this));
}
update();
// jQuery("body").append(tela);
jQuery("#text").append(c3.canvas);
writeText(c2.canvas, c2.context, "Create\nPublish\nDeliver").css("margin-left:20px");
jQuery("#text").css("background-color", "grey");
I have not found any way to add css in text please help me these
This could be a possible solution
let elementStyle = document.getElementById('text').style
elementStyle.backgroundColor = 'red'
elementStyle.marginLeft = '20px'

I need to make this canvas transparent but none of the solutions are working

I have tried all the jQuery tricks as well as the CSS tricks, but none of them work.. I don't really know anything about <canvas> but I've been trying to solve this for a day now.. can anybody help?
I am trying not mess up the code and just make the black background transparent so that I could use this canvas over a carousal..
// helper functions
const PI2 = Math.PI * 2
const random = (min, max) => Math.random() * (max - min + 1) + min | 0
const timestamp = _ => new Date().getTime()
// container
class Birthday {
constructor() {
this.resize()
// create a lovely place to store the firework
this.fireworks = []
this.counter = 0
}
resize() {
this.width = canvas.width = window.innerWidth
let center = this.width / 2 | 0
this.spawnA = center - center / 4 | 0
this.spawnB = center + center / 4 | 0
this.height = canvas.height = window.innerHeight
this.spawnC = this.height * .1
this.spawnD = this.height * .5
}
onClick(evt) {
let x = evt.clientX || evt.touches && evt.touches[0].pageX
let y = evt.clientY || evt.touches && evt.touches[0].pageY
let count = random(3, 5)
for (let i = 0; i < count; i++) this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
x,
y,
random(0, 260),
random(30, 110)))
this.counter = -1
}
update(delta) {
ctx.globalCompositeOperation = 'hard-light'
ctx.fillStyle = `rgba(20,20,20,${ 7 * delta })`
ctx.fillRect(0, 0, this.width, this.height)
ctx.globalCompositeOperation = 'lighter'
for (let firework of this.fireworks) firework.update(delta)
// if enough time passed... create new new firework
this.counter += delta * 3 // each second
if (this.counter >= 1) {
this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
random(0, this.width),
random(this.spawnC, this.spawnD),
random(0, 360),
random(30, 110)))
this.counter = 0
}
// remove the dead fireworks
if (this.fireworks.length > 1000) this.fireworks = this.fireworks.filter(firework => !firework.dead)
}
}
class Firework {
constructor(x, y, targetX, targetY, shade, offsprings) {
this.dead = false
this.offsprings = offsprings
this.x = x
this.y = y
this.targetX = targetX
this.targetY = targetY
this.shade = shade
this.history = []
}
update(delta) {
if (this.dead) return
let xDiff = this.targetX - this.x
let yDiff = this.targetY - this.y
if (Math.abs(xDiff) > 3 || Math.abs(yDiff) > 3) { // is still moving
this.x += xDiff * 2 * delta
this.y += yDiff * 2 * delta
this.history.push({
x: this.x,
y: this.y
})
if (this.history.length > 20) this.history.shift()
} else {
if (this.offsprings && !this.madeChilds) {
let babies = this.offsprings / 2
for (let i = 0; i < babies; i++) {
let targetX = this.x + this.offsprings * Math.cos(PI2 * i / babies) | 0
let targetY = this.y + this.offsprings * Math.sin(PI2 * i / babies) | 0
birthday.fireworks.push(new Firework(this.x, this.y, targetX, targetY, this.shade, 0))
}
}
this.madeChilds = true
this.history.shift()
}
if (this.history.length === 0) this.dead = true
else if (this.offsprings) {
for (let i = 0; this.history.length > i; i++) {
let point = this.history[i]
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,' + i + '%)'
ctx.arc(point.x, point.y, 1, 0, PI2, false)
ctx.fill()
}
} else {
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,50%)'
ctx.arc(this.x, this.y, 1, 0, PI2, false)
ctx.fill()
}
}
}
let canvas = document.getElementById('birthday')
let ctx = canvas.getContext('2d')
let then = timestamp()
let birthday = new Birthday
window.onresize = () => birthday.resize()
document.onclick = evt => birthday.onClick(evt)
document.ontouchstart = evt => birthday.onClick(evt)
;
(function loop() {
requestAnimationFrame(loop)
let now = timestamp()
let delta = now - then
then = now
birthday.update(delta / 1000)
})()
<canvas id="birthday"></canvas>
All you need to do is replace fillRect with clearRect in the update method of the Birthday class like this:
ctx.clearRect(0, 0, this.width, this.height)
You may need to make further adjustments to the color of the firework trail though, since it seems like it was supposed to match the background color.
If your canvas still isn't transparent, check your css to ensure that you're not setting the background color that way.
const PI2 = Math.PI * 2
const random = (min, max) => Math.random() * (max - min + 1) + min | 0
const timestamp = _ => new Date().getTime()
// container
class Birthday {
constructor() {
this.resize()
// create a lovely place to store the firework
this.fireworks = []
this.counter = 0
}
resize() {
this.width = canvas.width = window.innerWidth
let center = this.width / 2 | 0
this.spawnA = center - center / 4 | 0
this.spawnB = center + center / 4 | 0
this.height = canvas.height = window.innerHeight
this.spawnC = this.height * .1
this.spawnD = this.height * .5
}
onClick(evt) {
let x = evt.clientX || evt.touches && evt.touches[0].pageX
let y = evt.clientY || evt.touches && evt.touches[0].pageY
let count = random(3, 5)
for (let i = 0; i < count; i++) this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
x,
y,
random(0, 260),
random(30, 110)))
this.counter = -1
}
update(delta) {
ctx.globalCompositeOperation = 'hard-light'
ctx.fillStyle = `rgba(20,20,20,${ 7 * delta })`
ctx.clearRect(0, 0, this.width, this.height)
ctx.globalCompositeOperation = 'lighter'
for (let firework of this.fireworks) firework.update(delta)
// if enough time passed... create new new firework
this.counter += delta * 3 // each second
if (this.counter >= 1) {
this.fireworks.push(new Firework(
random(this.spawnA, this.spawnB),
this.height,
random(0, this.width),
random(this.spawnC, this.spawnD),
random(0, 360),
random(30, 110)))
this.counter = 0
}
// remove the dead fireworks
if (this.fireworks.length > 1000) this.fireworks = this.fireworks.filter(firework => !firework.dead)
}
}
class Firework {
constructor(x, y, targetX, targetY, shade, offsprings) {
this.dead = false
this.offsprings = offsprings
this.x = x
this.y = y
this.targetX = targetX
this.targetY = targetY
this.shade = shade
this.history = []
}
update(delta) {
if (this.dead) return
let xDiff = this.targetX - this.x
let yDiff = this.targetY - this.y
if (Math.abs(xDiff) > 3 || Math.abs(yDiff) > 3) { // is still moving
this.x += xDiff * 2 * delta
this.y += yDiff * 2 * delta
this.history.push({
x: this.x,
y: this.y
})
if (this.history.length > 20) this.history.shift()
} else {
if (this.offsprings && !this.madeChilds) {
let babies = this.offsprings / 2
for (let i = 0; i < babies; i++) {
let targetX = this.x + this.offsprings * Math.cos(PI2 * i / babies) | 0
let targetY = this.y + this.offsprings * Math.sin(PI2 * i / babies) | 0
birthday.fireworks.push(new Firework(this.x, this.y, targetX, targetY, this.shade, 0))
}
}
this.madeChilds = true
this.history.shift()
}
if (this.history.length === 0) this.dead = true
else if (this.offsprings) {
for (let i = 0; this.history.length > i; i++) {
let point = this.history[i]
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,' + i + '%)'
ctx.arc(point.x, point.y, 1, 0, PI2, false)
ctx.fill()
}
} else {
ctx.beginPath()
ctx.fillStyle = 'hsl(' + this.shade + ',100%,50%)'
ctx.arc(this.x, this.y, 1, 0, PI2, false)
ctx.fill()
}
}
}
let canvas = document.getElementById('birthday')
let ctx = canvas.getContext('2d')
let then = timestamp()
let birthday = new Birthday
window.onresize = () => birthday.resize()
document.onclick = evt => birthday.onClick(evt)
document.ontouchstart = evt => birthday.onClick(evt)
;
(function loop() {
requestAnimationFrame(loop)
let now = timestamp()
let delta = now - then
then = now
birthday.update(delta / 1000)
})()
div {
height : 100vh;
width : 100vw;
display : flex;
flex-direction : center;
align-items : center;
justify-content : center;
}
canvas {
position : absolute;
top : 0;
left : 0;
}
<div>Content Underneath</div>
<canvas id="birthday"></canvas>

Categories

Resources