0

I am slightly new with js and ran into an issue. I was trying to create a stars in the sky animation. I did so by creating small circles randomly on a canvas and then randomly selecting stars which are flickered (opacity is changed). I then realised the website was not working when scaled so I decided to implement an onevent for the window resize and when the window is resized I run the same functions again to recreate the same process but while clearing all the previous stars so they don't multiply. The issue here is that the clearRect method doesn't seem to be clearing the previously drawn stars for me. Any help on this would be very much appreciated :). Here is my code.

let starCollection  = [];
let randomStars     = [];
let numberofStars   = 100;
let flickeringStars = 50;

class Star{
    constructor(x,y,color,radius){
        this._canvas        = document.querySelector('canvas');
        this._canvas.width  = window.innerWidth;
        this._canvas.height = window.innerHeight; 
        this._c             = this._canvas.getContext('2d');
        this._radius        = radius;

        this._x       = x;
        this._y       = y;
        this._color   = color;     
    }

    //drawing individual stars
    draw(){
        //Drawing
        this._c.beginPath();
        this._c.arc(this._x,this._y,this._radius,0,Math.PI * 2,false);
        this._c.fillStyle   = this._color;
        this._c.strokeStyle = 'black';
        this._c.stroke();
        this._c.fill();
        this._c.closePath();
    }
    //Fade in and out for stars
    flicker(){

        setTimeout(()=>{this._color='#EBEBEB';},300);
        setTimeout(()=>{this._color='#D9D9D9';},600);
        setTimeout(()=>{this._color='#B6B6B6';},900);
        setTimeout(()=>{this._color='#898787';},1200);
        setTimeout(()=>{this._color='#4F4F4F';},1500);

        setTimeout(()=>{this._color='black';},1800);
        setTimeout(()=>{this._color='#4F4F4F';},2100);
        setTimeout(()=>{this._color='#898787';},2400);
        setTimeout(()=>{this._color='#B6B6B6';},2700);
        setTimeout(()=>{this._color='#D9D9D9';},3000);
        setTimeout(()=>{this._color='#EBEBEB';},3300);
        setTimeout(()=>{this._color='#FFFFFF';},3600);

        setTimeout(()=>{this.draw();},300);
        setTimeout(()=>{this.draw();},600);
        setTimeout(()=>{this.draw();},900);
        setTimeout(()=>{this.draw();},1200);
        setTimeout(()=>{this.draw();},1500);
        setTimeout(()=>{this.draw();},1800);
        setTimeout(()=>{this.draw();},2100);

        setTimeout(()=>{this.draw();},2400);
        setTimeout(()=>{this.draw();},2700);
        setTimeout(()=>{this.draw();},3000);
        setTimeout(()=>{this.draw();},3300);
        setTimeout(()=>{this.draw();},3600);

    }

}

window.addEventListener("showStars", ()=>{
    //Stars animation
    //Adding the stars to the array as objects
    for(let i=0;i<numberofStars;i++){
        let x           = Math.floor(Math.random()*window.innerWidth);
        let y           = Math.floor(Math.random()*window.innerHeight);
        let starSize    = (Math.random()+1)-0.7;
        starCollection.push(new Star(x,y,"white",starSize));
    }
    //Drawing all the stars on the screen
    for(let i=0;i<starCollection.length;i++){
        starCollection[i].draw();
    }
    //Storing random stars  
    const shuffleStars = ()=>{
        randomStars = [];
        for(let i=0;i<flickeringStars;i++){
            randomStars.push(Math.floor(Math.random()*starCollection.length))
        }
    }
    shuffleStars();


   //Flickering stars randomly
   const starflicker = ()=>{
    console.log(starCollection);
    console.log(randomStars);
            setTimeout(()=>{
                requestAnimationFrame(starflicker);
                for(let i=0;i<randomStars.length;i++){
                    starCollection[randomStars[i]].flicker();
                }
                shuffleStars();
            },500);
        }
        starflicker();
    })

    window.addEventListener("resize", ()=>{


        let canvas     = document.querySelector("canvas");
        let context    = canvas.getContext("2d");
        canvas.width   = window.innerWitdh;
        canvas.height  = window.innerHeight;
        context.clearRect(0,0,window.innerWidth, window.innerHeight);

        starCollection = [];
        randomStars    = [];

        let event      = new CustomEvent("showStars");
        dispatchEvent(event); 
    });

