@stringsync/vexml
Version:
MusicXML to Vexflow
97 lines (96 loc) • 2.96 kB
JavaScript
import { Point } from './point';
/** Represents a rectangle in a 2D coordinate system. */
export class Rect {
x;
y;
w;
h;
constructor(
/** upper-left corner x-coordinate */
x,
/** upper-left corner y-coordinate */
y,
/** total width */
w,
/** total height */
h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
static fromRectLike(rectLike) {
return new Rect(rectLike.x, rectLike.y, rectLike.w, rectLike.h);
}
static fromShape(shape) {
return new Rect(shape.left(), shape.top(), shape.right() - shape.left(), shape.bottom() - shape.top());
}
static fromRanges({ xRange, yRange }) {
return new Rect(xRange.start, yRange.start, xRange.getSize(), yRange.getSize());
}
static empty() {
return new Rect(0, 0, 0, 0);
}
static merge(rects) {
if (rects.length === 0) {
return Rect.empty();
}
const x = Math.min(...rects.map((rect) => rect.x));
const y = Math.min(...rects.map((rect) => rect.y));
const w = Math.max(...rects.map((rect) => rect.x + rect.w)) - x;
const h = Math.max(...rects.map((rect) => rect.y + rect.h)) - y;
return new Rect(x, y, w, h);
}
origin() {
return new Point(this.x, this.y);
}
center() {
return new Point(this.x + this.w / 2, this.y + this.h / 2);
}
topLeft() {
return new Point(this.x, this.y);
}
topRight() {
return new Point(this.x + this.w, this.y);
}
bottomLeft() {
return new Point(this.x, this.y + this.h);
}
bottomRight() {
return new Point(this.x + this.w, this.y + this.h);
}
translate(opts) {
const dx = opts.dx ?? 0;
const dy = opts.dy ?? 0;
return new Rect(this.x + dx, this.y + dy, this.w, this.h);
}
quadrants() {
const halfWidth = this.w / 2;
const halfHeight = this.h / 2;
const topRight = new Rect(this.x + halfWidth, this.y, halfWidth, halfHeight);
const topLeft = new Rect(this.x, this.y, halfWidth, halfHeight);
const bottomLeft = new Rect(this.x, this.y + halfHeight, halfWidth, halfHeight);
const bottomRight = new Rect(this.x + halfWidth, this.y + halfHeight, halfWidth, halfHeight);
return [topRight, topLeft, bottomLeft, bottomRight];
}
contains(point) {
return point.x >= this.x && point.x <= this.x + this.w && point.y >= this.y && point.y <= this.y + this.h;
}
toRectLike() {
return { x: this.x, y: this.y, w: this.w, h: this.h };
}
left() {
return this.x;
}
right() {
return this.x + this.w;
}
top() {
// NOTE: This assumes that the rectangle is not rotated.
return this.y;
}
bottom() {
// NOTE: This assumes that the rectangle is not rotated.
return this.y + this.h;
}
}