123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- import { useCallback, useContext, useEffect, useMemo, useState } from "react";
- import { DocumentControllerContext } from '$app/stores/effects/document/document_controller';
- import { useAppSelector } from '$app/stores/store';
- import { RegionGrid } from '$app/utils/region_grid';
- export function useNodesRect(container: HTMLDivElement) {
- const controller = useContext(DocumentControllerContext);
- 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 = useAppSelector((state) => {
- return state.document;
- });
- useEffect(() => {
- setVersion((v) => {
- if (v < Number.MAX_VALUE) return v + 1;
- return 0;
- });
- }, [data]);
- return version;
- }
|