Asynchronous loading problems

I'm working on a Pixel Grid Canvas to draw stuff to in Javascript. I got everything running as it should, but only on Firefox, and it only works after refreshing the page.

My question is: Why does this only give the proper output after a refresh and what can I do to make it have the proper output on the first try.

function PixelGridCanvas(){
	this.init = function(canvas, ps, gs, pc, gc){
		this.ctx = canvas.getContext("2d");
		this.pixelSize = ps;
		this.gridSize = gs;
		
		this.gridWidth = canvas.width/ps;
		this.gridHeight =  canvas.height/ps;
		
		if(this.gridWidth <= 1) this.gridWidth = 1;
		if(this.gridHeight <= 1) this.gridHeight = 1;
		
		this.pixelColor = pc;
		this.gridColor = gc;
	};
	
	this.clearCanvas = function(){
			
			this.ctx.fillStyle = this.pixelColor;
			this.ctx.fillRect(0,0, (this.gridWidth * this.pixelSize) - this.pixelSize, (this.gridHeight * this.pixelSize) - this.pixelSize);
			
			this.ctx.fillStyle = this.gridColor;
			var drawLine = false;
			
			for(var i = 0; i < this.gridWidth * 2; i++){
				if(drawLine) this.ctx.fillRect(i * this.pixelSize,0, this.pixelSize, ((this.gridHeight * this.pixelSize) * 2) + this.pixelSize);
				drawLine = !drawLine;
			}
			
			var drawLine = false;
			for(var i = 0; i < this.gridHeight * 2; i++){
				if(drawLine) this.ctx.fillRect(0,i * this.pixelSize, ((this.gridWidth * this.pixelSize) * 2) - this.pixelSize, this.pixelSize);
				drawLine = !drawLine;
			}
	};
	
	this.drawImageAt = function(src, destx, desty){
		console.log("drawImage");
		var img = new Image();
		img.src = src;
		var icanvas = document.createElement('canvas');
		icanvas.width = img.width;
		icanvas.height = img.height;
		var ictx = icanvas.getContext('2d');
		ictx.drawImage(img, 0, 0, img.width, img.height);
		
		for(var x = 0; x < icanvas.width; x++){
			for(var y = 0; y < icanvas.height; y++){
				
				//console.log("pixel");
				
				var pixel = ictx.getImageData(x, y, 1, 1);
				var data = pixel.data;
				var rgba = 'rgba(' + data[0] + ',' + data[1] +
							 ',' + data[2] + ',' + data[3] + ')';
							 
				this.ctx.fillStyle = rgba;
				this.ctx.fillRect((destx * this.pixelSize) + (x * this.pixelSize) + (x * this.pixelSize), (desty * this.pixelSize) + (y * this.pixelSize) + (y * this.pixelSize), this.pixelSize, this.pixelSize);
				
			}
		}
	};
	
	this.drawImage = function(src){
		this.drawImageAt(src,0,0);
	};
}
<html>
	<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> 
	<script src="js/pgc/main.js"></script>
	
	<script>
	$( document ).ready(function() {
		var c = document.getElementById("myCanvas");
		var pgc = new PixelGridCanvas();
		pgc.init(c, 2, 2, "#eeeeee", "#ffffff");
		
		pgc.clearCanvas();
		pgc.drawImage("imgs/test1.png");
		
		pgc.drawImageAt("imgs/test1.png", 50,50);
	});
	</script>
		
	</head>
	<body>
		<canvas id="myCanvas" width="320" height="320"></canvas>
		
		
	</body>
</html>

Here's a link to it running on my personal site: http://pgc.00ffff3.com/

edit:

enclosed the draw function in a onload for the image, but it still does the same thing. Am I understanding this wrong?

this.drawImageAt = function(src, destx, desty){
		console.log("drawImage");
		var img = new Image();
		
		img.onload = function () {
			var icanvas = document.createElement('canvas');
			icanvas.width = img.width;
			icanvas.height = img.height;
			var ictx = icanvas.getContext('2d');
			ictx.drawImage(img, 0, 0, img.width, img.height);
			
			for(var x = 0; x < icanvas.width; x++){
				for(var y = 0; y < icanvas.height; y++){
					
					//console.log("pixel");
					
					var pixel = ictx.getImageData(x, y, 1, 1);
					var data = pixel.data;
					var rgba = 'rgba(' + data[0] + ',' + data[1] +
								 ',' + data[2] + ',' + data[3] + ')';
								 
					this.ctx.fillStyle = rgba;
					this.ctx.fillRect((destx * this.pixelSize) + (x * this.pixelSize) + (x * this.pixelSize), (desty * this.pixelSize) + (y * this.pixelSize) + (y * this.pixelSize), this.pixelSize, this.pixelSize);
					
				}
			}
		}
		
		img.src = src;
	};

Answers 1

  • The primary reason is because you image load is asynchronous so for your code to work your images must be loaded before you try to paint it. You can preload the images in JS and then on success of all the image loads fire the drawImageAt method.


Related Articles