import React, { useRef, useState, useCallback } from 'react'; export const CAPTURE_SELECTOR = '.cs-overlay'; /** * Image preview with two endpoint markers for cross-section line control. * Markers are draggable when unlocked (no COORD input connected), * and fixed when locked (COORD input provides the position). * * Marker positions are driven by widget values (immediate React state), * not by backend overlay coords, so they move instantly during drag. */ export default function CrossSectionOverlay({ image, x1, y1, x2, y2, aLocked, bLocked, nodeId, onWidgetChange, showLine = true, }) { const containerRef = useRef(null); const [dragging, setDragging] = useState(null); // 'p1' or 'p2' const getCoords = useCallback((e) => { const rect = containerRef.current.getBoundingClientRect(); return { fx: Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)), fy: Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height)), }; }, []); const onPointerDown = useCallback((point) => (e) => { if (point === 'p1' && aLocked) return; if (point === 'p2' && bLocked) return; e.stopPropagation(); e.preventDefault(); e.target.setPointerCapture(e.pointerId); setDragging(point); }, [aLocked, bLocked]); const onPointerMove = useCallback((e) => { if (!dragging || !containerRef.current) return; const { fx, fy } = getCoords(e); const vx = parseFloat(fx.toFixed(3)); const vy = parseFloat(fy.toFixed(3)); if (dragging === 'p1') { onWidgetChange(nodeId, 'x1', vx); onWidgetChange(nodeId, 'y1', vy); } else { onWidgetChange(nodeId, 'x2', vx); onWidgetChange(nodeId, 'y2', vy); } }, [dragging, nodeId, onWidgetChange, getCoords]); const onPointerUp = useCallback(() => { setDragging(null); }, []); return (