Clear entire, transformed HTML5 Canvas while preserving context transform
I want to zoom and pan an HTML5 Canvas by transforming the context using translate()
and开发者_StackOverflow社区 scale()
, clearing the canvas, and then redrawing. Note that I am explicitly not calling save()
and restore()
around my transformations.
If I perform the standard ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
then the entire visible canvas will not be cleared; downscaling or panning may cause this initial rectangle to not exactly cover the drawing area.
If I perform the Webkit-friendly clearing method...
var w=canvas.width;
canvas.width = 0;
canvas.width = w;
...then the cumulative transformation of the context is reset.
How can I best clear the entire canvas context without losing my transformation?
Keeping track of all the transformation information like you are presumably doing is what several others so far have done (like cake.js and my own library, for two). I think doing this will pretty much be an inevitability for any large canvas library.
Ilmari of cake.js even complained to mozilla: https://bugzilla.mozilla.org/show_bug.cgi?id=408804
You could instead call save/restore around your clear method:
// I have lots of transforms right now
ctx.save();
ctx.setTransform(1,0,0,1,0,0);
// Will always clear the right space
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.restore();
// Still have my old transforms
Won't that satisfy your case?
For those who care to track their full context transforms, here's my code for doing so in an on-demand, per-context basis. This is prefaced with the usage that shows how to clear the full rectangle based on the transformed coordinates. You can see the code in use on my website.
window.onload = function(){
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
trackTransforms(ctx);
function redraw(){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);
// ...
}
}
// Adds ctx.getTransform(), returning an SVGMatrix
// Adds ctx.transformedPoint(x,y), returning an SVGPoint
function trackTransforms(ctx){
var svg = document.createElementNS("http://www.w3.org/2000/svg",'svg');
var xform = svg.createSVGMatrix();
ctx.getTransform = function(){ return xform; };
var savedTransforms = [];
var save = ctx.save;
ctx.save = function(){
savedTransforms.push(xform.translate(0,0));
return save.call(ctx);
};
var restore = ctx.restore;
ctx.restore = function(){
xform = savedTransforms.pop();
return restore.call(ctx);
};
var scale = ctx.scale;
ctx.scale = function(sx,sy){
xform = xform.scaleNonUniform(sx,sy);
return scale.call(ctx,sx,sy);
};
var rotate = ctx.rotate;
ctx.rotate = function(radians){
xform = xform.rotate(radians*180/Math.PI);
return rotate.call(ctx,radians);
};
var translate = ctx.translate;
ctx.translate = function(dx,dy){
xform = xform.translate(dx,dy);
return translate.call(ctx,dx,dy);
};
var transform = ctx.transform;
ctx.transform = function(a,b,c,d,e,f){
var m2 = svg.createSVGMatrix();
m2.a=a; m2.b=b; m2.c=c; m2.d=d; m2.e=e; m2.f=f;
xform = xform.multiply(m2);
return transform.call(ctx,a,b,c,d,e,f);
};
var setTransform = ctx.setTransform;
ctx.setTransform = function(a,b,c,d,e,f){
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx,a,b,c,d,e,f);
};
var pt = svg.createSVGPoint();
ctx.transformedPoint = function(x,y){
pt.x=x; pt.y=y;
return pt.matrixTransform(xform.inverse());
}
}
精彩评论