123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- import { useCallback, useEffect, useMemo, useState } from 'react';
- import { RegionGrid } from '$app/utils/region_grid';
- import { useSubscribeDocument, useSubscribeDocumentData } from '$app/components/document/_shared/SubscribeDoc.hooks';
- export function useNodesRect(container: HTMLDivElement) {
- const { controller } = useSubscribeDocument();
- const version = useVersionUpdate();
- const regionGrid = useMemo(() => {
- if (!controller) return null;
- return new RegionGrid(300);
- }, [controller]);
- const updateNodeRect = useCallback(
- (node: Element) => {
- const { x, y, width, height } = node.getBoundingClientRect();
- const id = node.getAttribute('data-block-id');
- if (!id) return;
- const rect = {
- id,
- x: x + container.scrollLeft,
- y: y + container.scrollTop,
- width,
- height,
- };
- regionGrid?.updateBlock(rect);
- },
- [container.scrollLeft, container.scrollTop, regionGrid]
- );
- const updateViewPortNodesRect = useCallback(() => {
- const nodes = container.querySelectorAll('[data-block-id]');
- nodes.forEach(updateNodeRect);
- }, [container, updateNodeRect]);
- // update nodes rect when data changed
- useEffect(() => {
- updateViewPortNodesRect();
- }, [version, updateViewPortNodesRect]);
- // update nodes rect when scroll
- useEffect(() => {
- container.addEventListener('scroll', updateViewPortNodesRect);
- return () => {
- container.removeEventListener('scroll', updateViewPortNodesRect);
- };
- }, [container, updateViewPortNodesRect]);
- const getIntersectedBlockIds = useCallback(
- (rect: { startX: number; startY: number; endX: number; endY: number }) => {
- if (!regionGrid) return [];
- const { startX, startY, endX, endY } = rect;
- const x = Math.min(startX, endX);
- const y = Math.min(startY, endY);
- const width = Math.abs(endX - startX);
- const height = Math.abs(endY - startY);
- return regionGrid
- .getIntersectingBlocks({
- x,
- y,
- width,
- height,
- })
- .map((block) => block.id);
- },
- [regionGrid]
- );
- return {
- getIntersectedBlockIds,
- };
- }
- function useVersionUpdate() {
- const [version, setVersion] = useState(0);
- const data = useSubscribeDocumentData();
- useEffect(() => {
- setVersion((v) => {
- if (v < Number.MAX_VALUE) return v + 1;
- return 0;
- });
- }, [data]);
- return version;
- }
|