mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-11 05:35:25 +03:00
clean up
This commit is contained in:
parent
bbca5ffdfa
commit
0863d43e04
@ -5,7 +5,6 @@ import Konva from "konva";
|
|||||||
import type { KonvaEventObject } from "konva/lib/Node";
|
import type { KonvaEventObject } from "konva/lib/Node";
|
||||||
import { Polygon } from "@/types/canvas";
|
import { Polygon } from "@/types/canvas";
|
||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
|
||||||
|
|
||||||
type PolygonCanvasProps = {
|
type PolygonCanvasProps = {
|
||||||
camera: string;
|
camera: string;
|
||||||
@ -14,7 +13,6 @@ type PolygonCanvasProps = {
|
|||||||
polygons: Polygon[];
|
polygons: Polygon[];
|
||||||
setPolygons: React.Dispatch<React.SetStateAction<Polygon[]>>;
|
setPolygons: React.Dispatch<React.SetStateAction<Polygon[]>>;
|
||||||
activePolygonIndex: number | null;
|
activePolygonIndex: number | null;
|
||||||
setActivePolygonIndex: React.Dispatch<React.SetStateAction<number | null>>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PolygonCanvas({
|
export function PolygonCanvas({
|
||||||
@ -24,77 +22,35 @@ export function PolygonCanvas({
|
|||||||
polygons,
|
polygons,
|
||||||
setPolygons,
|
setPolygons,
|
||||||
activePolygonIndex,
|
activePolygonIndex,
|
||||||
setActivePolygonIndex,
|
|
||||||
}: PolygonCanvasProps) {
|
}: PolygonCanvasProps) {
|
||||||
const [image, setImage] = useState<HTMLImageElement | undefined>();
|
const [image, setImage] = useState<HTMLImageElement | undefined>();
|
||||||
const imageRef = useRef<Konva.Image | null>(null);
|
const imageRef = useRef<Konva.Image | null>(null);
|
||||||
// const containerRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const stageRef = useRef<Konva.Stage>(null);
|
const stageRef = useRef<Konva.Stage>(null);
|
||||||
// const [points, setPoints] = useState<number[][]>([]);
|
|
||||||
// const [activePolygonIndex, setActivePolygonIndex] = useState<number | null>(
|
|
||||||
// null,
|
|
||||||
// );
|
|
||||||
// const [size, setSize] = useState<{ width: number; height: number }>({
|
|
||||||
// width: width,
|
|
||||||
// height: height,
|
|
||||||
// });
|
|
||||||
const apiHost = useApiHost();
|
const apiHost = useApiHost();
|
||||||
// const [position, setPosition] = useState([0, 0]);
|
|
||||||
// const [{ width: windowWidth }] = useResizeObserver(window);
|
|
||||||
|
|
||||||
const videoElement = useMemo(() => {
|
const videoElement = useMemo(() => {
|
||||||
if (camera && width && height) {
|
if (camera && width && height) {
|
||||||
// console.log("width:", containerRef.current.clientWidth);
|
|
||||||
// console.log("width:", containerRef.current.clientHeight);
|
|
||||||
const element = new window.Image();
|
const element = new window.Image();
|
||||||
element.width = width; //containerRef.current.clientWidth;
|
element.width = width;
|
||||||
element.height = height; //containerRef.current.clientHeight;
|
element.height = height;
|
||||||
element.src = `${apiHost}api/${camera}/latest.jpg`;
|
element.src = `${apiHost}api/${camera}/latest.jpg`;
|
||||||
// setSize({
|
|
||||||
// width: width,
|
|
||||||
// height: height,
|
|
||||||
// });
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}, [camera, width, height, apiHost]);
|
}, [camera, width, height, apiHost]);
|
||||||
|
|
||||||
// const imageScale = scaledWidth / 720;
|
|
||||||
// console.log("window width", windowWidth);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!videoElement) {
|
if (!videoElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const onload = function () {
|
const onload = function () {
|
||||||
setImage(videoElement);
|
setImage(videoElement);
|
||||||
// if (!imageRef.current) imageRef.current = videoElement;
|
|
||||||
console.log(videoElement, Date.now());
|
|
||||||
};
|
};
|
||||||
videoElement.addEventListener("load", onload);
|
videoElement.addEventListener("load", onload);
|
||||||
return () => {
|
return () => {
|
||||||
console.log("unloading");
|
|
||||||
videoElement.removeEventListener("load", onload);
|
videoElement.removeEventListener("load", onload);
|
||||||
};
|
};
|
||||||
}, [videoElement]);
|
}, [videoElement]);
|
||||||
|
|
||||||
// use Konva.Animation to redraw a layer
|
|
||||||
// useEffect(() => {
|
|
||||||
// //videoElement.play();
|
|
||||||
// if (!videoElement && !imageRef && !imageRef.current) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const layer = imageRef.current?.getLayer();
|
|
||||||
// console.log("layer", layer);
|
|
||||||
|
|
||||||
// const anim = new Konva.Animation(() => {}, layer);
|
|
||||||
// anim.start();
|
|
||||||
|
|
||||||
// return () => {
|
|
||||||
// anim.stop();
|
|
||||||
// };
|
|
||||||
// }, [videoElement]);
|
|
||||||
|
|
||||||
const getMousePos = (stage: Konva.Stage) => {
|
const getMousePos = (stage: Konva.Stage) => {
|
||||||
return [stage.getPointerPosition()!.x, stage.getPointerPosition()!.y];
|
return [stage.getPointerPosition()!.x, stage.getPointerPosition()!.y];
|
||||||
};
|
};
|
||||||
@ -104,7 +60,6 @@ export function PolygonCanvas({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const [firstPoint] = polygon.points;
|
const [firstPoint] = polygon.points;
|
||||||
console.log("first", firstPoint);
|
|
||||||
const distance = Math.hypot(
|
const distance = Math.hypot(
|
||||||
mousePos[0] - firstPoint[0],
|
mousePos[0] - firstPoint[0],
|
||||||
mousePos[1] - firstPoint[1],
|
mousePos[1] - firstPoint[1],
|
||||||
@ -116,23 +71,7 @@ export function PolygonCanvas({
|
|||||||
if (!activePolygonIndex || !polygons) {
|
if (!activePolygonIndex || !polygons) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("mouse down polygons", polygons);
|
|
||||||
console.log(activePolygonIndex);
|
|
||||||
|
|
||||||
// if (!polygons[activePolygonIndex].points.length) {
|
|
||||||
// // Start a new polygon
|
|
||||||
// const stage = e.target.getStage()!;
|
|
||||||
// const mousePos = getMousePos(stage);
|
|
||||||
// setPolygons([
|
|
||||||
// ...polygons,
|
|
||||||
// {
|
|
||||||
// name: "foo",
|
|
||||||
// points: [mousePos],
|
|
||||||
// isFinished: false,
|
|
||||||
// },
|
|
||||||
// ]);
|
|
||||||
// setActivePolygonIndex(polygons.length);
|
|
||||||
// } 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()!;
|
||||||
@ -148,7 +87,6 @@ export function PolygonCanvas({
|
|||||||
isFinished: true,
|
isFinished: true,
|
||||||
};
|
};
|
||||||
setPolygons(updatedPolygons);
|
setPolygons(updatedPolygons);
|
||||||
// setActivePolygonIndex(null);
|
|
||||||
} else {
|
} else {
|
||||||
if (!activePolygon.isFinished) {
|
if (!activePolygon.isFinished) {
|
||||||
// Add a new point to the active polygon
|
// Add a new point to the active polygon
|
||||||
@ -162,12 +100,6 @@ export function PolygonCanvas({
|
|||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = (e: KonvaEventObject<MouseEvent>) => {
|
|
||||||
const stage = e.target.getStage()!;
|
|
||||||
const mousePos = getMousePos(stage);
|
|
||||||
// setPosition(mousePos);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseOverStartPoint = (e: KonvaEventObject<MouseEvent>) => {
|
const handleMouseOverStartPoint = (e: KonvaEventObject<MouseEvent>) => {
|
||||||
if (activePolygonIndex !== null && polygons) {
|
if (activePolygonIndex !== null && polygons) {
|
||||||
const activePolygon = polygons[activePolygonIndex];
|
const activePolygon = polygons[activePolygonIndex];
|
||||||
@ -178,16 +110,13 @@ export function PolygonCanvas({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseOutStartPoint = (e: KonvaEventObject<MouseEvent>) => {
|
const handleMouseOutStartPoint = (e: KonvaEventObject<MouseEvent>) => {
|
||||||
// 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);
|
|
||||||
if (
|
if (
|
||||||
(!activePolygon.isFinished && activePolygon.points.length >= 3) ||
|
(!activePolygon.isFinished && activePolygon.points.length >= 3) ||
|
||||||
activePolygon.isFinished
|
activePolygon.isFinished
|
||||||
) {
|
) {
|
||||||
// console.log(e.currentTarget);
|
|
||||||
e.currentTarget.scale({ x: 1, y: 1 });
|
e.currentTarget.scale({ x: 1, y: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,14 +167,12 @@ 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}
|
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
>
|
>
|
||||||
<Layer>
|
<Layer>
|
||||||
|
|||||||
@ -53,9 +53,6 @@ export function PolygonControls({
|
|||||||
name: "new",
|
name: "new",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
console.log(polygons.length);
|
|
||||||
console.log(polygons);
|
|
||||||
console.log("active index", polygons.length);
|
|
||||||
setActivePolygonIndex(polygons.length);
|
setActivePolygonIndex(polygons.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -19,12 +19,10 @@ import {
|
|||||||
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";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { PolygonCanvas } from "./PolygonCanvas";
|
import { PolygonCanvas } from "./PolygonCanvas";
|
||||||
import { useApiHost } from "@/api";
|
|
||||||
import { Polygon } from "@/types/canvas";
|
import { Polygon } from "@/types/canvas";
|
||||||
import { interpolatePoints } from "@/utils/canvasUtil";
|
import { interpolatePoints } from "@/utils/canvasUtil";
|
||||||
import AutoUpdatingCameraImage from "../camera/AutoUpdatingCameraImage";
|
|
||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
import PolygonControls from "./PolygonControls";
|
import PolygonControls from "./PolygonControls";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
@ -50,10 +48,7 @@ export default function SettingsZones() {
|
|||||||
const [activePolygonIndex, setActivePolygonIndex] = useState<number | null>(
|
const [activePolygonIndex, setActivePolygonIndex] = useState<number | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const imgRef = useRef<HTMLImageElement | null>(null);
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const apiHost = useApiHost();
|
|
||||||
// const videoSource = `${apiHost}api/ptzcam/latest.jpg`;
|
|
||||||
|
|
||||||
const cameras = useMemo(() => {
|
const cameras = useMemo(() => {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
@ -73,55 +68,28 @@ export default function SettingsZones() {
|
|||||||
}
|
}
|
||||||
}, [config, selectedCamera]);
|
}, [config, selectedCamera]);
|
||||||
|
|
||||||
const cameraAspect = useMemo(() => {
|
const grow = useMemo(() => {
|
||||||
if (!cameraConfig) {
|
if (!cameraConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const aspectRatio = cameraConfig.detect.width / cameraConfig.detect.height;
|
const aspectRatio = cameraConfig.detect.width / cameraConfig.detect.height;
|
||||||
console.log("aspect", aspectRatio);
|
|
||||||
|
|
||||||
if (!aspectRatio) {
|
if (aspectRatio > 2) {
|
||||||
return "normal";
|
|
||||||
} else if (aspectRatio > 2) {
|
|
||||||
return "wide";
|
|
||||||
} else if (aspectRatio < 16 / 9) {
|
|
||||||
return "tall";
|
|
||||||
} else {
|
|
||||||
return "normal";
|
|
||||||
}
|
|
||||||
}, [cameraConfig]);
|
|
||||||
|
|
||||||
const grow = useMemo(() => {
|
|
||||||
if (cameraAspect == "wide") {
|
|
||||||
return "aspect-wide";
|
return "aspect-wide";
|
||||||
} else if (cameraAspect == "tall") {
|
} else if (aspectRatio < 16 / 9) {
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
return "size-full aspect-tall";
|
return "size-full aspect-tall";
|
||||||
} else {
|
} else {
|
||||||
return "size-full";
|
return "size-full";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "aspect-video";
|
return "size-full aspect-video";
|
||||||
}
|
}
|
||||||
}, [cameraAspect]);
|
}, [cameraConfig]);
|
||||||
|
|
||||||
// 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.
|
|
||||||
// https://github.com/blakeblackshear/frigate/issues/1657
|
|
||||||
let scrollBarWidth = 0;
|
|
||||||
// if (window.innerWidth && document.body.offsetWidth) {
|
|
||||||
// scrollBarWidth = window.innerWidth - document.body.offsetWidth;
|
|
||||||
// }
|
|
||||||
// const availableWidth = scrollBarWidth
|
|
||||||
// ? containerWidth + scrollBarWidth
|
|
||||||
// : containerWidth;
|
|
||||||
|
|
||||||
const availableWidth = containerWidth;
|
|
||||||
|
|
||||||
const { width, height } = cameraConfig
|
const { width, height } = cameraConfig
|
||||||
? cameraConfig.detect
|
? cameraConfig.detect
|
||||||
@ -129,12 +97,13 @@ export default function SettingsZones() {
|
|||||||
const aspectRatio = width / height;
|
const aspectRatio = width / height;
|
||||||
|
|
||||||
const stretch = false;
|
const stretch = false;
|
||||||
const fitAspect = 1;
|
const fitAspect = 0.75;
|
||||||
|
|
||||||
const scaledHeight = useMemo(() => {
|
const scaledHeight = useMemo(() => {
|
||||||
const scaledHeight =
|
const scaledHeight =
|
||||||
aspectRatio < (fitAspect ?? 0)
|
aspectRatio < (fitAspect ?? 0)
|
||||||
? Math.floor(containerHeight)
|
? Math.floor(containerHeight)
|
||||||
: Math.floor(availableWidth / aspectRatio);
|
: Math.floor(containerWidth / aspectRatio);
|
||||||
const finalHeight = stretch ? scaledHeight : Math.min(scaledHeight, height);
|
const finalHeight = stretch ? scaledHeight : Math.min(scaledHeight, height);
|
||||||
|
|
||||||
if (finalHeight > 0) {
|
if (finalHeight > 0) {
|
||||||
@ -143,16 +112,17 @@ export default function SettingsZones() {
|
|||||||
|
|
||||||
return 100;
|
return 100;
|
||||||
}, [
|
}, [
|
||||||
availableWidth,
|
|
||||||
aspectRatio,
|
aspectRatio,
|
||||||
|
containerWidth,
|
||||||
containerHeight,
|
containerHeight,
|
||||||
fitAspect,
|
fitAspect,
|
||||||
height,
|
height,
|
||||||
stretch,
|
stretch,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const scaledWidth = useMemo(
|
const scaledWidth = useMemo(
|
||||||
() => Math.ceil(scaledHeight * aspectRatio - scrollBarWidth),
|
() => Math.ceil(scaledHeight * aspectRatio),
|
||||||
[scaledHeight, aspectRatio, scrollBarWidth],
|
[scaledHeight, aspectRatio],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -175,37 +145,10 @@ export default function SettingsZones() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [cameraConfig, containerRef]);
|
}, [cameraConfig, containerRef]);
|
||||||
|
|
||||||
// const image = useMemo(() => {
|
|
||||||
// if (cameraConfig && containerRef && containerRef.current) {
|
|
||||||
// console.log("width:", containerRef.current.clientWidth);
|
|
||||||
// const element = new window.Image();
|
|
||||||
// element.width = containerRef.current.clientWidth;
|
|
||||||
// element.height = containerRef.current.clientHeight;
|
|
||||||
// element.src = `${apiHost}api/${cameraConfig.name}/latest.jpg`;
|
|
||||||
// return element;
|
|
||||||
// }
|
|
||||||
// }, [cameraConfig, apiHost, containerRef]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (image) {
|
|
||||||
// imgRef.current = image;
|
|
||||||
// }
|
|
||||||
// }, [image]);
|
|
||||||
|
|
||||||
if (!cameraConfig && !selectedCamera) {
|
if (!cameraConfig && !selectedCamera) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("selected camera", selectedCamera);
|
|
||||||
// console.log("threshold", motionThreshold);
|
|
||||||
// console.log("contour area", motionContourArea);
|
|
||||||
// console.log("zone polygons", zonePolygons);
|
|
||||||
|
|
||||||
// console.log("width:", containerRef.current.clientWidth);
|
|
||||||
// const element = new window.Image();
|
|
||||||
// element.width = containerRef.current.clientWidth;
|
|
||||||
// element.height = containerRef.current.clientHeight;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Heading as="h2">Zones</Heading>
|
<Heading as="h2">Zones</Heading>
|
||||||
@ -234,7 +177,7 @@ export default function SettingsZones() {
|
|||||||
{cameraConfig && (
|
{cameraConfig && (
|
||||||
<div className="flex flex-row justify-evenly">
|
<div className="flex flex-row justify-evenly">
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col justify-center items-center w-[50%] ${grow}`}
|
className={`flex flex-col justify-center items-center w-[60%] ${grow}`}
|
||||||
>
|
>
|
||||||
<div ref={containerRef} className="size-full">
|
<div ref={containerRef} className="size-full">
|
||||||
{cameraConfig ? (
|
{cameraConfig ? (
|
||||||
@ -245,7 +188,6 @@ export default function SettingsZones() {
|
|||||||
polygons={zonePolygons}
|
polygons={zonePolygons}
|
||||||
setPolygons={setZonePolygons}
|
setPolygons={setZonePolygons}
|
||||||
activePolygonIndex={activePolygonIndex}
|
activePolygonIndex={activePolygonIndex}
|
||||||
setActivePolygonIndex={setActivePolygonIndex}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Skeleton className="w-full h-full" />
|
<Skeleton className="w-full h-full" />
|
||||||
@ -295,6 +237,11 @@ export default function SettingsZones() {
|
|||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
<div>
|
||||||
|
scaled width: {scaledWidth}, scaled height: {scaledHeight},
|
||||||
|
container width: {containerWidth}, container height:
|
||||||
|
{containerHeight}
|
||||||
|
</div>
|
||||||
<PolygonControls
|
<PolygonControls
|
||||||
camera={cameraConfig.name}
|
camera={cameraConfig.name}
|
||||||
width={scaledWidth}
|
width={scaledWidth}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user