let starCollection = [];
let randomStars = [];
let numberofStars = 100;
let flickeringStars = 50;

class Star {
  constructor(x, y, color, radius) {
    this._canvas = document.querySelector('canvas');
    this._canvas.width = window.innerWidth;
    this._canvas.height = window.innerHeight;
    this._c = this._canvas.getContext('2d');
    this._radius = radius;

    this._x = x;
    this._y = y;
    this._color = color;
  }

  //drawing individual stars
  draw() {
    //Drawing
    this._c.beginPath();
    this._c.arc(this._x, this._y, this._radius, 0, Math.PI * 2, false);
    this._c.fillStyle = this._color;
    this._c.strokeStyle = 'black';
    this._c.stroke();
    this._c.fill();
    this._c.closePath();
  }
  //Fade in and out for stars
  flicker() {

    setTimeout(() => {
      this._color = '#EBEBEB';
    }, 300);
    setTimeout(() => {
      this._color = '#D9D9D9';
    }, 600);
    setTimeout(() => {
      this._color = '#B6B6B6';
    }, 900);
    setTimeout(() => {
      this._color = '#898787';
    }, 1200);
    setTimeout(() => {
      this._color = '#4F4F4F';
    }, 1500);

    setTimeout(() => {
      this._color = 'black';
    }, 1800);
    setTimeout(() => {
      this._color = '#4F4F4F';
    }, 2100);
    setTimeout(() => {
      this._color = '#898787';
    }, 2400);
    setTimeout(() => {
      this._color = '#B6B6B6';
    }, 2700);
    setTimeout(() => {
      this._color = '#D9D9D9';
    }, 3000);
    setTimeout(() => {
      this._color = '#EBEBEB';
    }, 3300);
    setTimeout(() => {
      this._color = '#FFFFFF';
    }, 3600);

    setTimeout(() => {
      this.draw();
    }, 300);
    setTimeout(() => {
      this.draw();
    }, 600);
    setTimeout(() => {
      this.draw();
    }, 900);
    setTimeout(() => {
      this.draw();
    }, 1200);
    setTimeout(() => {
      this.draw();
    }, 1500);
    setTimeout(() => {
      this.draw();
    }, 1800);
    setTimeout(() => {
      this.draw();
    }, 2100);

    setTimeout(() => {
      this.draw();
    }, 2400);
    setTimeout(() => {
      this.draw();
    }, 2700);
    setTimeout(() => {
      this.draw();
    }, 3000);
    setTimeout(() => {
      this.draw();
    }, 3300);
    setTimeout(() => {
      this.draw();
    }, 3600);

  }

}

window.addEventListener("showStars", () => {
  //Stars animation
  //Adding the stars to the array as objects
  for (let i = 0; i < numberofStars; i++) {
    let x = Math.floor(Math.random() * window.innerWidth);
    let y = Math.floor(Math.random() * window.innerHeight);
    let starSize = (Math.random() + 1) - 0.7;
    starCollection.push(new Star(x, y, "white", starSize));
  }
  //Drawing all the stars on the screen
  for (let i = 0; i < starCollection.length; i++) {
    starCollection[i].draw();
  }
  //Storing random stars  
  const shuffleStars = () => {
    randomStars = [];
    for (let i = 0; i < flickeringStars; i++) {
      randomStars.push(Math.floor(Math.random() * starCollection.length))
    }
  }
  shuffleStars();


  //Flickering stars randomly
  const starflicker = () => {
    console.log(starCollection);
    console.log(randomStars);
    setTimeout(() => {
      requestAnimationFrame(starflicker);
      for (let i = 0; i < randomStars.length; i++) {
        starCollection[randomStars[i]].flicker();
      }
      shuffleStars();
    }, 500);
  }
  starflicker();
})

