Why does the below canvas have a black background!! I have tried everything but it doesn't go!! Bcs of it the text below it is also not visible! I need it to be transparent to show the elements behind it and the background image of the body. Pls, help fast!! There is a similar question on StackOverflow but the solution given for that question doesn't work correctly for me.
"use strict";
let canvas, width, height, ctx;
let fireworks = [];
let particles = [];
function setup() {
canvas = document.getElementById("canvas");
setSize(canvas);
ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
fireworks.push(new Firework(Math.random()*(width-200) 100));
window.addEventListener("resize",windowResized);
document.addEventListener("click",onClick);
}
setTimeout(setup,1);
function loop(){
ctx.globalAlpha = 0.1;
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
ctx.globalAlpha = 1;
for(let i=0; i<fireworks.length; i ){
let done = fireworks[i].update();
fireworks[i].draw();
if(done) fireworks.splice(i, 1);
}
for(let i=0; i<particles.length; i ){
particles[i].update();
particles[i].draw();
if(particles[i].lifetime>80) particles.splice(i,1);
}
if(Math.random()<1/60) fireworks.push(new Firework(Math.random()*(width-200) 100));
}
setInterval(loop, 1/60);
//setInterval(loop, 100/60);
class Particle{
constructor(x, y, col){
this.x = x;
this.y = y;
this.col = col;
this.vel = randomVec(2);
this.lifetime = 0;
}
update(){
this.x = this.vel.x;
this.y = this.vel.y;
this.vel.y = 0.02;
this.vel.x *= 0.99;
this.vel.y *= 0.99;
this.lifetime ;
}
draw(){
ctx.globalAlpha = Math.max(1-this.lifetime/80, 0);
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
class Firework{
constructor(x){
this.x = x;
this.y = height;
this.isBlown = false;
this.col = randomCol();
}
update(){
this.y -= 3;
if(this.y < 350-Math.sqrt(Math.random()*500)*40){
this.isBlown = true;
for(let i=0; i<60; i ){
particles.push(new Particle(this.x, this.y, this.col))
}
}
return this.isBlown;
}
draw(){
ctx.globalAlpha = 1;
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
function randomCol(){
var letter = '0123456789ABCDEF';
var nums = [];
for(var i=0; i<3; i ){
nums[i] = Math.floor(Math.random()*256);
}
let brightest = 0;
for(var i=0; i<3; i ){
if(brightest<nums[i]) brightest = nums[i];
}
brightest /=255;
for(var i=0; i<3; i ){
nums[i] /= brightest;
}
let color = "#";
for(var i=0; i<3; i ){
color = letter[Math.floor(nums[i]/16)];
color = letter[Math.floor(nums[i])];
}
return color;
}
function randomVec(max){
let dir = Math.random()*Math.PI*2;
let spd = Math.random()*max;
return{x: Math.cos(dir)*spd, y: Math.sin(dir)*spd};
}
function setSize(canv){
canv.style.width = (innerWidth) "px";
canv.style.height = (innerHeight) "px";
width = innerWidth;
height = innerHeight;
canv.width = innerWidth*window.devicePixelRatio;
canv.height = innerHeight*window.devicePixelRatio;
canvas.getContext("2d").scale(window.devicePixelRatio, window.devicePixelRatio);
}
function onClick(e){
fireworks.push(new Firework(e.clientX));
}
function windowResized(){
setSize(canvas);
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
}
<canvas id="canvas"></canvas>
<h1>Hello</h1>
I request you to help me.
CodePudding user response:
I don't think there is an easy fix for what you are asking. You would need to store each particle into a buffer array with details about its color, position and so on.
You would need to then loop through the buffer and update any changes.
Then redraw each particle from the buffer to a freshly cleared screen.
It's all very doable but very heavy on the browser depending whether its a phone or a desktop tablet etc.
The easiest fix is the background being solid which is what you had.
Else you could be clever and use looping video in either AV1 or VP9 codecs as they have wide support for transparency.
If these options do not suite then coding it will be the only way I can see it working but anything more than a 1000 particles may cause fat hang ups and lag and not the buttery smooth FPS you would expect.
If anyone else knows a better solution for this problem then I would love to know :D
CodePudding user response:
globalCompositeOperation
To clear only pixels that have an alpha > 0 use the globalCompositeOperation property and set it to "destination-out"
.
This will let you partially delete the pixels (leaving the trails) without effecting the background.
You will need to restore the composite operation to "source-over"
.
The change to the function loop
as follows
function loop(){
ctx.globalAlpha = 0.1;
ctx.globalCompositeOperation = "destination-out"; // Add line
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "source-over"; // Add line
ctx.globalAlpha = 1;
//... rest of code
Example
Snippet is a copy of your code with the above changes.
Also add slight change to stop it crashing on SO snippet due to improper setup call order.
"use strict";
let canvas, width, height, ctx;
let fireworks = [];
let particles = [];
function setup() {
canvas = document.getElementById("canvas");
setSize(canvas);
ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
fireworks.push(new Firework(Math.random()*(width-200) 100));
window.addEventListener("resize",windowResized);
document.addEventListener("click",onClick);
setInterval(loop, 1/60);
}
setTimeout(setup,1);
function loop(){
ctx.globalAlpha = 0.1;
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
for(let i=0; i<fireworks.length; i ){
let done = fireworks[i].update();
fireworks[i].draw();
if(done) fireworks.splice(i, 1);
}
for(let i=0; i<particles.length; i ){
particles[i].update();
particles[i].draw();
if(particles[i].lifetime>80) particles.splice(i,1);
}
if(Math.random()<1/60) fireworks.push(new Firework(Math.random()*(width-200) 100));
}
class Particle{
constructor(x, y, col){
this.x = x;
this.y = y;
this.col = col;
this.vel = randomVec(2);
this.lifetime = 0;
}
update(){
this.x = this.vel.x;
this.y = this.vel.y;
this.vel.y = 0.02;
this.vel.x *= 0.99;
this.vel.y *= 0.99;
this.lifetime ;
}
draw(){
ctx.globalAlpha = Math.max(1-this.lifetime/80, 0);
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
class Firework{
constructor(x){
this.x = x;
this.y = height;
this.isBlown = false;
this.col = randomCol();
}
update(){
this.y -= 3;
if(this.y < 350-Math.sqrt(Math.random()*500)*40){
this.isBlown = true;
for(let i=0; i<60; i ){
particles.push(new Particle(this.x, this.y, this.col))
}
}
return this.isBlown;
}
draw(){
ctx.globalAlpha = 1;
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
function randomCol(){
var letter = '0123456789ABCDEF';
var nums = [];
for(var i=0; i<3; i ){
nums[i] = Math.floor(Math.random()*256);
}
let brightest = 0;
for(var i=0; i<3; i ){
if(brightest<nums[i]) brightest = nums[i];
}
brightest /=255;
for(var i=0; i<3; i ){
nums[i] /= brightest;
}
let color = "#";
for(var i=0; i<3; i ){
color = letter[Math.floor(nums[i]/16)];
color = letter[Math.floor(nums[i])];
}
return color;
}
function randomVec(max){
let dir = Math.random()*Math.PI*2;
let spd = Math.random()*max;
return{x: Math.cos(dir)*spd, y: Math.sin(dir)*spd};
}
function setSize(canv){
canv.style.width = (innerWidth) "px";
canv.style.height = (innerHeight) "px";
width = innerWidth;
height = innerHeight;
canv.width = innerWidth*window.devicePixelRatio;
canv.height = innerHeight*window.devicePixelRatio;
canvas.getContext("2d").scale(window.devicePixelRatio, window.devicePixelRatio);
}
function onClick(e){
fireworks.push(new Firework(e.clientX));
}
function windowResized(){
setSize(canvas);
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
}
canvas {
position: absolute;
top: 0px;
left: 0px;
}
code { background: #DEF; }
<canvas id="canvas"></canvas>
<h1>Trails</h1>
<p>Text under the canvas with trails using</p>
<code>ctx.globalCompositeOperation = "destination-out";</code>
CodePudding user response:
As I understand you wanted to have a white background for your canvas? Check this out!
"use strict";
let canvas, width, height, ctx;
let fireworks = [];
let particles = [];
function setup() {
canvas = document.getElementById("canvas");
setSize(canvas);
ctx = canvas.getContext("2d");
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
fireworks.push(new Firework(Math.random()*(width-200) 100));
window.addEventListener("resize",windowResized);
document.addEventListener("click",onClick);
}
setTimeout(setup,1);
function loop(){
ctx.globalAlpha = 0.1;
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height);
ctx.globalAlpha = 1;
for(let i=0; i<fireworks.length; i ){
let done = fireworks[i].update();
fireworks[i].draw();
if(done) fireworks.splice(i, 1);
}
for(let i=0; i<particles.length; i ){
particles[i].update();
particles[i].draw();
if(particles[i].lifetime>80) particles.splice(i,1);
}
if(Math.random()<1/60) fireworks.push(new Firework(Math.random()*(width-200) 100));
}
setInterval(loop, 1/60);
//setInterval(loop, 100/60);
class Particle{
constructor(x, y, col){
this.x = x;
this.y = y;
this.col = col;
this.vel = randomVec(2);
this.lifetime = 0;
}
update(){
this.x = this.vel.x;
this.y = this.vel.y;
this.vel.y = 0.02;
this.vel.x *= 0.99;
this.vel.y *= 0.99;
this.lifetime ;
}
draw(){
ctx.globalAlpha = Math.max(1-this.lifetime/80, 0);
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
class Firework{
constructor(x){
this.x = x;
this.y = height;
this.isBlown = false;
this.col = randomCol();
}
update(){
this.y -= 3;
if(this.y < 350-Math.sqrt(Math.random()*500)*40){
this.isBlown = true;
for(let i=0; i<60; i ){
particles.push(new Particle(this.x, this.y, this.col))
}
}
return this.isBlown;
}
draw(){
ctx.globalAlpha = 1;
ctx.fillStyle = this.col;
ctx.fillRect(this.x, this.y, 2, 2);
}
}
function randomCol(){
var letter = '0123456789ABCDEF';
var nums = [];
for(var i=0; i<3; i ){
nums[i] = Math.floor(Math.random()*256);
}
let brightest = 0;
for(var i=0; i<3; i ){
if(brightest<nums[i]) brightest = nums[i];
}
brightest /=255;
for(var i=0; i<3; i ){
nums[i] /= brightest;
}
let color = "#";
for(var i=0; i<3; i ){
color = letter[Math.floor(nums[i]/16)];
color = letter[Math.floor(nums[i])];
}
return color;
}
function randomVec(max){
let dir = Math.random()*Math.PI*2;
let spd = Math.random()*max;
return{x: Math.cos(dir)*spd, y: Math.sin(dir)*spd};
}
function setSize(canv){
canv.style.width = (innerWidth) "px";
canv.style.height = (innerHeight) "px";
width = innerWidth;
height = innerHeight;
canv.width = innerWidth*window.devicePixelRatio;
canv.height = innerHeight*window.devicePixelRatio;
canvas.getContext("2d").scale(window.devicePixelRatio, window.devicePixelRatio);
}
function onClick(e){
fireworks.push(new Firework(e.clientX));
}
function windowResized(){
setSize(canvas);
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, width, height);
}
<canvas id="canvas"></canvas>
<h1>Hey Try this out!</h1>
CodePudding user response:
change fill style to:
ctx.fillStyle = "rgba(0,0,0,0)";
ctx.fillRect(0, 0, width, height);