topical media & game development

talk show tell print

mobile-graphic-easel-src-easeljs-geom-Matrix2D.js / js



  /*
  * Matrix2D
  * Visit http://createjs.com/ for documentation, updates and examples.
  *
  * Copyright (c) 2010 gskinner.com, inc.
  * 
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
  * files (the "Software"), to deal in the Software without
  * restriction, including without limitation the rights to use,
  * copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following
  * conditions:
  * 
  * The above copyright notice and this permission notice shall be
  * included in all copies or substantial portions of the Software.
  * 
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  */
  
  // namespace:
  this.createjs = this.createjs||{};
  
  (function() {
  
  
Represents an affine transformation matrix, and provides tools for constructing and concatenating matrixes. @class Matrix2D @constructor
parameter: {Number} a Specifies the a property for the new matrix.
parameter: {Number} b Specifies the b property for the new matrix.
parameter: {Number} c Specifies the c property for the new matrix.
parameter: {Number} d Specifies the d property for the new matrix.
parameter: {Number} tx Specifies the tx property for the new matrix.
parameter: {Number} ty Specifies the ty property for the new matrix.

  
  var Matrix2D = function(a, b, c, d, tx, ty) {
    this.initialize(a, b, c, d, tx, ty);
  }
  var p = Matrix2D.prototype;
  
  // static public properties:
  
          
An identity matrix, representing a null transformation. Read-only. @property identity @static @type Matrix2D

  
          Matrix2D.identity = null; // set at bottom of class definition.
  
          
Multiplier for converting degrees to radians. Used internally by Matrix2D. Read-only. @property DEG_TO_RAD @static @final @type Number

  
          Matrix2D.DEG_TO_RAD = Math.PI/180;
  
  // public properties:
          
Position (0, 0) in a 3x3 affine transformation matrix. @property a @type Number

  
          p.a = 1;
  
          
Position (0, 1) in a 3x3 affine transformation matrix. @property b @type Number

  
          p.b = 0;
  
          
Position (1, 0) in a 3x3 affine transformation matrix. @property c @type Number

  
          p.c = 0;
  
          
Position (1, 1) in a 3x3 affine transformation matrix. @property d @type Number

  
          p.d = 1;
  
          
Position (2, 0) in a 3x3 affine transformation matrix. @property tx @type Number

  
          p.tx = 0;
  
          
Position (2, 1) in a 3x3 affine transformation matrix. @property ty @type Number

  
          p.ty = 0;
  
          
Property representing the alpha that will be applied to a display object. This is not part of matrix operations, but is used for operations like getConcatenatedMatrix to provide concatenated alpha values. @property alpha @type Number

  
          p.alpha = 1;
  
          
Property representing the shadow that will be applied to a display object. This is not part of matrix operations, but is used for operations like getConcatenatedMatrix to provide concatenated shadow values. @property shadow @type Shadow

  
          p.shadow  = null;
  
          
Property representing the compositeOperation that will be applied to a display object. This is not part of matrix operations, but is used for operations like getConcatenatedMatrix to provide concatenated compositeOperation values. You can find a list of valid composite operations at: <a href="https://developer.mozilla.org/en/Canvas_tutorial/Compositing">developer.mozilla.org/en/Canvas_tutorial/Compositing</a> @property compositeOperation @type String

  
          p.compositeOperation = null;
  
  // constructor:
          
Initialization method. @method initialize @protected
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.initialize = function(a, b, c, d, tx, ty) {
                  if (a != null) { this.a = a; }
                  this.b = b || 0;
                  this.c = c || 0;
                  if (d != null) { this.d = d; }
                  this.tx = tx || 0;
                  this.ty = ty || 0;
                  return this;
          }
  
  // public methods:
          
Concatenates the specified matrix properties with this matrix. All parameters are required. @method prepend
parameter: {Number} a
parameter: {Number} b
parameter: {Number} c
parameter: {Number} d
parameter: {Number} tx
parameter: {Number} ty
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.prepend = function(a, b, c, d, tx, ty) {
                  var tx1 = this.tx;
                  if (a != 1 || b != 0 || c != 0 || d != 1) {
                          var a1 = this.a;
                          var c1 = this.c;
                          this.a  = a1*a+this.b*c;
                          this.b  = a1*b+this.b*d;
                          this.c  = c1*a+this.d*c;
                          this.d  = c1*b+this.d*d;
                  }
                  this.tx = tx1*a+this.ty*c+tx;
                  this.ty = tx1*b+this.ty*d+ty;
                  return this;
          }
  
          
Appends the specified matrix properties with this matrix. All parameters are required. @method append
parameter: {Number} a
parameter: {Number} b
parameter: {Number} c
parameter: {Number} d
parameter: {Number} tx
parameter: {Number} ty
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.append = function(a, b, c, d, tx, ty) {
                  var a1 = this.a;
                  var b1 = this.b;
                  var c1 = this.c;
                  var d1 = this.d;
  
                  this.a  = a*a1+b*c1;
                  this.b  = a*b1+b*d1;
                  this.c  = c*a1+d*c1;
                  this.d  = c*b1+d*d1;
                  this.tx = tx*a1+ty*c1+this.tx;
                  this.ty = tx*b1+ty*d1+this.ty;
                  return this;
          }
  
          
Prepends the specified matrix with this matrix. @method prependMatrix
parameter: {Matrix2D} matrix

  
          p.prependMatrix = function(matrix) {
                  this.prepend(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
                  this.prependProperties(matrix.alpha, matrix.shadow,  matrix.compositeOperation);
                  return this;
          }
  
          
Appends the specified matrix with this matrix. @method appendMatrix
parameter: {Matrix2D} matrix
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.appendMatrix = function(matrix) {
                  this.append(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
                  this.appendProperties(matrix.alpha, matrix.shadow,  matrix.compositeOperation);
                  return this;
          }
  
          
Generates matrix properties from the specified display object transform properties, and prepends them with this matrix. For example, you can use this to generate a matrix from a display object: var mtx = new Matrix2D(); mtx.prependTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation); @method prependTransform
parameter: {Number} x
parameter: {Number} y
parameter: {Number} scaleX
parameter: {Number} scaleY
parameter: {Number} rotation
parameter: {Number} skewX
parameter: {Number} skewY
parameter: {Number} regX Optional.
parameter: {Number} regY Optional.
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.prependTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
                  if (rotation%360) {
                          var r = rotation*Matrix2D.DEG_TO_RAD;
                          var cos = Math.cos(r);
                          var sin = Math.sin(r);
                  } else {
                          cos = 1;
                          sin = 0;
                  }
  
                  if (regX || regY) {
                          // append the registration offset:
                          this.tx -= regX; this.ty -= regY;
                  }
                  if (skewX || skewY) {
                          // TODO: can this be combined into a single prepend operation?
                          skewX *= Matrix2D.DEG_TO_RAD;
                          skewY *= Matrix2D.DEG_TO_RAD;
                          this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0);
                          this.prepend(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y);
                  } else {
                          this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y);
                  }
                  return this;
          }
  
          
