forked from Github/frigate
New mask/zone editor and motion tuner (#11020)
* initial working konva * working multi polygons * multi zones * clean up * new zone dialog * clean up * relative coordinates and colors * fix color order * better motion tuner * objects for zones * progress * merge dev * edit pane * motion and object masks * filtering * add objects and unsaved to type * motion tuner, edit controls, tooltips * object and motion edit panes * polygon item component, switch color, object form, hover cards * working zone edit pane * working motion masks * object masks and deletion of all types * use FilterSwitch * motion tuner fixes and tweaks * clean up * tweaks * spaces in camera name * tweaks * allow dragging of points while drawing polygon * turn off editing mode when switching camera * limit interpolated coordinates and use crosshair cursor * padding * fix tooltip trigger for icons * konva tweaks * consolidate * fix top menu items on mobile
This commit is contained in:
172
web/src/components/settings/PolygonDrawer.tsx
Normal file
172
web/src/components/settings/PolygonDrawer.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Line, Circle, Group } from "react-konva";
|
||||
import {
|
||||
minMax,
|
||||
toRGBColorString,
|
||||
dragBoundFunc,
|
||||
flattenPoints,
|
||||
} from "@/utils/canvasUtil";
|
||||
import type { KonvaEventObject } from "konva/lib/Node";
|
||||
import Konva from "konva";
|
||||
import { Vector2d } from "konva/lib/types";
|
||||
|
||||
type PolygonDrawerProps = {
|
||||
points: number[][];
|
||||
isActive: boolean;
|
||||
isHovered: boolean;
|
||||
isFinished: boolean;
|
||||
color: number[];
|
||||
handlePointDragMove: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
||||
handleGroupDragEnd: (e: KonvaEventObject<MouseEvent | TouchEvent>) => void;
|
||||
handleMouseOverStartPoint: (
|
||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => void;
|
||||
handleMouseOutStartPoint: (
|
||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => void;
|
||||
handleMouseOverAnyPoint: (
|
||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => void;
|
||||
handleMouseOutAnyPoint: (
|
||||
e: KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => void;
|
||||
};
|
||||
|
||||
export default function PolygonDrawer({
|
||||
points,
|
||||
isActive,
|
||||
isHovered,
|
||||
isFinished,
|
||||
color,
|
||||
handlePointDragMove,
|
||||
handleGroupDragEnd,
|
||||
handleMouseOverStartPoint,
|
||||
handleMouseOutStartPoint,
|
||||
handleMouseOverAnyPoint,
|
||||
handleMouseOutAnyPoint,
|
||||
}: PolygonDrawerProps) {
|
||||
const vertexRadius = 6;
|
||||
const flattenedPoints = useMemo(() => flattenPoints(points), [points]);
|
||||
const [stage, setStage] = useState<Konva.Stage>();
|
||||
const [minMaxX, setMinMaxX] = useState([0, 0]);
|
||||
const [minMaxY, setMinMaxY] = useState([0, 0]);
|
||||
const groupRef = useRef<Konva.Group>(null);
|
||||
|
||||
const handleGroupMouseOver = (
|
||||
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => {
|
||||
if (!isFinished) return;
|
||||
e.target.getStage()!.container().style.cursor = "move";
|
||||
setStage(e.target.getStage()!);
|
||||
};
|
||||
|
||||
const handleGroupMouseOut = (
|
||||
e: Konva.KonvaEventObject<MouseEvent | TouchEvent>,
|
||||
) => {
|
||||
if (!e.target || !isFinished) return;
|
||||
e.target.getStage()!.container().style.cursor = "default";
|
||||
};
|
||||
|
||||
const handleGroupDragStart = () => {
|
||||
const arrX = points.map((p) => p[0]);
|
||||
const arrY = points.map((p) => p[1]);
|
||||
setMinMaxX(minMax(arrX));
|
||||
setMinMaxY(minMax(arrY));
|
||||
};
|
||||
|
||||
const groupDragBound = (pos: Vector2d) => {
|
||||
if (!stage) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
let { x, y } = pos;
|
||||
const sw = stage.width();
|
||||
const sh = stage.height();
|
||||
|
||||
if (minMaxY[0] + y < 0) y = -1 * minMaxY[0];
|
||||
if (minMaxX[0] + x < 0) x = -1 * minMaxX[0];
|
||||
if (minMaxY[1] + y > sh) y = sh - minMaxY[1];
|
||||
if (minMaxX[1] + x > sw) x = sw - minMaxX[1];
|
||||
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
const colorString = useCallback(
|
||||
(darkened: boolean) => {
|
||||
return toRGBColorString(color, darkened);
|
||||
},
|
||||
[color],
|
||||
);
|
||||
|
||||
return (
|
||||
<Group
|
||||
name="polygon"
|
||||
ref={groupRef}
|
||||
draggable={isActive && isFinished}
|
||||
onDragStart={isActive ? handleGroupDragStart : undefined}
|
||||
onDragEnd={isActive ? handleGroupDragEnd : undefined}
|
||||
dragBoundFunc={isActive ? groupDragBound : undefined}
|
||||
onMouseOver={isActive ? handleGroupMouseOver : undefined}
|
||||
onTouchStart={isActive ? handleGroupMouseOver : undefined}
|
||||
onMouseOut={isActive ? handleGroupMouseOut : undefined}
|
||||
>
|
||||
<Line
|
||||
points={flattenedPoints}
|
||||
stroke={colorString(true)}
|
||||
strokeWidth={3}
|
||||
closed={isFinished}
|
||||
fill={colorString(isActive || isHovered ? true : false)}
|
||||
/>
|
||||
{points.map((point, index) => {
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
const x = point[0];
|
||||
const y = point[1];
|
||||
const startPointAttr =
|
||||
index === 0
|
||||
? {
|
||||
hitStrokeWidth: 12,
|
||||
onMouseOver: handleMouseOverStartPoint,
|
||||
onMouseOut: handleMouseOutStartPoint,
|
||||
}
|
||||
: null;
|
||||
const otherPointsAttr =
|
||||
index !== 0
|
||||
? {
|
||||
onMouseOver: handleMouseOverAnyPoint,
|
||||
onMouseOut: handleMouseOutAnyPoint,
|
||||
}
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Circle
|
||||
key={index}
|
||||
x={x}
|
||||
y={y}
|
||||
radius={vertexRadius}
|
||||
stroke={colorString(true)}
|
||||
fill="#ffffff"
|
||||
strokeWidth={3}
|
||||
draggable={isActive}
|
||||
onDragMove={isActive ? handlePointDragMove : undefined}
|
||||
dragBoundFunc={(pos) => {
|
||||
if (stage) {
|
||||
return dragBoundFunc(
|
||||
stage.width(),
|
||||
stage.height(),
|
||||
vertexRadius,
|
||||
pos,
|
||||
);
|
||||
} else {
|
||||
return pos;
|
||||
}
|
||||
}}
|
||||
{...startPointAttr}
|
||||
{...otherPointsAttr}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user