UNPKG

@aurigma/design-atoms-model

Version:

Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.

222 lines 8.82 kB
import { PointF } from "./PointF"; import { EqualsOfFloatNumbers } from "./Common"; import { Matrix } from "./Matrix"; import { ArgumentException } from "../Exception"; import { EventWithSenderArg } from "../EventObject"; export class RectangleF { constructor(left, top, width, height) { this._propertyChanged = new EventWithSenderArg(); this._left = typeof left == "number" ? left : 0; this._top = typeof top == "number" ? top : 0; this._width = (typeof width == "number") ? width : 2; this._height = (typeof height == "number") ? height : 2; this._id = Math.random().toString(); } toJSON() { return { left: this.left, top: this.top, width: this.width, height: this.height, id: this._id }; } get left() { return this._left; } set left(value) { if (EqualsOfFloatNumbers(value, this._left, RectangleF._tolerance)) return; this._left = value; this._propertyChanged.notify(this, "left"); } get top() { return this._top; } set top(value) { if (EqualsOfFloatNumbers(value, this._top, RectangleF._tolerance)) return; this._top = value; this._propertyChanged.notify(this, "top"); } get width() { return this._width; } set width(value) { if (EqualsOfFloatNumbers(value, this._width, RectangleF._tolerance)) return; this._width = value; this._propertyChanged.notify(this, "width"); } get height() { return this._height; } set height(value) { if (EqualsOfFloatNumbers(value, this._height, RectangleF._tolerance)) return; this._height = value; this._propertyChanged.notify(this, "height"); } get id() { return this._id; } static FromLTRB(left, top, right, bottom) { var width = Math.abs(right - left); var height = Math.abs(bottom - top); return new RectangleF(Math.min(left, right), Math.min(top, bottom), width, height); } static fromLtrbObject(obj) { return RectangleF.FromLTRB(obj.left, obj.top, obj.right, obj.bottom); } static FromObject(object) { return new RectangleF(object.left, object.top, object.width, object.height); } /** * Creates a rectangle that represents the intersetion between a and b. * If there is no intersection, empty rectangle is returned. */ static intersect(a, b) { var maxLeft = Math.max(a.left, b.left); var minRight = Math.min(a.right, b.right); var maxTop = Math.max(a.top, b.top); var minBottom = Math.min(a.bottom, b.bottom); if (minRight >= maxLeft && minBottom >= maxTop) return new RectangleF(maxLeft, maxTop, minRight - maxLeft, minBottom - maxTop); return RectangleF.empty; } ; static union(a, b) { var x1 = Math.min(a.left, b.left); var x2 = Math.max(a.left + a.width, b.left + b.width); var y1 = Math.min(a.top, b.top); var y2 = Math.max(a.top + a.height, b.top + b.height); return new RectangleF(x1, y1, x2 - x1, y2 - y1); } ; static get empty() { return new RectangleF(0, 0, -1, -1); } equals(other) { return RectangleF.isEqual(this, other); } static isEqual(a, b, tolerance = 0.0001) { if (a == null && b == null) return true; if (a == null || b == null) return false; return EqualsOfFloatNumbers(a.left, b.left, tolerance) && EqualsOfFloatNumbers(a.top, b.top, tolerance) && EqualsOfFloatNumbers(a.width, b.width, tolerance) && EqualsOfFloatNumbers(a.height, b.height, tolerance); } contains(point, includeBorder, tolerance) { if (includeBorder == null) includeBorder = false; if (includeBorder) { if (typeof tolerance != "number") tolerance = 0.0001; var left = this.left, top = this.top, right = this.left + this.width, bottom = this.top + this.height; return (point.x > left || EqualsOfFloatNumbers(point.x, left, tolerance)) && (point.y > top || EqualsOfFloatNumbers(point.y, top, tolerance)) && (point.x < right || EqualsOfFloatNumbers(point.x, right, tolerance)) && (point.y < bottom || EqualsOfFloatNumbers(point.y, bottom, tolerance)); } else { return point.x > this.left && point.y > this.top && point.x < this.left + this.width && point.y < this.top + this.height; } } containsRectangle(rectangle) { var leftTop = new PointF(rectangle.left, rectangle.top); var rightBottom = new PointF(rectangle.right, rectangle.bottom); return this.contains(leftTop, true) && this.contains(rightBottom, true); } clone() { return new RectangleF(this.left, this.top, this.width, this.height); } isEmpty() { return (this.width <= 0) || (this.height <= 0); } inflate(size) { this.left -= size; this.top -= size; this.width += size * 2; this.height += size * 2; } /** * Determines if this rectangle intersects with rect */ intersectsWith(rect) { return (rect.left < this.right) && (this.left < rect.right) && (rect.top < this.bottom) && (this.top < rect.bottom); } updateByMatrix(matrix) { const deltaAngle = Math.abs(matrix.angle % 90); if (!EqualsOfFloatNumbers(deltaAngle, 0) && !EqualsOfFloatNumbers(deltaAngle, 90)) throw new ArgumentException(`RectangleF cannot be transformed by angle (${matrix.angle}!`); const oldLeftTopPoint = new PointF(this.left, this.top); const oldRightBottomPoint = new PointF(this.right, this.bottom); const newLeftTopPoint = matrix.transformPoint(oldLeftTopPoint); const newRightBottomPoint = matrix.transformPoint(oldRightBottomPoint); const oldRect = this.clone(); this._left = newLeftTopPoint.x; this._top = newLeftTopPoint.y; this._width = newRightBottomPoint.x - this._left; this._height = newRightBottomPoint.y - this._top; if (!oldRect.equals(this)) this._propertyChanged.notify(this); return this; } getExpanded(margin) { return RectangleF.FromLTRB(this.left - margin.left, this.top - margin.top, this.right + margin.right, this.bottom + margin.bottom); } toString() { var r = [this.left, this.top, this.width, this.height]; return r.join(","); } static fromString(str) { var parts = str.replace(", ", ",").split(","); return new RectangleF(parseFloat(parts[0]), parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])); } static fromPoints(point1, point2) { return RectangleF.FromLTRB(Math.min(point1.x, point2.x), Math.min(point1.y, point2.y), Math.max(point1.x, point2.x), Math.max(point1.y, point2.y)); } static getMatrix(initialRect, targetRect) { const result = new Matrix(); const initialRectCenter = initialRect.center; const targetRectCenter = targetRect.center; result.scaleRelativeToPoint(targetRect.width / initialRect.width, targetRect.height / initialRect.height, initialRectCenter); result.translate((targetRectCenter.x - initialRectCenter.x) / result.scaleX, (targetRectCenter.y - initialRectCenter.y) / result.scaleY); return result; } static getOverallBounds(rects) { if (rects == null || rects.length === 0) return RectangleF.empty; return rects.reduce((result, value) => { if (result == null) return result = value.clone(); return RectangleF.union(result, value); }); } set right(value) { this.width = value - this.left; } get right() { return this.left + this.width; } set bottom(value) { this.height = value - this.top; } get bottom() { return this.top + this.height; } get center() { return new PointF(this.left + this.width / 2, this.top + this.height / 2); } addPropertyChanged(listener) { this._propertyChanged.add(listener); } removePropertyChanged(listener) { this._propertyChanged.remove(listener); } } RectangleF._tolerance = 0.000001; //# sourceMappingURL=RectangleF.js.map