HTML5 Canvas获得变换矩阵?

tne*_*niv 27 javascript html5 canvas

有没有办法获得画布的当前变换矩阵?有一个context.setTransform()函数,但据我所知,似乎没有getTransform()等价.

更具体地说,我想获得矩阵的当前比例和平移元素.谷歌一直对此毫无帮助.

Sim*_*ris 30

不,根本就没有.:(

大多数canavs库(例如cake.js)已经实现了自己的矩阵类来跟踪当前的转换矩阵.

cake.js的创建者认为没有办法获得当前的矩阵是荒谬的,足以保证有关它错误报告.不幸的是,这是在2007年,并且没有努力在规范中包含getCurrentTransform.

编辑:我创建了一个简单的Transformation类,它允许您轻松地自己创建getCanvas()或跟踪Canvas的矩阵并排.这里是.我希望有所帮助!

编辑2012年6月:新规范确实包含了获取当前转换矩阵的方法!context.currentTransform可用于获取或设置当前变换矩阵.遗憾的是,虽然Firefox确实mozCurrentTransform在其上下文中具有特定于供应商的属性,但尚未实现它.所以你还不能使用它,但很快就会出现在规范中!

  • 看起来currentTransform可以在Chrome中运行 (2认同)

ell*_*ben 12

EDIT(2016年6月27日):WHATWG规范现在有一个函数getTransform()而不是currentTransform它,它在语义上看起来很清晰,它getTransform()创建了一个转换矩阵的副本.看起来主流浏览器仍然缺少它.

编辑,再次:

这是一个粗略的实现:

//in theory, SVGMatrix will be used by the Canvas API in the future;
//in practice, we can borrow an SVG matrix today!
var createMatrix = function() {
  var svgNamespace = "http://www.w3.org/2000/svg";
  return document.createElementNS(svgNamespace, "g").getCTM();
}

//`enhanceContext` takes a 2d canvas context and wraps its matrix-changing
//functions so that `context._matrix` should always correspond to its
//current transformation matrix.
//Call `enhanceContext` on a freshly-fetched 2d canvas context for best
//results.
var enhanceContext = function(context) {
  var m = createMatrix();
  context._matrix = m;

  //the stack of saved matrices
  context._savedMatrices = [m];

  var super_ = context.__proto__;
  context.__proto__ = ({

    //helper for manually forcing the canvas transformation matrix to
    //match the stored matrix.
    _setMatrix: function() {
      var m = this._matrix;
      super_.setTransform.call(this, m.a, m.b, m.c, m.d, m.e, m.f);
    },

    save: function() {
      this._savedMatrices.push(this._matrix);
      super_.save.call(this);
    },

    //if the stack of matrices we're managing doesn't have a saved matrix,
    //we won't even call the context's original `restore` method.
    restore: function() {
      if(this._savedMatrices.length == 0)
        return;
      super_.restore.call(this);
      this._matrix = this._savedMatrices.pop();
      this._setMatrix();
    },

    scale: function(x, y) {
      this._matrix = this._matrix.scaleNonUniform(x, y);
      super_.scale.call(this, x, y);
    },

    rotate: function(theta) {
      //canvas `rotate` uses radians, SVGMatrix uses degrees.
      this._matrix = this._matrix.rotate(theta * 180 / Math.PI);
      super_.rotate.call(this, theta);
    },

    translate: function(x, y) {
      this._matrix = this._matrix.translate(x, y);
      super_.translate.call(this, x, y);
    },

    transform: function(a, b, c, d, e, f) {
      var rhs = createMatrix();
      //2x2 scale-skew matrix
      rhs.a = a; rhs.b = b;
      rhs.c = c; rhs.d = d;

      //translation vector
      rhs.e = e; rhs.f = f;
      this._matrix = this._matrix.multiply(rhs);
      super_.transform.call(this, a, b, c, d, e, f);
    },

    //warning: `resetTransform` is not implemented in at least some browsers
    //and this is _not_ a shim.
    resetTransform: function() {
      this._matrix = createMatrix();
      super_.resetTransform.call(this);
    },

    __proto__: super_
  });

  return context;  
};
Run Code Online (Sandbox Code Playgroud)

编辑:该属性currentTransform 已添加到规范 ; 据报道,Firefox和Opera支持它.我检查了Firefox并发现它以供应商为前缀mozCurrentTransform.据推测,它可用于获取和设置变换矩阵.

老笨蛋,仍然是最好的:

如果您想获得当前的转换矩阵,您必须自己跟踪它.这样做的一种方法是使用Javascript的原型继承来添加getMatrix()方法并扩充修改矩阵的方法:

var context = canvas.getContext("2d");
var super = context.__proto__;
context.__proto__ = ({

  __proto__: super, //"inherit" default behavior

  getMatrix: function() { return this.matrix; },

  scale: function(x, y) {

    //assuming the matrix manipulations are already defined...
    var newMatrix = scaleMatrix(x, y, this.getMatrix());
    this.matrix = newMatrix;
    return super.scale.call(this, x, y);
  },
  /* similar things for rotate, translate, transform, setTransform */
  /* ... */
});
context.matrix = makeDefaultMatrix();
Run Code Online (Sandbox Code Playgroud)

要真正做到正确,您需要在使用上下文save()restore()方法时跟踪多个矩阵.