UNPKG

ag-grid-enterprise

Version:

AG Grid Enterprise Features

284 lines 11.3 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from) { for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) to[j] = from[i]; return to; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Matrix = void 0; var bbox_1 = require("./bbox"); /** * As of Jan 8, 2019, Firefox still doesn't implement * `getTransform(): DOMMatrix;` * `setTransform(transform?: DOMMatrix2DInit)` * in the `CanvasRenderingContext2D`. * Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=928150 * IE11 and Edge 44 also don't have the support. * Thus this class, to keep track of the current transform and * combine transformations. * Standards: * https://html.spec.whatwg.org/dev/canvas.html * https://www.w3.org/TR/geometry-1/ */ var Matrix = /** @class */ (function () { function Matrix(elements) { if (elements === void 0) { elements = [1, 0, 0, 1, 0, 0]; } this.elements = elements; } Object.defineProperty(Matrix.prototype, "e", { get: function () { return __spreadArray([], __read(this.elements)); }, enumerable: false, configurable: true }); Matrix.prototype.setElements = function (elements) { var e = this.elements; // `this.elements = elements.slice()` is 4-5 times slower // (in Chrome 71 and FF 64) than manually copying elements, // since slicing allocates new memory. // The performance of passing parameters individually // vs as an array is about the same in both browsers, so we // go with a single (array of elements) parameter, because // `setElements(elements)` and `setElements([a, b, c, d, e, f])` // calls give us roughly the same performance, versus // `setElements(...elements)` and `setElements(a, b, c, d, e, f)`, // where the spread operator causes a 20-30x performance drop // (30x when compiled to ES5's `.apply(this, elements)` // 20x when used natively). e[0] = elements[0]; e[1] = elements[1]; e[2] = elements[2]; e[3] = elements[3]; e[4] = elements[4]; e[5] = elements[5]; return this; }; Object.defineProperty(Matrix.prototype, "identity", { get: function () { var e = this.elements; return e[0] === 1 && e[1] === 0 && e[2] === 0 && e[3] === 1 && e[4] === 0 && e[5] === 0; }, enumerable: false, configurable: true }); /** * Performs the AxB matrix multiplication and saves the result * to `C`, if given, or to `A` otherwise. */ Matrix.prototype.AxB = function (A, B, C) { var a = A[0] * B[0] + A[2] * B[1], b = A[1] * B[0] + A[3] * B[1], c = A[0] * B[2] + A[2] * B[3], d = A[1] * B[2] + A[3] * B[3], e = A[0] * B[4] + A[2] * B[5] + A[4], f = A[1] * B[4] + A[3] * B[5] + A[5]; C = C !== null && C !== void 0 ? C : A; C[0] = a; C[1] = b; C[2] = c; C[3] = d; C[4] = e; C[5] = f; }; /** * The `other` matrix gets post-multiplied to the current matrix. * Returns the current matrix. * @param other */ Matrix.prototype.multiplySelf = function (other) { this.AxB(this.elements, other.elements); return this; }; /** * The `other` matrix gets post-multiplied to the current matrix. * Returns a new matrix. * @param other */ Matrix.prototype.multiply = function (other) { var elements = new Array(6); this.AxB(this.elements, other.elements, elements); return new Matrix(elements); }; Matrix.prototype.preMultiplySelf = function (other) { this.AxB(other.elements, this.elements, this.elements); return this; }; /** * Returns the inverse of this matrix as a new matrix. */ Matrix.prototype.inverse = function () { var el = this.elements; var a = el[0], b = el[1], c = el[2], d = el[3]; var e = el[4], f = el[5]; var rD = 1 / (a * d - b * c); // reciprocal of determinant a *= rD; b *= rD; c *= rD; d *= rD; return new Matrix([d, -b, -c, a, c * f - d * e, b * e - a * f]); }; /** * Save the inverse of this matrix to the given matrix. */ Matrix.prototype.inverseTo = function (other) { var el = this.elements; var a = el[0], b = el[1], c = el[2], d = el[3]; var e = el[4], f = el[5]; var rD = 1 / (a * d - b * c); // reciprocal of determinant a *= rD; b *= rD; c *= rD; d *= rD; other.setElements([d, -b, -c, a, c * f - d * e, b * e - a * f]); return this; }; Matrix.prototype.invertSelf = function () { var el = this.elements; var a = el[0], b = el[1], c = el[2], d = el[3]; var e = el[4], f = el[5]; var rD = 1 / (a * d - b * c); // reciprocal of determinant a *= rD; b *= rD; c *= rD; d *= rD; el[0] = d; el[1] = -b; el[2] = -c; el[3] = a; el[4] = c * f - d * e; el[5] = b * e - a * f; return this; }; Matrix.prototype.transformPoint = function (x, y) { var e = this.elements; return { x: x * e[0] + y * e[2] + e[4], y: x * e[1] + y * e[3] + e[5], }; }; Matrix.prototype.transformBBox = function (bbox, target) { var elements = this.elements; var xx = elements[0]; var xy = elements[1]; var yx = elements[2]; var yy = elements[3]; var h_w = bbox.width * 0.5; var h_h = bbox.height * 0.5; var cx = bbox.x + h_w; var cy = bbox.y + h_h; var w = Math.abs(h_w * xx) + Math.abs(h_h * yx); var h = Math.abs(h_w * xy) + Math.abs(h_h * yy); if (!target) { target = new bbox_1.BBox(0, 0, 0, 0); } target.x = cx * xx + cy * yx + elements[4] - w; target.y = cx * xy + cy * yy + elements[5] - h; target.width = w + w; target.height = h + h; return target; }; Matrix.prototype.toContext = function (ctx) { // It's fair to say that matrix multiplications are not cheap. // However, updating path definitions on every frame isn't either, so // it may be cheaper to just translate paths. It's also fair to // say, that most paths will have to be re-rendered anyway, say // rectangle paths in a bar chart, where an animation would happen when // the data set changes and existing bars are morphed into new ones. // Or a pie chart, where old sectors are also morphed into new ones. // Same for the line chart. The only plausible case where translating // existing paths would be enough, is the scatter chart, where marker // icons, typically circles, stay the same size. But if circle radii // are bound to some data points, even circle paths would have to be // updated. And thus it makes sense to optimize for fewer matrix // transforms, where transform matrices of paths are mostly identity // matrices and `x`/`y`, `centerX`/`centerY` and similar properties // are used to define a path at specific coordinates. And only groups // are used to collectively apply a transform to a set of nodes. // If the matrix is mostly identity (95% of the time), // the `if (this.isIdentity)` check can make this call 3-4 times // faster on average: https://jsperf.com/matrix-check-first-vs-always-set if (this.identity) { return; } var e = this.elements; ctx.transform(e[0], e[1], e[2], e[3], e[4], e[5]); }; Matrix.flyweight = function (sourceMatrix) { return Matrix.instance.setElements(sourceMatrix.elements); }; Matrix.updateTransformMatrix = function (matrix, scalingX, scalingY, rotation, translationX, translationY, opts) { // Assume that centers of scaling and rotation are at the origin. var _a = __read([0, 0], 2), bbcx = _a[0], bbcy = _a[1]; var sx = scalingX; var sy = scalingY; var scx; var scy; if (sx === 1 && sy === 1) { scx = 0; scy = 0; } else { scx = (opts === null || opts === void 0 ? void 0 : opts.scalingCenterX) == null ? bbcx : opts === null || opts === void 0 ? void 0 : opts.scalingCenterX; scy = (opts === null || opts === void 0 ? void 0 : opts.scalingCenterY) == null ? bbcy : opts === null || opts === void 0 ? void 0 : opts.scalingCenterY; } var r = rotation; var cos = Math.cos(r); var sin = Math.sin(r); var rcx; var rcy; if (r === 0) { rcx = 0; rcy = 0; } else { rcx = (opts === null || opts === void 0 ? void 0 : opts.rotationCenterX) == null ? bbcx : opts === null || opts === void 0 ? void 0 : opts.rotationCenterX; rcy = (opts === null || opts === void 0 ? void 0 : opts.rotationCenterY) == null ? bbcy : opts === null || opts === void 0 ? void 0 : opts.rotationCenterY; } var tx = translationX; var ty = translationY; // The transform matrix `M` is a result of the following transformations: // 1) translate the center of scaling to the origin // 2) scale // 3) translate back // 4) translate the center of rotation to the origin // 5) rotate // 6) translate back // 7) translate // (7) (6) (5) (4) (3) (2) (1) // | 1 0 tx | | 1 0 rcx | | cos -sin 0 | | 1 0 -rcx | | 1 0 scx | | sx 0 0 | | 1 0 -scx | // M = | 0 1 ty | * | 0 1 rcy | * | sin cos 0 | * | 0 1 -rcy | * | 0 1 scy | * | 0 sy 0 | * | 0 1 -scy | // | 0 0 1 | | 0 0 1 | | 0 0 1 | | 0 0 1 | | 0 0 1 | | 0 0 0 | | 0 0 1 | // Translation after steps 1-4 above: var tx4 = scx * (1 - sx) - rcx; var ty4 = scy * (1 - sy) - rcy; matrix.setElements([ cos * sx, sin * sx, -sin * sy, cos * sy, cos * tx4 - sin * ty4 + rcx + tx, sin * tx4 + cos * ty4 + rcy + ty, ]); return matrix; }; Matrix.fromContext = function (ctx) { var domMatrix = ctx.getTransform(); return new Matrix([domMatrix.a, domMatrix.b, domMatrix.c, domMatrix.d, domMatrix.e, domMatrix.f]); }; Matrix.instance = new Matrix(); return Matrix; }()); exports.Matrix = Matrix; //# sourceMappingURL=matrix.js.map