happy-dom
Version:
Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.
1,532 lines (1,400 loc) • 51.3 kB
text/typescript
import DOMPoint from '../DOMPoint.js';
import IDOMPointInit from '../IDOMPointInit.js';
import * as PropertySymbol from '../../PropertySymbol.js';
import TDOMMatrixInit from './TDOMMatrixInit.js';
import TDOMMatrix2DArray from './TDOMMatrix2DArray.js';
import TDOMMatrix3DArray from './TDOMMatrix3DArray.js';
import IDOMMatrixJSON from './IDOMMatrixJSON.js';
import IDOMMatrixCompatibleObject from './IDOMMatrixCompatibleObject.js';
const DEFAULT_MATRIX_JSON: IDOMMatrixJSON = {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0,
m11: 1,
m12: 0,
m13: 0,
m14: 0,
m21: 0,
m22: 1,
m23: 0,
m24: 0,
m31: 0,
m32: 0,
m33: 1,
m34: 0,
m41: 0,
m42: 0,
m43: 0,
m44: 1,
is2D: true,
isIdentity: true
};
const TRANSFORM_REGEXP = /([a-zA-Z0-9]+)\(([^)]+)\)/gm;
const TRANSFORM_PARAMETER_SPLIT_REGEXP = /[\s,]+/;
/**
* DOM Matrix.
*
* Based on:
* - https://github.com/trusktr/geometry-interfaces
* - https://github.com/thednp/dommatrix/tree/master
* - https://github.com/jarek-foksa/geometry-polyfill/blob/master/geometry-polyfill.js
* - https://github.com/Automattic/node-canvas/blob/master/lib/DOMMatrix.js
*
*
* 3D Matrix:
* _________________________
* | m11 | m21 | m31 | m41 |
* | m12 | m22 | m32 | m42 |
* | m13 | m23 | m33 | m43 |
* | m14 | m24 | m34 | m44 |
* -------------------------̣
*
* 2D Matrix:
* _________________________
* | m11 | m21 | 0 | m41 |
* | m12 | m22 | 0 | m42 |
* | 0 | 0 | 1 | 0 |
* | 0 | 0 | 0 | 1 |
* -------------------------
*
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrixReadOnly
*/
export default class DOMMatrixReadOnly {
public [PropertySymbol.m11]: number = 1;
public [PropertySymbol.m12]: number = 0;
public [PropertySymbol.m13]: number = 0;
public [PropertySymbol.m14]: number = 0;
public [PropertySymbol.m21]: number = 0;
public [PropertySymbol.m22]: number = 1;
public [PropertySymbol.m23]: number = 0;
public [PropertySymbol.m24]: number = 0;
public [PropertySymbol.m31]: number = 0;
public [PropertySymbol.m32]: number = 0;
public [PropertySymbol.m33]: number = 1;
public [PropertySymbol.m34]: number = 0;
public [PropertySymbol.m41]: number = 0;
public [PropertySymbol.m42]: number = 0;
public [PropertySymbol.m43]: number = 0;
public [PropertySymbol.m44]: number = 1;
/**
* Constructor.
*
* @param init Init parameter.
*/
constructor(init?: TDOMMatrixInit) {
if (init) {
this[PropertySymbol.setMatrixValue](init);
}
}
/**
* Returns the `a` value of the matrix.
*/
public get a(): number {
return this[PropertySymbol.m11];
}
/**
* Returns the `b` value of the matrix.
*/
public get b(): number {
return this[PropertySymbol.m12];
}
/**
* Returns the `c` value of the matrix.
*/
public get c(): number {
return this[PropertySymbol.m21];
}
/**
* Returns the `d` value of the matrix.
*/
public get d(): number {
return this[PropertySymbol.m22];
}
/**
* Returns the `e` value of the matrix.
*/
public get e(): number {
return this[PropertySymbol.m41];
}
/**
* Returns the `f` value of the matrix.
*/
public get f(): number {
return this[PropertySymbol.m42];
}
/**
* Returns the `m11` value of the matrix.
*/
public get m11(): number {
return this[PropertySymbol.m11];
}
/**
* Returns the `m12` value of the matrix.
*/
public get m12(): number {
return this[PropertySymbol.m12];
}
/**
* Returns the `m13` value of the matrix.
*/
public get m13(): number {
return this[PropertySymbol.m13];
}
/**
* Returns the `m14` value of the matrix.
*/
public get m14(): number {
return this[PropertySymbol.m14];
}
/**
* Returns the `m21` value of the matrix.
*/
public get m21(): number {
return this[PropertySymbol.m21];
}
/**
* Returns the `m22` value of the matrix.
*/
public get m22(): number {
return this[PropertySymbol.m22];
}
/**
* Returns the `m23` value of the matrix.
*/
public get m23(): number {
return this[PropertySymbol.m23];
}
/**
* Returns the `m24` value of the matrix.
*/
public get m24(): number {
return this[PropertySymbol.m24];
}
/**
* Returns the `m31` value of the matrix.
*/
public get m31(): number {
return this[PropertySymbol.m31];
}
/**
* Returns the `m32` value of the matrix.
*/
public get m32(): number {
return this[PropertySymbol.m32];
}
/**
* Returns the `m33` value of the matrix.
*/
public get m33(): number {
return this[PropertySymbol.m33];
}
/**
* Returns the `m34` value of the matrix.
*/
public get m34(): number {
return this[PropertySymbol.m34];
}
/**
* Returns the `m41` value of the matrix.
*/
public get m41(): number {
return this[PropertySymbol.m41];
}
/**
* Returns the `m42` value of the matrix.
*/
public get m42(): number {
return this[PropertySymbol.m42];
}
/**
* Returns the `m43` value of the matrix.
*/
public get m43(): number {
return this[PropertySymbol.m43];
}
/**
* Returns the `m44` value of the matrix.
*/
public get m44(): number {
return this[PropertySymbol.m44];
}
/**
* A `Boolean` whose value is `true` if the matrix is the identity matrix.
*
* The identity matrix is one in which every value is 0 except those on the main diagonal from top-left to bottom-right corner (in other words, where the offsets in each direction are equal).
*
* @returns "true" if the matrix is the identity matrix.
*/
public get isIdentity(): boolean {
return (
this[PropertySymbol.m11] === 1 &&
this[PropertySymbol.m12] === 0 &&
this[PropertySymbol.m13] === 0 &&
this[PropertySymbol.m14] === 0 &&
this[PropertySymbol.m21] === 0 &&
this[PropertySymbol.m22] === 1 &&
this[PropertySymbol.m23] === 0 &&
this[PropertySymbol.m24] === 0 &&
this[PropertySymbol.m31] === 0 &&
this[PropertySymbol.m32] === 0 &&
this[PropertySymbol.m33] === 1 &&
this[PropertySymbol.m34] === 0 &&
this[PropertySymbol.m41] === 0 &&
this[PropertySymbol.m42] === 0 &&
this[PropertySymbol.m43] === 0 &&
this[PropertySymbol.m44] === 1
);
}
/**
* A `Boolean` flag whose value is `true` if the matrix is a 2D matrix and `false` if the matrix is 3D.
*
* @returns "true" if the matrix is a 2D matrix.
*/
public get is2D(): boolean {
return (
this[PropertySymbol.m31] === 0 &&
this[PropertySymbol.m32] === 0 &&
this[PropertySymbol.m33] === 1 &&
this[PropertySymbol.m34] === 0 &&
this[PropertySymbol.m43] === 0 &&
this[PropertySymbol.m44] === 1
);
}
/**
* Returns a *Float32Array* containing elements which comprise the matrix.
*
* The method can return either the 16 elements or the 6 elements depending on the value of the `is2D` parameter.
*
* @param [is2D] Set to `true` to return a 2D matrix.
* @returns An *Array* representation of the matrix.
*/
public toFloat32Array(is2D?: boolean): Float32Array {
return Float32Array.from(this[PropertySymbol.toArray](is2D));
}
/**
* Returns a *Float64Array* containing elements which comprise the matrix.
*
* The method can return either the 16 elements or the 6 elements depending on the value of the `is2D` parameter.
*
* @param [is2D] Set to `true` to return a 2D matrix.
* @returns An *Array* representation of the matrix
*/
public toFloat64Array(is2D?: boolean): Float64Array {
return Float64Array.from(this[PropertySymbol.toArray](is2D));
}
/**
* Returns a string representation of the matrix in `CSS` matrix syntax, using the appropriate `CSS` matrix notation.
*
* Examples:
* - `matrix3d(m11, m12, m13, m14, m21, ...)`
* - `matrix(a, b, c, d, e, f)`
*
* @returns A string representation of the matrix.
*/
public toString(): string {
const is2D = this.is2D;
const values = this[PropertySymbol.toArray](is2D).join(', ');
const type = is2D ? 'matrix' : 'matrix3d';
return `${type}(${values})`;
}
/**
* Returns an Object that can be serialized to a JSON string.
*
* The result can be used as a second parameter for the `fromMatrix` static method to load values into another matrix instance.
*
* @returns An *Object* with matrix values.
*/
public toJSON(): IDOMMatrixJSON {
const { is2D, isIdentity } = this;
return {
m11: this[PropertySymbol.m11],
m12: this[PropertySymbol.m12],
m13: this[PropertySymbol.m13],
m14: this[PropertySymbol.m14],
m21: this[PropertySymbol.m21],
m22: this[PropertySymbol.m22],
m23: this[PropertySymbol.m23],
m24: this[PropertySymbol.m24],
m31: this[PropertySymbol.m31],
m32: this[PropertySymbol.m32],
m33: this[PropertySymbol.m33],
m34: this[PropertySymbol.m34],
m41: this[PropertySymbol.m41],
m42: this[PropertySymbol.m42],
m43: this[PropertySymbol.m43],
m44: this[PropertySymbol.m44],
a: this[PropertySymbol.m11],
b: this[PropertySymbol.m12],
c: this[PropertySymbol.m21],
d: this[PropertySymbol.m22],
e: this[PropertySymbol.m41],
f: this[PropertySymbol.m42],
is2D,
isIdentity
};
}
/**
* Returns a new DOMMatrix instance which is the result of this matrix multiplied by the passed matrix.
*
* @param secondMatrix DOMMatrix
* @returns A new DOMMatrix object.
*/
public multiply(secondMatrix: IDOMMatrixCompatibleObject): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.multiplySelf](secondMatrix);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a translation matrix containing the passed values.
*
* @param [x=0] X component of the translation value.
* @param [y=0] Y component of the translation value.
* @param [z=0] Z component of the translation value.
* @returns The resulted matrix
*/
public translate(x: number = 0, y: number = 0, z: number = 0): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.translateSelf](x, y, z);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a scale 2D matrix containing the passed values.
*
* @param [scaleX] X-Axis scale.
* @param [scaleY] Y-Axis scale.
* @param [scaleZ] Z-Axis scale.
* @param [originX] X-Axis scale.
* @param [originY] Y-Axis scale.
* @param [originZ] Z-Axis scale.
* @returns The resulted matrix
*/
public scale(
scaleX?: number,
scaleY?: number,
scaleZ = 1,
originX = 0,
originY = 0,
originZ = 0
): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.scaleSelf](scaleX, scaleY, scaleZ, originX, originY, originZ);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a scale 3D matrix containing the passed values.
*
* @param [scale] The scale factor.
* @param [originX] X-Axis scale.
* @param [originY] Y-Axis scale.
* @param [originZ] Z-Axis scale.
* @returns The resulted matrix
*/
public scale3d(scale = 1, originX = 0, originY = 0, originZ = 0): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.scale3dSelf](scale, originX, originY, originZ);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a scale 3D matrix containing the passed values.
*
* @param [scaleX] X-Axis scale.
* @param [scaleY] Y-Axis scale.
* @returns The resulted matrix
*/
public scaleNonUniform(scaleX = 1, scaleY = 1): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.scaleNonUniformSelf](scaleX, scaleY);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a rotation matrix with the given axis and `angle`.
*
* @param [x] The X component of the axis vector.
* @param [y] The Y component of the axis vector.
* @param [z] The Z component of the axis vector.
* @param [angle] Angle of rotation about the axis vector, in degrees.
* @returns The resulted matrix
*/
public rotateAxisAngle(x = 0, y = 0, z = 0, angle = 0): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.rotateAxisAngleSelf](x, y, z, angle);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by each of 3 rotation matrices about the major axes, first X, then Y, then Z.
*
* @param [x] X component of the rotation, or Z if Y and Z are null.
* @param [y] Y component of the rotation value.
* @param [z] Z component of the rotation value.
* @returns The resulted matrix
*/
public rotate(x = 0, y?: number, z?: number): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.rotateSelf](x, y, z);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix post multiplied by a rotation matrix with the angle between the specified vector and (1, 0).
*
* @param [x] X-Axis skew.
* @param [y] Y-Axis skew.
*/
public rotateFromVector(x = 0, y = 0): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.rotateFromVectorSelf](x, y);
return matrix;
}
/**
* Returns a new DOMMatrix instance that specifies a skew transformation along X-Axis by the given angle.
*
* @param angle Angle amount in degrees to skew.
* @returns The resulted matrix
*/
public skewX(angle: number): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.skewXSelf](angle);
return matrix;
}
/**
* Returns a new DOMMatrix instance that specifies a skew transformation along Y-Axis by the given angle.
*
* @param angle Angle amount in degrees to skew.
* @returns The resulted matrix
*/
public skewY(angle: number): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.skewYSelf](angle);
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix flipped on X-axis.
*/
public flipX(): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.flipXSelf]();
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix flipped on Y-axis.
*/
public flipY(): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.flipYSelf]();
return matrix;
}
/**
* Returns a new DOMMatrix instance which is this matrix inversed.
*/
public inverse(): DOMMatrixReadOnly {
const matrix = new (<typeof DOMMatrixReadOnly>this.constructor)(this);
matrix[PropertySymbol.invertSelf]();
return matrix;
}
/**
* Returns a new DOMPoint instance with the vector transformed using the matrix.
*
* @param domPoint DOM point compatible object.
* @returns A new DOMPoint object.
*/
public transformPoint(domPoint: IDOMPointInit): DOMPoint {
const xPoint = domPoint.x ?? 0;
const yPoint = domPoint.y ?? 0;
const zPoint = domPoint.z ?? 0;
const wPoint = domPoint.w ?? 1;
const x =
this[PropertySymbol.m11] * xPoint +
this[PropertySymbol.m21] * yPoint +
this[PropertySymbol.m31] * zPoint +
this[PropertySymbol.m41] * wPoint;
const y =
this[PropertySymbol.m12] * xPoint +
this[PropertySymbol.m22] * yPoint +
this[PropertySymbol.m32] * zPoint +
this[PropertySymbol.m42] * wPoint;
const z =
this[PropertySymbol.m13] * xPoint +
this[PropertySymbol.m23] * yPoint +
this[PropertySymbol.m33] * zPoint +
this[PropertySymbol.m43] * wPoint;
const w =
this[PropertySymbol.m14] * xPoint +
this[PropertySymbol.m24] * yPoint +
this[PropertySymbol.m34] * zPoint +
this[PropertySymbol.m44] * wPoint;
return new DOMPoint(x, y, z, w);
}
/**
* The `setMatrixValue` method replaces the existing matrix with one computed in the browser (e.g.`matrix(1,0.25,-0.25,1,0,0)`).
*
* @param source A `DOMMatrix`, `Float32Array`, `Float64Array`, `Array`, or DOMMatrix compatible object to set the matrix values from.
*/
public [PropertySymbol.setMatrixValue](source?: TDOMMatrixInit): void {
let matrix: DOMMatrixReadOnly;
// String
if (typeof source === 'string' && source.length && source !== 'none') {
matrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromString](source);
}
// Array
else if (
Array.isArray(source) ||
source instanceof Float64Array ||
source instanceof Float32Array
) {
matrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray](source);
}
// DOMMatrixReadOnly or IDOMMatrixCompatibleObject
else if (typeof source === 'object') {
matrix = (<typeof DOMMatrixReadOnly>this.constructor).fromMatrix(
<IDOMMatrixCompatibleObject>source
);
}
this[PropertySymbol.m11] = matrix[PropertySymbol.m11];
this[PropertySymbol.m12] = matrix[PropertySymbol.m12];
this[PropertySymbol.m13] = matrix[PropertySymbol.m13];
this[PropertySymbol.m14] = matrix[PropertySymbol.m14];
this[PropertySymbol.m21] = matrix[PropertySymbol.m21];
this[PropertySymbol.m22] = matrix[PropertySymbol.m22];
this[PropertySymbol.m23] = matrix[PropertySymbol.m23];
this[PropertySymbol.m24] = matrix[PropertySymbol.m24];
this[PropertySymbol.m31] = matrix[PropertySymbol.m31];
this[PropertySymbol.m32] = matrix[PropertySymbol.m32];
this[PropertySymbol.m33] = matrix[PropertySymbol.m33];
this[PropertySymbol.m34] = matrix[PropertySymbol.m34];
this[PropertySymbol.m41] = matrix[PropertySymbol.m41];
this[PropertySymbol.m42] = matrix[PropertySymbol.m42];
this[PropertySymbol.m43] = matrix[PropertySymbol.m43];
this[PropertySymbol.m44] = matrix[PropertySymbol.m44];
}
/**
* Applies a multiply operation to the current matrix.
*
* @param matrix Second matrix.
*/
public [PropertySymbol.multiplySelf](matrix: IDOMMatrixCompatibleObject): void {
if (!(matrix instanceof DOMMatrixReadOnly)) {
if (matrix?.m11 === undefined && matrix?.a !== undefined) {
matrix = Object.assign({}, DEFAULT_MATRIX_JSON, matrix);
matrix.m11 = matrix.a;
matrix.m12 = matrix.b;
matrix.m21 = matrix.c;
matrix.m22 = matrix.d;
matrix.m41 = matrix.e;
matrix.m42 = matrix.f;
} else {
matrix = Object.assign({}, DEFAULT_MATRIX_JSON, matrix);
}
}
const m11 =
this[PropertySymbol.m11] * matrix.m11 +
this[PropertySymbol.m21] * matrix.m12 +
this[PropertySymbol.m31] * matrix.m13 +
this[PropertySymbol.m41] * matrix.m14;
const m21 =
this[PropertySymbol.m11] * matrix.m21 +
this[PropertySymbol.m21] * matrix.m22 +
this[PropertySymbol.m31] * matrix.m23 +
this[PropertySymbol.m41] * matrix.m24;
const m31 =
this[PropertySymbol.m11] * matrix.m31 +
this[PropertySymbol.m21] * matrix.m32 +
this[PropertySymbol.m31] * matrix.m33 +
this[PropertySymbol.m41] * matrix.m34;
const m41 =
this[PropertySymbol.m11] * matrix.m41 +
this[PropertySymbol.m21] * matrix.m42 +
this[PropertySymbol.m31] * matrix.m43 +
this[PropertySymbol.m41] * matrix.m44;
const m12 =
this[PropertySymbol.m12] * matrix.m11 +
this[PropertySymbol.m22] * matrix.m12 +
this[PropertySymbol.m32] * matrix.m13 +
this[PropertySymbol.m42] * matrix.m14;
const m22 =
this[PropertySymbol.m12] * matrix.m21 +
this[PropertySymbol.m22] * matrix.m22 +
this[PropertySymbol.m32] * matrix.m23 +
this[PropertySymbol.m42] * matrix.m24;
const m32 =
this[PropertySymbol.m12] * matrix.m31 +
this[PropertySymbol.m22] * matrix.m32 +
this[PropertySymbol.m32] * matrix.m33 +
this[PropertySymbol.m42] * matrix.m34;
const m42 =
this[PropertySymbol.m12] * matrix.m41 +
this[PropertySymbol.m22] * matrix.m42 +
this[PropertySymbol.m32] * matrix.m43 +
this[PropertySymbol.m42] * matrix.m44;
const m13 =
this[PropertySymbol.m13] * matrix.m11 +
this[PropertySymbol.m23] * matrix.m12 +
this[PropertySymbol.m33] * matrix.m13 +
this[PropertySymbol.m43] * matrix.m14;
const m23 =
this[PropertySymbol.m13] * matrix.m21 +
this[PropertySymbol.m23] * matrix.m22 +
this[PropertySymbol.m33] * matrix.m23 +
this[PropertySymbol.m43] * matrix.m24;
const m33 =
this[PropertySymbol.m13] * matrix.m31 +
this[PropertySymbol.m23] * matrix.m32 +
this[PropertySymbol.m33] * matrix.m33 +
this[PropertySymbol.m43] * matrix.m34;
const m43 =
this[PropertySymbol.m13] * matrix.m41 +
this[PropertySymbol.m23] * matrix.m42 +
this[PropertySymbol.m33] * matrix.m43 +
this[PropertySymbol.m43] * matrix.m44;
const m14 =
this[PropertySymbol.m14] * matrix.m11 +
this[PropertySymbol.m24] * matrix.m12 +
this[PropertySymbol.m34] * matrix.m13 +
this[PropertySymbol.m44] * matrix.m14;
const m24 =
this[PropertySymbol.m14] * matrix.m21 +
this[PropertySymbol.m24] * matrix.m22 +
this[PropertySymbol.m34] * matrix.m23 +
this[PropertySymbol.m44] * matrix.m24;
const m34 =
this[PropertySymbol.m14] * matrix.m31 +
this[PropertySymbol.m24] * matrix.m32 +
this[PropertySymbol.m34] * matrix.m33 +
this[PropertySymbol.m44] * matrix.m34;
const m44 =
this[PropertySymbol.m14] * matrix.m41 +
this[PropertySymbol.m24] * matrix.m42 +
this[PropertySymbol.m34] * matrix.m43 +
this[PropertySymbol.m44] * matrix.m44;
this[PropertySymbol.m11] = m11;
this[PropertySymbol.m12] = m12;
this[PropertySymbol.m13] = m13;
this[PropertySymbol.m14] = m14;
this[PropertySymbol.m21] = m21;
this[PropertySymbol.m22] = m22;
this[PropertySymbol.m23] = m23;
this[PropertySymbol.m24] = m24;
this[PropertySymbol.m31] = m31;
this[PropertySymbol.m32] = m32;
this[PropertySymbol.m33] = m33;
this[PropertySymbol.m34] = m34;
this[PropertySymbol.m41] = m41;
this[PropertySymbol.m42] = m42;
this[PropertySymbol.m43] = m43;
this[PropertySymbol.m44] = m44;
}
/**
* Applies translate to the matrix.
*
* This method is equivalent to the CSS `translate3d()` function.
*
* @see https://drafts.csswg.org/css-transforms-1/#TranslateDefined
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate3d
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param [x] X-Axis position.
* @param [y] Y-Axis position.
* @param [z] Z-Axis position.
*/
public [PropertySymbol.translateSelf](x: number = 0, y: number = 0, z: number = 0): void {
// prettier-ignore
const translationMatrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1,
]);
this[PropertySymbol.multiplySelf](translationMatrix);
}
/**
* Applies a scale to the matrix.
*
* This method is equivalent to the CSS `scale()` function.
*
* @see https://drafts.csswg.org/css-transforms-1/#ScaleDefined
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param [scaleX] X-Axis scale.
* @param [scaleY] Y-Axis scale.
* @param [scaleZ] Z-Axis scale.
* @param [originX] X-Axis scale.
* @param [originY] Y-Axis scale.
* @param [originZ] Z-Axis scale.
*/
public [PropertySymbol.scaleSelf](
scaleX?: number,
scaleY?: number,
scaleZ = 1,
originX = 0,
originY = 0,
originZ = 0
): void {
// If scaleY is missing, set scaleY to the value of scaleX.
scaleX = scaleX === undefined ? 1 : Number(scaleX);
scaleY = scaleY === undefined ? scaleX : Number(scaleY);
if (originX !== 0 || originY !== 0 || originZ !== 0) {
this[PropertySymbol.translateSelf](originX, originY, originZ);
}
if (scaleX !== 1 || scaleY !== 1 || scaleZ !== 1) {
// prettier-ignore
this[PropertySymbol.multiplySelf]((<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
scaleX, 0, 0, 0,
0, scaleY, 0, 0,
0, 0, scaleZ, 0,
0, 0, 0, 1,
]));
}
if (originX !== 0 || originY !== 0 || originZ !== 0) {
this[PropertySymbol.translateSelf](-originX, -originY, -originZ);
}
}
/**
* Applies a scale to the matrix.
*
* This method is equivalent to the CSS `scale()` function.
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale3d
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param [scale] The scale factor.
* @param [originX] X-Axis scale.
* @param [originY] Y-Axis scale.
* @param [originZ] Z-Axis scale.
*/
public [PropertySymbol.scale3dSelf](scale = 1, originX = 0, originY = 0, originZ = 0): void {
if (originX !== 0 || originY !== 0 || originZ !== 0) {
this[PropertySymbol.translateSelf](originX, originY, originZ);
}
if (scale !== 1) {
// prettier-ignore
this[PropertySymbol.multiplySelf]((<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, 0,
0, 0, 0, 1,
]));
}
if (originX !== 0 || originY !== 0 || originZ !== 0) {
this[PropertySymbol.translateSelf](-originX, -originY, -originZ);
}
}
/**
* Applies a scale to the matrix.
*
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param [scaleX] X-Axis scale.
* @param [scaleY] Y-Axis scale.
*/
public [PropertySymbol.scaleNonUniformSelf](scaleX = 1, scaleY = 1): void {
if (scaleX === 1 && scaleY === 1) {
return;
}
// prettier-ignore
this[PropertySymbol.multiplySelf]((<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
scaleX, 0, 0, 0,
0, scaleY, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
/**
* Applies a rotation to the matrix.
*
* This method is equivalent to the CSS `rotate3d()` function.
*
* @see https://drafts.fxtf.org/geometry/#dom-dommatrixreadonly-rotateaxisangleself
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d
* @param [x] X-Axis vector.
* @param [y] Y-Axis vector.
* @param [z] Z-Axis vector.
* @param [angle] Angle in degrees of the rotation.
*/
public [PropertySymbol.rotateAxisAngleSelf](x = 0, y = 0, z = 0, angle = 0): void {
x = Number(x);
y = Number(y);
z = Number(z);
angle = Number(angle);
if (isNaN(x) || isNaN(y) || isNaN(z) || isNaN(angle)) {
throw new TypeError(
`Failed to execute 'rotateAxisAngleSelf' on 'DOMMatrix': The arguments must be numbers.`
);
}
const length = Math.hypot(x, y, z);
if (length === 0) {
return;
}
if (length !== 1) {
x /= length;
y /= length;
z /= length;
}
// Degree to radian divided by 2
const alpha = -((angle * Math.PI) / 360);
const round = this.#round;
const sc = Math.sin(alpha) * Math.cos(alpha);
const sq = Math.sin(alpha) * Math.sin(alpha);
// We round it as the calculation is off by about 0.000000000000001, which causes the matrix to be different from the browser.
// The rounding doesn't solve the issue for all cases, it would be better to find a more accurate solution.
const m11 = round(1 - 2 * (y * y + z * z) * sq);
const m12 = round(2 * (x * y * sq + z * sc));
const m13 = round(2 * (x * z * sq - y * sc));
const m21 = round(2 * (x * y * sq - z * sc));
const m22 = round(1 - 2 * (x * x + z * z) * sq);
const m23 = round(2 * (y * z * sq + x * sc));
const m31 = round(2 * (x * z * sq + y * sc));
const m32 = round(2 * (y * z * sq - x * sc));
const m33 = round(1 - 2 * (x * x + y * y) * sq);
// prettier-ignore
const matrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
m11, m21, m31, 0,
m12, m22, m32, 0,
m13, m23, m33, 0,
0, 0, 0, 1
]);
this[PropertySymbol.multiplySelf](matrix);
}
/**
* Applies a rotation to the matrix.
*
* @see http://en.wikipedia.org/wiki/Rotation_matrix
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param [x] X-Axis rotation in degrees.
* @param [y] Y-Axis rotation in degrees.
* @param [z] Z-Axis rotation in degrees.
*/
public [PropertySymbol.rotateSelf](x = 0, y?: number, z?: number): void {
// If Y and Z are both missing, set Z to the value of X and set X and Y to 0.
if (y === undefined && z === undefined) {
z = x;
x = 0;
y = 0;
}
// If Y is still missing, set Y to 0.
if (y === undefined) {
y = 0;
}
// If Z is still missing, set Z to 0
if (z === undefined) {
z = 0;
}
x = Number(x);
y = Number(y);
z = Number(z);
if (isNaN(x) || isNaN(y) || isNaN(z)) {
throw new TypeError(
`Failed to execute 'rotateSelf' on 'DOMMatrix': The arguments must be numbers.`
);
}
if (z !== 0) {
this[PropertySymbol.rotateAxisAngleSelf](0, 0, 1, z);
}
if (y !== 0) {
this[PropertySymbol.rotateAxisAngleSelf](0, 1, 0, y);
}
if (x !== 0) {
this[PropertySymbol.rotateAxisAngleSelf](1, 0, 0, x);
}
}
/**
* Modifies the matrix by rotating it by the angle between the specified vector and (1, 0).
*
* @param x The X component of the axis vector.
* @param y The Y component of the axis vector.
*/
public [PropertySymbol.rotateFromVectorSelf](x = 0, y = 0): void {
if (x === 0 && y === 0) {
return;
}
this[PropertySymbol.rotateSelf]((Math.atan2(y, x) * 180) / Math.PI);
}
/**
* Applies a skew operation to the matrix on the X axis.
*
* This method is equivalent to the CSS `skewX()` function.
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewX
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param angle Angle in degrees.
*/
public [PropertySymbol.skewXSelf](angle: number): void {
const matrix = Object.assign({}, DEFAULT_MATRIX_JSON);
const value = Math.tan((angle * Math.PI) / 180);
matrix.m21 = value;
matrix.c = value;
this[PropertySymbol.multiplySelf](matrix);
}
/**
* Applies a skew operation to the matrix on the Y axis.
*
* This method is equivalent to the CSS `skewY()` function.
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewY
* @see https://www.w3.org/TR/css-transforms-1/#transform-functions
* @param angle Angle in degrees.
*/
public [PropertySymbol.skewYSelf](angle: number): void {
const matrix = Object.assign({}, DEFAULT_MATRIX_JSON);
const value = Math.tan((angle * Math.PI) / 180);
matrix.m12 = value;
matrix.b = value;
this[PropertySymbol.multiplySelf](matrix);
}
/**
* Applies a flip operation to the matrix on the X axis.
*/
public [PropertySymbol.flipXSelf](): void {
// prettier-ignore
const matrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
this[PropertySymbol.multiplySelf](matrix);
}
/**
* Applies a flip operation to the matrix on the Y axis.
*/
public [PropertySymbol.flipYSelf](): void {
// prettier-ignore
const matrix = (<typeof DOMMatrixReadOnly>this.constructor)[PropertySymbol.fromArray]([
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
this[PropertySymbol.multiplySelf](matrix);
}
/**
* Applies an inversion operation to the matrix.
*/
public [PropertySymbol.invertSelf](): void {
const m11 =
this[PropertySymbol.m22] * this[PropertySymbol.m33] * this[PropertySymbol.m44] -
this[PropertySymbol.m22] * this[PropertySymbol.m34] * this[PropertySymbol.m43] -
this[PropertySymbol.m32] * this[PropertySymbol.m23] * this[PropertySymbol.m44] +
this[PropertySymbol.m32] * this[PropertySymbol.m24] * this[PropertySymbol.m43] +
this[PropertySymbol.m42] * this[PropertySymbol.m23] * this[PropertySymbol.m34] -
this[PropertySymbol.m42] * this[PropertySymbol.m24] * this[PropertySymbol.m33];
const m12 =
-this[PropertySymbol.m12] * this[PropertySymbol.m33] * this[PropertySymbol.m44] +
this[PropertySymbol.m12] * this[PropertySymbol.m34] * this[PropertySymbol.m43] +
this[PropertySymbol.m32] * this[PropertySymbol.m13] * this[PropertySymbol.m44] -
this[PropertySymbol.m32] * this[PropertySymbol.m14] * this[PropertySymbol.m43] -
this[PropertySymbol.m42] * this[PropertySymbol.m13] * this[PropertySymbol.m34] +
this[PropertySymbol.m42] * this[PropertySymbol.m14] * this[PropertySymbol.m33];
const m13 =
this[PropertySymbol.m12] * this[PropertySymbol.m23] * this[PropertySymbol.m44] -
this[PropertySymbol.m12] * this[PropertySymbol.m24] * this[PropertySymbol.m43] -
this[PropertySymbol.m22] * this[PropertySymbol.m13] * this[PropertySymbol.m44] +
this[PropertySymbol.m22] * this[PropertySymbol.m14] * this[PropertySymbol.m43] +
this[PropertySymbol.m42] * this[PropertySymbol.m13] * this[PropertySymbol.m24] -
this[PropertySymbol.m42] * this[PropertySymbol.m14] * this[PropertySymbol.m23];
const m14 =
-this[PropertySymbol.m12] * this[PropertySymbol.m23] * this[PropertySymbol.m34] +
this[PropertySymbol.m12] * this[PropertySymbol.m24] * this[PropertySymbol.m33] +
this[PropertySymbol.m22] * this[PropertySymbol.m13] * this[PropertySymbol.m34] -
this[PropertySymbol.m22] * this[PropertySymbol.m14] * this[PropertySymbol.m33] -
this[PropertySymbol.m32] * this[PropertySymbol.m13] * this[PropertySymbol.m24] +
this[PropertySymbol.m32] * this[PropertySymbol.m14] * this[PropertySymbol.m23];
const det =
this[PropertySymbol.m11] * m11 +
this[PropertySymbol.m21] * m12 +
this[PropertySymbol.m31] * m13 +
this[PropertySymbol.m41] * m14;
// If the current matrix is not invertible set all attributes to NaN and set is 2D to false.
if (det === 0) {
this[PropertySymbol.m11] = NaN;
this[PropertySymbol.m12] = NaN;
this[PropertySymbol.m13] = NaN;
this[PropertySymbol.m14] = NaN;
this[PropertySymbol.m21] = NaN;
this[PropertySymbol.m22] = NaN;
this[PropertySymbol.m23] = NaN;
this[PropertySymbol.m24] = NaN;
this[PropertySymbol.m31] = NaN;
this[PropertySymbol.m32] = NaN;
this[PropertySymbol.m33] = NaN;
this[PropertySymbol.m34] = NaN;
this[PropertySymbol.m41] = NaN;
this[PropertySymbol.m42] = NaN;
this[PropertySymbol.m43] = NaN;
this[PropertySymbol.m44] = NaN;
return;
}
const m21 =
-this[PropertySymbol.m21] * this[PropertySymbol.m33] * this[PropertySymbol.m44] +
this[PropertySymbol.m21] * this[PropertySymbol.m34] * this[PropertySymbol.m43] +
this[PropertySymbol.m31] * this[PropertySymbol.m23] * this[PropertySymbol.m44] -
this[PropertySymbol.m31] * this[PropertySymbol.m24] * this[PropertySymbol.m43] -
this[PropertySymbol.m41] * this[PropertySymbol.m23] * this[PropertySymbol.m34] +
this[PropertySymbol.m41] * this[PropertySymbol.m24] * this[PropertySymbol.m33];
const m22 =
this[PropertySymbol.m11] * this[PropertySymbol.m33] * this[PropertySymbol.m44] -
this[PropertySymbol.m11] * this[PropertySymbol.m34] * this[PropertySymbol.m43] -
this[PropertySymbol.m31] * this[PropertySymbol.m13] * this[PropertySymbol.m44] +
this[PropertySymbol.m31] * this[PropertySymbol.m14] * this[PropertySymbol.m43] +
this[PropertySymbol.m41] * this[PropertySymbol.m13] * this[PropertySymbol.m34] -
this[PropertySymbol.m41] * this[PropertySymbol.m14] * this[PropertySymbol.m33];
const m23 =
-this[PropertySymbol.m11] * this[PropertySymbol.m23] * this[PropertySymbol.m44] +
this[PropertySymbol.m11] * this[PropertySymbol.m24] * this[PropertySymbol.m43] +
this[PropertySymbol.m21] * this[PropertySymbol.m13] * this[PropertySymbol.m44] -
this[PropertySymbol.m21] * this[PropertySymbol.m14] * this[PropertySymbol.m43] -
this[PropertySymbol.m41] * this[PropertySymbol.m13] * this[PropertySymbol.m24] +
this[PropertySymbol.m41] * this[PropertySymbol.m14] * this[PropertySymbol.m23];
const m24 =
this[PropertySymbol.m11] * this[PropertySymbol.m23] * this[PropertySymbol.m34] -
this[PropertySymbol.m11] * this[PropertySymbol.m24] * this[PropertySymbol.m33] -
this[PropertySymbol.m21] * this[PropertySymbol.m13] * this[PropertySymbol.m34] +
this[PropertySymbol.m21] * this[PropertySymbol.m14] * this[PropertySymbol.m33] +
this[PropertySymbol.m31] * this[PropertySymbol.m13] * this[PropertySymbol.m24] -
this[PropertySymbol.m31] * this[PropertySymbol.m14] * this[PropertySymbol.m23];
const m31 =
this[PropertySymbol.m21] * this[PropertySymbol.m32] * this[PropertySymbol.m44] -
this[PropertySymbol.m21] * this[PropertySymbol.m34] * this[PropertySymbol.m42] -
this[PropertySymbol.m31] * this[PropertySymbol.m22] * this[PropertySymbol.m44] +
this[PropertySymbol.m31] * this[PropertySymbol.m24] * this[PropertySymbol.m42] +
this[PropertySymbol.m41] * this[PropertySymbol.m22] * this[PropertySymbol.m34] -
this[PropertySymbol.m41] * this[PropertySymbol.m24] * this[PropertySymbol.m32];
const m32 =
-this[PropertySymbol.m11] * this[PropertySymbol.m32] * this[PropertySymbol.m44] +
this[PropertySymbol.m11] * this[PropertySymbol.m34] * this[PropertySymbol.m42] +
this[PropertySymbol.m31] * this[PropertySymbol.m12] * this[PropertySymbol.m44] -
this[PropertySymbol.m31] * this[PropertySymbol.m14] * this[PropertySymbol.m42] -
this[PropertySymbol.m41] * this[PropertySymbol.m12] * this[PropertySymbol.m34] +
this[PropertySymbol.m41] * this[PropertySymbol.m14] * this[PropertySymbol.m32];
const m33 =
this[PropertySymbol.m11] * this[PropertySymbol.m22] * this[PropertySymbol.m44] -
this[PropertySymbol.m11] * this[PropertySymbol.m24] * this[PropertySymbol.m42] -
this[PropertySymbol.m21] * this[PropertySymbol.m12] * this[PropertySymbol.m44] +
this[PropertySymbol.m21] * this[PropertySymbol.m14] * this[PropertySymbol.m42] +
this[PropertySymbol.m41] * this[PropertySymbol.m12] * this[PropertySymbol.m24] -
this[PropertySymbol.m41] * this[PropertySymbol.m14] * this[PropertySymbol.m22];
const m34 =
-this[PropertySymbol.m11] * this[PropertySymbol.m22] * this[PropertySymbol.m34] +
this[PropertySymbol.m11] * this[PropertySymbol.m24] * this[PropertySymbol.m32] +
this[PropertySymbol.m21] * this[PropertySymbol.m12] * this[PropertySymbol.m34] -
this[PropertySymbol.m21] * this[PropertySymbol.m14] * this[PropertySymbol.m32] -
this[PropertySymbol.m31] * this[PropertySymbol.m12] * this[PropertySymbol.m24] +
this[PropertySymbol.m31] * this[PropertySymbol.m14] * this[PropertySymbol.m22];
const m41 =
-this[PropertySymbol.m21] * this[PropertySymbol.m32] * this[PropertySymbol.m43] +
this[PropertySymbol.m21] * this[PropertySymbol.m33] * this[PropertySymbol.m42] +
this[PropertySymbol.m31] * this[PropertySymbol.m22] * this[PropertySymbol.m43] -
this[PropertySymbol.m31] * this[PropertySymbol.m23] * this[PropertySymbol.m42] -
this[PropertySymbol.m41] * this[PropertySymbol.m22] * this[PropertySymbol.m33] +
this[PropertySymbol.m41] * this[PropertySymbol.m23] * this[PropertySymbol.m32];
const m42 =
this[PropertySymbol.m11] * this[PropertySymbol.m32] * this[PropertySymbol.m43] -
this[PropertySymbol.m11] * this[PropertySymbol.m33] * this[PropertySymbol.m42] -
this[PropertySymbol.m31] * this[PropertySymbol.m12] * this[PropertySymbol.m43] +
this[PropertySymbol.m31] * this[PropertySymbol.m13] * this[PropertySymbol.m42] +
this[PropertySymbol.m41] * this[PropertySymbol.m12] * this[PropertySymbol.m33] -
this[PropertySymbol.m41] * this[PropertySymbol.m13] * this[PropertySymbol.m32];
const m43 =
-this[PropertySymbol.m11] * this[PropertySymbol.m22] * this[PropertySymbol.m43] +
this[PropertySymbol.m11] * this[PropertySymbol.m23] * this[PropertySymbol.m42] +
this[PropertySymbol.m21] * this[PropertySymbol.m12] * this[PropertySymbol.m43] -
this[PropertySymbol.m21] * this[PropertySymbol.m13] * this[PropertySymbol.m42] -
this[PropertySymbol.m41] * this[PropertySymbol.m12] * this[PropertySymbol.m23] +
this[PropertySymbol.m41] * this[PropertySymbol.m13] * this[PropertySymbol.m22];
const m44 =
this[PropertySymbol.m11] * this[PropertySymbol.m22] * this[PropertySymbol.m33] -
this[PropertySymbol.m11] * this[PropertySymbol.m23] * this[PropertySymbol.m32] -
this[PropertySymbol.m21] * this[PropertySymbol.m12] * this[PropertySymbol.m33] +
this[PropertySymbol.m21] * this[PropertySymbol.m13] * this[PropertySymbol.m32] +
this[PropertySymbol.m31] * this[PropertySymbol.m12] * this[PropertySymbol.m23] -
this[PropertySymbol.m31] * this[PropertySymbol.m13] * this[PropertySymbol.m22];
this[PropertySymbol.m11] = m11 / det || 0;
this[PropertySymbol.m12] = m12 / det || 0;
this[PropertySymbol.m13] = m13 / det || 0;
this[PropertySymbol.m14] = m14 / det || 0;
this[PropertySymbol.m21] = m21 / det || 0;
this[PropertySymbol.m22] = m22 / det || 0;
this[PropertySymbol.m23] = m23 / det || 0;
this[PropertySymbol.m24] = m24 / det || 0;
this[PropertySymbol.m31] = m31 / det || 0;
this[PropertySymbol.m32] = m32 / det || 0;
this[PropertySymbol.m33] = m33 / det || 0;
this[PropertySymbol.m34] = m34 / det || 0;
this[PropertySymbol.m41] = m41 / det || 0;
this[PropertySymbol.m42] = m42 / det || 0;
this[PropertySymbol.m43] = m43 / det || 0;
this[PropertySymbol.m44] = m44 / det || 0;
}
/**
* Returns an *Array* containing elements which comprise the matrix.
*
* @param matrix Matrix to convert.
* @param [is2D] If the matrix is 2D.
* @returns Array representation of the matrix.
*/
public [PropertySymbol.toArray](is2D: boolean = false): TDOMMatrix2DArray | TDOMMatrix3DArray {
if (is2D) {
return [
this[PropertySymbol.m11],
this[PropertySymbol.m12],
this[PropertySymbol.m21],
this[PropertySymbol.m22],
this[PropertySymbol.m41],
this[PropertySymbol.m42]
];
}
return [
this[PropertySymbol.m11],
this[PropertySymbol.m12],
this[PropertySymbol.m13],
this[PropertySymbol.m14],
this[PropertySymbol.m21],
this[PropertySymbol.m22],
this[PropertySymbol.m23],
this[PropertySymbol.m24],
this[PropertySymbol.m31],
this[PropertySymbol.m32],
this[PropertySymbol.m33],
this[PropertySymbol.m34],
this[PropertySymbol.m41],
this[PropertySymbol.m42],
this[PropertySymbol.m43],
this[PropertySymbol.m44]
];
}
/**
* Rounds the value to the given number of decimals.
*
* @param value The value to round.
* @param [decimals] The number of decimals to round to.
*/
#round(value: number, decimals: number = 1e15): number {
return Math.round(value * decimals) / decimals;
}
/**
* Returns a new `DOMMatrix` instance given an existing matrix.
*
* @param matrix Matrix.
*/
public static fromMatrix(matrix: IDOMMatrixCompatibleObject): DOMMatrixReadOnly {
if (!(matrix instanceof DOMMatrixReadOnly)) {
if (matrix?.m11 === undefined && matrix?.a !== undefined) {
matrix = Object.assign({}, DEFAULT_MATRIX_JSON, matrix);
matrix.m11 = matrix.a;
matrix.m12 = matrix.b;
matrix.m21 = matrix.c;
matrix.m22 = matrix.d;
matrix.m41 = matrix.e;
matrix.m42 = matrix.f;
} else {
matrix = Object.assign({}, DEFAULT_MATRIX_JSON, matrix);
}
}
return this[PropertySymbol.fromArray]([
matrix.m11,
matrix.m12,
matrix.m13,
matrix.m14,
matrix.m21,
matrix.m22,
matrix.m23,
matrix.m24,
matrix.m31,
matrix.m32,
matrix.m33,
matrix.m34,
matrix.m41,
matrix.m42,
matrix.m43,
matrix.m44
]);
}
/**
* Returns a new `DOMMatrix` instance given an array of 16/6 floating point values.
*
* @param array An `Array` to feed values from.
* @returns DOMMatrix instance.
*/
public static fromFloat32Array(array: Float32Array): DOMMatrixReadOnly {
return this[PropertySymbol.fromArray](array);
}
/**
* Returns a new `DOMMatrix` instance given an array of 16/6 floating point values.
*
* @param array An `Array` to feed values from.
* @returns DOMMatrix instance.
*/
public static fromFloat64Array(array: Float64Array): DOMMatrixReadOnly {
return this[PropertySymbol.fromArray](array);
}
/**
* Returns a new `DOMMatrix` instance given an array of 16/6 floating point values.
*
* Conditions:
* - If the array has six values, the result is a 2D matrix.
* - If the array has 16 values, the result is a 3D matrix.
* - Otherwise, a TypeError exception is thrown.
*
* @param array An `Array` to feed values from.
* @returns DOMMatrix instance.
*/
public static [PropertySymbol.fromArray](
array: any[] | Float32Array | Float64Array
): DOMMatrixReadOnly {
if (
!(array instanceof Float64Array || array instanceof Float32Array || Array.isArray(array)) ||
(array.length !== 6 && array.length !== 16)
) {
throw TypeError(
`Failed to execute 'fromArray' on '${this.name}': '${String(
array
)}' is not a compatible array.`
);
}
const matrix = new (<typeof DOMMatrixReadOnly>this)();
if (array.length === 16) {
const [m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44] =
array;
matrix[PropertySymbol.m11] = m11;
matrix[PropertySymbol.m12] = m12;
matrix[PropertySymbol.m13] = m13;
matrix[PropertySymbol.m14] = m14;
matrix[PropertySymbol.m21] = m21;
matrix[PropertySymbol.m22] = m22;
matrix[PropertySymbol.m23] = m23;
matrix[PropertySymbol.m24] = m24;
matrix[PropertySymbol.m31] = m31;
matrix[PropertySymbol.m32] = m32;
matrix[PropertySymbol.m33] = m33;
matrix[PropertySymbol.m34] = m34;
matrix[PropertySymbol.m41] = m41;
matrix[PropertySymbol.m42] = m42;
matrix[PropertySymbol.m43] = m43;
matrix[PropertySymbol.m44] = m44;
} else if (array.length === 6) {
const [m11, m12, m21, m22, m41, m42] = array;
matrix[PropertySymbol.m11] = m11;
matrix[PropertySymbol.m12] = m12;
matrix[PropertySymbol.m21] = m21;
matrix[PropertySymbol.m22] = m22;
matrix[PropertySymbol.m41] = m41;
matrix[PropertySymbol.m42] = m42;
}
return matrix;
}
/**
* Returns a new `DOMMatrix` instance from a DOM transform string.
*
* @param source valid CSS transform string syntax.
* @returns DOMMatrix instance.
*/
public static [PropertySymbol.fromString](source: string): DOMMatrixReadOnly {
if (typeof source !== 'string') {
throw TypeError(
`Failed to execute 'setMatrixValue' on '${this.name}': Expected '${String(
source
)}' to be a string.`
);
}
const domMatrix = new (<typeof DOMMatrixReadOnly>this)();
const regexp = new RegExp(TRANSFORM_REGEXP);
let match: RegExpMatchArray | null;
while ((match = regexp.exec(source))) {
const name = match[1];
const parameters: number[] = <number[]>(
(<unknown>match[2].split(TRANSFORM_PARAMETER_SPLIT_REGEXP))
);
for (let i = 0, max = parameters.length; i < max; i++) {
parameters[i] = this[PropertySymbol.getLength](<string>(<unknown>parameters[i]));
}
const [x, y, z, a] = parameters;
switch (name) {
case 'perspective':
if (!isNaN(x) && x !== 0 && y === undefined && z === undefined) {
domMatrix[PropertySymbol.m34] = -1 / x;
}
break;
case 'translate':
if (!isNaN(x) && z === undefined) {
domMatrix[PropertySymbol.translateSelf](x, y || 0, 0);
}
break;
case 'translate3d':
if (!isNaN(x) && !isNaN(y) && !isNaN(z)) {
domMatrix[PropertySymbol.translateSelf](x, y, z);
}
break;
case 'translateX':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.translateSelf](x);
}
break;
case 'translateY':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.translateSelf](0, x);
}
break;
case 'translateZ':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.translateSelf](0, 0, x);
}
break;
case 'matrix':
case 'matrix3d':
if (parameters.length === 6 || parameters.length === 16) {
domMatrix[PropertySymbol.setMatrixValue](this[PropertySymbol.fromArray](parameters));
}
break;
case 'rotate':
case 'rotateZ':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.rotateSelf](0, 0, x);
}
break;
case 'rotateX':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.rotateSelf](x, 0, 0);
}
break;
case 'rotateY':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.rotateSelf](0, x, 0);
}
case 'rotate3d':
if (!isNaN(x) && !isNaN(y) && !isNaN(z) && !isNaN(a)) {
domMatrix[PropertySymbol.rotateAxisAngleSelf](x, y, z, a);
}
break;
case 'scale':
if (!isNaN(x) && x !== 1 && z === undefined) {
domMatrix[PropertySymbol.scaleSelf](x, isNaN(y) ? x : y);
}
break;
case 'scale3d':
if (!isNaN(x) && !isNaN(y) && !isNaN(z)) {
domMatrix[PropertySymbol.scaleSelf](x, y, z);
}
break;
case 'scaleX':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.scaleSelf](x, 1, 1);
}
break;
case 'scaleY':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.scaleSelf](1, x, 1);
}
break;
case 'scaleZ':
if (!isNaN(x) && y === undefined && z === undefined) {
domMatrix[PropertySymbol.scaleSelf](1, 1, x);
}
break;
case 'skew':
if (!isNaN(x)) {
domMatrix[PropertySymbol.skewXSelf](x);
}
if (!isNaN(y)) {
domMatrix[PropertySymbol.skewYSelf](y);
}
break;
case 's