Today I wanted to write the second part of my Framework Design mini series - but then I found out something interesting about HTML5 canvas. I will write the framework design post later this week.

Soooo…. I was again experimenting with the HTML5 canvas. When I was writing scribblingspree.com, I found out that the canvas uses it’s own width and height properties when calculating coordinates, no matter how big it really is. This means, the following canvas will work as if it was 100x100 pixels large, even though it really is larger, depending on the screen size:

<head>
	<style>
	.drawing_canvas {
		width: 100%;
		height: 100%;
	
		cursor: crosshair;
	}
	</style>
</head>
<body>
	<canvas class="drawing_canvas" width="100" height="100">
	</canvas>
</body>

So, in the above canvas, a line from [0, 0] to [100, 100] will be drawn across the entire window, not just from the top left corner to the point [100px, 100px]. This behavior was pretty consistent across browsers - at least on the desktop, but also on Android - so I calculated a factor based on canvas.width and canvas.scrollWidth and used that to calculate the correct coordinates.

Also, when processing mouse events, the event object has properties offsetX and offsetY. These properties represent the mouse position relative to the element on which the event occured. So, these properties can be used directly for calculating the coordinates within the canvas as described above.

This did not work on the iPad. Not at all.

It seems like the browser on the iPad uses the actual size of the canvas to calculate coordinates. Setting the width and height of the canvas to be equal to the scroll width and scroll height did it for me, but it only works as long as the window is not resized. On resize this has to be done again.

Also, the touch event on the iOS browser does not contain the properties offsetX and offsetY. This means that I have to work with the page coordinates of the touch event. But there is one little inconvenience with using the page coordinates: One has to know the top and left offset of the canvas, which is not immediately available in JavaScript. With this neat trick I came up with the following solution that works on the iPad and on the desktop:

DrawingCanvas = function(canvasId) {
	var canvas = document.getElementById(canvasId);
	this.canvas = canvas;

	this.canvas.width = this.canvas.scrollWidth;
	this.canvas.height = this.canvas.scrollHeight;

	var that = this;
	this.canvas.addEventListener('touchstart', 
		function(e) {
			e.preventDefault(); 
			that.canvasTouchDragStart(e);});
	/* ... */
}

DrawingCanvas.prototype = {
	canvasTouchDragStart : function(e) {
		var x = e.touches[0].offsetX;
		var y = e.touches[0].offsetY;
		
		if(x === undefined) {
			var totalOffsetX = 0;
			var totalOffsetY = 0;
			var curElement = this.canvas;
			
			do{
				totalOffsetX += curElement.offsetLeft;
				totalOffsetY += curElement.offsetTop;
			} while(curElement = currentElement.offsetParent)
			x = event.pageX - totalOffsetX;
			y = event.pageY - totalOffsetY;
		}
		this.canvasDragStart(e, x, y);
	},
	/* ... */
}

You might also be interested in...