diff --git a/web/src/hooks/resize-observer.ts b/web/src/hooks/resize-observer.ts index dc1e18d41..13e79f58c 100644 --- a/web/src/hooks/resize-observer.ts +++ b/web/src/hooks/resize-observer.ts @@ -1,7 +1,11 @@ import { MutableRefObject, useEffect, useMemo, useState } from "react"; -export function useResizeObserver(...refs: MutableRefObject[]) { - const [dimensions, setDimensions] = useState( +type RefType = MutableRefObject | Window; + +export function useResizeObserver(...refs: RefType[]) { + const [dimensions, setDimensions] = useState< + { width: number; height: number; x: number; y: number }[] + >( new Array(refs.length).fill({ width: 0, height: 0, @@ -21,14 +25,18 @@ export function useResizeObserver(...refs: MutableRefObject[]) { useEffect(() => { refs.forEach((ref) => { - if (ref.current) { + if (ref instanceof Window) { + resizeObserver.observe(document.body); + } else if (ref.current) { resizeObserver.observe(ref.current); } }); return () => { refs.forEach((ref) => { - if (ref.current) { + if (ref instanceof Window) { + resizeObserver.unobserve(document.body); + } else if (ref.current) { resizeObserver.unobserve(ref.current); } }); diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index c3f42ac0d..70b9ba34d 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -15,6 +15,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { TooltipProvider } from "@/components/ui/tooltip"; +import { useResizeObserver } from "@/hooks/resize-observer"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; import { CameraConfig } from "@/types/frigateConfig"; import { CameraPtzInfo } from "@/types/ptz"; @@ -61,6 +62,8 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { const navigate = useNavigate(); const { isPortrait } = useMobileOrientation(); const mainRef = useRef(null); + const [{ width: windowWidth, height: windowHeight }] = + useResizeObserver(window); // camera features @@ -102,12 +105,12 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { if (isMobile) { if (isPortrait) { - return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; + return "absolute left-0 right-0"; } else { if (aspect > 16 / 9) { - return "absolute left-12 top-[50%] -translate-y-[50%]"; + return "absolute left-0 top-[50%] -translate-y-[50%]"; } else { - return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]"; + return "absolute top-0 bottom-0 left-[50%] -translate-x-[50%]"; } } } @@ -119,12 +122,28 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { return "absolute inset-y-0 left-[50%] -translate-x-[50%]"; } } else if (aspect > 2) { - return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; + return "absolute left-0 right-0 top-[50%] -translate-y-[50%]"; } else { - return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]"; + return "absolute top-0 bottom-0 left-[50%] -translate-x-[50%]"; } }, [camera, fullscreen, isPortrait]); + const windowAspectRatio = useMemo(() => { + return windowWidth / windowHeight; + }, [windowWidth, windowHeight]); + + const cameraAspectRatio = useMemo(() => { + return camera.detect.width / camera.detect.height; + }, [camera]); + + const aspectRatio = useMemo( + () => + windowAspectRatio < cameraAspectRatio + ? windowAspectRatio - 0.05 + : cameraAspectRatio - 0.03, + [cameraAspectRatio, windowAspectRatio], + ); + return (
-
+
+
{isMobile && (