Skip to content

Commit 1f1d546

Browse files
authored
fix masks and zones layout issues at high browser zoom levels (blakeblackshear#22181)
1 parent 4232cc4 commit 1f1d546

3 files changed

Lines changed: 48 additions & 13 deletions

File tree

web/src/components/settings/PolygonCanvas.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export function PolygonCanvas({
258258
const updatedPolygons = [...polygons];
259259
const activePolygon = updatedPolygons[activePolygonIndex];
260260

261-
if (containerRef.current && !activePolygon.isFinished) {
261+
if (containerRef.current && activePolygon && !activePolygon.isFinished) {
262262
containerRef.current.style.cursor = "crosshair";
263263
}
264264
};

web/src/components/settings/PolygonItem.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export default function PolygonItem({
329329

330330
<div
331331
key={index}
332-
className="transition-background my-1.5 flex flex-row items-center justify-between rounded-lg p-1 duration-100"
332+
className="transition-background relative my-1.5 flex flex-row items-center justify-between rounded-lg p-1 duration-100"
333333
data-index={index}
334334
onMouseEnter={() => setHoveredPolygonIndex(index)}
335335
onMouseLeave={() => setHoveredPolygonIndex(null)}
@@ -341,7 +341,7 @@ export default function PolygonItem({
341341
}}
342342
>
343343
<div
344-
className={`flex items-center ${
344+
className={`flex min-w-0 items-center ${
345345
hoveredPolygonIndex === index
346346
? "text-primary"
347347
: "text-primary-variant"
@@ -359,7 +359,7 @@ export default function PolygonItem({
359359
type="button"
360360
onClick={handleToggleEnabled}
361361
disabled={isLoading || polygon.enabled_in_config === false}
362-
className="mr-2 cursor-pointer border-none bg-transparent p-0 transition-opacity hover:opacity-70 disabled:cursor-not-allowed disabled:opacity-50"
362+
className="mr-2 shrink-0 cursor-pointer border-none bg-transparent p-0 transition-opacity hover:opacity-70 disabled:cursor-not-allowed disabled:opacity-50"
363363
>
364364
<PolygonItemIcon
365365
className="size-5"
@@ -469,7 +469,15 @@ export default function PolygonItem({
469469
</>
470470
)}
471471
{!isMobile && hoveredPolygonIndex === index && (
472-
<div className="flex flex-row items-center gap-2">
472+
<div
473+
className="absolute inset-y-0 right-0 flex flex-row items-center gap-2 rounded-r-lg pl-8 pr-1"
474+
style={{
475+
background:
476+
polygon.color.length === 3
477+
? `linear-gradient(to right, transparent 0%, rgba(${polygon.color[2]},${polygon.color[1]},${polygon.color[0]},0.85) 40%)`
478+
: "linear-gradient(to right, transparent 0%, rgba(220,0,0,0.85) 40%)",
479+
}}
480+
>
473481
<Tooltip>
474482
<TooltipTrigger asChild>
475483
<IconWrapper

web/src/views/settings/MasksAndZonesView.tsx

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export default function MasksAndZonesView({
6464
);
6565
const containerRef = useRef<HTMLDivElement | null>(null);
6666
const [editPane, setEditPane] = useState<PolygonType | undefined>(undefined);
67+
const editPaneRef = useRef(editPane);
68+
editPaneRef.current = editPane;
69+
const prevScaledRef = useRef<{ w: number; h: number } | null>(null);
6770
const [activeLine, setActiveLine] = useState<number | undefined>();
6871
const [snapPoints, setSnapPoints] = useState(false);
6972

@@ -350,12 +353,36 @@ export default function MasksAndZonesView({
350353
...globalObjectMasks,
351354
...objectMasks,
352355
]);
353-
setEditingPolygons([
354-
...zones,
355-
...motionMasks,
356-
...globalObjectMasks,
357-
...objectMasks,
358-
]);
356+
// Don't overwrite editingPolygons during editing – layout shifts
357+
// from switching to the edit pane can trigger a resize which
358+
// recalculates scaledWidth/scaledHeight and would discard the
359+
// newly-added polygon. Instead, rescale existing points
360+
// proportionally.
361+
if (editPaneRef.current === undefined) {
362+
setEditingPolygons([
363+
...zones,
364+
...motionMasks,
365+
...globalObjectMasks,
366+
...objectMasks,
367+
]);
368+
} else if (
369+
prevScaledRef.current &&
370+
(prevScaledRef.current.w !== scaledWidth ||
371+
prevScaledRef.current.h !== scaledHeight)
372+
) {
373+
const prevW = prevScaledRef.current.w;
374+
const prevH = prevScaledRef.current.h;
375+
setEditingPolygons((prev) =>
376+
prev.map((poly) => ({
377+
...poly,
378+
points: poly.points.map(([x, y]) => [
379+
(x / prevW) * scaledWidth,
380+
(y / prevH) * scaledHeight,
381+
]),
382+
})),
383+
);
384+
}
385+
prevScaledRef.current = { w: scaledWidth, h: scaledHeight };
359386
}
360387
// we know that these deps are correct
361388
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -431,7 +458,7 @@ export default function MasksAndZonesView({
431458
{cameraConfig && editingPolygons && (
432459
<div className="flex size-full flex-col md:flex-row">
433460
<Toaster position="top-center" closeButton={true} />
434-
<div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12">
461+
<div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12 md:min-w-0 md:shrink-0">
435462
{editPane == "zone" && (
436463
<ZoneEditPane
437464
polygons={editingPolygons}
@@ -707,7 +734,7 @@ export default function MasksAndZonesView({
707734
<div
708735
ref={containerRef}
709736
className={cn(
710-
"flex max-h-[50%] md:h-dvh md:max-h-full md:w-7/12 md:grow",
737+
"flex max-h-[50%] min-w-0 md:h-dvh md:max-h-full md:w-7/12 md:grow",
711738
isDesktop && "md:mr-3",
712739
)}
713740
>

0 commit comments

Comments
 (0)