Ask coding questions

← Back to all posts
HTML5/JavaScript performance slowdown
mwilki7 (545)

I'm working on a menu system for my JavaScript Canvas game.
Press M to open the menu
https://repl.it/@mwilki7/Canvas-Basketball

The game works but the menu system seems to slow down the longer it stays open.

I've tried debugging it with F12 performance tab and noticed it spends a lot of time waiting for the system to do something. Other than that, I'm not sure where to look. There are no memory leaks (as far as I can tell from task manager).

Does anyone have any suggestions or ideas on how I figure out what's causing the performance slow down?

menu.js

class Menu
{
    ...
    addItem(label, color)
    {
        var tempx = -1;
        var tempy = -1;
        var tempw = -1;
        var temph = -1;
        var titleheader = 40;
        if (this.itemlist.length == 0)
        {
            tempx = this.x + this.w/2 - ctx.measureText(label).width/2 + 4; 
            tempy = this.y - 20 + DEFAULT_MENUITEM_FONT_SIZE + this.fontsize + titleheader;
            tempw = this.w - ctx.measureText(label).width/2 + 12;
            temph = this.h / this.itemlist.length - 20;
        }
        else
        {
            tempx = this.x + this.w/2 - ctx.measureText(label).width/2 - 8;
            tempy = this.y + (this.itemlist.length - 1) * this.h/(this.itemlist.length + 1) - 20 + DEFAULT_MENUITEM_FONT_SIZE + this.fontsize + titleheader;
            tempw = this.w - ctx.measureText(label).width/2;
            temph = this.h / this.itemlist.length - 20;
        }

        // LIST: {x,y,w,h,item}
        this.itemlist.push({x: tempx, y: tempy, w: tempw, h: temph, item: new MenuItem(label, color)});
        this.recalculateDimensions();
    }
    checkMove(cursor)
    {
        for (var i = 0; i < this.itemlist.length; i++)
        {
            var elem = this.itemlist[i];
            var xv = elem.x - elem.w/2 + 8;
            var yv = elem.y;
            var wv = elem.w;
            var hv = elem.h;
            var obj = {x: xv, y: yv, w: wv, h: hv};
            if (checkPointCollision(obj, cursor))
            {
                this.itemlist[i].item.bSelected = true;
            }
            else
            {
                this.itemlist[i].item.bSelected = false;
            }
        }
    }
    removeItem(item)
    {
        for (var i = 0; i < itemlist.length; i++)
            if (this.itemlist[i] == item)
                this.itemlist.splice(i, 1);   
    }
    recalculateDimensions()
    {
        if (this.itemlist.length == 0)
            return;
        var titleheader = 40;
        for (var i = 0; i < this.itemlist.length; i++)
        {
            var elem = this.itemlist[i];
            var item = elem.item;
            // Each element in itemlist is: {x,y,w,h,item} 
            elem.x = this.x + this.w/2 - ctx.measureText(item.label).width/2 + 4;
            elem.y = this.y + i * this.h/(this.itemlist.length + 1) - 20 + item.fontsize + this.fontsize + titleheader;
            elem.w = this.w - ctx.measureText(item.label).width/2 - 8;
            elem.h = this.h / this.itemlist.length - 20;            
        }
    }
    draw()
    {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.w, this.h);
        ctx.font = this.fontsize + "px Arial";
        ctx.fillStyle = this.fontcolor;
        ctx.fillText(this.title, this.x + this.w/2 - ctx.measureText(this.title).width/2, this.y + this.fontsize);
        var titleheader = 40;

        for (var i = 0; i < this.itemlist.length; i++)
        {
            var elem = this.itemlist[i];
            var item = elem.item;
            // Each element in itemlist is: {x,y,w,h,item}
            item.draw(elem.x, elem.y, elem.w, elem.h, i);
        }
        
    }
    close()
    {

    }
}

menuitem.js

class MenuItem
{
    ...
    draw(x, y, w, h, id)
    {
        ctx.font = this.fontsize + "px Arial";        
        var color         = colorNameToHex(this.fillcolor);
        var oppositecolor = invertColor(color, true);
        if (id == 5 && this.bSelected)
            var d = 0;
            // DEBUG HERE FOR THAT DUMB LAST CELL FILLING PROBLEM
        if (!this.bSelected)
        {
            ctx.fillStyle   = color;
            ctx.strokeStyle = color;
            ctx.fillRect(x - w/2 + this.label.length, y, w, h);

            ctx.fillStyle = oppositecolor;
            ctx.rect(x - w/2 + this.label.length, y, w, h);
            ctx.stroke();

            ctx.fillText(this.label, x, y + this.fontsize*2);
        }
        else
        {
            ctx.fillStyle   = oppositecolor;
            ctx.strokeStyle = oppositecolor;
            ctx.fillRect(x - w/2 + this.label.length, y, w, h);

            ctx.fillStyle = color;
            ctx.rect(x - w/2 + this.label.length, y, w, h);
            ctx.stroke();

            ctx.fillText(this.label, x, y + this.fontsize*2);

            if (id == 6)
            {
                //debug breakpoint
            }
        }

    }
    ...
}
Commentshotnewtop
niorg2606 (187)

Haha nice little game :)
I don't see any kind of performance issues in the menu on my machine. What's your computer's specs? That might be the cause.

mwilki7 (545)

@niorg2606 Glad you like it :D

I've tested this on an Intel HD laptop and a Intel HD desktop.
Though with a large number of circles on the screen it doesn't seem to slow down too bad.

If you leave the menu on long enough it looks like it starts to get slower and slower. I've tried this on two different machines.

I've recently added touch support (working out some bugs though) so if you wanted to fool with this on your phone, now you can.

Also another snippet that I thought might have something to do with the slow down (if my computer is not the culprit).

canvas.addEventListener('mousemove', function (event)
    {
        mousepos = getMousePos(event);
        for(var i = 0; i < menulist.length; i++)
        {
            menulist[i].checkMove(mousepos);
        }
    });