# My HTML Canvas went blank

I tried to draw Mario Sprites in my HTML Canvas, but it always went blank. Anybody knows why?

var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
var mario;
var marioSprite;
var tiles;
var speedX = 1;

//marioSprite Specification
mario = {
//target picture specification X & Y, Width & Height
px:276,
py: 44,
pwidth: 16,
pheight: 16,
//drawing on Canvas specification X & Y, Width & Height
cx: 16,
cy: 116,
cwidth:16,
cheight:16,
}

//draw Mario in Canvas
function drawMarioSprite(){
marioSprite = new Image();
marioSprite.src = 'file:///C:/Users/MASTONO ALI/Desktop/img/characters.gif';
ctx.drawImage(marioSprite,
mario.px, mario.py, mario.pwidth, mario.pheight,
mario.cx, mario.cy, mario.cwidth, mario.cheight);
});
this.position = function() {
this.mario.cx += speedX;
}
position();
}//drawMarioSprite() end

//drawTiles and tilesLoop
function drawTiles() {
tiles = new Image();
tiles.src = 'file:///C:/Users/MASTONO ALI/Desktop/img/tiles.png';
tilesLoop();
});
}
function tilesLoop(){
for (let x = 0; x < 25; x++){
for (let y = 11; y < 13; y++){
ctx.drawImage(tiles,
0, 0, 26, 26,
x*12, y*12, 20, 20);
}
}
}//drawTiles() end

function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMarioSprite();
drawTiles();
window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);



You probably don't want to call the drawing code inside the 'load' event handler, since for that to happen more than once, you would need to load the image multiple times which you also don't want to do. See the docs

You should load the images once at startup and then draw them from the pre-loaded data.

In this case, since you do the drawing code repeatedly with requestAnimationFrame, once the image actually loads it will be drawn correctly, if you just remove the load eventlisteners and just directly call the drawing code.

That is, change

    marioSprite.addEventListener('load', e => {
ctx.drawImage(marioSprite,
mario.px, mario.py, mario.pwidth, mario.pheight,
mario.cx, mario.cy, mario.cwidth, mario.cheight);
});


to

    ctx.drawImage(marioSprite,
mario.px, mario.py, mario.pwidth, mario.pheight,
mario.cx, mario.cy, mario.cwidth, mario.cheight);


and

    tiles.addEventListener('load', e => {
tilesLoop();
});


to

    tilesLoop();

• One of the most annoying parts when doing game development in HTML+JavaScript is that you can never rely on any asset being actually loaded. Which is why I usually create a Sprite class which is both responsible for loading and drawing an image, and when the image didn't load yet, the draw function just does nothing. Another option is to use a preloader which loads all the assets and to not start rendering until the onload-callbacks of all assets were called. – Philipp Jul 31 '20 at 14:12