Newer
Older
NocodeToolOnRDL / src / hooks / useDragComponent.ts
@Sakoda2269 Sakoda2269 11 days ago 4 KB 命名修正
import type { Component, UIData } from "../types/component";
import { useEffect, useMemo, useState } from "react";

export function useDragComponent(
    selectingComponent: Component | null,
    selectingComponentIndex: number,
    moveComponent: (index: number, uiData: UIData) => void,
    scale: number,
    widgetScale: number
) {

    const [componentX, setComponentX] = useState<number>(0);
    const [componentY, setComponentY] = useState<number>(0);
    const [componentW, setComponentW] = useState<number>(0);
    const [componentH, setComponentH] = useState<number>(0);
    const baseX = useMemo(() => selectingComponent ? selectingComponent.uiData.posX : 0, [selectingComponent])
    const baseY = useMemo(() => selectingComponent ? selectingComponent.uiData.posY : 0, [selectingComponent])
    const baseW = useMemo(() => selectingComponent ? selectingComponent.uiData.width : 0, [selectingComponent])
    const baseH = useMemo(() => selectingComponent ? selectingComponent.uiData.height : 0, [selectingComponent])

    const [prevX, setPrevX] = useState<number>(0);
    const [prevY, setPrevY] = useState<number>(0);

    const MIN_WIDTH = 50;
    const MIN_HEIGHT = 20;

    useEffect(() => {
        // eslint-disable-next-line react-hooks/set-state-in-effect
        setComponentX(baseX);
    }, [baseX])

    useEffect(() => {
        // eslint-disable-next-line react-hooks/set-state-in-effect
        setComponentY(baseY)
    }, [baseY])

    useEffect(() => {
        // eslint-disable-next-line react-hooks/set-state-in-effect
        setComponentW(baseW);
    }, [baseW]);

    useEffect(() => {
        // eslint-disable-next-line react-hooks/set-state-in-effect
        setComponentH(baseH);
    }, [baseH])

    const onDragStart = (e: React.DragEvent) => {
        e.stopPropagation();
        setPrevX(e.clientX);
        setPrevY(e.clientY);
        const img = new Image();
        img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMB/VEvKukAAAAASUVORK5CYII="; // 1x1透明PNG
        e.dataTransfer.setDragImage(img, 0, 0);
    }

    const draggingComponent = (e: React.DragEvent) => {
        e.stopPropagation();
        if (e.clientX == 0 || e.clientY == 0) {
            return;
        }
        setComponentX((prev) => prev + (e.clientX - prevX) / (scale * widgetScale))
        setComponentY((prev) => prev + (e.clientY - prevY) / (scale * widgetScale))
        setPrevX(e.clientX);
        setPrevY(e.clientY);
    }

    const draggingSquare = (e: React.DragEvent, index: number) => {
        e.stopPropagation()
        if (e.clientX == 0 || e.clientY == 0) {
            return;
        }
        const dx = (e.clientX - prevX) / (scale * widgetScale);
        const dy = (e.clientY - prevY) / (scale * widgetScale);
        if (index == 0) {
            if (componentW - dx > MIN_WIDTH) {
                setComponentX((prev) => prev + dx)
                setComponentW((prev) => prev - dx);
            }
            if (componentH - dy > MIN_HEIGHT) {
                setComponentY((prev) => prev + dy)
                setComponentH((prev) => prev - dy);
            }
        } else if (index == 1) {
            if (componentW + dx > MIN_WIDTH) {
                setComponentW((prev) => prev + dx);
            }
            if (componentH - dy > MIN_HEIGHT) {
                setComponentY((prev) => prev + dy)
                setComponentH((prev) => prev - dy);
            }
        } else if (index == 2) {
            if (componentW + dx > MIN_WIDTH) {
                setComponentW((prev) => prev + dx);
            }
            if (componentH + dy > MIN_HEIGHT) {
                setComponentH((prev) => prev + dy);
            }
        } else {
            if (componentW - dx > MIN_WIDTH) {
                setComponentX((prev) => prev + dx)
                setComponentW((prev) => prev - dx);
            }
            if (componentH + dy > MIN_HEIGHT) {
                setComponentH((prev) => prev + dy);
            }
        }
        setPrevX(e.clientX);
        setPrevY(e.clientY);
    }

    const onDragEnd = (e: React.DragEvent) => {
        e.stopPropagation();
        if (!selectingComponent) return;
        const nextUiData: UIData = {
            posX: componentX,
            posY: componentY,
            width: componentW,
            height: componentH
        }
        moveComponent(selectingComponentIndex, nextUiData);
    }

    return {
        componentX,
        componentY,
        componentW,
        componentH,
        onDragStart,
        draggingComponent,
        draggingSquare,
        onDragEnd
    };

}