folk-canvas/lib/DOMTransform.ts

155 lines
3.4 KiB
TypeScript

import { Point } from './types';
interface DOMTransformInit {
x?: number;
y?: number;
rotationX?: number;
rotationY?: number;
rotationZ?: number;
}
/**
* Represents a 2D transform with position and rotation,
* capable of transforming points between local and parent coordinate spaces.
*/
export class DOMTransform {
// Private properties for position and rotation
#x: number;
#y: number;
#rotationX: number;
#rotationY: number;
#rotationZ: number;
// Internal transformation matrices
#transformMatrix: DOMMatrix;
#inverseMatrix: DOMMatrix;
constructor(init: DOMTransformInit = {}) {
this.#x = init.x ?? 0;
this.#y = init.y ?? 0;
this.#rotationX = init.rotationX ?? 0;
this.#rotationY = init.rotationY ?? 0;
this.#rotationZ = init.rotationZ ?? 0;
// Initialize with identity matrices
this.#transformMatrix = new DOMMatrix();
this.#inverseMatrix = new DOMMatrix();
this.#updateMatrices();
}
get x(): number {
return this.#x;
}
set x(value: number) {
this.#x = value;
this.#updateMatrices();
}
get y(): number {
return this.#y;
}
set y(value: number) {
this.#y = value;
this.#updateMatrices();
}
get rotationX(): number {
return this.#rotationX;
}
set rotationX(value: number) {
this.#rotationX = value;
this.#updateMatrices();
}
get rotationY(): number {
return this.#rotationY;
}
set rotationY(value: number) {
this.#rotationY = value;
this.#updateMatrices();
}
get rotationZ(): number {
return this.#rotationZ;
}
set rotationZ(value: number) {
this.#rotationZ = value;
this.#updateMatrices();
}
get rotation(): number {
return this.#rotationZ;
}
set rotation(value: number) {
this.#rotationZ = value;
this.#updateMatrices();
}
// Matrix accessors
get matrix(): DOMMatrix {
return this.#transformMatrix;
}
get inverse(): DOMMatrix {
return this.#inverseMatrix;
}
/**
* Converts a point from parent space to local space.
*/
toPoint(point: Point): Point {
// Transform using DOMMatrix directly without DOMPoint
const { a, b, c, d, e, f } = this.#inverseMatrix;
return {
x: point.x * a + point.y * c + e,
y: point.x * b + point.y * d + f,
};
}
/**
* Converts a point from local space to parent space.
*/
toInversePoint(point: Point): Point {
const { a, b, c, d, e, f } = this.#transformMatrix;
return {
x: point.x * a + point.y * c + e,
y: point.x * b + point.y * d + f,
};
}
/**
* Generates a CSS transform string representing the transformation.
*/
toCssString(): string {
return this.#transformMatrix.toString();
}
/**
* Converts the transform's properties to a JSON serializable object.
*/
toJSON() {
return {
x: this.x,
y: this.y,
rotationX: this.rotationX,
rotationY: this.rotationY,
rotationZ: this.rotationZ,
};
}
/**
* Updates the transformation matrices based on the current position and rotation.
*/
#updateMatrices() {
// Create a fresh identity matrix
this.#transformMatrix = new DOMMatrix()
.translate(this.#x, this.#y)
.rotate(0, 0, this.#rotationZ)
.rotate(0, this.#rotationY, 0)
.rotate(this.#rotationX, 0, 0);
// DOMMatrix has built-in inverse calculation
this.#inverseMatrix = this.#transformMatrix.inverse();
}
}