@itwin/core-react
Version:
A react component library of iTwin.js UI general purpose components
280 lines • 10.3 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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