From e55a3d3439b2583d67c31813a3deb5f9424714e5 Mon Sep 17 00:00:00 2001 From: NlightN22 Date: Mon, 17 Mar 2025 02:09:51 +0700 Subject: [PATCH] fix live camera initial resolution add resize observer from frigate --- src/hooks/resize-observer.ts | 69 +++++++++++++++++++ src/pages/LiveCameraPage.tsx | 5 +- .../components/players/JSMpegPlayer.tsx | 5 +- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 src/hooks/resize-observer.ts diff --git a/src/hooks/resize-observer.ts b/src/hooks/resize-observer.ts new file mode 100644 index 0000000..1e174af --- /dev/null +++ b/src/hooks/resize-observer.ts @@ -0,0 +1,69 @@ +import { MutableRefObject, useEffect, useMemo, useState } from "react"; + +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, + x: -Infinity, + y: -Infinity, + }), + ); + const resizeObserver = useMemo( + () => + new ResizeObserver((entries) => { + window.requestAnimationFrame(() => { + setDimensions((prevDimensions) => { + const newDimensions = entries.map((entry) => entry.contentRect); + if ( + JSON.stringify(prevDimensions) !== JSON.stringify(newDimensions) + ) { + return newDimensions; + } + return prevDimensions; + }); + }); + }), + [], + ); + + useEffect(() => { + refs.forEach((ref) => { + if (ref instanceof Window) { + resizeObserver.observe(document.body); + } else if (ref.current) { + resizeObserver.observe(ref.current); + } + }); + + return () => { + refs.forEach((ref) => { + if (ref instanceof Window) { + resizeObserver.unobserve(document.body); + } else if (ref.current) { + resizeObserver.unobserve(ref.current); + } + }); + }; + }, [refs, resizeObserver]); + + if (dimensions.length == refs.length) { + return dimensions; + } else { + const items = [...dimensions]; + for (let i = dimensions.length; i < refs.length; i++) { + items.push({ + width: 0, + height: 0, + x: -Infinity, + y: -Infinity, + }); + } + + return items; + } +} diff --git a/src/pages/LiveCameraPage.tsx b/src/pages/LiveCameraPage.tsx index cec5064..bb5eb09 100644 --- a/src/pages/LiveCameraPage.tsx +++ b/src/pages/LiveCameraPage.tsx @@ -8,9 +8,11 @@ import OverlayCogwheelLoader from '../shared/components/loaders/OverlayCogwheelL import Player from '../widgets/Player'; import CameraPageHeader from '../widgets/header/CameraPageHeader'; import RetryErrorPage from './RetryErrorPage'; +import { LegacyRef, useRef } from 'react'; const LiveCameraPage = () => { const { t } = useTranslation() + const containerRef = useRef(null) let { id: cameraId } = useParams<'id'>() if (!cameraId) throw Error('Camera id does not exist') @@ -25,12 +27,13 @@ const LiveCameraPage = () => { return ( - + ); diff --git a/src/shared/components/players/JSMpegPlayer.tsx b/src/shared/components/players/JSMpegPlayer.tsx index 85a3635..23d91af 100644 --- a/src/shared/components/players/JSMpegPlayer.tsx +++ b/src/shared/components/players/JSMpegPlayer.tsx @@ -5,6 +5,8 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { cn } from "../../utils/class.merge"; import { PlayerStatsType } from "../../../types/live"; +import { isProduction } from "../../env.const"; +import { useResizeObserver } from "../../../hooks/resize-observer"; type JSMpegPlayerProps = { url: string; @@ -52,7 +54,8 @@ const JSMpegPlayer = ( [containerRef, containerRef.current, internalContainerRef], ); - const { height: containerHeight, width: containerWidth } = useViewportSize() + const [{ width: containerWidth, height: containerHeight }] = + useResizeObserver(selectedContainerRef); const stretch = true; const aspectRatio = width / height;