new TransformDOMRect
This commit is contained in:
parent
ba2b819ea4
commit
9817a9fd2b
|
|
@ -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) {}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue