> The ExplorerCanvas lib has been hugely improved, and I don't think
> there can be lots of performance improvements now. The silverlight
> version is slow too, and it is not really maintained, as we lose lots
> of the advantages of a built-in functionality (VML) like events, etc.
Oh? I was told the Silverlight version was going to be merged with
the VML version, implying to me that it is (or will soon be) exactly
as well-maintained as the VML version, since they will be the same
thing.
> I can only suggest you to close the paths with closePath when you have
> opened one, it speeds up a little bit the process.
> Keep in mind that the implementation of Canvas using VML is and always
> will be slower when adding paths to the drawing.
Yes, I would assume this is correct.
> Sadly, Canvas may
> never be implemented in IE,
What makes you say that? Has Microsoft stated this?
> the only fast solution would be Flash, but
> this may not be a good solution.
Yeah, Flash is nothing like Canvas. I'm certainly not touching it.
Not sure if this is the same issue, but if you look at this demo
(which now works in IE8 thanks to a patch by TommyM):
http://www.browserpilot.com/canvascompass.php
... it gradually slows down as well. The reason is that excanvas
creates a new layer every time you draw a new element or make a
rotation. Over time, this create a lot of overhead. To solve it, I
had to create my own "hack" of a library, using excanvas as a base,
that calls progid:DXImageTransform.Microsoft.Matrix() directly.
Maybe not the best method, but it solved my problem.
>> It's curious to me that the VML version starts off at a great
>> speed then slows down
>> dramatically the longer you use it. Do you have any idea why that
>> would happen
>
> Not sure if this is the same issue, but if you look at this demo
> (which now works in IE8 thanks to a patch by TommyM):
>
> http://www.browserpilot.com/canvascompass.php
>
> ... it gradually slows down as well. The reason is that excanvas
> creates a new layer every time you draw a new element or make a
> rotation. Over time, this create a lot of overhead.
Right. VML is vector drawing, so each vector you draw needs to be
tracked separately. The more vectors you draw, the more vectors it
needs to keep track of and the slower it gets. In contrast, every
browser with a real canvas implementation treats it as a bitmapped
image. You can manipulate the pixels in the bitmap in any way you
like, but in the end, it's just a grid of pixels, and nothing you do
to it will cause there to be more pixels to deal with, so it's always
the same speed.
> To solve it, I
> had to create my own "hack" of a library, using excanvas as a base,
> that calls progid:DXImageTransform.Microsoft.Matrix() directly.
>
> Maybe not the best method, but it solved my problem.
Could you discuss this more? Why is this a hack? What are the
implications of using this method? Why is it "not the best method"?
In what ways would this be better, or worse, than what excanvas does
today? I am not familiar with Microsoft's proprietary drawing
commands so any information you can provide would be helpful.
It's not beautiful, and it's not finished.
> What are the implications of using this method? Why is it "not the best method"?
> In what ways would this be better, or worse, than what excanvas does today?
I don't support all of canvas; I just needed a way to do unlimited
rotations without getting bogged down by thousands of VML layers.
Here is what I have. You can take out the parts regarding pitch in
the rotate function and make it even smaller:
if (!document.createElement('canvas').getContext) {
(function() {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var abs = m.abs;
var sqrt = m.sqrt;
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
var slice = Array.prototype.slice;
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
var G_vmlCanvasManager_ = {
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));
}
},
init_: function(doc) {
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
}
return el;
}
};
G_vmlCanvasManager_.init();
function CanvasRenderingContext2D_(surfaceElement) {
// Canvas context properties
this.canvas = surfaceElement;
this.element_ = surfaceElement.firstChild;
//this.element_.style.filter="progid:DXImageTransform.Microsoft.Matrix(FilterType='nearest
neighbor',SizingMethod='auto expand',M11='1.0')";
this.width = this.canvas.clientWidth;
this.height = this.canvas.clientHeight;
}
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.fillRect=function(aX,aY,aWidth,aHeight){return;};
contextPrototype.save=function(){return;};
contextPrototype.restore=function(){return;};
contextPrototype.translate=function(aX,aY){return;};
contextPrototype.drawImage=function(img,x,y){return;};
contextPrototype.rotate = function(aRot,pitch) {
var c = mc(aRot);
var s = ms(aRot);
this.element_.style.filter =
"progid:DXImageTransform.Microsoft.Matrix(FilterType='nearest
neighbor',SizingMethod='auto expand',M11=" + c + ", M12=" + (-s) + ",
M21=" + s + ", M22=" + c + ")";
//this.element_.filters.item(0).M11 = c;
//this.element_.filters.item(0).M12 = (-s);
//this.element_.filters.item(0).M21 = s;
//this.element_.filters.item(0).M22 = c;
this.element_.style.left=((this.width-this.element_.offsetWidth)/2)+'px';
if (aRot < 3.14 || aRot > 4.71) {
this.element_.style.top=(((this.height-this.element_.offsetHeight)/2)+pitch)+'px';
} else {
this.element_.style.top=(((this.height-this.element_.offsetHeight)/2)-pitch)+'px';
}
};
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
})();
}
Right, you wouldn't. You'd use this instead of excanvas.
I posted the code in response to Ryan's request for more info; it may
not be appropriate for what you need. The main point is, though, that
excanvas creates a new VML element every time you move or rotate your
image, so you will have to come up with a way to circumvent that so
that your app doesn't become progressively slower.
Kind regards,
- Jay