diff --git a/web/src/components/player/LivePlayer.tsx b/web/src/components/player/LivePlayer.tsx index 2de13e802..2978717b7 100644 --- a/web/src/components/player/LivePlayer.tsx +++ b/web/src/components/player/LivePlayer.tsx @@ -93,7 +93,7 @@ export default function LivePlayer({ if (liveMode == "webrtc") { player = ( []) { - 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..b0d8483ba 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 @@ -105,7 +108,7 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; } 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%]"; } @@ -114,17 +117,33 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { if (fullscreen) { if (aspect > 16 / 9) { - return "absolute inset-x-0 top-[50%] -translate-y-[50%]"; + return "absolute inset-x-2 top-[50%] -translate-y-[50%]"; } else { - return "absolute inset-y-0 left-[50%] -translate-x-[50%]"; + return "absolute inset-y-2 left-[50%] -translate-x-[50%]"; } - } else if (aspect > 2) { - return "absolute left-2 right-2 top-[50%] -translate-y-[50%]"; } else { return "absolute top-2 bottom-2 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(() => { + if (isMobile || fullscreen) { + return cameraAspectRatio; + } else { + return windowAspectRatio < cameraAspectRatio + ? windowAspectRatio - 0.05 + : cameraAspectRatio - 0.03; + } + }, [cameraAspectRatio, windowAspectRatio, fullscreen]); + return (
-
+
+
{isMobile && (