UNPKG

cupiditatea

Version:

A two-dimensional drawing api meant for modern browsers.

376 lines (270 loc) 8.19 kB
(function(Two) { /** * Constants */ var cos = Math.cos, sin = Math.sin, tan = Math.tan; /** * Two.Matrix contains an array of elements that represent * the two dimensional 3 x 3 matrix as illustrated below: * * ===== * a b c * d e f * g h i // this row is not really used in 2d transformations * ===== * * String order is for transform strings: a, d, b, e, c, f * * @class */ var Matrix = Two.Matrix = function(a, b, c, d, e, f) { this.elements = new Two.Array(9); var elements = a; if (!_.isArray(elements)) { elements = _.toArray(arguments); } // initialize the elements with default values. this.identity().set(elements); }; _.extend(Matrix, { Identity: [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ], /** * Multiply two matrix 3x3 arrays */ Multiply: function(A, B, C) { if (B.length <= 3) { // Multiply Vector var x, y, z, e = A; var a = B[0] || 0, b = B[1] || 0, c = B[2] || 0; // Go down rows first // a, d, g, b, e, h, c, f, i x = e[0] * a + e[1] * b + e[2] * c; y = e[3] * a + e[4] * b + e[5] * c; z = e[6] * a + e[7] * b + e[8] * c; return { x: x, y: y, z: z }; } var A0 = A[0], A1 = A[1], A2 = A[2]; var A3 = A[3], A4 = A[4], A5 = A[5]; var A6 = A[6], A7 = A[7], A8 = A[8]; var B0 = B[0], B1 = B[1], B2 = B[2]; var B3 = B[3], B4 = B[4], B5 = B[5]; var B6 = B[6], B7 = B[7], B8 = B[8]; C = C || new Two.Array(9); C[0] = A0 * B0 + A1 * B3 + A2 * B6; C[1] = A0 * B1 + A1 * B4 + A2 * B7; C[2] = A0 * B2 + A1 * B5 + A2 * B8; C[3] = A3 * B0 + A4 * B3 + A5 * B6; C[4] = A3 * B1 + A4 * B4 + A5 * B7; C[5] = A3 * B2 + A4 * B5 + A5 * B8; C[6] = A6 * B0 + A7 * B3 + A8 * B6; C[7] = A6 * B1 + A7 * B4 + A8 * B7; C[8] = A6 * B2 + A7 * B5 + A8 * B8; return C; } }); _.extend(Matrix.prototype, Backbone.Events, { /** * Takes an array of elements or the arguments list itself to * set and update the current matrix's elements. Only updates * specified values. */ set: function(a) { var elements = a; if (!_.isArray(elements)) { elements = _.toArray(arguments); } _.extend(this.elements, elements); return this.trigger(Two.Events.change); }, /** * Turn matrix to identity, like resetting. */ identity: function() { this.set(Matrix.Identity); return this; }, /** * Multiply scalar or multiply by another matrix. */ multiply: function(a, b, c, d, e, f, g, h, i) { var elements = arguments, l = elements.length; // Multiply scalar if (l <= 1) { _.each(this.elements, function(v, i) { this.elements[i] = v * a; }, this); return this.trigger(Two.Events.change); } if (l <= 3) { // Multiply Vector var x, y, z; a = a || 0; b = b || 0; c = c || 0; e = this.elements; // Go down rows first // a, d, g, b, e, h, c, f, i x = e[0] * a + e[1] * b + e[2] * c; y = e[3] * a + e[4] * b + e[5] * c; z = e[6] * a + e[7] * b + e[8] * c; return { x: x, y: y, z: z }; } // Multiple matrix var A = this.elements; var B = elements; var A0 = A[0], A1 = A[1], A2 = A[2]; var A3 = A[3], A4 = A[4], A5 = A[5]; var A6 = A[6], A7 = A[7], A8 = A[8]; var B0 = B[0], B1 = B[1], B2 = B[2]; var B3 = B[3], B4 = B[4], B5 = B[5]; var B6 = B[6], B7 = B[7], B8 = B[8]; this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6; this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7; this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8; this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6; this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7; this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8; this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6; this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7; this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8; return this.trigger(Two.Events.change); }, inverse: function(out) { var a = this.elements; out = out || new Two.Matrix(); var a00 = a[0], a01 = a[1], a02 = a[2]; var a10 = a[3], a11 = a[4], a12 = a[5]; var a20 = a[6], a21 = a[7], a22 = a[8]; var b01 = a22 * a11 - a12 * a21; var b11 = -a22 * a10 + a12 * a20; var b21 = a21 * a10 - a11 * a20; // Calculate the determinant var det = a00 * b01 + a01 * b11 + a02 * b21; if (!det) { return null; } det = 1.0 / det; out.elements[0] = b01 * det; out.elements[1] = (-a22 * a01 + a02 * a21) * det; out.elements[2] = (a12 * a01 - a02 * a11) * det; out.elements[3] = b11 * det; out.elements[4] = (a22 * a00 - a02 * a20) * det; out.elements[5] = (-a12 * a00 + a02 * a10) * det; out.elements[6] = b21 * det; out.elements[7] = (-a21 * a00 + a01 * a20) * det; out.elements[8] = (a11 * a00 - a01 * a10) * det; return out; }, /** * Set a scalar onto the matrix. */ scale: function(sx, sy) { var l = arguments.length; if (l <= 1) { sy = sx; } return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1); }, /** * Rotate the matrix. */ rotate: function(radians) { var c = cos(radians); var s = sin(radians); return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1); }, /** * Translate the matrix. */ translate: function(x, y) { return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1); }, /* * Skew the matrix by an angle in the x axis direction. */ skewX: function(radians) { var a = tan(radians); return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1); }, /* * Skew the matrix by an angle in the y axis direction. */ skewY: function(radians) { var a = tan(radians); return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1); }, /** * Create a transform string to be used with rendering apis. */ toString: function(fullMatrix) { var temp = []; this.toArray(fullMatrix, temp); return temp.join(' '); }, /** * Create a transform array to be used with rendering apis. */ toArray: function(fullMatrix, output) { var elements = this.elements; var hasOutput = !!output; var a = parseFloat(elements[0].toFixed(3)); var b = parseFloat(elements[1].toFixed(3)); var c = parseFloat(elements[2].toFixed(3)); var d = parseFloat(elements[3].toFixed(3)); var e = parseFloat(elements[4].toFixed(3)); var f = parseFloat(elements[5].toFixed(3)); if (!!fullMatrix) { var g = parseFloat(elements[6].toFixed(3)); var h = parseFloat(elements[7].toFixed(3)); var i = parseFloat(elements[8].toFixed(3)); if (hasOutput) { output[0] = a; output[1] = d; output[2] = g; output[3] = b; output[4] = e; output[5] = h; output[6] = c; output[7] = f; output[8] = i; return; } return [ a, d, g, b, e, h, c, f, i ]; } if (hasOutput) { output[0] = a; output[1] = d; output[2] = b; output[3] = e; output[4] = c; output[5] = f; return; } return [ a, d, b, e, c, f // Specific format see LN:19 ]; }, /** * Clone the current matrix. */ clone: function() { var a, b, c, d, e, f, g, h, i; a = this.elements[0]; b = this.elements[1]; c = this.elements[2]; d = this.elements[3]; e = this.elements[4]; f = this.elements[5]; g = this.elements[6]; h = this.elements[7]; i = this.elements[8]; return new Two.Matrix(a, b, c, d, e, f, g, h, i); } }); })(Two);