-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathuseBBoxObserver.ts
More file actions
49 lines (44 loc) · 1.59 KB
/
useBBoxObserver.ts
File metadata and controls
49 lines (44 loc) · 1.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import type { RefCallback } from 'react';
import { useCallback, useRef, useState } from 'react';
const initialSize = { x: 0, y: 0, width: 0, height: 0 };
export function useBBoxObserver<ElementType extends SVGGraphicsElement>() {
// Actual current size of the observed element
const [size, setSize] = useState(initialSize);
// Previous size to compare in the observer and avoid unnecessary rerenders.
const previousSize = useRef(initialSize);
// Contains a function to cleanup the previous observer when the observed element changes.
const cleanupPrevious = useRef<() => void>(null);
// Ref callback to do the observation.
const ref: RefCallback<ElementType> = useCallback((element) => {
if (cleanupPrevious.current) {
cleanupPrevious.current();
}
if (element !== null) {
const observer = new ResizeObserver(([entry]) => {
const bbox = (entry?.target as ElementType).getBBox();
const previous = previousSize.current;
if (
previous.x !== bbox.x ||
previous.y !== bbox.y ||
previous.width !== bbox.width ||
previous.height !== bbox.height
) {
// Only update the size if any of the values has changed.
const newSize = {
x: bbox.x,
y: bbox.y,
width: bbox.width,
height: bbox.height,
};
previousSize.current = newSize;
setSize(newSize);
}
});
observer.observe(element);
cleanupPrevious.current = () => {
observer.unobserve(element);
};
}
}, []);
return { ref, ...size };
}