Archive for April, 2009

Developing with a Brand New Canvas

Posted in Code, Theory on April 8th, 2009 by Peter Wooley – Be the first to comment

“I can’t generate 1000 images—it’s not practical, I can’t use a server-side script—there’s the sandbox and it’s lame, but there has to be some way to just use JavaScript to generate pixel data,” I thought.

Since releasing Gmail FavIcon Alerts version 2.5, I’ve spent a ton of time trying to figure out how to make it better. Thankfully, users were more than happy to help. After talking with some friends, I realized that the key feature missing from all of the favicon message count scripts was dynamic unread message count—being able to know exactly how many messages you had by looking at your favicon. But, how could this be done? Embedding the images as base64 is how most of the scripts work, but base64 is lengthy, and storing 1000 iterations to give exact unread message counts up to 999 would be ridiculous in both size and scope.

Thankfully, while teaching the WDIM355 Client-Side Scripting class at the Art Institute of Portland, the students showed quite an interest in the Canvas tag. After playing with it for a bit, they detailed how they were using it. The methods currently available consist of things like fillRect(), strokeRect(), and drawImage(). It felt like Flash, but lower-level, geekier even.

It suddenly made sense: draw the unread count over the icon using the canvas tag! Starting on a Friday evening, I began. First, I drew a red square in the middle of  a 16×16 pixel Canvas, and it worked! I started drawing shapes, patterns and anything I could to test the speed and capabilities. I couldn’t have been happier. Then I hit a snag: images.

Working with images is never the best experience, but drawing them with the Canvas tag, it turns out, is just plain awful. Because speed is important, the script really needed to keep the images embedded. Base64 is great for that, but I discovered a little issue with the drawImage() function of the canvas: you have to supply it with a standard Image object or HTMLImageElement. This didn’t seem like a problem, until I started setting the Image.src to a Data URI. For some reason, I couldn’t get the images to load and I kept getting the NS_ERROR_DOM_SECURITY_ERR error. After quite a bit of searching, I discovered that, for security reasons, Image objects can’t have their src attribute set to a Data URI!

After nearly giving up, I took a break with my wife, and at some point during the break, I came up with a crazy idea: use fillRect() and a 16×16 array to draw the image, pixel-by-pixel. Crazy, you say? Loco, indeed. I spent the next hour writing the loop and adding each individual hex value into an array. I argued that writing a script to do it would have taken longer—I was wrong. After a bit of number confusion on my part, I got it working and it was beautiful. Literally, pixel-for-pixel, it matched. I had to take a minute to enjoy the hack that sat before me.

Dynamically-generated unread faviconThe last step was to add the numbers, which turned out to be the easiest part. I created a pixel map of Tyler’s pixel numbers, did some math and drew the background. Even though it took a bit more tweaking, I basically came out with the finished product!

It took plenty of hours, involved several people I’m grateful to, and was some of the most fun I’ve had hacking since I first picked up the script! And now, the script has now been featured on Lifehacker twice, for 2.5 and now 3.0! And it just past 8,000 installs!