romgrk-2d-geometry
Version:
Javascript library for 2d geometry
86 lines (73 loc) • 2.4 kB
text/typescript
import Errors from '../utils/errors'
import { Matrix } from './Matrix'
import type { Box } from './Box'
import type { Point } from './Point'
import type { Vector } from './Vector'
export type AnyShape = Shape<unknown>
let ORIGIN_POINT: Point
/**
* Base class representing shape
* Implement common methods of affine transformations
*/
export class Shape<T> {
get name(): string {
throw(Errors.CANNOT_INVOKE_ABSTRACT_METHOD);
}
get box(): Box {
throw(Errors.CANNOT_INVOKE_ABSTRACT_METHOD);
}
clone() {
throw(Errors.CANNOT_INVOKE_ABSTRACT_METHOD);
}
/**
* Returns new shape translated by given vector.
* Translation vector may be also defined by a pair of numbers.
*/
translate(v: Vector): T;
translate(p: { x: number, y: number }): T;
translate(x: number, y: number): T;
translate(a: unknown, b?: unknown): T {
return this.transform(new Matrix().translate(a as any, b as any))
}
/**
* Returns new shape rotated by given angle around given center point.
* If center point is omitted, rotates around zero point (0,0).
* Positive value of angle defines rotation in counterclockwise direction,
* negative angle defines rotation in clockwise direction
* @param angle - angle in radians
* @param [center=(0,0)] center
*/
rotate(angle: number, center: Point = ORIGIN_POINT): T {
return this.transform(new Matrix().rotate(angle, center.x, center.y));
}
/**
* Return new shape with coordinates multiplied by scaling factor
*/
scale(s: number): T;
scale(sx: number, sy: number): T;
scale(a: unknown, b?: unknown): T {
return this.transform(new Matrix().scale(a, b ?? a));
}
transform(...args): T {
throw(Errors.CANNOT_INVOKE_ABSTRACT_METHOD);
}
/**
* This method returns an object that defines how data will be
* serialized when called JSON.stringify() method
* @returns {Object}
*/
toJSON() {
return Object.assign({}, this, {name: this.name});
}
svg(attrs = {}) {
throw(Errors.CANNOT_INVOKE_ABSTRACT_METHOD);
}
}
/**
* There is a circular dependency between Shape & Point, so we inject point later
* when everything is properly defined.
* @private
*/
export function _setupShape(point: Function) {
ORIGIN_POINT = point()
}