Generates matrix properties from the specified display object transform properties, and appends them with this matrix. For example, you can use this to generate a matrix from a display object: var mtx = new Matrix2D(); mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation); @method appendTransform
parameter: {Number} x
parameter: {Number} y
parameter: {Number} scaleX
parameter: {Number} scaleY
parameter: {Number} rotation
parameter: {Number} skewX
parameter: {Number} skewY
parameter: {Number} regX Optional.
parameter: {Number} regY Optional.
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.appendTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
                  if (rotation%360) {
                          var r = rotation*Matrix2D.DEG_TO_RAD;
                          var cos = Math.cos(r);
                          var sin = Math.sin(r);
                  } else {
                          cos = 1;
                          sin = 0;
                  }
  
                  if (skewX || skewY) {
                          // TODO: can this be combined into a single append?
                          skewX *= Matrix2D.DEG_TO_RAD;
                          skewY *= Matrix2D.DEG_TO_RAD;
                          this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y);
                          this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0);
                  } else {
                          this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y);
                  }
  
                  if (regX || regY) {
                          // prepend the registration offset:
                          this.tx -= regX*this.a+regY*this.c; 
                          this.ty -= regX*this.b+regY*this.d;
                  }
                  return this;
          }
  
          
Applies a rotation transformation to the matrix. @method rotate
parameter: {Number} angle The angle in radians. To use degrees, multiply by Math.PI/180.
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.rotate = function(angle) {
                  var cos = Math.cos(angle);
                  var sin = Math.sin(angle);
  
                  var a1 = this.a;
                  var c1 = this.c;
                  var tx1 = this.tx;
  
                  this.a = a1*cos-this.b*sin;
                  this.b = a1*sin+this.b*cos;
                  this.c = c1*cos-this.d*sin;
                  this.d = c1*sin+this.d*cos;
                  this.tx = tx1*cos-this.ty*sin;
                  this.ty = tx1*sin+this.ty*cos;
                  return this;
          }
  
          
Applies a skew transformation to the matrix. @method skew
parameter: {Number} skewX The amount to skew horizontally in degrees.
parameter: {Number} skewY The amount to skew vertically in degrees.
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.skew = function(skewX, skewY) {
                  skewX = skewX*Matrix2D.DEG_TO_RAD;
                  skewY = skewY*Matrix2D.DEG_TO_RAD;
                  this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), 0, 0);
                  return this;
          }
  
          
Applies a scale transformation to the matrix. @method scale
parameter: {Number} x
parameter: {Number} y
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.scale = function(x, y) {
                  this.a *= x;
                  this.d *= y;
                  this.tx *= x;
                  this.ty *= y;
                  return this;
          }
  
          
Translates the matrix on the x and y axes. @method translate
parameter: {Number} x
parameter: {Number} y
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.translate = function(x, y) {
                  this.tx += x;
                  this.ty += y;
                  return this;
          }
  
          
