From 1f1d546326ffaa10144f78067050dd655b1b4266 Mon Sep 17 00:00:00 2001
From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Date: Sun, 1 Mar 2026 14:41:33 -0600
Subject: [PATCH] fix masks and zones layout issues at high browser zoom levels
(#22181)
---
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" && (