Lazy loading excanvas.js
My code fix has been updated for Explorer Canvas v3. Since Explorer Canvas v3 addresses issues with Internet Explorer 8, I recommend upgrading ASAP.
excanvas.js is a script that enables developers to use the canvas element in Internet Explorer; since IE doesn’t support canvas or the canvas API, the excanvas script converts (most) canvas commands to Vector Markup Language (VML), the only vector rendering language supported natively in Internet Explorer.
excanvas is designed specifically for Internet Explorer, so most people simply use a conditional comment to load it in IE and avoid loading it in other browsers:
<!--[if IE]> <script type="text/javascript" src="/scripts/excanvas.js" src="/scripts/excanvas.js"> <![endif]-->
This works fine if you have access to the HTML file that needs to load excanvas, but what if you can’t edit the HTML? This was my predicament with a recent project; I decided to use a lazy loader approach (on-demand loading) and load excanvas.js dynamically.
I started by developing an HTML example page that used the canvas element and had the excanvas.js file hard-coded. Everything worked as planned. I then took out the hard-coded excanvas.js file and replaced it with a JavaScript-based lazy loader. Guess what? It didn’t work.
I scratched my head for a while and did some more testing. The strange thing was that excanvas.js was loading when and where it was supposed to, but the script itself wasn’t firing.
After digging around the excanvas.js source code a bit, I found the problem: the script contains an init function that only gets invoked when the document’s readystate changes. If the document is already loaded, the readystate won’t change and the init function will never fire!
A simple modification to the excanvas.js file fixed the problem:
Original code (starting at line 87 of excanvas.js)
init: function(opt_doc) { if (/MSIE/.test(navigator.userAgent) && !window.opera) { var doc = opt_doc || document; // Create a dummy element so that IE will allow canvas elements to be // recognized. doc.createElement('canvas'); doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); } },
Modified version
init: function(opt_doc) { if (/MSIE/.test(navigator.userAgent) && !window.opera) { var doc = opt_doc || document; // Create a dummy element so that IE will allow canvas elements to be // recognized. doc.createElement('canvas'); if(doc.readyState !== "complete"){ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); } else { this.init_(doc); } } },
Basically all we’re doing is checking to see if the readystate is already “completed” before attempting to do attachEvent. If the state is completed, we don’t need attachEvent and can just invoke this.init_ directly.
What others are saying... (2 comments so far) You can follow all responses to this entry through this post's comments feed (RSS).
I have the same problem. So I load dinamically the excanvas.js, then create a canvas element, init that element with G_vmlCanvasManager.initElement(element) and draw on it, and it works.
But there’s a problem. If the document already contains a canvas element and you’re trying to load excanvas when the document is fully loaded, you’re getting a Unknown error in js. So your method works if there’s no canvas element in the initial page…
Good catch, thanks for letting me know
Want a gravatar? They're easy and free! Just sign up at gravatar.com
Add your two cents!