mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-05 14:47:40 +03:00
Fix fit-to-screen drag: use newItem.x/y grid coords instead of mouse pixels
Replace getBoundingClientRect+clientX/Y with newItem.x/y from react-grid-layout. With noCompactor, newItem reports the free grid position where the element was dropped — reliable across all rows without pixel math or scroll issues. Also remove handleFitDrag/fitDragRef (no longer needed) and generate a full snapBack layout so displaced items snap back correctly on no-op drops. https://claude.ai/code/session_01Cu7YDRKZrYX3sBs6g9w2dy
This commit is contained in:
parent
8fc7f6bdb7
commit
95b9b0b7b9
@ -468,41 +468,24 @@ export default function DraggableGridLayout({
|
|||||||
}, [fitToScreen, fitGridParams, cameras, includeBirdseye, birdseyeConfig]);
|
}, [fitToScreen, fitGridParams, cameras, includeBirdseye, birdseyeConfig]);
|
||||||
|
|
||||||
const [fitLayoutOverride, setFitLayoutOverride] = useState<Layout | undefined>();
|
const [fitLayoutOverride, setFitLayoutOverride] = useState<Layout | undefined>();
|
||||||
const fitDragRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFitLayoutOverride(undefined);
|
setFitLayoutOverride(undefined);
|
||||||
}, [fitGridParams, cameras, includeBirdseye]);
|
}, [fitGridParams, cameras, includeBirdseye]);
|
||||||
|
|
||||||
const handleFitDrag = useCallback(
|
|
||||||
(
|
|
||||||
_layout: Layout,
|
|
||||||
_oldItem: LayoutItem | null,
|
|
||||||
newItem: LayoutItem | null,
|
|
||||||
) => {
|
|
||||||
if (newItem) {
|
|
||||||
fitDragRef.current = newItem.i;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleFitDragStop = useCallback(
|
const handleFitDragStop = useCallback(
|
||||||
(
|
(
|
||||||
_layout: Layout,
|
_layout: Layout,
|
||||||
_oldItem: LayoutItem | null,
|
_oldItem: LayoutItem | null,
|
||||||
newItem: LayoutItem | null,
|
newItem: LayoutItem | null,
|
||||||
_placeholder: LayoutItem | null,
|
_placeholder: LayoutItem | null,
|
||||||
event: Event,
|
_event: Event,
|
||||||
) => {
|
) => {
|
||||||
if (!fitToScreen || !fitGridParams) return;
|
if (!fitToScreen || !fitGridParams || !newItem) return;
|
||||||
|
|
||||||
const w = fitGridParams.gridUnitsPerCam;
|
const w = fitGridParams.gridUnitsPerCam;
|
||||||
const colsPerRow = fitGridParams.colsPerRow;
|
const colsPerRow = fitGridParams.colsPerRow;
|
||||||
const draggedId = fitDragRef.current ?? newItem?.i;
|
const draggedId = newItem.i;
|
||||||
fitDragRef.current = null;
|
|
||||||
|
|
||||||
if (!draggedId) return;
|
|
||||||
|
|
||||||
const currentOrder = fitLayoutOverride ?? fitLayout ?? [];
|
const currentOrder = fitLayoutOverride ?? fitLayout ?? [];
|
||||||
const orderedNames = [...currentOrder]
|
const orderedNames = [...currentOrder]
|
||||||
@ -512,24 +495,11 @@ export default function DraggableGridLayout({
|
|||||||
})
|
})
|
||||||
.map((item) => item.i);
|
.map((item) => item.i);
|
||||||
|
|
||||||
const gridEl = containerRef.current?.querySelector(
|
|
||||||
".grid-layout",
|
|
||||||
) as HTMLElement | null;
|
|
||||||
if (!gridEl) return;
|
|
||||||
|
|
||||||
const mouseEvent = event as MouseEvent;
|
|
||||||
const rect = gridEl.getBoundingClientRect();
|
|
||||||
const mouseRelX = mouseEvent.clientX - rect.left;
|
|
||||||
const mouseRelY = mouseEvent.clientY - rect.top;
|
|
||||||
|
|
||||||
const cellWidthPx = rect.width / colsPerRow;
|
|
||||||
const cellHeightPx = cellHeight * w;
|
|
||||||
|
|
||||||
const targetCol = Math.max(
|
const targetCol = Math.max(
|
||||||
0,
|
0,
|
||||||
Math.min(Math.floor(mouseRelX / cellWidthPx), colsPerRow - 1),
|
Math.min(Math.round(newItem.x / w), colsPerRow - 1),
|
||||||
);
|
);
|
||||||
const targetRow = Math.max(0, Math.floor(mouseRelY / cellHeightPx));
|
const targetRow = Math.max(0, Math.round(newItem.y / w));
|
||||||
const totalRows = Math.ceil(orderedNames.length / colsPerRow);
|
const totalRows = Math.ceil(orderedNames.length / colsPerRow);
|
||||||
const clampedRow = Math.min(targetRow, totalRows - 1);
|
const clampedRow = Math.min(targetRow, totalRows - 1);
|
||||||
const targetIndex = Math.min(
|
const targetIndex = Math.min(
|
||||||
@ -538,8 +508,16 @@ export default function DraggableGridLayout({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const sourceIndex = orderedNames.indexOf(draggedId);
|
const sourceIndex = orderedNames.indexOf(draggedId);
|
||||||
|
const snapBack = orderedNames.map((name, index) => ({
|
||||||
|
i: name,
|
||||||
|
x: (index % colsPerRow) * w,
|
||||||
|
y: Math.floor(index / colsPerRow) * w,
|
||||||
|
w,
|
||||||
|
h: w,
|
||||||
|
}));
|
||||||
|
|
||||||
if (sourceIndex === -1 || sourceIndex === targetIndex) {
|
if (sourceIndex === -1 || sourceIndex === targetIndex) {
|
||||||
setFitLayoutOverride((prev) => (prev ? [...prev] : prev));
|
setFitLayoutOverride(snapBack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,7 +537,7 @@ export default function DraggableGridLayout({
|
|||||||
|
|
||||||
setFitLayoutOverride(normalized);
|
setFitLayoutOverride(normalized);
|
||||||
},
|
},
|
||||||
[fitToScreen, fitGridParams, fitLayoutOverride, fitLayout, cellHeight, containerRef],
|
[fitToScreen, fitGridParams, fitLayoutOverride, fitLayout],
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeGridLayout = useMemo(() => {
|
const activeGridLayout = useMemo(() => {
|
||||||
@ -941,7 +919,6 @@ export default function DraggableGridLayout({
|
|||||||
dragConfig={{
|
dragConfig={{
|
||||||
enabled: isEditMode,
|
enabled: isEditMode,
|
||||||
}}
|
}}
|
||||||
onDrag={fitToScreen ? handleFitDrag : undefined}
|
|
||||||
onDragStop={fitToScreen ? handleFitDragStop : handleLayoutChange}
|
onDragStop={fitToScreen ? handleFitDragStop : handleLayoutChange}
|
||||||
onResize={handleResize}
|
onResize={handleResize}
|
||||||
onResizeStart={() => setShowCircles(false)}
|
onResizeStart={() => setShowCircles(false)}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user