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 }
 |