@zag-js/rect-utils 0.70.0 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +51 -123
- package/dist/index.mjs +2 -51
- package/package.json +2 -3
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/src/affine-transform.ts +0 -177
- package/src/align.ts +0 -26
- package/src/clamp.ts +0 -26
- package/src/closest.ts +0 -44
- package/src/compass.ts +0 -25
- package/src/constrain.ts +0 -15
- package/src/contains.ts +0 -14
- package/src/distance.ts +0 -44
- package/src/equality.ts +0 -13
- package/src/from-element.ts +0 -61
- package/src/from-points.ts +0 -15
- package/src/from-range.ts +0 -27
- package/src/from-rotation.ts +0 -41
- package/src/from-window.ts +0 -34
- package/src/index.ts +0 -20
- package/src/intersection.ts +0 -32
- package/src/operations.ts +0 -35
- package/src/polygon.ts +0 -67
- package/src/rect.ts +0 -66
- package/src/resize.ts +0 -106
- package/src/types.ts +0 -92
- package/src/union.ts +0 -16
package/src/affine-transform.ts
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import type { Point } from "./types"
|
|
2
|
-
|
|
3
|
-
export class AffineTransform {
|
|
4
|
-
m00: number
|
|
5
|
-
m01: number
|
|
6
|
-
m02: number
|
|
7
|
-
m10: number
|
|
8
|
-
m11: number
|
|
9
|
-
m12: number
|
|
10
|
-
|
|
11
|
-
constructor([m00, m01, m02, m10, m11, m12]: Iterable<number> = [0, 0, 0, 0, 0, 0]) {
|
|
12
|
-
this.m00 = m00
|
|
13
|
-
this.m01 = m01
|
|
14
|
-
this.m02 = m02
|
|
15
|
-
this.m10 = m10
|
|
16
|
-
this.m11 = m11
|
|
17
|
-
this.m12 = m12
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
applyTo(point: Point): Point {
|
|
21
|
-
const { x, y } = point
|
|
22
|
-
const { m00, m01, m02, m10, m11, m12 } = this
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
x: m00 * x + m01 * y + m02,
|
|
26
|
-
y: m10 * x + m11 * y + m12,
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
prepend(other: AffineTransform): AffineTransform {
|
|
31
|
-
return new AffineTransform([
|
|
32
|
-
this.m00 * other.m00 + this.m01 * other.m10, // m00
|
|
33
|
-
this.m00 * other.m01 + this.m01 * other.m11, // m01
|
|
34
|
-
this.m00 * other.m02 + this.m01 * other.m12 + this.m02, // m02
|
|
35
|
-
this.m10 * other.m00 + this.m11 * other.m10, // m10
|
|
36
|
-
this.m10 * other.m01 + this.m11 * other.m11, // m11
|
|
37
|
-
this.m10 * other.m02 + this.m11 * other.m12 + this.m12, // m12
|
|
38
|
-
])
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
append(other: AffineTransform): AffineTransform {
|
|
42
|
-
return new AffineTransform([
|
|
43
|
-
other.m00 * this.m00 + other.m01 * this.m10, // m00
|
|
44
|
-
other.m00 * this.m01 + other.m01 * this.m11, // m01
|
|
45
|
-
other.m00 * this.m02 + other.m01 * this.m12 + other.m02, // m02
|
|
46
|
-
other.m10 * this.m00 + other.m11 * this.m10, // m10
|
|
47
|
-
other.m10 * this.m01 + other.m11 * this.m11, // m11
|
|
48
|
-
other.m10 * this.m02 + other.m11 * this.m12 + other.m12, // m12
|
|
49
|
-
])
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get determinant() {
|
|
53
|
-
return this.m00 * this.m11 - this.m01 * this.m10
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
get isInvertible() {
|
|
57
|
-
const det = this.determinant
|
|
58
|
-
|
|
59
|
-
return isFinite(det) && isFinite(this.m02) && isFinite(this.m12) && det !== 0
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
invert() {
|
|
63
|
-
const det = this.determinant
|
|
64
|
-
|
|
65
|
-
return new AffineTransform([
|
|
66
|
-
this.m11 / det, // m00
|
|
67
|
-
-this.m01 / det, // m01
|
|
68
|
-
(this.m01 * this.m12 - this.m11 * this.m02) / det, // m02
|
|
69
|
-
-this.m10 / det, // m10
|
|
70
|
-
this.m00 / det, // m11
|
|
71
|
-
(this.m10 * this.m02 - this.m00 * this.m12) / det, // m12
|
|
72
|
-
])
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get array(): number[] {
|
|
76
|
-
return [this.m00, this.m01, this.m02, this.m10, this.m11, this.m12, 0, 0, 1]
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get float32Array(): Float32Array {
|
|
80
|
-
return new Float32Array(this.array)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Static
|
|
84
|
-
|
|
85
|
-
static get identity(): AffineTransform {
|
|
86
|
-
return new AffineTransform([1, 0, 0, 0, 1, 0])
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
static rotate(theta: number, origin?: Point): AffineTransform {
|
|
90
|
-
const rotation = new AffineTransform([Math.cos(theta), -Math.sin(theta), 0, Math.sin(theta), Math.cos(theta), 0])
|
|
91
|
-
|
|
92
|
-
if (origin && (origin.x !== 0 || origin.y !== 0)) {
|
|
93
|
-
return AffineTransform.multiply(
|
|
94
|
-
AffineTransform.translate(origin.x, origin.y),
|
|
95
|
-
rotation,
|
|
96
|
-
AffineTransform.translate(-origin.x, -origin.y),
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return rotation
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
rotate: (typeof AffineTransform)["rotate"] = (...args) => {
|
|
104
|
-
return this.prepend(AffineTransform.rotate(...args))
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
static scale(sx: number, sy: number = sx, origin: Point = { x: 0, y: 0 }): AffineTransform {
|
|
108
|
-
const scale = new AffineTransform([sx, 0, 0, 0, sy, 0])
|
|
109
|
-
|
|
110
|
-
if (origin.x !== 0 || origin.y !== 0) {
|
|
111
|
-
return AffineTransform.multiply(
|
|
112
|
-
AffineTransform.translate(origin.x, origin.y),
|
|
113
|
-
scale,
|
|
114
|
-
AffineTransform.translate(-origin.x, -origin.y),
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return scale
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
scale: (typeof AffineTransform)["scale"] = (...args) => {
|
|
122
|
-
return this.prepend(AffineTransform.scale(...args))
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static translate(tx: number, ty: number): AffineTransform {
|
|
126
|
-
return new AffineTransform([1, 0, tx, 0, 1, ty])
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
translate: (typeof AffineTransform)["translate"] = (...args) => {
|
|
130
|
-
return this.prepend(AffineTransform.translate(...args))
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
static multiply(...[first, ...rest]: AffineTransform[]): AffineTransform {
|
|
134
|
-
if (!first) return AffineTransform.identity
|
|
135
|
-
return rest.reduce((result, item) => result.prepend(item), first)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
get a() {
|
|
139
|
-
return this.m00
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
get b() {
|
|
143
|
-
return this.m10
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get c() {
|
|
147
|
-
return this.m01
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
get d() {
|
|
151
|
-
return this.m11
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
get tx() {
|
|
155
|
-
return this.m02
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
get ty() {
|
|
159
|
-
return this.m12
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
get scaleComponents(): Point {
|
|
163
|
-
return { x: this.a, y: this.d }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
get translationComponents(): Point {
|
|
167
|
-
return { x: this.tx, y: this.ty }
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
get skewComponents(): Point {
|
|
171
|
-
return { x: this.c, y: this.b }
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
toString() {
|
|
175
|
-
return `matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.tx}, ${this.ty})`
|
|
176
|
-
}
|
|
177
|
-
}
|
package/src/align.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { AlignOptions, HAlign, Rect, VAlign } from "./types"
|
|
2
|
-
|
|
3
|
-
function hAlign(a: Rect, ref: Rect, h: HAlign): Rect {
|
|
4
|
-
let x = ref.minX
|
|
5
|
-
if (h === "left-inside") x = ref.minX
|
|
6
|
-
if (h === "left-outside") x = ref.minX - ref.width
|
|
7
|
-
if (h === "right-inside") x = ref.maxX - ref.width
|
|
8
|
-
if (h === "right-outside") x = ref.maxX
|
|
9
|
-
if (h === "center") x = ref.midX - ref.width / 2
|
|
10
|
-
return { ...a, x }
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function vAlign(a: Rect, ref: Rect, v: VAlign): Rect {
|
|
14
|
-
let y = ref.minY
|
|
15
|
-
if (v === "top-inside") y = ref.minY
|
|
16
|
-
if (v === "top-outside") y = ref.minY - a.height
|
|
17
|
-
if (v === "bottom-inside") y = ref.maxY - a.height
|
|
18
|
-
if (v === "bottom-outside") y = ref.maxY
|
|
19
|
-
if (v === "center") y = ref.midY - a.height / 2
|
|
20
|
-
return { ...a, y }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function alignRect(a: Rect, ref: Rect, options: AlignOptions): Rect {
|
|
24
|
-
const { h, v } = options
|
|
25
|
-
return vAlign(hAlign(a, ref, h), ref, v)
|
|
26
|
-
}
|
package/src/clamp.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Point, RectInit, Size } from "./types"
|
|
2
|
-
|
|
3
|
-
const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)
|
|
4
|
-
|
|
5
|
-
export const clampPoint = (position: Point, size: Size, boundaryRect: RectInit) => {
|
|
6
|
-
const x = clamp(position.x, boundaryRect.x, boundaryRect.x + boundaryRect.width - size.width)
|
|
7
|
-
const y = clamp(position.y, boundaryRect.y, boundaryRect.y + boundaryRect.height - size.height)
|
|
8
|
-
return { x, y }
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const defaultMinSize: Size = {
|
|
12
|
-
width: 0,
|
|
13
|
-
height: 0,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const defaultMaxSize: Size = {
|
|
17
|
-
width: Infinity,
|
|
18
|
-
height: Infinity,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const clampSize = (size: Size, minSize = defaultMinSize, maxSize = defaultMaxSize) => {
|
|
22
|
-
return {
|
|
23
|
-
width: Math.min(Math.max(size.width, minSize!.width), maxSize!.width),
|
|
24
|
-
height: Math.min(Math.max(size.height, minSize!.height), maxSize!.height),
|
|
25
|
-
}
|
|
26
|
-
}
|
package/src/closest.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { distance } from "./distance"
|
|
2
|
-
import type { Point, Rect, RectSide } from "./types"
|
|
3
|
-
|
|
4
|
-
export function closest(...pts: Point[]) {
|
|
5
|
-
return (a: Point): Point => {
|
|
6
|
-
const ds = pts.map((b) => distance(b, a))
|
|
7
|
-
const c = Math.min.apply(Math, ds)
|
|
8
|
-
return pts[ds.indexOf(c)]
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function closestSideToRect(ref: Rect, r: Rect): RectSide {
|
|
13
|
-
if (r.maxX <= ref.minX) return "left"
|
|
14
|
-
if (r.minX >= ref.maxX) return "right"
|
|
15
|
-
if (r.maxY <= ref.minY) return "top"
|
|
16
|
-
if (r.minY >= ref.maxY) return "bottom"
|
|
17
|
-
return "left"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function closestSideToPoint(ref: Rect, p: Point): RectSide {
|
|
21
|
-
const { x, y } = p
|
|
22
|
-
|
|
23
|
-
const dl = x - ref.minX
|
|
24
|
-
const dr = ref.maxX - x
|
|
25
|
-
const dt = y - ref.minY
|
|
26
|
-
const db = ref.maxY - y
|
|
27
|
-
|
|
28
|
-
let closest = dl
|
|
29
|
-
let side: RectSide = "left"
|
|
30
|
-
|
|
31
|
-
if (dr < closest) {
|
|
32
|
-
closest = dr
|
|
33
|
-
side = "right"
|
|
34
|
-
}
|
|
35
|
-
if (dt < closest) {
|
|
36
|
-
closest = dt
|
|
37
|
-
side = "top"
|
|
38
|
-
}
|
|
39
|
-
if (db < closest) {
|
|
40
|
-
side = "bottom"
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return side
|
|
44
|
-
}
|
package/src/compass.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Point } from "./types"
|
|
2
|
-
|
|
3
|
-
export type CompassDirection = "n" | "ne" | "e" | "se" | "s" | "sw" | "w" | "nw"
|
|
4
|
-
|
|
5
|
-
export const compassDirectionMap: Record<CompassDirection, Point> = {
|
|
6
|
-
n: { x: 0.5, y: 0 },
|
|
7
|
-
ne: { x: 1, y: 0 },
|
|
8
|
-
e: { x: 1, y: 0.5 },
|
|
9
|
-
se: { x: 1, y: 1 },
|
|
10
|
-
s: { x: 0.5, y: 1 },
|
|
11
|
-
sw: { x: 0, y: 1 },
|
|
12
|
-
w: { x: 0, y: 0.5 },
|
|
13
|
-
nw: { x: 0, y: 0 },
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const oppositeDirectionMap: Record<CompassDirection, CompassDirection> = {
|
|
17
|
-
n: "s",
|
|
18
|
-
ne: "sw",
|
|
19
|
-
e: "w",
|
|
20
|
-
se: "nw",
|
|
21
|
-
s: "n",
|
|
22
|
-
sw: "ne",
|
|
23
|
-
w: "e",
|
|
24
|
-
nw: "se",
|
|
25
|
-
}
|
package/src/constrain.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { RectInit } from "./types"
|
|
2
|
-
|
|
3
|
-
// given a rect and a boundary, return a new rect that is constrained within the boundary
|
|
4
|
-
// resize or reposition the rect so that it fits within the boundary
|
|
5
|
-
export const constrainRect = (rect: RectInit, boundary: RectInit): RectInit => {
|
|
6
|
-
const left = Math.max(boundary.x, Math.min(rect.x, boundary.x + boundary.width - rect.width))
|
|
7
|
-
const top = Math.max(boundary.y, Math.min(rect.y, boundary.y + boundary.height - rect.height))
|
|
8
|
-
|
|
9
|
-
return {
|
|
10
|
-
x: left,
|
|
11
|
-
y: top,
|
|
12
|
-
width: Math.min(rect.width, boundary.width),
|
|
13
|
-
height: Math.min(rect.height, boundary.height),
|
|
14
|
-
}
|
|
15
|
-
}
|
package/src/contains.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { getRectCorners, isRect } from "./rect"
|
|
2
|
-
import type { Point, Rect } from "./types"
|
|
3
|
-
|
|
4
|
-
export function containsPoint(r: Rect, p: Point): boolean {
|
|
5
|
-
return r.minX <= p.x && p.x <= r.maxX && r.minY <= p.y && p.y <= r.maxY
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function containsRect(a: Rect, b: Rect): boolean {
|
|
9
|
-
return Object.values(getRectCorners(b)).every((c) => containsPoint(a, c))
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function contains(r: Rect, v: Rect | Point): boolean {
|
|
13
|
-
return isRect(v) ? containsRect(r, v) : containsPoint(r, v)
|
|
14
|
-
}
|
package/src/distance.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { intersects } from "./intersection"
|
|
2
|
-
import type { Point, Rect, RectSide } from "./types"
|
|
3
|
-
|
|
4
|
-
export interface DistanceValue extends Point {
|
|
5
|
-
value: number
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function distance(a: Point, b: Point = { x: 0, y: 0 }): number {
|
|
9
|
-
return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2))
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function distanceFromPoint(r: Rect, p: Point): DistanceValue {
|
|
13
|
-
let x = 0
|
|
14
|
-
let y = 0
|
|
15
|
-
|
|
16
|
-
if (p.x < r.x) x = r.x - p.x
|
|
17
|
-
else if (p.x > r.maxX) x = p.x - r.maxX
|
|
18
|
-
|
|
19
|
-
if (p.y < r.y) y = r.y - p.y
|
|
20
|
-
else if (p.y > r.maxY) y = p.y - r.maxY
|
|
21
|
-
return { x, y, value: distance({ x, y }) }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function distanceFromRect(a: Rect, b: Rect): DistanceValue {
|
|
25
|
-
if (intersects(a, b)) return { x: 0, y: 0, value: 0 }
|
|
26
|
-
const left = a.x < b.x ? a : b
|
|
27
|
-
const right = b.x < a.x ? a : b
|
|
28
|
-
const upper = a.y < b.y ? a : b
|
|
29
|
-
const lower = b.y < a.y ? a : b
|
|
30
|
-
let x = left.x === right.x ? 0 : right.x - left.maxX
|
|
31
|
-
x = Math.max(0, x)
|
|
32
|
-
let y = upper.y === lower.y ? 0 : lower.y - upper.maxY
|
|
33
|
-
y = Math.max(0, y)
|
|
34
|
-
return { x, y, value: distance({ x, y }) }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function distanceBtwEdges(a: Rect, b: Rect): Record<RectSide, number> {
|
|
38
|
-
return {
|
|
39
|
-
left: b.x - a.x,
|
|
40
|
-
top: b.y - a.y,
|
|
41
|
-
right: a.maxX - b.maxX,
|
|
42
|
-
bottom: a.maxY - b.maxY,
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/equality.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Point, RectInit, Size } from "./types"
|
|
2
|
-
|
|
3
|
-
export const isSizeEqual = (a: Size, b: Size) => {
|
|
4
|
-
return a.width === b.width && a.height === b.height
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const isPointEqual = (a: Point, b: Point) => {
|
|
8
|
-
return a.x === b.x && a.y === b.y
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const isRectEqual = (a: RectInit, b: RectInit) => {
|
|
12
|
-
return isPointEqual(a, b) && isSizeEqual(a, b)
|
|
13
|
-
}
|
package/src/from-element.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import type { Rect } from "./types"
|
|
3
|
-
|
|
4
|
-
const styleCache = new WeakMap<HTMLElement, any>()
|
|
5
|
-
|
|
6
|
-
function getCacheComputedStyle(el: HTMLElement) {
|
|
7
|
-
if (!styleCache.has(el)) {
|
|
8
|
-
const win = el.ownerDocument.defaultView || window
|
|
9
|
-
styleCache.set(el, win.getComputedStyle(el))
|
|
10
|
-
}
|
|
11
|
-
return styleCache.get(el)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function getElementRect(el: HTMLElement, opts: ElementRectOptions = {}): Rect {
|
|
15
|
-
return createRect(getClientRect(el, opts))
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type ElementRectOptions = {
|
|
19
|
-
/**
|
|
20
|
-
* Whether to exclude the element's scrollbar size from the calculation.
|
|
21
|
-
*/
|
|
22
|
-
excludeScrollbar?: boolean
|
|
23
|
-
/**
|
|
24
|
-
* Whether to exclude the element's borders from the calculation.
|
|
25
|
-
*/
|
|
26
|
-
excludeBorders?: boolean
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function getClientRect(el: HTMLElement, opts: ElementRectOptions = {}) {
|
|
30
|
-
const { excludeScrollbar = false, excludeBorders = false } = opts
|
|
31
|
-
|
|
32
|
-
const { x, y, width, height } = el.getBoundingClientRect()
|
|
33
|
-
const r = { x, y, width, height }
|
|
34
|
-
|
|
35
|
-
const style = getCacheComputedStyle(el)
|
|
36
|
-
|
|
37
|
-
const { borderLeftWidth, borderTopWidth, borderRightWidth, borderBottomWidth } = style
|
|
38
|
-
|
|
39
|
-
const borderXWidth = sum(borderLeftWidth, borderRightWidth)
|
|
40
|
-
const borderYWidth = sum(borderTopWidth, borderBottomWidth)
|
|
41
|
-
|
|
42
|
-
if (excludeBorders) {
|
|
43
|
-
r.width -= borderXWidth
|
|
44
|
-
r.height -= borderYWidth
|
|
45
|
-
r.x += px(borderLeftWidth)
|
|
46
|
-
r.y += px(borderTopWidth)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (excludeScrollbar) {
|
|
50
|
-
const scrollbarWidth = el.offsetWidth - el.clientWidth - borderXWidth
|
|
51
|
-
const scrollbarHeight = el.offsetHeight - el.clientHeight - borderYWidth
|
|
52
|
-
r.width -= scrollbarWidth
|
|
53
|
-
r.height -= scrollbarHeight
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return r
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const px = (v: string) => parseFloat(v.replace("px", ""))
|
|
60
|
-
|
|
61
|
-
const sum = (...vals: string[]) => vals.reduce((sum, v) => sum + (v ? px(v) : 0), 0)
|
package/src/from-points.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import type { Point, Rect } from "./types"
|
|
3
|
-
|
|
4
|
-
export function getRectFromPoints(...pts: Point[]): Rect {
|
|
5
|
-
const xs = pts.map((p) => p.x)
|
|
6
|
-
const ys = pts.map((p) => p.y)
|
|
7
|
-
|
|
8
|
-
const x = Math.min(...xs)
|
|
9
|
-
const y = Math.min(...ys)
|
|
10
|
-
|
|
11
|
-
const width = Math.max(...xs) - x
|
|
12
|
-
const height = Math.max(...ys) - y
|
|
13
|
-
|
|
14
|
-
return createRect({ x, y, width, height })
|
|
15
|
-
}
|
package/src/from-range.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import { getElementRect } from "./from-element"
|
|
3
|
-
import { union } from "./union"
|
|
4
|
-
import type { Rect } from "./types"
|
|
5
|
-
|
|
6
|
-
export function fromRange(range: Range): Rect {
|
|
7
|
-
let rs: Rect[] = []
|
|
8
|
-
const rects = Array.from(range.getClientRects())
|
|
9
|
-
|
|
10
|
-
if (rects.length) {
|
|
11
|
-
rs = rs.concat(rects.map(createRect))
|
|
12
|
-
return union.apply(undefined, rs)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
let start: Node | ParentNode | null = range.startContainer
|
|
16
|
-
|
|
17
|
-
if (start.nodeType === Node.TEXT_NODE) {
|
|
18
|
-
start = start.parentNode
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (start instanceof HTMLElement) {
|
|
22
|
-
const r = getElementRect(start)
|
|
23
|
-
rs.push({ ...r, x: r.maxX, width: 0 })
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return union.apply(undefined, rs)
|
|
27
|
-
}
|
package/src/from-rotation.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { createRect, getRectCorners } from "./rect"
|
|
2
|
-
import type { Point, Rect } from "./types"
|
|
3
|
-
|
|
4
|
-
export function toRad(d: number) {
|
|
5
|
-
return ((d % 360) * Math.PI) / 180
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function rotate(a: Point, d: number, c: Point): Point {
|
|
9
|
-
const r = toRad(d)
|
|
10
|
-
|
|
11
|
-
const sin = Math.sin(r)
|
|
12
|
-
const cos = Math.cos(r)
|
|
13
|
-
|
|
14
|
-
const x = a.x - c.x
|
|
15
|
-
const y = a.y - c.y
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
x: c.x + x * cos - y * sin,
|
|
19
|
-
y: c.y + x * sin + y * cos,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function getRotationRect(r: Rect, deg: number): Rect {
|
|
24
|
-
const rr = Object.values(getRectCorners(r)).map((p) => rotate(p, deg, r.center))
|
|
25
|
-
|
|
26
|
-
const xs = rr.map((p) => p.x)
|
|
27
|
-
const ys = rr.map((p) => p.y)
|
|
28
|
-
|
|
29
|
-
const minX = Math.min(...xs)
|
|
30
|
-
const minY = Math.min(...ys)
|
|
31
|
-
|
|
32
|
-
const maxX = Math.max(...xs)
|
|
33
|
-
const maxY = Math.max(...ys)
|
|
34
|
-
|
|
35
|
-
return createRect({
|
|
36
|
-
x: minX,
|
|
37
|
-
y: minY,
|
|
38
|
-
width: maxX - minX,
|
|
39
|
-
height: maxY - minY,
|
|
40
|
-
})
|
|
41
|
-
}
|
package/src/from-window.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import type { Rect } from "./types"
|
|
3
|
-
|
|
4
|
-
export type WindowRectOptions = {
|
|
5
|
-
/**
|
|
6
|
-
* Whether to exclude the element's scrollbar size from the calculation.
|
|
7
|
-
*/
|
|
8
|
-
excludeScrollbar?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Creates a rectange from window object
|
|
13
|
-
*/
|
|
14
|
-
export function getWindowRect(win: Window, opts: WindowRectOptions = {}): Rect {
|
|
15
|
-
return createRect(getViewportRect(win, opts))
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get the rect of the window with the option to exclude the scrollbar
|
|
20
|
-
*/
|
|
21
|
-
export function getViewportRect(win: Window, opts: WindowRectOptions) {
|
|
22
|
-
const { excludeScrollbar = false } = opts
|
|
23
|
-
const { innerWidth, innerHeight, document: doc, visualViewport } = win
|
|
24
|
-
const width = visualViewport?.width || innerWidth
|
|
25
|
-
const height = visualViewport?.height || innerHeight
|
|
26
|
-
const rect = { x: 0, y: 0, width, height }
|
|
27
|
-
if (excludeScrollbar) {
|
|
28
|
-
const scrollbarWidth = innerWidth - doc.documentElement.clientWidth
|
|
29
|
-
const scrollbarHeight = innerHeight - doc.documentElement.clientHeight
|
|
30
|
-
rect.width -= scrollbarWidth
|
|
31
|
-
rect.height -= scrollbarHeight
|
|
32
|
-
}
|
|
33
|
-
return rect
|
|
34
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export * from "./affine-transform"
|
|
2
|
-
export * from "./align"
|
|
3
|
-
export * from "./clamp"
|
|
4
|
-
export * from "./closest"
|
|
5
|
-
export * from "./constrain"
|
|
6
|
-
export * from "./contains"
|
|
7
|
-
export * from "./distance"
|
|
8
|
-
export * from "./equality"
|
|
9
|
-
export * from "./from-element"
|
|
10
|
-
export * from "./from-points"
|
|
11
|
-
export * from "./from-range"
|
|
12
|
-
export * from "./from-rotation"
|
|
13
|
-
export * from "./from-window"
|
|
14
|
-
export * from "./intersection"
|
|
15
|
-
export * from "./operations"
|
|
16
|
-
export * from "./polygon"
|
|
17
|
-
export * from "./rect"
|
|
18
|
-
export * from "./resize"
|
|
19
|
-
export * from "./types"
|
|
20
|
-
export * from "./union"
|
package/src/intersection.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import type { Rect, RectSide } from "./types"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Checks if a Rect intersects another Rect
|
|
6
|
-
*/
|
|
7
|
-
export function intersects(a: Rect, b: Rect): boolean {
|
|
8
|
-
return a.x < b.maxX && a.y < b.maxY && a.maxX > b.x && a.maxY > b.y
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Returns a new Rect that represents the intersection between two Rects
|
|
13
|
-
*/
|
|
14
|
-
export function intersection(a: Rect, b: Rect): Rect {
|
|
15
|
-
const x = Math.max(a.x, b.x)
|
|
16
|
-
const y = Math.max(a.y, b.y)
|
|
17
|
-
const x2 = Math.min(a.x + a.width, b.x + b.width)
|
|
18
|
-
const y2 = Math.min(a.y + a.height, b.y + b.height)
|
|
19
|
-
return createRect({ x, y, width: x2 - x, height: y2 - y })
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Returns whether two rects collide along each edge
|
|
24
|
-
*/
|
|
25
|
-
export function collisions(a: Rect, b: Rect): Record<RectSide, boolean> {
|
|
26
|
-
return {
|
|
27
|
-
top: a.minY <= b.minY,
|
|
28
|
-
right: a.maxX >= b.maxX,
|
|
29
|
-
bottom: a.maxY >= b.maxY,
|
|
30
|
-
left: a.minX <= b.minX,
|
|
31
|
-
}
|
|
32
|
-
}
|
package/src/operations.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { createRect } from "./rect"
|
|
2
|
-
import type { Point, Rect, RectInset, SymmetricRectInset } from "./types"
|
|
3
|
-
|
|
4
|
-
export const isSymmetric = (v: any): v is SymmetricRectInset => "dx" in v || "dy" in v
|
|
5
|
-
|
|
6
|
-
export function inset(r: Rect, i: RectInset | SymmetricRectInset): Rect {
|
|
7
|
-
const v = isSymmetric(i) ? { left: i.dx, right: i.dx, top: i.dy, bottom: i.dy } : i
|
|
8
|
-
const { top = 0, right = 0, bottom = 0, left = 0 } = v
|
|
9
|
-
return createRect({
|
|
10
|
-
x: r.x + left,
|
|
11
|
-
y: r.y + top,
|
|
12
|
-
width: r.width - left - right,
|
|
13
|
-
height: r.height - top - bottom,
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function expand(r: Rect, v: number | SymmetricRectInset): Rect {
|
|
18
|
-
const value = typeof v === "number" ? { dx: -v, dy: -v } : v
|
|
19
|
-
return inset(r, value)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function shrink(r: Rect, v: number | SymmetricRectInset): Rect {
|
|
23
|
-
const value = typeof v === "number" ? { dx: -v, dy: -v } : v
|
|
24
|
-
return inset(r, value)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function shift(r: Rect, o: Partial<Point>): Rect {
|
|
28
|
-
const { x = 0, y = 0 } = o
|
|
29
|
-
return createRect({
|
|
30
|
-
x: r.x + x,
|
|
31
|
-
y: r.y + y,
|
|
32
|
-
width: r.width,
|
|
33
|
-
height: r.height,
|
|
34
|
-
})
|
|
35
|
-
}
|