add more tests

This commit is contained in:
Orion Reed 2024-12-07 02:26:11 -05:00
parent b40ba06404
commit acc29c6c78
2 changed files with 399 additions and 117 deletions

View File

@ -127,8 +127,8 @@ describe('TransformDOMRect', () => {
}); });
}); });
describe('corner setters', () => { describe('corner', () => {
test('setTopLeft maintains rectangle properties', () => { test('setTopLeft with local space coordinates', () => {
const rect = new TransformDOMRect({ const rect = new TransformDOMRect({
x: 100, x: 100,
y: 100, y: 100,
@ -136,14 +136,15 @@ describe('TransformDOMRect', () => {
height: 100, height: 100,
}); });
rect.setTopLeft({ x: 50, y: 50 }); // Move top-left corner 50 units right and 25 units down in local space
expect(rect.x).toBe(50); rect.setTopLeft({ x: 50, y: 25 });
expect(rect.y).toBe(50); expect(rect.x).toBe(150); // Original x + local x
expect(rect.width).toBe(250); // Increased by 50 expect(rect.y).toBe(125); // Original y + local y
expect(rect.height).toBe(150); // Increased by 50 expect(rect.width).toBe(150); // Original width - local x
expect(rect.height).toBe(75); // Original height - local y
}); });
test('setTopRight maintains rectangle properties', () => { test('setTopRight with local space coordinates', () => {
const rect = new TransformDOMRect({ const rect = new TransformDOMRect({
x: 100, x: 100,
y: 100, y: 100,
@ -151,14 +152,15 @@ describe('TransformDOMRect', () => {
height: 100, height: 100,
}); });
rect.setTopRight({ x: 350, y: 50 }); // Set top-right corner to local coordinates (150, 25)
expect(rect.x).toBe(100); rect.setTopRight({ x: 150, y: 25 });
expect(rect.y).toBe(50); expect(rect.x).toBe(100); // Original x unchanged
expect(rect.width).toBe(350); expect(rect.y).toBe(125); // Original y + local y
expect(rect.height).toBe(150); expect(rect.width).toBe(150); // New local x
expect(rect.height).toBe(75); // Original height - local y
}); });
test('setBottomRight maintains rectangle properties', () => { test('setBottomRight with local space coordinates', () => {
const rect = new TransformDOMRect({ const rect = new TransformDOMRect({
x: 100, x: 100,
y: 100, y: 100,
@ -166,14 +168,15 @@ describe('TransformDOMRect', () => {
height: 100, height: 100,
}); });
rect.setBottomRight({ x: 350, y: 250 }); // Set bottom-right corner to local coordinates (150, 75)
expect(rect.x).toBe(100); rect.setBottomRight({ x: 150, y: 75 });
expect(rect.y).toBe(100); expect(rect.x).toBe(100); // Original x unchanged
expect(rect.width).toBe(350); expect(rect.y).toBe(100); // Original y unchanged
expect(rect.height).toBe(250); expect(rect.width).toBe(150); // New local x
expect(rect.height).toBe(75); // New local y
}); });
test('setBottomLeft maintains rectangle properties', () => { test('setBottomLeft with local space coordinates', () => {
const rect = new TransformDOMRect({ const rect = new TransformDOMRect({
x: 100, x: 100,
y: 100, y: 100,
@ -181,14 +184,15 @@ describe('TransformDOMRect', () => {
height: 100, height: 100,
}); });
rect.setBottomLeft({ x: 50, y: 250 }); // Move bottom-left corner 50 units right in local space
expect(rect.x).toBe(50); rect.setBottomLeft({ x: 50, y: 75 });
expect(rect.y).toBe(100); expect(rect.x).toBe(150); // Original x + local x
expect(rect.width).toBe(250); expect(rect.y).toBe(100); // Original y unchanged
expect(rect.height).toBe(250); expect(rect.width).toBe(150); // Original width - local x
expect(rect.height).toBe(75); // New local y
}); });
test('corner setters work with rotation', () => { test('corner setters with rotation', () => {
const rect = new TransformDOMRect({ const rect = new TransformDOMRect({
x: 100, x: 100,
y: 100, y: 100,
@ -197,11 +201,18 @@ describe('TransformDOMRect', () => {
rotation: Math.PI / 4, // 45 degrees rotation: Math.PI / 4, // 45 degrees
}); });
const newTopLeft = rect.toParentSpace({ x: 0, y: 0 }); // Move top-left corner in local space
rect.setTopLeft(newTopLeft); rect.setTopLeft({ x: 50, y: 25 });
const transformedTopLeft = rect.toLocalSpace(newTopLeft); // Verify the dimensions are correct
expectPointClose(transformedTopLeft, { x: 0, y: 0 }); expect(rect.width).toBe(150); // Original width - local x
expect(rect.height).toBe(75); // Original height - local y
// Verify we can still transform points correctly
const localPoint = { x: 0, y: 0 };
const parentPoint = rect.toParentSpace(localPoint);
const backToLocal = rect.toLocalSpace(parentPoint);
expectPointClose(backToLocal, localPoint);
}); });
test('setBottomRight works with upside down rotation', () => { test('setBottomRight works with upside down rotation', () => {
@ -213,15 +224,184 @@ describe('TransformDOMRect', () => {
rotation: Math.PI, // 180 degrees - upside down rotation: Math.PI, // 180 degrees - upside down
}); });
rect.setBottomRight({ x: 350, y: 250 }); // Set bottom-right corner in local space
expect(rect.x).toBe(100); rect.setBottomRight({ x: 150, y: 75 });
expect(rect.y).toBe(100);
expect(rect.width).toBe(250);
expect(rect.height).toBe(150);
// Verify the corner is actually at the expected position expect(rect.width).toBe(150);
const transformedBottomRight = rect.toParentSpace(rect.bottomRight); expect(rect.height).toBe(75);
expectPointClose(transformedBottomRight, { x: 350, y: 250 });
// Verify the corner is actually at the expected position in local space
expectPointClose(rect.bottomRight, { x: 150, y: 75 });
});
});
describe('point conversion with rotation', () => {
test('converts points correctly with 90-degree rotation', () => {
const rect = new TransformDOMRect({
x: 100,
y: 100,
width: 200,
height: 100,
rotation: Math.PI / 2, // 90 degrees
});
// Test points in local space and their expected parent space coordinates
const testCases = [
{
local: { x: 0, y: 0 }, // Top-left
parent: { x: 150, y: 50 }, // After rotation: center + (-height/2, -width/2)
},
{
local: { x: 200, y: 0 }, // Top-right
parent: { x: 150, y: 250 }, // After rotation: center + (height/2, -width/2)
},
{
local: { x: 100, y: 50 }, // Center
parent: { x: 200, y: 150 }, // After rotation: stays at center
},
];
testCases.forEach(({ local, parent }) => {
const toParent = rect.toParentSpace(local);
expectPointClose(toParent, parent);
const backToLocal = rect.toLocalSpace(toParent);
expectPointClose(backToLocal, local);
});
});
test('converts points correctly with 45-degree rotation', () => {
const rect = new TransformDOMRect({
x: 100,
y: 100,
width: 100,
height: 100,
rotation: Math.PI / 4, // 45 degrees
});
// Center point should remain at the same position after transformation
const center = { x: 50, y: 50 }; // Center in local space
const centerInParent = rect.toParentSpace(center);
expectPointClose(centerInParent, { x: 150, y: 150 }); // Center in parent space
// Test a point on the edge
const edge = { x: 100, y: 50 }; // Right-middle in local space
const edgeInParent = rect.toParentSpace(edge);
// At 45 degrees, this point should be √2/2 * 100 units right and up from center
expectPointClose(edgeInParent, {
x: 150 + Math.cos(Math.PI / 4) * 50,
y: 150 + Math.sin(Math.PI / 4) * 50,
});
});
test('maintains relative positions through multiple transformations', () => {
const rect = new TransformDOMRect({
x: 100,
y: 100,
width: 100,
height: 100,
rotation: Math.PI / 6, // 30 degrees
});
// Create a grid of test points
const gridPoints: Point[] = [];
for (let x = 0; x <= 100; x += 25) {
for (let y = 0; y <= 100; y += 25) {
gridPoints.push({ x, y });
}
}
// Verify all points maintain their relative distances
gridPoints.forEach((point1, i) => {
gridPoints.forEach((point2, j) => {
if (i === j) return;
// Calculate distance in local space
const dx = point2.x - point1.x;
const dy = point2.y - point1.y;
const localDistance = Math.sqrt(dx * dx + dy * dy);
// Transform points to parent space
const parent1 = rect.toParentSpace(point1);
const parent2 = rect.toParentSpace(point2);
// Calculate distance in parent space
const pdx = parent2.x - parent1.x;
const pdy = parent2.y - parent1.y;
const parentDistance = Math.sqrt(pdx * pdx + pdy * pdy);
// Distances should be preserved
expect(parentDistance).toBeCloseTo(localDistance);
});
});
});
test('handles edge cases with various rotations', () => {
const testRotations = [
0, // No rotation
Math.PI / 2, // 90 degrees
Math.PI, // 180 degrees
(3 * Math.PI) / 2, // 270 degrees
Math.PI / 6, // 30 degrees
Math.PI / 3, // 60 degrees
(2 * Math.PI) / 3, // 120 degrees
(5 * Math.PI) / 6, // 150 degrees
];
testRotations.forEach((rotation) => {
const rect = new TransformDOMRect({
x: 100,
y: 100,
width: 100,
height: 50,
rotation,
});
// Test various points including corners and edges
const testPoints = [
{ x: 0, y: 0 }, // Top-left
{ x: 100, y: 0 }, // Top-right
{ x: 100, y: 50 }, // Bottom-right
{ x: 0, y: 50 }, // Bottom-left
{ x: 50, y: 25 }, // Center
{ x: 50, y: 0 }, // Top middle
{ x: 100, y: 25 }, // Right middle
{ x: 50, y: 50 }, // Bottom middle
{ x: 0, y: 25 }, // Left middle
];
testPoints.forEach((localPoint) => {
const parentPoint = rect.toParentSpace(localPoint);
const backToLocal = rect.toLocalSpace(parentPoint);
expectPointClose(backToLocal, localPoint);
});
});
});
test('maintains aspect ratio through transformations', () => {
const rect = new TransformDOMRect({
x: 100,
y: 100,
width: 200,
height: 100,
rotation: Math.PI / 3, // 60 degrees
});
// Test diagonal distances
const topLeft = { x: 0, y: 0 };
const bottomRight = { x: 200, y: 100 };
const topLeftParent = rect.toParentSpace(topLeft);
const bottomRightParent = rect.toParentSpace(bottomRight);
// Calculate distances
const localDiagonal = Math.sqrt(Math.pow(bottomRight.x - topLeft.x, 2) + Math.pow(bottomRight.y - topLeft.y, 2));
const parentDiagonal = Math.sqrt(
Math.pow(bottomRightParent.x - topLeftParent.x, 2) + Math.pow(bottomRightParent.y - topLeftParent.y, 2)
);
// Distances should be preserved
expect(parentDiagonal).toBeCloseTo(localDiagonal);
}); });
}); });
}); });
@ -235,21 +415,18 @@ describe('TransformDOMRectReadonly', () => {
height: 50, height: 50,
}); });
expect(() => { rect.x = 20;
rect.x = 20; rect.y = 30;
}).toThrow(); rect.width = 200;
expect(() => { rect.height = 100;
rect.y = 30; rect.rotation = Math.PI;
}).toThrow();
expect(() => { // Values should remain unchanged
rect.width = 200; expect(rect.x).toBe(10);
}).toThrow(); expect(rect.y).toBe(20);
expect(() => { expect(rect.width).toBe(100);
rect.height = 100; expect(rect.height).toBe(50);
}).toThrow(); expect(rect.rotation).toBe(0);
expect(() => {
rect.rotation = Math.PI;
}).toThrow();
}); });
test('allows reading properties', () => { test('allows reading properties', () => {

View File

@ -9,18 +9,32 @@ interface TransformDOMRectInit {
rotation?: number; rotation?: number;
} }
/**
* Represents a rectangle with position, size, and rotation,
* capable of transforming points between local and parent coordinate spaces.
*
* **Coordinate System:**
* - The origin `(0, 0)` is at the **top-left corner**.
* - Positive `x` values extend **to the right**.
* - Positive `y` values extend **downward**.
* - Rotation is **clockwise**, in **radians**, around the rectangle's **center**.
*/
export class TransformDOMRect implements DOMRect { export class TransformDOMRect implements DOMRect {
// Private properties // Private properties for position, size, and rotation
private _x: number; private _x: number; // X-coordinate of the top-left corner
private _y: number; private _y: number; // Y-coordinate of the top-left corner
private _width: number; private _width: number; // Width of the rectangle
private _height: number; private _height: number; // Height of the rectangle
private _rotation: number; private _rotation: number; // Rotation angle in radians, clockwise
// Internal matrices // Internal transformation matrices
#transformMatrix: Matrix; #transformMatrix: Matrix; // Transforms from local to parent space
#inverseMatrix: Matrix; #inverseMatrix: Matrix; // Transforms from parent to local space
/**
* Constructs a new `TransformDOMRect`.
* @param init - Optional initial values.
*/
constructor(init: TransformDOMRectInit = {}) { constructor(init: TransformDOMRectInit = {}) {
this._x = init.x ?? 0; this._x = init.x ?? 0;
this._y = init.y ?? 0; this._y = init.y ?? 0;
@ -28,14 +42,17 @@ export class TransformDOMRect implements DOMRect {
this._height = init.height ?? 0; this._height = init.height ?? 0;
this._rotation = init.rotation ?? 0; this._rotation = init.rotation ?? 0;
// Initialize matrices // Initialize transformation matrices
this.#transformMatrix = Matrix.Identity(); this.#transformMatrix = Matrix.Identity();
this.#inverseMatrix = Matrix.Identity(); this.#inverseMatrix = Matrix.Identity();
// Update matrices based on current properties
this.#updateMatrices(); this.#updateMatrices();
} }
// Getters and setters for properties // Getters and setters for properties
/** Gets or sets the **x-coordinate** of the top-left corner. */
get x(): number { get x(): number {
return this._x; return this._x;
} }
@ -44,6 +61,7 @@ export class TransformDOMRect implements DOMRect {
this.#updateMatrices(); this.#updateMatrices();
} }
/** Gets or sets the **y-coordinate** of the top-left corner. */
get y(): number { get y(): number {
return this._y; return this._y;
} }
@ -52,6 +70,7 @@ export class TransformDOMRect implements DOMRect {
this.#updateMatrices(); this.#updateMatrices();
} }
/** Gets or sets the **width** of the rectangle. */
get width(): number { get width(): number {
return this._width; return this._width;
} }
@ -60,6 +79,7 @@ export class TransformDOMRect implements DOMRect {
this.#updateMatrices(); this.#updateMatrices();
} }
/** Gets or sets the **height** of the rectangle. */
get height(): number { get height(): number {
return this._height; return this._height;
} }
@ -68,6 +88,7 @@ export class TransformDOMRect implements DOMRect {
this.#updateMatrices(); this.#updateMatrices();
} }
/** Gets or sets the **rotation angle** in radians, **clockwise**. */
get rotation(): number { get rotation(): number {
return this._rotation; return this._rotation;
} }
@ -77,35 +98,53 @@ export class TransformDOMRect implements DOMRect {
} }
// DOMRect read-only properties // DOMRect read-only properties
/** The **left** coordinate of the rectangle (same as `x`). */
get left(): number { get left(): number {
return this.x; return this.x;
} }
/** The **top** coordinate of the rectangle (same as `y`). */
get top(): number { get top(): number {
return this.y; return this.y;
} }
/** The **right** coordinate of the rectangle (`x + width`). */
get right(): number { get right(): number {
return this.x + this.width; return this.x + this.width;
} }
/** The **bottom** coordinate of the rectangle (`y + height`). */
get bottom(): number { get bottom(): number {
return this.y + this.height; return this.y + this.height;
} }
// Updates the transformation matrices using instance functions /**
* Updates the transformation matrices based on the current position,
* size, and rotation of the rectangle.
*
* The transformation sequence is:
* 1. **Translate** to the center of the rectangle.
* 2. **Rotate** around the center.
* 3. **Translate** back to the top-left corner.
*/
#updateMatrices() { #updateMatrices() {
// Reset the transformMatrix to identity // Reset the transformMatrix to identity
this.#transformMatrix.identity(); this.#transformMatrix.identity();
// Compute the center point // Compute the center point of the rectangle
const centerX = this._x + this._width / 2; const centerX = this._x + this._width / 2;
const centerY = this._y + this._height / 2; const centerY = this._y + this._height / 2;
// Apply transformations: translate to center, rotate, translate back // Apply transformations in this order:
this.#transformMatrix.translate(centerX, centerY); // 1. Translate to center
this.#transformMatrix.rotate(this._rotation); // 2. Rotate around center
this.#transformMatrix.translate(-this._width / 2, -this._height / 2); // 3. Translate back to position
this.#transformMatrix
.translate(centerX, centerY)
.rotate(this._rotation)
.translate(-centerX, -centerY)
.translate(this._x, this._y);
// Update inverseMatrix as the inverse of transformMatrix // Update inverseMatrix as the inverse of transformMatrix
this.#inverseMatrix = this.#transformMatrix.clone().invert(); this.#inverseMatrix = this.#transformMatrix.clone().invert();
@ -120,33 +159,57 @@ export class TransformDOMRect implements DOMRect {
return this.#inverseMatrix; return this.#inverseMatrix;
} }
// Converts a point from parent space to local space /**
* Converts a point from **parent space** to **local space**.
* @param point - The point in parent coordinate space.
* @returns The point in local coordinate space.
*/
toLocalSpace(point: Point): Point { toLocalSpace(point: Point): Point {
return this.#inverseMatrix.applyToPoint(point); return this.#inverseMatrix.applyToPoint(point);
} }
// Converts a point from local space to parent space /**
* Converts a point from **local space** to **parent space**.
* @param point - The point in local coordinate space.
* @returns The point in parent coordinate space.
*/
toParentSpace(point: Point): Point { toParentSpace(point: Point): Point {
return this.#transformMatrix.applyToPoint(point); return this.#transformMatrix.applyToPoint(point);
} }
// Local space corners // Local space corners
/**
* Gets the **top-left** corner of the rectangle in **local space** (before transformation).
*/
get topLeft(): Point { get topLeft(): Point {
return { x: 0, y: 0 }; return { x: 0, y: 0 };
} }
/**
* Gets the **top-right** corner of the rectangle in **local space** (before transformation).
*/
get topRight(): Point { get topRight(): Point {
return { x: this.width, y: 0 }; return { x: this.width, y: 0 };
} }
/**
* Gets the **bottom-right** corner of the rectangle in **local space** (before transformation).
*/
get bottomRight(): Point { get bottomRight(): Point {
return { x: this.width, y: this.height }; return { x: this.width, y: this.height };
} }
/**
* Gets the **bottom-left** corner of the rectangle in **local space** (before transformation).
*/
get bottomLeft(): Point { get bottomLeft(): Point {
return { x: 0, y: this.height }; return { x: 0, y: this.height };
} }
/**
* Gets the **center point** of the rectangle in **parent space**.
*/
get center(): Point { get center(): Point {
return { return {
x: this.x + this.width / 2, x: this.x + this.width / 2,
@ -154,14 +217,26 @@ export class TransformDOMRect implements DOMRect {
}; };
} }
/**
* Gets the four corner vertices of the rectangle in **local space**.
* @returns An array of points in the order: top-left, top-right, bottom-right, bottom-left.
*/
vertices(): Point[] { vertices(): Point[] {
return [this.topLeft, this.topRight, this.bottomRight, this.bottomLeft]; return [this.topLeft, this.topRight, this.bottomRight, this.bottomLeft];
} }
/**
* Generates a CSS transform string representing the rectangle's transformation.
* @returns A string suitable for use in CSS `transform` properties.
*/
toCssString(): string { toCssString(): string {
return this.transformMatrix.toCssString(); return this.transformMatrix.toCssString();
} }
/**
* Converts the rectangle's properties to a JSON serializable object.
* @returns An object containing the rectangle's `x`, `y`, `width`, `height`, and `rotation`.
*/
toJSON() { toJSON() {
return { return {
x: this.x, x: this.x,
@ -172,42 +247,59 @@ export class TransformDOMRect implements DOMRect {
}; };
} }
/**
* Sets the **top-left** corner of the rectangle in **local space**, adjusting the position, width, and height accordingly.
* @param point - The new top-left corner point in local coordinate space.
*/
setTopLeft(point: Point) { setTopLeft(point: Point) {
const oldBottomRight = this.toParentSpace(this.bottomRight); this._x += point.x;
this._x = point.x; this._y += point.y;
this._y = point.y; this._width -= point.x;
this._width = oldBottomRight.x - point.x; this._height -= point.y;
this._height = oldBottomRight.y - point.y;
this.#updateMatrices(); this.#updateMatrices();
} }
/**
* Sets the **top-right** corner of the rectangle in **local space**, adjusting the position, width, and height accordingly.
* @param point - The new top-right corner point in local coordinate space.
*/
setTopRight(point: Point) { setTopRight(point: Point) {
const oldBottomLeft = this.toParentSpace(this.bottomLeft); this._y += point.y;
this._y = point.y; this._width = point.x;
this._width = point.x - this._x; this._height -= point.y;
this._height = oldBottomLeft.y - point.y;
this.#updateMatrices(); this.#updateMatrices();
} }
/**
* Sets the **bottom-right** corner of the rectangle in **local space**, adjusting the width and height accordingly.
* @param point - The new bottom-right corner point in local coordinate space.
*/
setBottomRight(point: Point) { setBottomRight(point: Point) {
this._width = point.x; this._width = point.x;
this._height = point.y; this._height = point.y;
this.#updateMatrices(); this.#updateMatrices();
} }
/**
* Sets the **bottom-left** corner of the rectangle in **local space**, adjusting the position, width, and height accordingly.
* @param point - The new bottom-left corner point in local coordinate space.
*/
setBottomLeft(point: Point) { setBottomLeft(point: Point) {
const oldTopRight = this.toParentSpace(this.topRight); this._x += point.x;
this._x = point.x; this._width -= point.x;
this._width = oldTopRight.x - point.x; this._height = point.y;
this._height = point.y - this._y;
this.#updateMatrices(); this.#updateMatrices();
} }
/**
* Computes the **axis-aligned bounding box** of the transformed rectangle in **parent space**.
* @returns An object representing the bounding rectangle with properties: `x`, `y`, `width`, `height`.
*/
getBounds(): DOMRectInit { getBounds(): DOMRectInit {
// Transform all vertices to parent space // Transform all vertices to parent space
const transformedVertices = this.vertices().map((v) => this.toParentSpace(v)); const transformedVertices = this.vertices().map((v) => this.toParentSpace(v));
// Find min and max points // Find min and max coordinates
const xs = transformedVertices.map((v) => v.x); const xs = transformedVertices.map((v) => v.x);
const ys = transformedVertices.map((v) => v.y); const ys = transformedVertices.map((v) => v.y);
@ -225,85 +317,98 @@ export class TransformDOMRect implements DOMRect {
} }
} }
// Read-only version of TransformDOMRect /**
* A **read-only** version of `TransformDOMRect` that prevents modification of position,
* size, and rotation properties.
*/
export class TransformDOMRectReadonly extends TransformDOMRect { export class TransformDOMRectReadonly extends TransformDOMRect {
constructor(init: TransformDOMRectInit = {}) { constructor(init: TransformDOMRectInit = {}) {
super(init); super(init);
} }
// Explicit getter overrides // Explicit overrides for all getters from parent class
get x(): number { override get x(): number {
return super.x; return super.x;
} }
get y(): number { override get y(): number {
return super.y; return super.y;
} }
get width(): number { override get width(): number {
return super.width; return super.width;
} }
get height(): number { override get height(): number {
return super.height; return super.height;
} }
get rotation(): number { override get rotation(): number {
return super.rotation; return super.rotation;
} }
// DOMRect property getters override get left(): number {
get left(): number {
return super.left; return super.left;
} }
get top(): number { override get top(): number {
return super.top; return super.top;
} }
get right(): number { override get right(): number {
return super.right; return super.right;
} }
get bottom(): number { override get bottom(): number {
return super.bottom; return super.bottom;
} }
// Override all setters to prevent modification override get transformMatrix(): Matrix {
set x(value: number) { return super.transformMatrix;
throw new Error('Cannot modify readonly TransformDOMRect');
} }
set y(value: number) { override get inverseMatrix(): Matrix {
throw new Error('Cannot modify readonly TransformDOMRect'); return super.inverseMatrix;
} }
set width(value: number) { override get topLeft(): Point {
throw new Error('Cannot modify readonly TransformDOMRect'); return super.topLeft;
} }
set height(value: number) { override get topRight(): Point {
throw new Error('Cannot modify readonly TransformDOMRect'); return super.topRight;
} }
set rotation(value: number) { override get bottomRight(): Point {
throw new Error('Cannot modify readonly TransformDOMRect'); return super.bottomRight;
} }
// Override vertex setter methods override get bottomLeft(): Point {
setTopLeft(point: Point): void { return super.bottomLeft;
throw new Error('Cannot modify readonly TransformDOMRect');
} }
setTopRight(point: Point): void { override get center(): Point {
throw new Error('Cannot modify readonly TransformDOMRect'); return super.center;
} }
setBottomRight(point: Point): void { // Add no-op setters
throw new Error('Cannot modify readonly TransformDOMRect'); override set x(value: number) {
// no-op
} }
setBottomLeft(point: Point): void { override set y(value: number) {
throw new Error('Cannot modify readonly TransformDOMRect'); // no-op
}
override set width(value: number) {
// no-op
}
override set height(value: number) {
// no-op
}
override set rotation(value: number) {
// no-op
} }
} }