javascript 清除整个转换后的 HTML5 Canvas,同时保留上下文转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5526486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 17:29:56  来源:igfitidea点击:

Clear entire, transformed HTML5 Canvas while preserving context transform

javascripthtmlcanvas

提问by Phrogz

I want to zoom and pan an HTML5 Canvas by transforming the context using translate()and scale(), clearing the canvas, and then redrawing. Note that I am explicitly notcalling save()and restore()around my transformations.

我想通过使用translate()和转换上下文scale(),清除画布,然后重绘来缩放和平移 HTML5 画布。请注意,我明确没有调用save()restore()绕过我的转换。

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.

如果我执行标准,ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)那么整个可见画布将不会被清除;缩小或平移可能会导致此初始矩形不完全覆盖绘图区域。

If I perform the Webkit-friendly clearing method...

如果我执行 Webkit 友好的清除方法......

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?

如何在不丢失转换的情况下最好地清除整个画布上下文?

回答by Simon Sarris

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.

像您可能正在做的那样跟踪所有转换信息,这是迄今为止其他几个人所做的(例如 cake.js 和我自己的库,两个)。我认为这样做对于任何大型画布库来说都是不可避免的。

Ilmari of cake.js even complained to mozilla: https://bugzilla.mozilla.org/show_bug.cgi?id=408804

cake.js 的 Ilmari 甚至向 mozilla 抱怨:https://bugzilla.mozilla.org/show_bug.cgi?id=408804

You could instead call save/restore around your clear method:

您可以改为在 clear 方法周围调用 save/restore:

// 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?

这不能满足你的情况吗?

回答by Phrogz

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 useon 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());
  }
}