mirror of
https://github.com/1disk/edp445.git
synced 2024-08-14 22:47:02 +00:00
866 lines
19 KiB
JavaScript
866 lines
19 KiB
JavaScript
const { inspect } = require('util')
|
|
/*
|
|
* vendored in order to fix its dependence on the window global [cds 2020/08/04]
|
|
* otherwise unchanged from https://github.com/jarek-foksa/geometry-polyfill/tree/f36bbc8f4bc43539d980687904ce46c8e915543d
|
|
*/
|
|
|
|
// @info
|
|
// DOMPoint polyfill
|
|
// @src
|
|
// https://drafts.fxtf.org/geometry/#DOMPoint
|
|
// https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/geometry/dom_point_read_only.cc
|
|
class DOMPoint {
|
|
constructor(x = 0, y = 0, z = 0, w = 1) {
|
|
this.x = x
|
|
this.y = y
|
|
this.z = z
|
|
this.w = w
|
|
}
|
|
|
|
static fromPoint(otherPoint) {
|
|
return new DOMPoint(
|
|
otherPoint.x,
|
|
otherPoint.y,
|
|
otherPoint.z !== undefined ? otherPoint.z : 0,
|
|
otherPoint.w !== undefined ? otherPoint.w : 1,
|
|
)
|
|
}
|
|
|
|
matrixTransform(matrix) {
|
|
if ((matrix.is2D || matrix instanceof SVGMatrix) && this.z === 0 && this.w === 1) {
|
|
return new DOMPoint(
|
|
this.x * matrix.a + this.y * matrix.c + matrix.e,
|
|
this.x * matrix.b + this.y * matrix.d + matrix.f,
|
|
0,
|
|
1,
|
|
)
|
|
} else {
|
|
return new DOMPoint(
|
|
this.x * matrix.m11 + this.y * matrix.m21 + this.z * matrix.m31 + this.w * matrix.m41,
|
|
this.x * matrix.m12 + this.y * matrix.m22 + this.z * matrix.m32 + this.w * matrix.m42,
|
|
this.x * matrix.m13 + this.y * matrix.m23 + this.z * matrix.m33 + this.w * matrix.m43,
|
|
this.x * matrix.m14 + this.y * matrix.m24 + this.z * matrix.m34 + this.w * matrix.m44,
|
|
)
|
|
}
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
x: this.x,
|
|
y: this.y,
|
|
z: this.z,
|
|
w: this.w,
|
|
}
|
|
}
|
|
}
|
|
|
|
// @info
|
|
// DOMRect polyfill
|
|
// @src
|
|
// https://drafts.fxtf.org/geometry/#DOMRect
|
|
// https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/geometry/dom_rect_read_only.cc
|
|
|
|
class DOMRect {
|
|
constructor(x = 0, y = 0, width = 0, height = 0) {
|
|
this.x = x
|
|
this.y = y
|
|
this.width = width
|
|
this.height = height
|
|
}
|
|
|
|
static fromRect(otherRect) {
|
|
return new DOMRect(otherRect.x, otherRect.y, otherRect.width, otherRect.height)
|
|
}
|
|
|
|
get top() {
|
|
return this.y
|
|
}
|
|
|
|
get left() {
|
|
return this.x
|
|
}
|
|
|
|
get right() {
|
|
return this.x + this.width
|
|
}
|
|
|
|
get bottom() {
|
|
return this.y + this.height
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
x: this.x,
|
|
y: this.y,
|
|
width: this.width,
|
|
height: this.height,
|
|
top: this.top,
|
|
left: this.left,
|
|
right: this.right,
|
|
bottom: this.bottom,
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const propertyName of ['top', 'right', 'bottom', 'left']) {
|
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(DOMRect.prototype, propertyName)
|
|
propertyDescriptor.enumerable = true
|
|
Object.defineProperty(DOMRect.prototype, propertyName, propertyDescriptor)
|
|
}
|
|
|
|
// @info
|
|
// DOMMatrix polyfill (SVG 2)
|
|
// @src
|
|
// https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/geometry/dom_matrix_read_only.cc
|
|
// https://github.com/tocharomera/generativecanvas/blob/master/node-canvas/lib/DOMMatrix.js
|
|
|
|
const M11 = 0,
|
|
M12 = 1,
|
|
M13 = 2,
|
|
M14 = 3
|
|
const M21 = 4,
|
|
M22 = 5,
|
|
M23 = 6,
|
|
M24 = 7
|
|
const M31 = 8,
|
|
M32 = 9,
|
|
M33 = 10,
|
|
M34 = 11
|
|
const M41 = 12,
|
|
M42 = 13,
|
|
M43 = 14,
|
|
M44 = 15
|
|
|
|
const A = M11,
|
|
B = M12
|
|
const C = M21,
|
|
D = M22
|
|
const E = M41,
|
|
F = M42
|
|
|
|
const DEGREE_PER_RAD = 180 / Math.PI
|
|
const RAD_PER_DEGREE = Math.PI / 180
|
|
|
|
const VALUES = Symbol('values')
|
|
const IS_2D = Symbol('is2D')
|
|
|
|
function parseMatrix(init) {
|
|
let parsed = init.replace(/matrix\(/, '').split(/,/, 7)
|
|
|
|
if (parsed.length !== 6) {
|
|
throw new Error(`Failed to parse ${init}`)
|
|
}
|
|
|
|
parsed = parsed.map(parseFloat)
|
|
|
|
return [parsed[0], parsed[1], 0, 0, parsed[2], parsed[3], 0, 0, 0, 0, 1, 0, parsed[4], parsed[5], 0, 1]
|
|
}
|
|
|
|
function parseMatrix3d(init) {
|
|
const parsed = init.replace(/matrix3d\(/, '').split(/,/, 17)
|
|
|
|
if (parsed.length !== 16) {
|
|
throw new Error(`Failed to parse ${init}`)
|
|
}
|
|
|
|
return parsed.map(parseFloat)
|
|
}
|
|
|
|
function parseTransform(tform) {
|
|
const type = tform.split(/\(/, 1)[0]
|
|
|
|
if (type === 'matrix') {
|
|
return parseMatrix(tform)
|
|
} else if (type === 'matrix3d') {
|
|
return parseMatrix3d(tform)
|
|
} else {
|
|
throw new Error(`${type} parsing not implemented`)
|
|
}
|
|
}
|
|
|
|
const setNumber2D = (receiver, index, value) => {
|
|
if (typeof value !== 'number') {
|
|
throw new TypeError('Expected number')
|
|
}
|
|
|
|
receiver[VALUES][index] = value
|
|
}
|
|
|
|
const setNumber3D = (receiver, index, value) => {
|
|
if (typeof value !== 'number') {
|
|
throw new TypeError('Expected number')
|
|
}
|
|
|
|
if (index === M33 || index === M44) {
|
|
if (value !== 1) {
|
|
receiver[IS_2D] = false
|
|
}
|
|
} else if (value !== 0) {
|
|
receiver[IS_2D] = false
|
|
}
|
|
|
|
receiver[VALUES][index] = value
|
|
}
|
|
|
|
const newInstance = (values) => {
|
|
const instance = Object.create(DOMMatrix.prototype)
|
|
instance.constructor = DOMMatrix
|
|
instance[IS_2D] = true
|
|
instance[VALUES] = values
|
|
|
|
return instance
|
|
}
|
|
|
|
const multiply = (first, second) => {
|
|
const dest = new Float64Array(16)
|
|
|
|
for (let i = 0; i < 4; i++) {
|
|
for (let j = 0; j < 4; j++) {
|
|
let sum = 0
|
|
|
|
for (let k = 0; k < 4; k++) {
|
|
sum += first[i * 4 + k] * second[k * 4 + j]
|
|
}
|
|
|
|
dest[i * 4 + j] = sum
|
|
}
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
class DOMMatrix {
|
|
get m11() {
|
|
return this[VALUES][M11]
|
|
}
|
|
set m11(value) {
|
|
setNumber2D(this, M11, value)
|
|
}
|
|
get m12() {
|
|
return this[VALUES][M12]
|
|
}
|
|
set m12(value) {
|
|
setNumber2D(this, M12, value)
|
|
}
|
|
get m13() {
|
|
return this[VALUES][M13]
|
|
}
|
|
set m13(value) {
|
|
setNumber3D(this, M13, value)
|
|
}
|
|
get m14() {
|
|
return this[VALUES][M14]
|
|
}
|
|
set m14(value) {
|
|
setNumber3D(this, M14, value)
|
|
}
|
|
get m21() {
|
|
return this[VALUES][M21]
|
|
}
|
|
set m21(value) {
|
|
setNumber2D(this, M21, value)
|
|
}
|
|
get m22() {
|
|
return this[VALUES][M22]
|
|
}
|
|
set m22(value) {
|
|
setNumber2D(this, M22, value)
|
|
}
|
|
get m23() {
|
|
return this[VALUES][M23]
|
|
}
|
|
set m23(value) {
|
|
setNumber3D(this, M23, value)
|
|
}
|
|
get m24() {
|
|
return this[VALUES][M24]
|
|
}
|
|
set m24(value) {
|
|
setNumber3D(this, M24, value)
|
|
}
|
|
get m31() {
|
|
return this[VALUES][M31]
|
|
}
|
|
set m31(value) {
|
|
setNumber3D(this, M31, value)
|
|
}
|
|
get m32() {
|
|
return this[VALUES][M32]
|
|
}
|
|
set m32(value) {
|
|
setNumber3D(this, M32, value)
|
|
}
|
|
get m33() {
|
|
return this[VALUES][M33]
|
|
}
|
|
set m33(value) {
|
|
setNumber3D(this, M33, value)
|
|
}
|
|
get m34() {
|
|
return this[VALUES][M34]
|
|
}
|
|
set m34(value) {
|
|
setNumber3D(this, M34, value)
|
|
}
|
|
get m41() {
|
|
return this[VALUES][M41]
|
|
}
|
|
set m41(value) {
|
|
setNumber2D(this, M41, value)
|
|
}
|
|
get m42() {
|
|
return this[VALUES][M42]
|
|
}
|
|
set m42(value) {
|
|
setNumber2D(this, M42, value)
|
|
}
|
|
get m43() {
|
|
return this[VALUES][M43]
|
|
}
|
|
set m43(value) {
|
|
setNumber3D(this, M43, value)
|
|
}
|
|
get m44() {
|
|
return this[VALUES][M44]
|
|
}
|
|
set m44(value) {
|
|
setNumber3D(this, M44, value)
|
|
}
|
|
|
|
get a() {
|
|
return this[VALUES][A]
|
|
}
|
|
set a(value) {
|
|
setNumber2D(this, A, value)
|
|
}
|
|
get b() {
|
|
return this[VALUES][B]
|
|
}
|
|
set b(value) {
|
|
setNumber2D(this, B, value)
|
|
}
|
|
get c() {
|
|
return this[VALUES][C]
|
|
}
|
|
set c(value) {
|
|
setNumber2D(this, C, value)
|
|
}
|
|
get d() {
|
|
return this[VALUES][D]
|
|
}
|
|
set d(value) {
|
|
setNumber2D(this, D, value)
|
|
}
|
|
get e() {
|
|
return this[VALUES][E]
|
|
}
|
|
set e(value) {
|
|
setNumber2D(this, E, value)
|
|
}
|
|
get f() {
|
|
return this[VALUES][F]
|
|
}
|
|
set f(value) {
|
|
setNumber2D(this, F, value)
|
|
}
|
|
|
|
get is2D() {
|
|
return this[IS_2D]
|
|
}
|
|
|
|
get isIdentity() {
|
|
const values = this[VALUES]
|
|
|
|
return (
|
|
values[M11] === 1 &&
|
|
values[M12] === 0 &&
|
|
values[M13] === 0 &&
|
|
values[M14] === 0 &&
|
|
values[M21] === 0 &&
|
|
values[M22] === 1 &&
|
|
values[M23] === 0 &&
|
|
values[M24] === 0 &&
|
|
values[M31] === 0 &&
|
|
values[M32] === 0 &&
|
|
values[M33] === 1 &&
|
|
values[M34] === 0 &&
|
|
values[M41] === 0 &&
|
|
values[M42] === 0 &&
|
|
values[M43] === 0 &&
|
|
values[M44] === 1
|
|
)
|
|
}
|
|
|
|
static fromMatrix(init) {
|
|
if (init instanceof DOMMatrix) {
|
|
return new DOMMatrix(init[VALUES])
|
|
} else if (init instanceof SVGMatrix) {
|
|
return new DOMMatrix([init.a, init.b, init.c, init.d, init.e, init.f])
|
|
} else {
|
|
throw new TypeError('Expected DOMMatrix')
|
|
}
|
|
}
|
|
|
|
static fromFloat32Array(init) {
|
|
if (!(init instanceof Float32Array)) throw new TypeError('Expected Float32Array')
|
|
return new DOMMatrix(init)
|
|
}
|
|
|
|
static fromFloat64Array(init) {
|
|
if (!(init instanceof Float64Array)) throw new TypeError('Expected Float64Array')
|
|
return new DOMMatrix(init)
|
|
}
|
|
|
|
// @type
|
|
// (Float64Array) => void
|
|
constructor(init) {
|
|
this[IS_2D] = true
|
|
|
|
this[VALUES] = new Float64Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
|
|
|
|
// Parse CSS transformList
|
|
if (typeof init === 'string') {
|
|
if (init === '') {
|
|
return
|
|
} else {
|
|
const tforms = init.split(/\)\s+/, 20).map(parseTransform)
|
|
|
|
if (tforms.length === 0) {
|
|
return
|
|
}
|
|
|
|
init = tforms[0]
|
|
|
|
for (let i = 1; i < tforms.length; i++) {
|
|
init = multiply(tforms[i], init)
|
|
}
|
|
}
|
|
}
|
|
|
|
let i = 0
|
|
|
|
if (init && init.length === 6) {
|
|
setNumber2D(this, A, init[i++])
|
|
setNumber2D(this, B, init[i++])
|
|
setNumber2D(this, C, init[i++])
|
|
setNumber2D(this, D, init[i++])
|
|
setNumber2D(this, E, init[i++])
|
|
setNumber2D(this, F, init[i++])
|
|
} else if (init && init.length === 16) {
|
|
setNumber2D(this, M11, init[i++])
|
|
setNumber2D(this, M12, init[i++])
|
|
setNumber3D(this, M13, init[i++])
|
|
setNumber3D(this, M14, init[i++])
|
|
setNumber2D(this, M21, init[i++])
|
|
setNumber2D(this, M22, init[i++])
|
|
setNumber3D(this, M23, init[i++])
|
|
setNumber3D(this, M24, init[i++])
|
|
setNumber3D(this, M31, init[i++])
|
|
setNumber3D(this, M32, init[i++])
|
|
setNumber3D(this, M33, init[i++])
|
|
setNumber3D(this, M34, init[i++])
|
|
setNumber2D(this, M41, init[i++])
|
|
setNumber2D(this, M42, init[i++])
|
|
setNumber3D(this, M43, init[i++])
|
|
setNumber3D(this, M44, init[i])
|
|
} else if (init !== undefined) {
|
|
throw new TypeError('Expected string or array.')
|
|
}
|
|
}
|
|
|
|
dump() {
|
|
const mat = this[VALUES]
|
|
console.info([mat.slice(0, 4), mat.slice(4, 8), mat.slice(8, 12), mat.slice(12, 16)])
|
|
}
|
|
|
|
[inspect.custom](depth, options) {
|
|
if (depth < 0) return '[DOMMatrix]'
|
|
|
|
const { a, b, c, d, e, f, is2D, isIdentity } = this
|
|
if (this.is2D) {
|
|
return `DOMMatrix ${inspect({ a, b, c, d, e, f, is2D, isIdentity }, { colors: true })}`
|
|
} else {
|
|
const { m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44, is2D, isIdentity } = this
|
|
return `DOMMatrix ${inspect(
|
|
{
|
|
a,
|
|
b,
|
|
c,
|
|
d,
|
|
e,
|
|
f,
|
|
m11,
|
|
m12,
|
|
m13,
|
|
m14,
|
|
m21,
|
|
m22,
|
|
m23,
|
|
m24,
|
|
m31,
|
|
m32,
|
|
m33,
|
|
m34,
|
|
m41,
|
|
m42,
|
|
m43,
|
|
m44,
|
|
is2D,
|
|
isIdentity,
|
|
},
|
|
{ colors: true },
|
|
)}`
|
|
}
|
|
}
|
|
|
|
multiply(other) {
|
|
return newInstance(this[VALUES]).multiplySelf(other)
|
|
}
|
|
|
|
multiplySelf(other) {
|
|
this[VALUES] = multiply(other[VALUES], this[VALUES])
|
|
|
|
if (!other.is2D) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
preMultiplySelf(other) {
|
|
this[VALUES] = multiply(this[VALUES], other[VALUES])
|
|
|
|
if (!other.is2D) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
translate(tx, ty, tz) {
|
|
return newInstance(this[VALUES]).translateSelf(tx, ty, tz)
|
|
}
|
|
|
|
translateSelf(tx = 0, ty = 0, tz = 0) {
|
|
this[VALUES] = multiply([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1], this[VALUES])
|
|
|
|
if (tz !== 0) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
scale(scaleX, scaleY, scaleZ, originX, originY, originZ) {
|
|
return newInstance(this[VALUES]).scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)
|
|
}
|
|
|
|
scale3d(scale, originX, originY, originZ) {
|
|
return newInstance(this[VALUES]).scale3dSelf(scale, originX, originY, originZ)
|
|
}
|
|
|
|
scale3dSelf(scale, originX, originY, originZ) {
|
|
return this.scaleSelf(scale, scale, scale, originX, originY, originZ)
|
|
}
|
|
|
|
scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ) {
|
|
// Not redundant with translate's checks because we need to negate the values later.
|
|
if (typeof originX !== 'number') originX = 0
|
|
if (typeof originY !== 'number') originY = 0
|
|
if (typeof originZ !== 'number') originZ = 0
|
|
|
|
this.translateSelf(originX, originY, originZ)
|
|
|
|
if (typeof scaleX !== 'number') scaleX = 1
|
|
if (typeof scaleY !== 'number') scaleY = scaleX
|
|
if (typeof scaleZ !== 'number') scaleZ = 1
|
|
|
|
this[VALUES] = multiply([scaleX, 0, 0, 0, 0, scaleY, 0, 0, 0, 0, scaleZ, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
this.translateSelf(-originX, -originY, -originZ)
|
|
|
|
if (scaleZ !== 1 || originZ !== 0) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
rotateFromVector(x, y) {
|
|
return newInstance(this[VALUES]).rotateFromVectorSelf(x, y)
|
|
}
|
|
|
|
rotateFromVectorSelf(x = 0, y = 0) {
|
|
const theta = x === 0 && y === 0 ? 0 : Math.atan2(y, x) * DEGREE_PER_RAD
|
|
return this.rotateSelf(theta)
|
|
}
|
|
|
|
rotate(rotX, rotY, rotZ) {
|
|
return newInstance(this[VALUES]).rotateSelf(rotX, rotY, rotZ)
|
|
}
|
|
|
|
rotateSelf(rotX, rotY, rotZ) {
|
|
if (rotY === undefined && rotZ === undefined) {
|
|
rotZ = rotX
|
|
rotX = rotY = 0
|
|
}
|
|
|
|
if (typeof rotY !== 'number') rotY = 0
|
|
if (typeof rotZ !== 'number') rotZ = 0
|
|
|
|
if (rotX !== 0 || rotY !== 0) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
rotX *= RAD_PER_DEGREE
|
|
rotY *= RAD_PER_DEGREE
|
|
rotZ *= RAD_PER_DEGREE
|
|
|
|
let c = Math.cos(rotZ)
|
|
let s = Math.sin(rotZ)
|
|
|
|
this[VALUES] = multiply([c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
c = Math.cos(rotY)
|
|
s = Math.sin(rotY)
|
|
|
|
this[VALUES] = multiply([c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
c = Math.cos(rotX)
|
|
s = Math.sin(rotX)
|
|
|
|
this[VALUES] = multiply([1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
return this
|
|
}
|
|
|
|
rotateAxisAngle(x, y, z, angle) {
|
|
return newInstance(this[VALUES]).rotateAxisAngleSelf(x, y, z, angle)
|
|
}
|
|
|
|
rotateAxisAngleSelf(x = 0, y = 0, z = 0, angle = 0) {
|
|
const length = Math.sqrt(x * x + y * y + z * z)
|
|
|
|
if (length === 0) {
|
|
return this
|
|
}
|
|
|
|
if (length !== 1) {
|
|
x /= length
|
|
y /= length
|
|
z /= length
|
|
}
|
|
|
|
angle *= RAD_PER_DEGREE
|
|
|
|
const c = Math.cos(angle)
|
|
const s = Math.sin(angle)
|
|
const t = 1 - c
|
|
const tx = t * x
|
|
const ty = t * y
|
|
|
|
this[VALUES] = multiply(
|
|
[
|
|
tx * x + c,
|
|
tx * y + s * z,
|
|
tx * z - s * y,
|
|
0,
|
|
tx * y - s * z,
|
|
ty * y + c,
|
|
ty * z + s * x,
|
|
0,
|
|
tx * z + s * y,
|
|
ty * z - s * x,
|
|
t * z * z + c,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
],
|
|
this[VALUES],
|
|
)
|
|
|
|
if (x !== 0 || y !== 0) {
|
|
this[IS_2D] = false
|
|
}
|
|
|
|
return this
|
|
}
|
|
|
|
skewX(sx) {
|
|
return newInstance(this[VALUES]).skewXSelf(sx)
|
|
}
|
|
|
|
skewXSelf(sx) {
|
|
if (typeof sx !== 'number') {
|
|
return this
|
|
}
|
|
|
|
const t = Math.tan(sx * RAD_PER_DEGREE)
|
|
|
|
this[VALUES] = multiply([1, 0, 0, 0, t, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
return this
|
|
}
|
|
|
|
skewY(sy) {
|
|
return newInstance(this[VALUES]).skewYSelf(sy)
|
|
}
|
|
|
|
skewYSelf(sy) {
|
|
if (typeof sy !== 'number') {
|
|
return this
|
|
}
|
|
|
|
const t = Math.tan(sy * RAD_PER_DEGREE)
|
|
|
|
this[VALUES] = multiply([1, t, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], this[VALUES])
|
|
|
|
return this
|
|
}
|
|
|
|
flipX() {
|
|
return newInstance(multiply([-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], this[VALUES]))
|
|
}
|
|
|
|
flipY() {
|
|
return newInstance(multiply([1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], this[VALUES]))
|
|
}
|
|
|
|
inverse() {
|
|
return newInstance(this[VALUES]).invertSelf()
|
|
}
|
|
|
|
invertSelf() {
|
|
if (this[IS_2D]) {
|
|
const det = this[VALUES][A] * this[VALUES][D] - this[VALUES][B] * this[VALUES][C]
|
|
|
|
// Invertable
|
|
if (det !== 0) {
|
|
const result = new DOMMatrix()
|
|
|
|
result.a = this[VALUES][D] / det
|
|
result.b = -this[VALUES][B] / det
|
|
result.c = -this[VALUES][C] / det
|
|
result.d = this[VALUES][A] / det
|
|
result.e = (this[VALUES][C] * this[VALUES][F] - this[VALUES][D] * this[VALUES][E]) / det
|
|
result.f = (this[VALUES][B] * this[VALUES][E] - this[VALUES][A] * this[VALUES][F]) / det
|
|
|
|
return result
|
|
}
|
|
|
|
// Not invertable
|
|
else {
|
|
this[IS_2D] = false
|
|
|
|
this[VALUES] = [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN]
|
|
}
|
|
} else {
|
|
throw new Error('3D matrix inversion is not implemented.')
|
|
}
|
|
}
|
|
|
|
setMatrixValue(transformList) {
|
|
const temp = new DOMMatrix(transformList)
|
|
|
|
this[VALUES] = temp[VALUES]
|
|
this[IS_2D] = temp[IS_2D]
|
|
|
|
return this
|
|
}
|
|
|
|
transformPoint(point) {
|
|
const x = point.x
|
|
const y = point.y
|
|
const z = point.z
|
|
const w = point.w
|
|
|
|
const values = this[VALUES]
|
|
|
|
const nx = values[M11] * x + values[M21] * y + values[M31] * z + values[M41] * w
|
|
const ny = values[M12] * x + values[M22] * y + values[M32] * z + values[M42] * w
|
|
const nz = values[M13] * x + values[M23] * y + values[M33] * z + values[M43] * w
|
|
const nw = values[M14] * x + values[M24] * y + values[M34] * z + values[M44] * w
|
|
|
|
return new DOMPoint(nx, ny, nz, nw)
|
|
}
|
|
|
|
toFloat32Array() {
|
|
return Float32Array.from(this[VALUES])
|
|
}
|
|
|
|
toFloat64Array() {
|
|
return this[VALUES].slice(0)
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
a: this.a,
|
|
b: this.b,
|
|
c: this.c,
|
|
d: this.d,
|
|
e: this.e,
|
|
f: this.f,
|
|
m11: this.m11,
|
|
m12: this.m12,
|
|
m13: this.m13,
|
|
m14: this.m14,
|
|
m21: this.m21,
|
|
m22: this.m22,
|
|
m23: this.m23,
|
|
m24: this.m24,
|
|
m31: this.m31,
|
|
m32: this.m32,
|
|
m33: this.m33,
|
|
m34: this.m34,
|
|
m41: this.m41,
|
|
m42: this.m42,
|
|
m43: this.m43,
|
|
m44: this.m44,
|
|
is2D: this.is2D,
|
|
isIdentity: this.isIdentity,
|
|
}
|
|
}
|
|
|
|
toString() {
|
|
if (this.is2D) {
|
|
return `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`
|
|
} else {
|
|
return `matrix3d(${this[VALUES].join(', ')})`
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const propertyName of [
|
|
'a',
|
|
'b',
|
|
'c',
|
|
'd',
|
|
'e',
|
|
'f',
|
|
'm11',
|
|
'm12',
|
|
'm13',
|
|
'm14',
|
|
'm21',
|
|
'm22',
|
|
'm23',
|
|
'm24',
|
|
'm31',
|
|
'm32',
|
|
'm33',
|
|
'm34',
|
|
'm41',
|
|
'm42',
|
|
'm43',
|
|
'm44',
|
|
'is2D',
|
|
'isIdentity',
|
|
]) {
|
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(DOMMatrix.prototype, propertyName)
|
|
propertyDescriptor.enumerable = true
|
|
Object.defineProperty(DOMMatrix.prototype, propertyName, propertyDescriptor)
|
|
}
|
|
|
|
module.exports = { DOMPoint, DOMMatrix, DOMRect }
|