UNPKG

immutable-transform-matrix

Version:
306 lines (252 loc) 8.44 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _extendableImmutable = require('extendable-immutable'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * A library for creating affine transform matrix (3x3) that are Immutable. * These matrices can be used for matrix calcuations on SVG CTMs (current transform matrix). * * @module immutable-transform-matrix */ /** * @class Matrix * @extends Immutable.Map */ var Matrix = function (_Map) { (0, _inherits3.default)(Matrix, _Map); /** * Construct a Matrix. Creates an Identiy matrix if no params are supplied. * @param {number} a * @param {number} b * @param {number} c * @param {number} d * @param {number} e * @param {number} f */ function Matrix() { (0, _classCallCheck3.default)(this, Matrix); if (arguments.length > 0) { var _this = (0, _possibleConstructorReturn3.default)(this, (Matrix.__proto__ || (0, _getPrototypeOf2.default)(Matrix)).call(this, { a: arguments.length <= 0 ? undefined : arguments[0], b: arguments.length <= 1 ? undefined : arguments[1], c: arguments.length <= 2 ? undefined : arguments[2], d: arguments.length <= 3 ? undefined : arguments[3], e: arguments.length <= 4 ? undefined : arguments[4], f: arguments.length <= 5 ? undefined : arguments[5] })); } else { var _this = (0, _possibleConstructorReturn3.default)(this, (Matrix.__proto__ || (0, _getPrototypeOf2.default)(Matrix)).call(this, { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 })); } return (0, _possibleConstructorReturn3.default)(_this); } /** * Construct a new Matrix constructed from an SVGMatrix * @param {SVGMatrix} ctm * @return {Matrix} */ (0, _createClass3.default)(Matrix, [{ key: 'transform', /** * Multiplies current matrix with new matrix values. * @param {number} a2 - scale x * @param {number} b2 - shear y * @param {number} c2 - shear x * @param {number} d2 - scale y * @param {number} e2 - translate x * @param {number} f2 - translate y * @return {Matrix} */ value: function transform(a2, b2, c2, d2, e2, f2) { var a1 = this.get('a'); var b1 = this.get('b'); var c1 = this.get('c'); var d1 = this.get('d'); var e1 = this.get('e'); var f1 = this.get('f'); return this.withMutations(function (matrix) { return matrix.set('a', a1 * a2 + c1 * b2).set('b', b1 * a2 + d1 * b2).set('c', a1 * c2 + c1 * d2).set('d', b1 * c2 + d1 * d2).set('e', a1 * e2 + c1 * f2 + e1).set('f', b1 * e2 + d1 * f2 + f1); }); } /** * Scales current matrix accumulative. * If the second param is ommitted it scale uniformly. * @param {number} sx - scale factor x (1 does nothing) * @param {number} [sy] - scale factor y (1 does nothing) * @return {Matrix} */ }, { key: 'scale', value: function scale() { var sx = arguments.length <= 0 ? undefined : arguments[0]; var sy = sx; if (arguments.length > 1) { sy = arguments.length <= 1 ? undefined : arguments[1]; } return this.transform(sx, 0, 0, sy, 0, 0); } /** * Translate current matrix accumulative. * @param {number} tx - translation for x * @param {number} ty - translation for y * @return {Matrix} */ }, { key: 'translate', value: function translate(tx, ty) { return this.transform(1, 0, 0, 1, tx, ty); } /** * Rotates current matrix accumulative by angle. * @param {number} angle - angle in radians * @return {Matrix} */ }, { key: 'rotate', value: function rotate(angle) { var cos = Math.cos(angle); var sin = Math.sin(angle); return this.transform(cos, sin, -sin, cos, 0, 0); } /** * Helper method to make a rotation based on an angle in degrees. * @param {number} angle - angle in degrees * @return {Matrix} */ }, { key: 'rotateDeg', value: function rotateDeg(angle) { return this.rotate(angle * Math.PI / 180); } /** * Multiplies current matrix with an other matrix. * @param {Matrix} m - the other matrix * @return {Matrix} */ }, { key: 'multiply', value: function multiply(matrix) { return this.transform(matrix.get('a'), matrix.get('b'), matrix.get('c'), matrix.get('d'), matrix.get('e'), matrix.get('f')); } /** * @return {boolean} true if identity (no transforms applied) */ }, { key: 'isIdentity', value: function isIdentity() { return this.get('a') === 1 && this.get('b') === 0 && this.get('c') === 0 && this.get('d') === 1 && this.get('e') === 0 && this.get('f') === 0; } /** * @return {string} */ }, { key: 'toString', value: function toString() { var values = [this.get('a'), this.get('b'), this.get('c'), this.get('d'), this.get('e'), this.get('f')]; return 'matrix(' + values.join() + ')'; } /** * @return {number} determinant of the current matrix */ }, { key: 'determinant', value: function determinant() { return this.get('a') * this.get('d') - this.get('b') * this.get('c'); } /** * @return {boolean} true if matrix is invertible */ }, { key: 'isInvertible', value: function isInvertible() { return this.determinant() !== 0; } /** * @return {Matrix} inverse of the current matrix. * @throws Will throw an error if the matrix is not invertable */ }, { key: 'inverse', value: function inverse() { if (this.isIdentity()) { return new Matrix(); } if (!this.isInvertible()) { throw new Error('Matrix is not invertible.'); } var dt = this.determinant(); var a = this.get('a'); var b = this.get('b'); var c = this.get('c'); var d = this.get('d'); var e = this.get('e'); var f = this.get('f'); return this.withMutations(function (matrix) { return matrix.set('a', d / dt).set('b', -b / dt).set('c', -c / dt).set('d', a / dt).set('e', (c * f - d * e) / dt).set('f', -(a * f - b * e) / dt); }); } /** * @param {Matrix} m - matrix divisor * @return {Matrix} * @throws Will throw if m is not invertible or not a Matrix */ }, { key: 'divide', value: function divide(m) { if (!(m instanceof Matrix)) { throw new Error('Must pass a Matrix to divide.'); } if (!m.isInvertible()) { throw new Error('Input matrix is not invertible.'); } var inverse = m.inverse(); return this.transform(inverse.get('a'), inverse.get('b'), inverse.get('c'), inverse.get('d'), inverse.get('e'), inverse.get('f')); } /** * Apply current matrix to x and y point. * * @param {number} x - value for x * @param {number} y - value for y * @returns {{x: number, y: number}} A new transformed point object */ }, { key: 'applyToPoint', value: function applyToPoint(x, y) { return { x: x * this.get('a') + y * this.get('c') + this.get('e'), y: x * this.get('b') + y * this.get('d') + this.get('f') }; } }], [{ key: 'fromCTM', value: function fromCTM(ctm) { var a = ctm.a, b = ctm.b, c = ctm.c, d = ctm.d, e = ctm.e, f = ctm.f; return new Matrix(a, b, c, d, e, f); } }]); return Matrix; }(_extendableImmutable.Map); exports.default = Matrix;