Extending PixiJS Coordinate Classes with Vector Utilities and Reactive Observers
To augmant PixiJS coordinate handling, extend the IPoint interface and attach mathematical utilities directly to the Point and ObservablePoint prototypes. Create a dedicated extension module and register the new signatures within the PixiJS namespace.
import { IPoint, Point, ObservablePoint } from 'pixi.js';
declare module 'pixi.js' {
interface IPoint {
magnitude(): number;
offsetBy(target: IPoint): Point;
differenceFrom(target: IPoint): Point;
}
}
Point.prototype.magnitude = function (): number {
return Math.hypot(this.x, this.y);
};
Point.prototype.offsetBy = function (target: IPoint): Point {
return new Point(this.x + target.x, this.y + target.y);
};
Point.prototype.differenceFrom = function (target: IPoint): Point {
return new Point(this.x - target.x, this.y - target.y);
};
// Propagate implementations to ObservablePoint to avoid duplication
ObservablePoint.prototype.magnitude = Point.prototype.magnitude;
ObservablePoint.prototype.offsetBy = Point.prototype.offsetBy;
ObservablePoint.prototype.differenceFrom = Point.prototype.differenceFrom;
Module augmentation ensures TypeScript recognizes these additions acros all compatible classes. Since ObservablePoint shares the same structural contract as Point, reusing the prototype assignments maintains consistency without redundant logic.
The implementation can be validated by initializing coordinates, computing vector properties, and monitoring dynamic updates through a reactive callback mechanism.
import { Point, ObservablePoint } from 'pixi.js';
import './vector-extensions';
const baseVector = new Point(3, 4);
console.log(`Distance from origin: ${baseVector.magnitude()}`);
const translationDelta = new Point(5, 1);
const shiftedVector = baseVector.offsetBy(translationDelta);
console.log(`Resulting coordinates: (${shiftedVector.x}, ${shiftedVector.y})`);
function logPositionUpdate(currentX: number, currentY: number): void {
console.log(`Observer triggered: (${currentX.toFixed(1)}, ${currentY.toFixed(1)})`);
}
function applyCoordinates(observer: ObservablePoint, xVal: number, yVal: number): void {
observer.set(xVal, yVal);
}
const trackedPosition = new ObservablePoint(
() => logPositionUpdate(trackedPosition.x, trackedPosition.y),
null,
0,
0
);
let iteration = 0;
const limit = 15;
const tickRate = 350;
const animationLoop = setInterval(() => {
const nextX = iteration * 1.2;
const nextY = iteration * 0.8 + 3;
applyCoordinates(trackedPosition, nextX, nextY);
if (iteration >= limit) {
clearInterval(animationLoop);
}
iteration++;
}, tickRate);
ObservablePoint executes its bound callback immediately whenever set() modifies the stored coordinates, making it ideal for synchronizing UI elements or game entities. The polling loop simulates continuous positional adjustments, advancing through a predefined range before terminating the interval to prevent unnecessary rseource consumption.