multi zones

This commit is contained in:
Josh Hawkins 2024-04-08 11:02:35 -05:00
parent 8610b02ddb
commit bbca5ffdfa
3 changed files with 126 additions and 68 deletions

View File

@ -72,6 +72,7 @@ export function PolygonCanvas({
}; };
videoElement.addEventListener("load", onload); videoElement.addEventListener("load", onload);
return () => { return () => {
console.log("unloading");
videoElement.removeEventListener("load", onload); videoElement.removeEventListener("load", onload);
}; };
}, [videoElement]); }, [videoElement]);
@ -112,34 +113,34 @@ export function PolygonCanvas({
}; };
const handleMouseDown = (e: KonvaEventObject<MouseEvent>) => { const handleMouseDown = (e: KonvaEventObject<MouseEvent>) => {
if (activePolygonIndex === null || !polygons) { if (!activePolygonIndex || !polygons) {
return; return;
} }
console.log("mouse down polygons", polygons); console.log("mouse down polygons", polygons);
console.log(activePolygonIndex); console.log(activePolygonIndex);
if (!polygons[activePolygonIndex].points.length) { // if (!polygons[activePolygonIndex].points.length) {
// Start a new polygon // // Start a new polygon
const stage = e.target.getStage()!; // const stage = e.target.getStage()!;
const mousePos = getMousePos(stage); // const mousePos = getMousePos(stage);
setPolygons([ // setPolygons([
...polygons, // ...polygons,
{ // {
name: "foo", // name: "foo",
points: [mousePos], // points: [mousePos],
isFinished: false, // isFinished: false,
}, // },
]); // ]);
setActivePolygonIndex(polygons.length); // setActivePolygonIndex(polygons.length);
} else { // } else {
const updatedPolygons = [...polygons]; const updatedPolygons = [...polygons];
const activePolygon = updatedPolygons[activePolygonIndex]; const activePolygon = updatedPolygons[activePolygonIndex];
const stage = e.target.getStage()!; const stage = e.target.getStage()!;
const mousePos = getMousePos(stage); const mousePos = getMousePos(stage);
if ( if (
isMouseOverPoint(activePolygon, mousePos) && activePolygon.points.length >= 3 &&
activePolygon.points.length >= 3 isMouseOverPoint(activePolygon, mousePos)
) { ) {
// Close the polygon // Close the polygon
updatedPolygons[activePolygonIndex] = { updatedPolygons[activePolygonIndex] = {
@ -158,7 +159,7 @@ export function PolygonCanvas({
setPolygons(updatedPolygons); setPolygons(updatedPolygons);
} }
} }
} // }
}; };
const handleMouseMove = (e: KonvaEventObject<MouseEvent>) => { const handleMouseMove = (e: KonvaEventObject<MouseEvent>) => {
@ -177,16 +178,16 @@ export function PolygonCanvas({
}; };
const handleMouseOutStartPoint = (e: KonvaEventObject<MouseEvent>) => { const handleMouseOutStartPoint = (e: KonvaEventObject<MouseEvent>) => {
console.log("active index:", activePolygonIndex); // console.log("active index:", activePolygonIndex);
e.currentTarget.scale({ x: 1, y: 1 }); e.currentTarget.scale({ x: 1, y: 1 });
if (activePolygonIndex !== null && polygons) { if (activePolygonIndex !== null && polygons) {
const activePolygon = polygons[activePolygonIndex]; const activePolygon = polygons[activePolygonIndex];
console.log(activePolygon); // console.log(activePolygon);
if ( if (
(!activePolygon.isFinished && activePolygon.points.length >= 3) || (!activePolygon.isFinished && activePolygon.points.length >= 3) ||
activePolygon.isFinished activePolygon.isFinished
) { ) {
console.log(e.currentTarget); // console.log(e.currentTarget);
e.currentTarget.scale({ x: 1, y: 1 }); e.currentTarget.scale({ x: 1, y: 1 });
} }
} }
@ -237,13 +238,14 @@ export function PolygonCanvas({
setPolygons(updatedPolygons); setPolygons(updatedPolygons);
} }
}; };
// console.log("rendering canvas", Date.now());
return ( return (
<Stage <Stage
ref={stageRef} ref={stageRef}
width={width} width={width}
height={height} height={height}
onMouseMove={handleMouseMove} // onMouseMove={handleMouseMove}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}
> >
<Layer> <Layer>
@ -255,8 +257,7 @@ export function PolygonCanvas({
width={width} width={width}
height={height} height={height}
/> />
{polygons && {polygons?.map((polygon, index) => (
polygons.map((polygon, index) => (
<PolygonDrawer <PolygonDrawer
key={index} key={index}
points={polygon.points} points={polygon.points}

View File

@ -8,6 +8,14 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import useSWR from "swr"; import useSWR from "swr";
import ActivityIndicator from "@/components/indicators/activity-indicator"; import ActivityIndicator from "@/components/indicators/activity-indicator";
@ -21,6 +29,7 @@ import { isDesktop } from "react-device-detect";
import PolygonControls from "./PolygonControls"; import PolygonControls from "./PolygonControls";
import { Skeleton } from "../ui/skeleton"; import { Skeleton } from "../ui/skeleton";
import { useResizeObserver } from "@/hooks/resize-observer"; import { useResizeObserver } from "@/hooks/resize-observer";
import { LuPencil } from "react-icons/lu";
const parseCoordinates = (coordinatesString: string) => { const parseCoordinates = (coordinatesString: string) => {
const coordinates = coordinatesString.split(","); const coordinates = coordinatesString.split(",");
@ -97,26 +106,30 @@ export default function SettingsZones() {
} }
}, [cameraAspect]); }, [cameraAspect]);
const [{ width: containerWidth, height: containerHeight }] = // const [{ width: containerWidth, height: containerHeight }] =
useResizeObserver(containerRef); // useResizeObserver(containerRef);
const containerWidth = containerRef.current?.clientWidth;
const containerHeight = containerRef.current?.clientHeight;
// Add scrollbar width (when visible) to the available observer width to eliminate screen juddering. // Add scrollbar width (when visible) to the available observer width to eliminate screen juddering.
// https://github.com/blakeblackshear/frigate/issues/1657 // https://github.com/blakeblackshear/frigate/issues/1657
let scrollBarWidth = 0; let scrollBarWidth = 0;
if (window.innerWidth && document.body.offsetWidth) { // if (window.innerWidth && document.body.offsetWidth) {
scrollBarWidth = window.innerWidth - document.body.offsetWidth; // scrollBarWidth = window.innerWidth - document.body.offsetWidth;
} // }
const availableWidth = scrollBarWidth // const availableWidth = scrollBarWidth
? containerWidth + scrollBarWidth // ? containerWidth + scrollBarWidth
: containerWidth; // : containerWidth;
const availableWidth = containerWidth;
const { width, height } = cameraConfig const { width, height } = cameraConfig
? cameraConfig.detect ? cameraConfig.detect
: { width: 1, height: 1 }; : { width: 1, height: 1 };
const aspectRatio = width / height; const aspectRatio = width / height;
const stretch = true; const stretch = false;
const fitAspect = 1.8; const fitAspect = 1;
const scaledHeight = useMemo(() => { const scaledHeight = useMemo(() => {
const scaledHeight = const scaledHeight =
aspectRatio < (fitAspect ?? 0) aspectRatio < (fitAspect ?? 0)
@ -158,7 +171,9 @@ export default function SettingsZones() {
})), })),
); );
} }
}, [cameraConfig, containerRef, scaledWidth, scaledHeight]); // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cameraConfig, containerRef]);
// const image = useMemo(() => { // const image = useMemo(() => {
// if (cameraConfig && containerRef && containerRef.current) { // if (cameraConfig && containerRef && containerRef.current) {
@ -193,7 +208,7 @@ export default function SettingsZones() {
return ( return (
<> <>
<Heading as="h2">Motion Detection Tuner</Heading> <Heading as="h2">Zones</Heading>
<div className="flex items-center space-x-2 mt-5"> <div className="flex items-center space-x-2 mt-5">
<Select value={selectedCamera} onValueChange={setSelectedCamera}> <Select value={selectedCamera} onValueChange={setSelectedCamera}>
<SelectTrigger className="w-[180px]"> <SelectTrigger className="w-[180px]">
@ -238,6 +253,48 @@ export default function SettingsZones() {
</div> </div>
</div> </div>
<div className="w-[30%]"> <div className="w-[30%]">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Name</TableHead>
<TableHead className="max-w-[200px]">Coordinates</TableHead>
<TableHead>Edit</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{zonePolygons.map((polygon, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{polygon.name}
</TableCell>
<TableCell className="max-w-[200px] text-wrap">
<code>
{JSON.stringify(
interpolatePoints(
polygon.points,
scaledWidth,
scaledHeight,
cameraConfig.detect.width,
cameraConfig.detect.height,
),
null,
0,
)}
</code>
</TableCell>
<TableCell>
{" "}
<div
className="cursor-pointer"
onClick={() => setActivePolygonIndex(index)}
>
<LuPencil className="size-4 text-white" />
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<PolygonControls <PolygonControls
camera={cameraConfig.name} camera={cameraConfig.name}
width={scaledWidth} width={scaledWidth}
@ -256,8 +313,8 @@ export default function SettingsZones() {
polygon.points, polygon.points,
scaledWidth, scaledWidth,
scaledHeight, scaledHeight,
cameraConfig.detect.width, 1,
cameraConfig.detect.height, 1,
), ),
), ),
null, null,

View File

@ -58,7 +58,7 @@ export const interpolatePoints = (
for (const [x, y] of points) { for (const [x, y] of points) {
const newX = (x * newWidth) / width; const newX = (x * newWidth) / width;
const newY = (y * newHeight) / height; const newY = (y * newHeight) / height;
newPoints.push([Math.floor(newX), Math.floor(newY)]); newPoints.push([newX, newY]);
} }
return newPoints; return newPoints;