UNPKG

@itwin/core-react

Version:

A react component library of iTwin.js UI general purpose components

280 lines 10.3 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Utilities */ import { Point } from "./Point.js"; /** Available corners of [[Rectangle]]. * @internal */ export var Corner; (function (Corner) { Corner[Corner["TopLeft"] = 0] = "TopLeft"; Corner[Corner["TopRight"] = 1] = "TopRight"; Corner[Corner["BottomRight"] = 2] = "BottomRight"; Corner[Corner["BottomLeft"] = 3] = "BottomLeft"; })(Corner || (Corner = {})); /** Describes and provides methods to work with 2d bounds. * @internal */ export class Rectangle { left; top; right; bottom; /** Creates rectangle from [[RectangleProps]]. */ static create(props) { return new Rectangle(props.left, props.top, props.right, props.bottom); } /** Creates rectangle from [[SizeProps]]. */ static createFromSize(size) { return new Rectangle(0, 0, size.width, size.height); } /** Create a rectangle with 2 pairs of xy candidates. Theses are compared and shuffled as needed for the rectangle. */ static createXYXY(xA, yA, xB, yB) { return new Rectangle(Math.min(xA, xB), Math.min(yA, yB), Math.max(xA, xB), Math.max(yA, yB)); } /** Creates rectangle with specified bounds. */ constructor(left = 0, top = 0, right = 0, bottom = 0) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } /** @returns Size of this rectangle. */ getSize() { const width = this.getWidth(); const height = this.getHeight(); return { width, height }; } /** @returns Width of this rectangle. */ getWidth() { return this.right - this.left; } /** @returns Height of this rectangle. */ getHeight() { return this.bottom - this.top; } /** @returns Position of specified corner. */ getCorner(corner) { switch (corner) { case Corner.TopLeft: { return this.topLeft(); } case Corner.TopRight: { return new Point(this.right, this.top); } case Corner.BottomLeft: { return new Point(this.left, this.bottom); } case Corner.BottomRight: { return new Point(this.right, this.bottom); } } } /** * Inset the bounds of this rectangle. * @note Negative arguments will increase the size of rectangle. * @returns New [[Rectangle]] with modified bounds. */ inset(left, top, right, bottom) { return new Rectangle(this.left + left, this.top + top, this.right - right, this.bottom - bottom); } /** * Offsets the rectangle along the X and Y axes. * @returns New [[Rectangle]] with modified position. */ offset(offset) { return new Rectangle(this.left + offset.x, this.top + offset.y, this.right + offset.x, this.bottom + offset.y); } /** * Offsets the rectangle along the X axis. * @returns New [[Rectangle]] with modified position along X axis. */ offsetX(offset) { return new Rectangle(this.left + offset, this.top, this.right + offset, this.bottom); } /** * Offsets the rectangle along the Y axis. * @returns New [[Rectangle]] with modified position along Y axis. */ offsetY(offset) { return new Rectangle(this.left, this.top + offset, this.right, this.bottom + offset); } /** * Moves the top left corner of rectangle to specified point. * @returns New [[Rectangle]] with modified position. */ setPosition(position) { return new Rectangle(position.x, position.y, position.x + this.getWidth(), position.y + this.getHeight()); } /** * Sets the height of the rectangle. * @note Only [[Edge.Bottom]] is subject to change. * @returns New [[Rectangle]] with modified height. */ setHeight(height) { return new Rectangle(this.left, this.top, this.right, this.top + height); } /** * Sets the width of the rectangle. * @note Only [[Edge.Right]] is subject to change. * @returns New [[Rectangle]] with modified width. */ setWidth(width) { return new Rectangle(this.left, this.top, this.left + width, this.bottom); } /** * Sets the height and width of the rectangle. * @note Only [[Edge.Bottom]] and [[Edge.Right]] are subjects to change. * @returns New [[Rectangle]] with modified height. */ setSize(size) { return new Rectangle(this.left, this.top, this.left + size.width, this.top + size.height); } /** Checks if bounds of two rectangles match. */ equals(other) { if (this.left === other.left && this.top === other.top && this.right === other.right && this.bottom === other.bottom) return true; return false; } /** * Checks if point is within bounds of the rectangle. * @note Inclusive. */ containsPoint(point) { return (point.x >= this.left && point.x <= this.right && point.y >= this.top && point.y <= this.bottom); } /** * Checks if a point given as x,y is within the rectangle. * @note Inclusive. */ containsXY(x, y) { return this.containsPoint({ x, y }); } /** * @returns true if this rectangle contains other rectangle. * @note Inclusive. */ contains(other) { return (other.left >= this.left && other.right <= this.right && other.top >= this.top && other.bottom <= this.bottom); } /** @returns New [[Rectangle]] which is contained in other rectangle. */ containIn(other) { let contained = this.containVerticallyIn(other); contained = contained.containHorizontallyIn(other); return contained; } /** @returns New [[Rectangle]] which is vertically contained in other rectangle. */ containVerticallyIn(other) { const contained = this.offsetY(Math.min(other.bottom - this.bottom, 0)); return contained.offsetY(Math.max(other.top - contained.top, 0)); } /** @returns New [[Rectangle]] which is horizontally contained in other rectangle. */ containHorizontallyIn(other) { const contained = this.offsetX(Math.min(other.right - this.right, 0)); return contained.offsetX(Math.max(other.left - contained.left, 0)); } /** @returns [[Corner.TopLeft]] position of this rectangle. */ topLeft() { return new Point(this.left, this.top); } /** @returns Center point position of this rectangle. */ center() { const x = this.left + (this.right - this.left) / 2; const y = this.top + (this.bottom - this.top) / 2; return new Point(x, y); } /** @returns true if this rectangle intersects other rectangle. */ intersects(other) { return (this.left < other.right && this.right > other.left && this.top < other.bottom && this.bottom > other.top); } /** * Merges outer edges of this and other rectangles. * @returns New [[Rectangle]] with merged bounds. */ outerMergeWith(other) { const left = Math.min(this.left, other.left); const top = Math.min(this.top, other.top); const right = Math.max(this.right, other.right); const bottom = Math.max(this.bottom, other.bottom); return new Rectangle(left, top, right, bottom); } /** * Vertically divides this rectangle into specified number of equal height segments. * @returns Vertical rectangle segment. */ getVerticalSegmentBounds(segmentId, numberOfSegments) { const segmentHeight = this.getHeight() / numberOfSegments; const top = segmentId * segmentHeight; return this.inset(0, top, 0, 0).setHeight(segmentHeight); } /** * Horizontally divides this rectangle into specified number of equal width segments. * @returns Horizontal rectangle segment. */ getHorizontalSegmentBounds(segmentId, numberOfSegments) { const segmentWidth = this.getWidth() / numberOfSegments; const left = segmentId * segmentWidth; return this.inset(left, 0, 0, 0).setWidth(segmentWidth); } /** * Calculates the shortest distance between this rectangle and a given point. * @returns The shortest distance to a point. */ getShortestDistanceToPoint(point) { let shortestDistance = 0; if (point.x < this.left) { if (point.y < this.top) shortestDistance = hypotenuseXY(this.left - point.x, this.top - point.y); else if (point.y <= this.bottom) shortestDistance = this.left - point.x; else shortestDistance = hypotenuseXY(this.left - point.x, this.bottom - point.y); } else if (point.x <= this.right) { if (point.y < this.top) shortestDistance = this.top - point.y; else if (point.y <= this.bottom) shortestDistance = 0; else shortestDistance = point.y - this.bottom; } else { if (point.y < this.top) shortestDistance = hypotenuseXY(this.right - point.x, this.top - point.y); else if (point.y <= this.bottom) shortestDistance = point.x - this.right; else shortestDistance = hypotenuseXY(this.right - point.x, this.bottom - point.y); } return shortestDistance; } /** @returns [[RectangleProps]] object for this rectangle. */ toProps() { return { bottom: this.bottom, left: this.left, right: this.right, top: this.top, }; } } function hypotenuseXY(x, y) { return Math.sqrt(x * x + y * y); } //# sourceMappingURL=Rectangle.js.map