/** * based on * https://github.com/CreateJS/EaselJS/blob/631cdffb85eff9413dab43b4676f059b4232d291/src/easeljs/geom/Matrix2D.js */ const DEG_TO_RAD = Math.PI / 180; /** * Represents an affine transformation matrix, and provides tools for constructing and concatenating matrices. * * This matrix can be visualized as: * * [ a c tx * b d ty * 0 0 1 ] * * Note the locations of b and c. * * @class Matrix2D * @param {Number} [a=1] Specifies the a property for the new matrix. * @param {Number} [b=0] Specifies the b property for the new matrix. * @param {Number} [c=0] Specifies the c property for the new matrix. * @param {Number} [d=1] Specifies the d property for the new matrix. * @param {Number} [tx=0] Specifies the tx property for the new matrix. * @param {Number} [ty=0] Specifies the ty property for the new matrix. * @constructor **/ export default class Matrix2D { constructor(a, b, c, d, tx, ty) { this.setTransform(a, b, c, d, tx, ty); // public properties: // assigned in the setValues method. /** * Position (0, 0) in a 3x3 affine transformation matrix. * @property a * @type Number **/ /** * Position (0, 1) in a 3x3 affine transformation matrix. * @property b * @type Number **/ /** * Position (1, 0) in a 3x3 affine transformation matrix. * @property c * @type Number **/ /** * Position (1, 1) in a 3x3 affine transformation matrix. * @property d * @type Number **/ /** * Position (2, 0) in a 3x3 affine transformation matrix. * @property tx * @type Number **/ /** * Position (2, 1) in a 3x3 affine transformation matrix. * @property ty * @type Number **/ } /** * Set current matrix to new absolute matrix. * @method setTransform * @param {Number} [a=1] Specifies the a property for the new matrix. * @param {Number} [b=0] Specifies the b property for the new matrix. * @param {Number} [c=0] Specifies the c property for the new matrix. * @param {Number} [d=1] Specifies the d property for the new matrix. * @param {Number} [tx=0] Specifies the tx property for the new matrix. * @param {Number} [ty=0] Specifies the ty property for the new matrix. * @return {Matrix2D} This instance. Useful for chaining method calls. */ setTransform = function(a, b, c, d, tx, ty) { /*eslint eqeqeq:0*/ this.a = a == null ? 1 : a; this.b = b || 0; this.c = c || 0; this.d = d == null ? 1 : d; this.tx = tx || 0; this.ty = ty || 0; return this; }; /** * Reset current matrix to an identity matrix. * @method reset * @return {Matrix2D} This matrix. Useful for chaining method calls. **/ reset = function() { this.a = this.d = 1; this.b = this.c = this.tx = this.ty = 0; return this; }; /** * Returns an array with current matrix values. * @method toArray * @return {Array} an array with current matrix values. **/ toArray = function() { return [this.a, this.b, this.c, this.d, this.tx, this.ty]; }; /** * Copies all properties from the specified matrix to this matrix. * @method copy * @param {Matrix2D} matrix The matrix to copy properties from. * @return {Matrix2D} This matrix. Useful for chaining method calls. */ copy = function(matrix) { return this.setTransform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); }; /** * Clones current instance and returning a new matrix. * @method clone * @return {Matrix2D} a clone of the Matrix2D instance. **/ clone = function() { return new Matrix2D(this.a, this.b, this.c, this.d, this.tx, this.ty); }; /** * Prepends the specified matrix properties to this matrix. * This is the equivalent of multiplying `(specified matrix) * (this matrix)`. * All parameters are required. * @method prepend * @param {Number} a * @param {Number} b * @param {Number} c * @param {Number} d * @param {Number} tx * @param {Number} ty * @return {Matrix2D} This matrix. Useful for chaining method calls. **/ prepend = function(a, b, c, d, tx, ty) { var a1 = this.a; var c1 = this.c; var tx1 = this.tx; this.a = a * a1 + c * this.b; this.b = b * a1 + d * this.b; this.c = a * c1 + c * this.d; this.d = b * c1 + d * this.d; this.tx = a * tx1 + c * this.ty + tx; this.ty = b * tx1 + d * this.ty + ty; return this; }; /** * Appends the specified matrix properties to this matrix. All parameters are required. * This is the equivalent of multiplying `(this matrix) * (specified matrix)`. * @method append * @param {Number} a * @param {Number} b * @param {Number} c * @param {Number} d * @param {Number} tx * @param {Number} ty * @return {Matrix2D} This matrix. Useful for chaining method calls. **/ append = function(a, b, c, d, tx, ty) { var a1 = this.a; var b1 = this.b; var c1 = this.c; var d1 = this.d; if (a !== 1 || b !== 0 || c !== 0 || d !== 1) { this.a = a1 * a + c1 * b; this.b = b1 * a + d1 * b; this.c = a1 * c + c1 * d; this.d = b1 * c + d1 * d; } this.tx = a1 * tx + c1 * ty + this.tx; this.ty = b1 * tx + d1 * ty + this.ty; return this; }; /** * Generates matrix properties from the specified display object transform properties, and appends them to this matrix. * For example, you can use this to generate a matrix representing the transformations of a display object: * * var mtx = new createjs.Matrix2D(); * mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation); * @method appendTransform * @param {Number} x * @param {Number} y * @param {Number} scaleX * @param {Number} scaleY * @param {Number} rotation * @param {Number} skewX * @param {Number} skewY * @param {Number} regX Optional. * @param {Number} regY Optional. * @return {Matrix2D} This matrix. Useful for chaining method calls. **/ appendTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) { if (rotation % 360) { var r = rotation * 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 operation? skewX *= DEG_TO_RAD; skewY *= 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) { // append the registration offset: this.tx -= regX * this.a + regY * this.c; this.ty -= regX * this.b + regY * this.d; } return this; }; /** * Generates matrix properties from the specified display object transform properties, and prepends them to this matrix. * For example, you could calculate the combined transformation for a child object using: * * var o = myDisplayObject; * var mtx = new createjs.Matrix2D(); * do { * // prepend each parent's transformation in turn: * mtx.prependTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY); * } while (o = o.parent); * * Note that the above example would not account for {{#crossLink "DisplayObject/transformMatrix:property"}}{{/crossLink}} * values. See {{#crossLink "Matrix2D/prependMatrix"}}{{/crossLink}} for an example that does. * @method prependTransform * @param {Number} x * @param {Number} y * @param {Number} scaleX * @param {Number} scaleY * @param {Number} rotation * @param {Number} skewX * @param {Number} skewY * @param {Number} regX Optional. * @param {Number} regY Optional. * @return {Matrix2D} This matrix. Useful for chaining method calls. **/ prependTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) { if (rotation % 360) { var r = rotation * DEG_TO_RAD; var cos = Math.cos(r); var sin = Math.sin(r); } else { cos = 1; sin = 0; } if (regX || regY) { // prepend the registration offset: this.tx -= regX; this.ty -= regY; } if (skewX || skewY) { // TODO: can this be combined into a single prepend operation? skewX *= DEG_TO_RAD; skewY *= 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; }; }