From 470e8567deec83e97ac27748ce70cc5798874e6a Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:10:32 -0600 Subject: [PATCH] fix masks and zones layout issues at high browser zoom levels --- web/src/components/settings/PolygonCanvas.tsx | 2 +- web/src/components/settings/PolygonItem.tsx | 16 +++++-- web/src/views/settings/MasksAndZonesView.tsx | 43 +++++++++++++++---- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/web/src/components/settings/PolygonCanvas.tsx b/web/src/components/settings/PolygonCanvas.tsx index 30b203bd3..0db8db258 100644 --- a/web/src/components/settings/PolygonCanvas.tsx +++ b/web/src/components/settings/PolygonCanvas.tsx @@ -258,7 +258,7 @@ export function PolygonCanvas({ const updatedPolygons = [...polygons]; const activePolygon = updatedPolygons[activePolygonIndex]; - if (containerRef.current && !activePolygon.isFinished) { + if (containerRef.current && activePolygon && !activePolygon.isFinished) { containerRef.current.style.cursor = "crosshair"; } }; diff --git a/web/src/components/settings/PolygonItem.tsx b/web/src/components/settings/PolygonItem.tsx index 8fc6b639e..13522f9fc 100644 --- a/web/src/components/settings/PolygonItem.tsx +++ b/web/src/components/settings/PolygonItem.tsx @@ -329,7 +329,7 @@ export default function PolygonItem({
setHoveredPolygonIndex(index)} onMouseLeave={() => setHoveredPolygonIndex(null)} @@ -341,7 +341,7 @@ export default function PolygonItem({ }} >
)} {!isMobile && hoveredPolygonIndex === index && ( -
+
(null); const [editPane, setEditPane] = useState(undefined); + const editPaneRef = useRef(editPane); + editPaneRef.current = editPane; + const prevScaledRef = useRef<{ w: number; h: number } | null>(null); const [activeLine, setActiveLine] = useState(); const [snapPoints, setSnapPoints] = useState(false); @@ -350,12 +353,36 @@ export default function MasksAndZonesView({ ...globalObjectMasks, ...objectMasks, ]); - setEditingPolygons([ - ...zones, - ...motionMasks, - ...globalObjectMasks, - ...objectMasks, - ]); + // Don't overwrite editingPolygons during editing – layout shifts + // from switching to the edit pane can trigger a resize which + // recalculates scaledWidth/scaledHeight and would discard the + // newly-added polygon. Instead, rescale existing points + // proportionally. + if (editPaneRef.current === undefined) { + setEditingPolygons([ + ...zones, + ...motionMasks, + ...globalObjectMasks, + ...objectMasks, + ]); + } else if ( + prevScaledRef.current && + (prevScaledRef.current.w !== scaledWidth || + prevScaledRef.current.h !== scaledHeight) + ) { + const prevW = prevScaledRef.current.w; + const prevH = prevScaledRef.current.h; + setEditingPolygons((prev) => + prev.map((poly) => ({ + ...poly, + points: poly.points.map(([x, y]) => [ + (x / prevW) * scaledWidth, + (y / prevH) * scaledHeight, + ]), + })), + ); + } + prevScaledRef.current = { w: scaledWidth, h: scaledHeight }; } // we know that these deps are correct // eslint-disable-next-line react-hooks/exhaustive-deps @@ -431,7 +458,7 @@ export default function MasksAndZonesView({ {cameraConfig && editingPolygons && (
-
+
{editPane == "zone" && (