A bit of background: we are trying to port a game written in Adobe Flash to HTML5 using Processing.js.
Flash
An SWF (Flash) file is placed inside a page using HTML <object>/<embed> tags. The size of the SWF as displayed on the user’s computer is dicated by the width/height attribute of the <embed> tag and if that’s a percentage – the size of the parent container.
Because Flash is all vectors (let’s say for simplicity’s sake) – it can be displayed very nicely at any size, and if you specified 100% for width/height then the size of the SWF on the page will be automatically changed when the browser window is resized.
Here’s a demo. I took the flash file from here, it was so hard to find a simple demo!
That’s really nice, and makes thinking about differently-sized screens for your application unnecessary – Flash handles it all for you automatically.
Canvas/Processing.js – scaling at all
Not so with Canvas/Processing.js. You specify a desired fixed size and that’s that. No 100%, no auto stretch, nothing. That’s called a problem in search of a solution!
I tried lots of things, but the first thing I got to work was using CSS for the sizing. You can set a width/height CSS property on your canvas and then the CSS renderer will do the scaling, positioning, and the reflow. Unfortunately though this is the simplest form of resize and it looks aweful even if you’re only scaling up a little.
So even though you can do this resize dynamically – it’s pretty useless other than as a reflow reference.
Then I looked some more at the Canvas scale() function, and its equivalent in Processing.js. This one does a rescale of everything, but transparently to the code. So evn if you were drawing a line from 0 to 200 – that instruction would be changed behind the scenes with a scale of 4.0 to 0 to 800, resulting in a properly drawn line:
Much nicer! All the lines in the sketch are drawn using line() and ellipse(), the image on the top is a JPG and the one at the bottom is an SVG. The one thing that makes this tricky is that you need to change the size of the canvas as a separate step from the scale() call and the order of the two calls matters.
Here is a live demo for you to see it yourself.
Canvas/Processing.js – auto scaling & reflow nightmare
I thought – “great, I’m almost done!” but I thought that too soon. The problem is – even though I can do nice resizes, it will not happen automatically. So I’m still a way off from the Flash sample I started this post with.
Reflow is no laughing matter, I’d say half of the Firefox rendering engine deals just with reflow, with recursion dozens of levels deep. And that’s written in C++ in the framework with access to everything. Becuse Canvas was designed with a fixed size in mind – it seems I have no choice but to do the same stuff in Javascript.
I tried for a few hours and got it to almost work, but in the end gave up. Even a hacky implementation with my sizing the canvas to the parent element’s size didn’t work very well at all. I won’t go into details, it’s complicated stuff.
So I’ve gone for a compromise. Instead of resizing to any parent element – I assume the Canvas’s parent is the body (with no padding/margin), listen to onresize events for the entire window, and scale the canvas to the size of the window. Not universally useful, but still way better than nothing.
Here’s a demo (resize the popup window to see it).
Next steps?
Probably not for me, not in the near future. It would be great if this problem was solved universally – not only for all use cases but for all browsers. I have other things to do though, so I don’t think it’s going to be me looking into this further.