window.addEventListener("resize", () => {


  let canvas = document.querySelector("canvas");
  let context = canvas.getContext("2d");
  canvas.width = window.innerWitdh;
  canvas.height = window.innerHeight;
  context.clearRect(0, 0, window.innerWidth, window.innerHeight);

  starCollection = [];
  randomStars = [];

  let event = new CustomEvent("showStars");
  dispatchEvent(event);
});
body{
background-color:black;
}
<html>
<body>
<canvas></canvas>
</body>
</html>
braX
  • 11,506
  • 5
  • 20
  • 33
  • The clearRect() should be working fine. Can you confirm that your arrays are being emptied on resize? – georgedum Jun 07 '20 at 18:04
  • @georgedum yes as shown on the "resize" event handler the arrays are emptied each time the window is resized. The whole issue is with there being too many stars for some reason when the window is resized. Technically it should only have 100 stars no matter the size of the window. – Jesus Johan Godinho Jun 07 '20 at 18:19
  • @georgedum can you help me with this? – Jesus Johan Godinho Jun 08 '20 at 14:27

1 Answers1

0

Your problem is in the flicker function. Those setTimeouts still fire even after your resize function. So they call this.draw() even though those stars were removed from your array. The function still remembers what 'this' is.

You can clear all your timeouts like this:

  window.addEventListener("resize", () => {
    let canvas = document.querySelector("canvas");
    let context = canvas.getContext("2d");
    canvas.width = window.innerWitdh;
    canvas.height = window.innerHeight;
    context.clearRect(0, 0, window.innerWidth, window.innerHeight);
    starCollection = [];
    randomStars = [];

    var id = window.setTimeout(function () { }, 0);
    while (id--) {
      window.clearTimeout(id); // will do nothing if no timeout with id is present
    }

    let event = new CustomEvent("showStars");
    dispatchEvent(event);
});

Here's an example with 10 stars, 5 of which are flickering. I made the stars bigger so it's easier to see.

<html>

<head>
    <style>
        body {
            background: black;
        }
    </style>
</head>

