I've done this by removing the initialisation code that checks through
all the canvas elements, and exposing the initElement method on the
G_vmlCanvasManager_ to the outside world.
I then created a very simple behaviour that applies this method to any
canvas tag when it is displayed.
Using the behaviour is a simple matter of
<style>
canvas {
behavior: url(augmentcanvas.htc);
}
</style>
This has enabled me to use
object.appendChild(document.createElement('canvas')); successfully,
although I still can't do object.innerHTML="<canvas></canvas>"; in IE.
Have you considered implementing the whole of this library as a
behavior?
Are you interested in me contributing the behaviour that I have?
kyb
This can already be done; the docs are just lacking. I filed this as a
bug and made a couple attachments:
http://sourceforge.net/tracker/index.php?func=detail&aid=1720855&group_id=163391&atid=827560
In example4.html: the function (constructor) Box has:
// new canvas element
var cv = document.getElementsByTagName('body')[0].appendChild(
document.createElement('canvas')
);
// fix new canvas in IE (note it must be append to the document first)
if (typeof G_vmlCanvasManager != 'undefined') {
// you must reassign the element to the return of this method.
cv = G_vmlCanvasManager.initElement(cv);
}
Also note: For Safari support you can't just set cv.height/width, you
must use cv.setAttribute('width', 100), etc.
--
Steve
http://mrclay.org/
> In example4.html: the function (constructor) Box has:
>
> // new canvas element
> var cv = document.getElementsByTagName('body')[0].appendChild(
> document.createElement('canvas')
> );
> // fix new canvas in IE (note it must be append to the document first)
> if (typeof G_vmlCanvasManager != 'undefined') {
> // you must reassign the element to the return of this method.
> cv = G_vmlCanvasManager.initElement(cv);
>
> }
Thanks for looking at this, however I think that my solution is nicer.
The behaviour canvas.htc file goes like this:
<PUBLIC:COMPONENT>
<PUBLIC:ATTACH EVENT="onreadystatechange" ONEVENT="Loaded()" />
<SCRIPT LANGUAGE="JScript">
function Loaded()
{
var element = event.srcElement;
var canvasMan = element.document.parentWindow.G_vmlCanvasManager;
if (canvasMan && !element.getContext) {
canvasMan.initElement(element);
}
}
</SCRIPT>
</PUBLIC:COMPONENT>
And to include it in your document, you simply need
canvas {
behavior: url(test.htc);
}
In your style sheet.
This means that you don't have to have that initElement call
everywhere that you create a canvas element - the browser does it for
you.
kyb
sorry about the dodgy cut & paste. I obviously meant
canvas {
behavior: url(canvas.htc);
}
here.
I also would prefer a solution that "fix"es new canvas elements, rather
than requiring user code to call initElement. If a behavior would do
this (and be faster than looping through getElementsByTagName('canvas'))
then that might be great. For compactness it'd be nice if all the code
could be in the .htc file. We could have the user include the behavior
in their CSS or include a tiny JS script that adds the style. What is
cleaner about an all-JS solution is that you don't have to worry about
file paths and whatever content-type .htc requires.
Before I figured out how to fix new elements with the existing script, I
submitted a patch that fixed new elements by wrapping
document.createElement, but the use of a closure would probably have led
to leaks.
http://sourceforge.net/tracker/download.php?group_id=163391&atid=827560&file_id=229404&aid=1720150
After realizing G_vmlCanvasManager was accessible I closed the bug, but
that approach might still be worth looking at.
If you can avoid the fixElement_ call, then you can call initElement
immediately on created canvas elements before adding them to the document:
...
initElement: function (el, newEl) {
if (!newEl) {
el = this.fixElement_(el);
}
...
After the anonymous script runs, we could then wrap createElement:
...
})();
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
G_vmlCanvasManager.ce_ = document.createElement;
document.createElement = function (tagName) {
var el = G_vmlCanvasManager.ce_(tagName);
if ('CANVAS' != tagName.toUpperCase()) {
return el;
}
// initialize (but dont "fix" element)
G_vmlCanvasManager.initElement(el, true);
return el;
};
}
} // if
Thoughts? Would wrapping createElement be a huge mistake? Can behaviors
be in-lined so that the .htc file isn't necessary?
--
Steve Clay
http://mrclay.org/
Pretty sneaky. I've had trouble before in IE wrapping other
builtins. Have you tried it in this case? Does it work? I thought
that the element had to be in the DOM already for the code to work.
Obviously, you'd be introducing a performance hit on every call of
createElement, but for most pages that wouldn't be a massive problem.
I believe that it may be possible to do the whole thing as a
behaviour, but I'm not really an expert, I might look at it some more
another time. A friend has pointed out that there are performance
implications with using behaviours, so they might not be as suitable
as I'd thought.
kyb