new TransformDOMRect

This commit is contained in:
Orion Reed 2024-12-06 17:07:38 -05:00
parent ba2b819ea4
commit 9817a9fd2b
1 changed files with 164 additions and 101 deletions

View File

@ -1,5 +1,5 @@
import { Point } from './types'; import { Point } from './types';
import { Vector } from './Vector'; import { Matrix } from './Matrix';
interface TransformDOMRectInit { interface TransformDOMRectInit {
height?: number; height?: number;
@ -10,52 +10,73 @@ interface TransformDOMRectInit {
} }
export class TransformDOMRect implements DOMRect { export class TransformDOMRect implements DOMRect {
#other: TransformDOMRectInit; // Private properties
private _x: number;
private _y: number;
private _width: number;
private _height: number;
private _rotation: number;
constructor(other: TransformDOMRectInit = {}) { // Internal matrices
this.#other = other; #transformMatrix: Matrix;
#inverseMatrix: Matrix;
constructor(init: TransformDOMRectInit = {}) {
this._x = init.x ?? 0;
this._y = init.y ?? 0;
this._width = init.width ?? 0;
this._height = init.height ?? 0;
this._rotation = init.rotation ?? 0;
// Initialize matrices
this.#transformMatrix = Matrix.Identity();
this.#inverseMatrix = Matrix.Identity();
this.#updateMatrices();
} }
// Getters and setters for properties
get x(): number { get x(): number {
return this.#other.x ?? 0; return this._x;
} }
set x(x: number) { set x(value: number) {
this.#other.x = x; this._x = value;
this.#reset(); this.#updateMatrices();
} }
get y(): number { get y(): number {
return this.#other.y ?? 0; return this._y;
} }
set y(y: number) { set y(value: number) {
this.#other.y = y; this._y = value;
this.#reset(); this.#updateMatrices();
}
get height(): number {
return this.#other.height ?? 0;
}
set height(height: number) {
this.#other.height = height;
this.#reset();
} }
get width(): number { get width(): number {
return this.#other.width ?? 0; return this._width;
} }
set width(width: number) { set width(value: number) {
this.#other.width = width; this._width = value;
this.#reset(); this.#updateMatrices();
}
get height(): number {
return this._height;
}
set height(value: number) {
this._height = value;
this.#updateMatrices();
} }
get rotation(): number { get rotation(): number {
return this.#other.rotation ?? 0; return this._rotation;
} }
set rotation(rotation: number) { set rotation(value: number) {
this.#other.rotation = rotation; this._rotation = value;
this.#reset(); this.#updateMatrices();
} }
// DOMRect read-only properties
get left(): number { get left(): number {
return this.x; return this.x;
} }
@ -72,99 +93,141 @@ export class TransformDOMRect implements DOMRect {
return this.y + this.height; return this.y + this.height;
} }
#center: Point | null = null; // Updates the transformation matrices using instance functions
/** Returns the center point in worldspace coordinates */ #updateMatrices() {
// Reset the transformMatrix to identity
this.#transformMatrix.identity();
// Compute the center point
const centerX = this._x + this._width / 2;
const centerY = this._y + this._height / 2;
// Apply transformations: translate to center, rotate, translate back
this.#transformMatrix.translate(centerX, centerY);
this.#transformMatrix.rotate(this._rotation);
this.#transformMatrix.translate(-this._width / 2, -this._height / 2);
// Update inverseMatrix as the inverse of transformMatrix
this.#inverseMatrix = this.#transformMatrix.clone().invert();
}
// Accessors for the transformation matrices
get transformMatrix(): Matrix {
return this.#transformMatrix;
}
get inverseMatrix(): Matrix {
return this.#inverseMatrix;
}
// Converts a point from parent space to local space
toLocalSpace(point: Point): Point {
return this.#inverseMatrix.applyToPoint(point);
}
// Converts a point from local space to parent space
toParentSpace(point: Point): Point {
return this.#transformMatrix.applyToPoint(point);
}
// Local space corners
get topLeft(): Point {
return { x: 0, y: 0 };
}
get topRight(): Point {
return { x: this.width, y: 0 };
}
get bottomRight(): Point {
return { x: this.width, y: this.height };
}
get bottomLeft(): Point {
return { x: 0, y: this.height };
}
get center(): Point { get center(): Point {
if (this.#center === null) { return {
this.#center = { x: this.x + this.width / 2,
x: this.x + this.width / 2, y: this.y + this.height / 2,
y: this.y + this.height / 2, };
};
}
return this.#center;
} }
#topLeft: Point | null = null;
get topLeft() {
if (this.#topLeft === null) {
this.#topLeft = Vector.rotateAround({ x: this.x, y: this.y }, this.center, this.rotation);
}
return this.#topLeft;
}
#topRight: Point | null = null;
get topRight() {
if (this.#topRight === null) {
this.#topRight = Vector.rotateAround({ x: this.right, y: this.y }, this.center, this.rotation);
}
return this.#topRight;
}
#bottomRight: Point | null = null;
get bottomRight() {
if (this.#bottomRight === null) {
this.#bottomRight = Vector.rotateAround({ x: this.right, y: this.bottom }, this.center, this.rotation);
}
return this.#bottomRight;
}
#bottomLeft: Point | null = null;
get bottomLeft() {
if (this.#bottomLeft === null) {
this.#bottomLeft = Vector.rotateAround({ x: this.x, y: this.bottom }, this.center, this.rotation);
}
return this.#bottomLeft;
}
#reset() {
this.#center = null;
this.#topLeft = null;
this.#topRight = null;
this.#bottomLeft = null;
this.#bottomRight = null;
}
/** Returns all the vertices in worldspace coordinates */
vertices(): Point[] { vertices(): Point[] {
return []; return [this.topLeft, this.topRight, this.bottomRight, this.bottomLeft];
}
toCssString(): string {
return this.transformMatrix.toCssString();
} }
toJSON() { toJSON() {
return {}; return {
x: this.x,
y: this.y,
width: this.width,
height: this.height,
rotation: this.rotation,
};
}
setTopLeft(point: Point) {
const oldBottomRight = this.bottomRight;
this._width = oldBottomRight.x - point.x;
this._height = oldBottomRight.y - point.y;
this._x = point.x;
this._y = point.y;
this.#updateMatrices();
}
setTopRight(point: Point) {
const oldBottomLeft = this.bottomLeft;
this._width = point.x;
this._height = oldBottomLeft.y - point.y;
this._y = point.y;
this.#updateMatrices();
}
setBottomRight(point: Point) {
this._width = point.x;
this._height = point.y;
this.#updateMatrices();
}
setBottomLeft(point: Point) {
const oldTopRight = this.topRight;
this._width = oldTopRight.x - point.x;
this._height = point.y;
this._x = point.x;
this.#updateMatrices();
} }
} }
// We cant just override the setter, we need to override the getter and setter. // Read-only version of TransformDOMRect
export class TransformDOMRectReadonly extends TransformDOMRect { export class TransformDOMRectReadonly extends TransformDOMRect {
#other: TransformDOMRectInit; constructor(init: TransformDOMRectInit = {}) {
super(init);
constructor(other: TransformDOMRectInit = {}) {
super(other);
this.#other = other;
} }
get x(): number { // Override setters to prevent modification
return this.#other.x ?? 0; set x(value: number) {
throw new Error('Cannot modify readonly TransformDOMRect');
} }
set x(x: number) {}
get y(): number { set y(value: number) {
return this.#other.y ?? 0; throw new Error('Cannot modify readonly TransformDOMRect');
} }
set y(y: number) {}
get height(): number { set width(value: number) {
return this.#other.height ?? 0; throw new Error('Cannot modify readonly TransformDOMRect');
} }
set height(height: number) {}
get width(): number { set height(value: number) {
return this.#other.width ?? 0; throw new Error('Cannot modify readonly TransformDOMRect');
} }
set width(width: number) {}
get rotation(): number { set rotation(value: number) {
return this.#other.rotation ?? 0; throw new Error('Cannot modify readonly TransformDOMRect');
} }
set rotation(rotation: number) {}
} }