-
-
Notifications
You must be signed in to change notification settings - Fork 642
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
"simplify" anchorPoint definition using a new
ObservablePoint
class…
… (lighter than the previous ObservableVector2d class, and with Point class being more than enough for an anchorPoint)
- Loading branch information
Showing
8 changed files
with
232 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import { Point } from "./point.ts"; | ||
|
||
/** | ||
* Represents a point in a 2D coordinate system that can be observed for changes. | ||
*/ | ||
/** | ||
* Represents an observable point in 2D space. | ||
*/ | ||
export class ObservablePoint { | ||
private _callback: () => void; | ||
private _point: Point; | ||
private _revoke: () => void; | ||
|
||
private callBackEnabled: boolean = true; | ||
|
||
type: "ObservablePoint"; | ||
|
||
/** | ||
* Creates a new ObservablePoint instance. | ||
* @param x - The x-coordinate of the point. Default is 0. | ||
* @param y - The y-coordinate of the point. Default is 0. | ||
* @param callback - The callback function to be called when the point changes. Default is undefined. | ||
*/ | ||
constructor(x: number = 0, y: number = 0, callback?: () => void) { | ||
const { proxy, revoke } = Proxy.revocable(new Point(x, y), { | ||
set: (target, property, value) => { | ||
if (property === "x" || property === "y") { | ||
Reflect.set(target, property, value); | ||
if (this.callBackEnabled) { | ||
this._callback?.(); | ||
} | ||
return true; | ||
} | ||
return false; | ||
}, | ||
}); | ||
|
||
this._revoke = revoke; | ||
this._point = proxy; | ||
|
||
if (callback) { | ||
this.setCallback(callback); | ||
} | ||
} | ||
|
||
/** | ||
* Sets the x and y coordinates of the point. | ||
* @param x - The new x-coordinate value. | ||
* @param y - The new y-coordinate value. | ||
* @returns Reference to this object for method chaining. | ||
*/ | ||
set(x = 0, y = 0) { | ||
this._point.x = x; | ||
this._point.y = y; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the x and y coordinates of the point without triggering the callback. | ||
* @param x - The new x-coordinate value. | ||
* @param y - The new y-coordinate value. | ||
* @returns Reference to this object for method chaining. | ||
*/ | ||
setMuted(x = 0, y = 0) { | ||
this.callBackEnabled = false; | ||
this._point.x = x; | ||
this._point.y = y; | ||
this.callBackEnabled = true; | ||
return this; | ||
} | ||
|
||
/** | ||
* Gets the x-coordinate of the point. | ||
*/ | ||
get x() { | ||
return this._point.x; | ||
} | ||
|
||
/** | ||
* Sets the x-coordinate of the point. | ||
* @param value - The new x-coordinate value. | ||
*/ | ||
set x(value: number) { | ||
this._point.x = value; | ||
} | ||
|
||
/** | ||
* Gets the y-coordinate of the point. | ||
*/ | ||
get y() { | ||
return this._point.y; | ||
} | ||
|
||
/** | ||
* Sets the y-coordinate of the point. | ||
* @param value - The new y-coordinate value. | ||
*/ | ||
set y(value: number) { | ||
this._point.y = value; | ||
} | ||
|
||
/** | ||
* Sets the callback function to be called when the point changes. | ||
* @param callback - The callback function. | ||
*/ | ||
setCallback(callback: () => void) { | ||
this._callback = callback; | ||
} | ||
|
||
/** | ||
* Checks if the point is equal to the given coordinates or another ObservablePoint. | ||
* @param x - The x-coordinate or the ObservablePoint to compare. | ||
* @param y - The y-coordinate. Required if the first parameter is a number. | ||
* @returns True if the point is equal to the given coordinates or another ObservablePoint, false otherwise. | ||
*/ | ||
equals(x: number, y: number): boolean; | ||
equals(point: ObservablePoint): boolean; | ||
equals(xOrPoint: number | ObservablePoint, y?: number | undefined) { | ||
return this._point.equals(xOrPoint as any, y as any); | ||
} | ||
|
||
/** | ||
* Creates a clone of the ObservablePoint. | ||
* @returns A new ObservablePoint instance with the same coordinates and callback function. | ||
*/ | ||
clone() { | ||
return new ObservablePoint(this._point.x, this._point.y, this._callback); | ||
} | ||
|
||
/** | ||
* Revokes the proxy object, preventing further access to the ObservablePoint instance. | ||
*/ | ||
revoke() { | ||
this._revoke(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { describe, expect, it } from "vitest"; | ||
import { ObservablePoint, Point } from "../src/index.js"; | ||
|
||
describe("ObservablePoint : constructor", () => { | ||
it("creates a new ObservablePoint instance with default values", () => { | ||
const observablePoint = new ObservablePoint(); | ||
expect(observablePoint.x).toEqual(0); | ||
expect(observablePoint.y).toEqual(0); | ||
}); | ||
|
||
it("creates a new ObservablePoint instance with specified values", () => { | ||
const observablePoint = new ObservablePoint(10, 20); | ||
expect(observablePoint.x).toEqual(10); | ||
expect(observablePoint.y).toEqual(20); | ||
}); | ||
|
||
it("values can be compared with a Point object", () => { | ||
const observablePoint = new ObservablePoint(10, 30); | ||
const point = new Point(10, 30); | ||
expect(observablePoint.equals(point)).toEqual(true); | ||
}); | ||
|
||
it("triggers the callback function when setting values", () => { | ||
let callbackCalled = false; | ||
const callback = () => { | ||
callbackCalled = true; | ||
}; | ||
const observablePoint = new ObservablePoint(0, 0, callback); | ||
expect(observablePoint.x).toEqual(0); | ||
expect(observablePoint.y).toEqual(0); | ||
expect(callbackCalled).toEqual(false); | ||
|
||
observablePoint.x = 10; | ||
expect(observablePoint.x).toEqual(10); | ||
expect(callbackCalled).toEqual(true); | ||
}); | ||
|
||
it("triggers the callback function when calling set()", () => { | ||
let callbackCalled = false; | ||
const callback = () => { | ||
callbackCalled = true; | ||
}; | ||
const observablePoint = new ObservablePoint(0, 0, callback); | ||
expect(observablePoint.x).toEqual(0); | ||
expect(observablePoint.y).toEqual(0); | ||
expect(callbackCalled).toEqual(false); | ||
|
||
observablePoint.set(10, 20); | ||
expect(observablePoint.equals(10, 20)).toEqual(true); | ||
expect(callbackCalled).toEqual(true); | ||
}); | ||
|
||
it("does not trigger the callback function when using setMuted", () => { | ||
let callbackCalled = false; | ||
const callback = () => { | ||
callbackCalled = true; | ||
}; | ||
const observablePoint = new ObservablePoint(0, 0, callback); | ||
expect(observablePoint.x).toEqual(0); | ||
expect(observablePoint.y).toEqual(0); | ||
expect(callbackCalled).toEqual(false); | ||
|
||
observablePoint.setMuted(10, 20); | ||
expect(observablePoint.equals(10, 20)).toEqual(true); | ||
expect(callbackCalled).toEqual(false); | ||
}); | ||
|
||
it("does not trigger the callback function when revoked", () => { | ||
let callbackCalled = false; | ||
const callback = () => { | ||
callbackCalled = true; | ||
}; | ||
const observablePoint = new ObservablePoint(0, 0, callback); | ||
expect(observablePoint.x).toEqual(0); | ||
expect(observablePoint.y).toEqual(0); | ||
expect(callbackCalled).toEqual(false); | ||
|
||
observablePoint.revoke(); | ||
expect(() => { | ||
observablePoint.set(20, 10); | ||
}).toThrow(); | ||
}); | ||
}); |