Sets the properties of the matrix to those of an identity matrix (one that applies a null transformation). @method identity
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.identity = function() {
                  this.alpha = this.a = this.d = 1;
                  this.b = this.c = this.tx = this.ty = 0;
                  this.shadow = this.compositeOperation = null;
                  return this;
          }
  
          
Inverts the matrix, causing it to perform the opposite transformation. @method invert
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.invert = function() {
                  var a1 = this.a;
                  var b1 = this.b;
                  var c1 = this.c;
                  var d1 = this.d;
                  var tx1 = this.tx;
                  var n = a1*d1-b1*c1;
  
                  this.a = d1/n;
                  this.b = -b1/n;
                  this.c = -c1/n;
                  this.d = a1/n;
                  this.tx = (c1*this.ty-d1*tx1)/n;
                  this.ty = -(a1*this.ty-b1*tx1)/n;
                  return this;
          }
  
          
Returns true if the matrix is an identity matrix. @method isIdentity
returns: {Boolean}

  
          p.isIdentity = function() {
                  return this.tx == 0 && this.ty == 0 && this.a == 1 && this.b == 0 && this.c == 0 && this.d == 1;
          }
  
          
Decomposes the matrix into transform properties (x, y, scaleX, scaleY, and rotation). Note that this these values may not match the transform properties you used to generate the matrix, though they will produce the same visual results. @method decompose
parameter: {Object} target The object to apply the transform properties to. If null, then a new object will be returned.
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.decompose = function(target) {
                  // TODO: it would be nice to be able to solve for whether the matrix can be decomposed into only scale/rotation
                  // even when scale is negative
                  if (target == null) { target = {}; }
                  target.x = this.tx;
                  target.y = this.ty;
                  target.scaleX = Math.sqrt(this.a * this.a + this.b * this.b);
                  target.scaleY = Math.sqrt(this.c * this.c + this.d * this.d);
  
                  var skewX = Math.atan2(-this.c, this.d);
                  var skewY = Math.atan2(this.b, this.a);
  
                  if (skewX == skewY) {
                          target.rotation = skewY/Matrix2D.DEG_TO_RAD;
                          if (this.a < 0 && this.d >= 0) {
                                  target.rotation += (target.rotation <= 0) ? 180 : -180;
                          }
                          target.skewX = target.skewY = 0;
                  } else {
                          target.skewX = skewX/Matrix2D.DEG_TO_RAD;
                          target.skewY = skewY/Matrix2D.DEG_TO_RAD;
                  }
                  return target;
          }
  
          
Reinitializes all matrix properties to those specified. @method appendProperties
parameter: {Number} a
parameter: {Number} b
parameter: {Number} c
parameter: {Number} d
parameter: {Number} tx
parameter: {Number} ty
parameter: {Number} alpha desired alpha value
parameter: {Shadow} shadow desired shadow value
parameter: {String} compositeOperation desired composite operation value
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.reinitialize = function(a,b,c,d,tx,ty,alpha,shadow,compositeOperation) {
                  this.initialize(a,b,c,d,tx,ty);
                  this.alpha = alpha || 1;
                  this.shadow = shadow;
                  this.compositeOperation = compositeOperation;
                  return this;
          }
  
          
Appends the specified visual properties to the current matrix. @method appendProperties
parameter: {Number} alpha desired alpha value
parameter: {Shadow} shadow desired shadow value
parameter: {String} compositeOperation desired composite operation value
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.appendProperties = function(alpha, shadow, compositeOperation) {
                  this.alpha *= alpha;
                  this.shadow = shadow || this.shadow;
                  this.compositeOperation = compositeOperation || this.compositeOperation;
                  return this;
          }
  
          
Prepends the specified visual properties to the current matrix. @method prependProperties
parameter: {Number} alpha desired alpha value
parameter: {Shadow} shadow desired shadow value
parameter: {String} compositeOperation desired composite operation value
returns: {Matrix2D} This matrix. Useful for chaining method calls.

  
          p.prependProperties = function(alpha, shadow, compositeOperation) {
                  this.alpha *= alpha;
                  this.shadow = this.shadow || shadow;
                  this.compositeOperation = this.compositeOperation || compositeOperation;
                  return this;
          }
  
          
Returns a clone of the Matrix2D instance. @method clone
returns: {Matrix2D} a clone of the Matrix2D instance.

  
          p.clone = function() {
                  var mtx = new Matrix2D(this.a, this.b, this.c, this.d, this.tx, this.ty);
                  mtx.shadow = this.shadow;
                  mtx.alpha = this.alpha;
                  mtx.compositeOperation = this.compositeOperation;
                  return mtx;
          }
  
          
Returns a string representation of this object. @method toString
returns: {String} a string representation of the instance.

  
          p.toString = function() {
                  return "[Matrix2D (a="+this.a+" b="+this.b+" c="+this.c+" d="+this.d+" tx="+this.tx+" ty="+this.ty+")]";
          }
  
          // this has to be populated after the class is defined:
          Matrix2D.identity = new Matrix2D(1, 0, 0, 1, 0, 0);
  
  createjs.Matrix2D = Matrix2D;
  }());


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.