<body>
    <canvas></canvas>

    <script>

        let starCollection = [];
        let randomStars = [];
        let numberofStars = 10;
        let flickeringStars = 5;

        class Star {
            constructor(x, y, color, radius) {
                this._canvas = document.querySelector('canvas');
                this._canvas.width = window.innerWidth;
                this._canvas.height = window.innerHeight;
                this._c = this._canvas.getContext('2d');
                this._radius = radius;

                this._x = x;
                this._y = y;
                this._color = color;
            }

            //drawing individual stars
            draw() {
                //Drawing
                this._c.beginPath();
                this._c.arc(this._x, this._y, this._radius, 0, Math.PI * 2, false);
                this._c.fillStyle = this._color;
                this._c.strokeStyle = 'black';
                this._c.stroke();
                this._c.fill();
                this._c.closePath();
            }
            //Fade in and out for stars
            flicker() {

                setTimeout(() => {
                    this._color = '#EBEBEB';
                }, 300);
                setTimeout(() => {
                    this._color = '#D9D9D9';
                }, 600);
                setTimeout(() => {
                    this._color = '#B6B6B6';
                }, 900);
                setTimeout(() => {
                    this._color = '#898787';
                }, 1200);
                setTimeout(() => {
                    this._color = '#4F4F4F';
                }, 1500);

                setTimeout(() => {
                    this._color = 'black';
                }, 1800);
                setTimeout(() => {
                    this._color = '#4F4F4F';
                }, 2100);
                setTimeout(() => {
                    this._color = '#898787';
                }, 2400);
                setTimeout(() => {
                    this._color = '#B6B6B6';
                }, 2700);
                setTimeout(() => {
                    this._color = '#D9D9D9';
                }, 3000);
                setTimeout(() => {
                    this._color = '#EBEBEB';
                }, 3300);
                setTimeout(() => {
                    this._color = '#FFFFFF';
                }, 3600);

                setTimeout(() => {
                    this.draw();
                }, 300);
                setTimeout(() => {
                    this.draw();
                }, 600);
                setTimeout(() => {
                    this.draw();
                }, 900);
                setTimeout(() => {
                    this.draw();
                }, 1200);
                setTimeout(() => {
                    this.draw();
                }, 1500);
                setTimeout(() => {
                    this.draw();
                }, 1800);
                setTimeout(() => {
                    this.draw();
                }, 2100);

                setTimeout(() => {
                    this.draw();
                }, 2400);
                setTimeout(() => {
                    this.draw();
                }, 2700);
                setTimeout(() => {
                    this.draw();
                }, 3000);
                setTimeout(() => {
                    this.draw();
                }, 3300);
                setTimeout(() => {
                    this.draw();
                }, 3600);

            }

        }

        window.addEventListener("showStars", () => {
            //Stars animation
            //Adding the stars to the array as objects
            for (let i = 0; i < numberofStars; i++) {
                let x = Math.floor(Math.random() * window.innerWidth);
                let y = Math.floor(Math.random() * window.innerHeight);
                // let starSize = (Math.random() + 1) - 0.7;
                let starSize = 10;
                starCollection.push(new Star(x, y, "white", starSize));
            }
            //Drawing all the stars on the screen
            for (let i = 0; i < starCollection.length; i++) {
                starCollection[i].draw();
            }
            //Storing random stars  
            const shuffleStars = () => {
                randomStars = [];
                for (let i = 0; i < flickeringStars; i++) {
                    randomStars.push(Math.floor(Math.random() * starCollection.length))
                }
            }
            shuffleStars();


            //Flickering stars randomly
            const starflicker = () => {
                console.log(starCollection);
                console.log(randomStars);
                setTimeout(() => {
                    requestAnimationFrame(starflicker);
                    for (let i = 0; i < randomStars.length; i++) {
                        starCollection[randomStars[i]].flicker();
                    }
                    shuffleStars();
                }, 500);
            }
            starflicker();
        })

        window.addEventListener("resize", () => {


            let canvas = document.querySelector("canvas");
            let context = canvas.getContext("2d");
            canvas.width = window.innerWitdh;
            canvas.height = window.innerHeight;
            context.clearRect(0, 0, window.innerWidth, window.innerHeight);

            starCollection = [];
            randomStars = [];
            var id = window.setTimeout(function () { }, 0);
            while (id--) {
                window.clearTimeout(id); // will do nothing if no timeout with id is present
            }

            let event = new CustomEvent("showStars");
            dispatchEvent(event);
        });
        dispatchEvent(new CustomEvent("showStars"))
    </script>

</body>

</html>

Check this post for more info on how that timeout clearing code works: javascript: Clear all timeouts?

georgedum
  • 491
  • 3
  • 10
  • I've tried to clear the timeout in the flicker function and then restarting the timeout function each time the window is resized, but the problem still persists. any help would be appreciated. – Jesus Johan Godinho Jun 08 '20 at 22:00
  • You don't need to restart your timeouts. You're starting a bunch of new ones every time you call flicker(). Just clear them all once whenever you resize. I can put together a fiddle in a little bit. – georgedum Jun 09 '20 at 00:43
  • @georedum thanks a lot mate. That worked like a charm. Thanks for the explanation and all your help. I really do appreciate it. Once again thanks a loooooooot. – Jesus Johan Godinho Jun 09 '20 at 13:10