2

I've just started learning javascript. My problem is, that the website is slowing down after a few seconds. I'm using setinterval to "tick" the things on the screen and i feel like this might be the cause of the problem.

Here is my code:

var r = [];
var ctx;

function init() {
    ctx = document.getElementById("canvas").getContext("2d");
    for(var i = 0; i < 20; i++) {
        var x = Math.floor(Math.random() * (ctx.canvas.width - 20)) + 10;
        var y = Math.floor(Math.random() * (ctx.canvas.height - 20)) + 10;
        r.push(new Rect(x,y, 10, 10, ctx));
    }
window.setInterval(tick,10);
window.setInterval(draw,10);
} 

function tick() {
    for(var i = 0; i < r.length; i++) {
        r[i].tick();
    }
} 

function draw() {
    ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
    for(var i = 0; i < r.length; i++) {
        r[i].draw();
        }
        ctx.lineWidth = 5;
        ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
        ctx.stroke();
} 

Here's another class:

class Rect {
    constructor(x, y, width, height, ctx) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.cxt = ctx;
        this.xVel = 2.5;
        this.yVel = 2.5;

        if (Math.random() < 0.5) {
            this.xVel = -this.xVel;
        }

        if (Math.random() < 0.5) {
            this.yVel = -this.yVel;
        }
    } 

    tick(){
        this.x += this.xVel;
        this.y += this.yVel;
        if (this.x + this.width >= ctx.canvas.width | this.x <= 0){
            this.xVel = -this.xVel;
        }
        if (this.y + this.height >= ctx.canvas.height | this.y <= 0){
        this.yVel = -this.yVel;
        }
    }

    draw() {
        ctx.fillRect(this.x,this.y,this.width,this.height);
    } 
} 

So what exactly is the cause of this issue and how can i fix it?

You can download the files here: https://drive.google.com/file/d/1pg4ASPvjbo2ua_7cCvQvzucLgbegtiw6/view?usp=sharing

amsjntz
  • 98
  • 11
  • 2
    Please add a [mcve] - click the `<>` and create a snippet that runs – mplungjan Apr 01 '18 at 07:22
  • No need to call `setInterval` twice, rather do this : `setInterval(function(){tick();draw();},10);`. –  Apr 01 '18 at 07:28
  • Nobody is going to download any files, as they could be infected with a virus. A working code snippet reproducing the issue should be within the question, so it always will be available, which is often not the case with external resources. – Asons Apr 01 '18 at 07:53

2 Answers2

5

This issue is in your draw function.

Canvas-es remember all the lines drawn, over time it slows down your animation.

The solution is to reset the lines drawn list by calling ctx.beginPath()

function draw() {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    for (var i = 0; i < r.length; i++) {
        r[i].draw();
    }
    ctx.beginPath()
    ctx.lineWidth = 5;
    ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
    ctx.stroke();
}
Eponyme Web
  • 966
  • 5
  • 10
1

First of all the screen only refreshes at a rate of 16 milliseconds (assuming 60 frames per second). So calling the two function at 10 milliseconds is a bit overkill. But in the modern browser, we now have a native support to do anything when the screen refreshes. Its called request animation frame: requestAnimationFrame(animationrDrawCallback).

You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame. Now back to your code, it can be refactored like this:

const r = [];
const ctx;

function init() {
    ctx = document.getElementById("canvas").getContext("2d");

    for(let i = 0; i < 20; i++) {
        const x = Math.floor(Math.random() * (ctx.canvas.width - 20)) + 10;
        const y = Math.floor(Math.random() * (ctx.canvas.height - 20)) + 10;

        r.push(new Rect(x,y, 10, 10, ctx));
    }

    // start our animation
    window.requestAnimationFrame(render);
} 

function render() {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    r.forEach((item) => {
        item.trick();
        item.draw();
    })

    ctx.beginPath();
    ctx.lineWidth = 5;
    ctx.rect(0,0,ctx.canvas.width,ctx.canvas.height);
    ctx.stroke();

    // this will be called at next screen refresh
    window.requestAnimationFrame(render);
}

The BIGGEST BONUS of using requestAnimationFrame is that it will stop executing when the tab is no longer in focus. Big boost for smartphones. Hope this helps.

Vijay Dev
  • 1,024
  • 7
  • 14