mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 19:17:41 +03:00
clickable overlay div to navigate to full camera view
This commit is contained in:
parent
f549d2c0ab
commit
f73a7086f9
@ -13,6 +13,7 @@ type LivePlayerProps = {
|
|||||||
liveMode: LivePlayerMode;
|
liveMode: LivePlayerMode;
|
||||||
pip?: boolean;
|
pip?: boolean;
|
||||||
containerRef: React.MutableRefObject<HTMLDivElement | null>;
|
containerRef: React.MutableRefObject<HTMLDivElement | null>;
|
||||||
|
playerRef?: React.MutableRefObject<HTMLDivElement | null>;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ export default function BirdseyeLivePlayer({
|
|||||||
liveMode,
|
liveMode,
|
||||||
pip,
|
pip,
|
||||||
containerRef,
|
containerRef,
|
||||||
|
playerRef,
|
||||||
onClick,
|
onClick,
|
||||||
}: LivePlayerProps) {
|
}: LivePlayerProps) {
|
||||||
let player;
|
let player;
|
||||||
@ -76,7 +78,9 @@ export default function BirdseyeLivePlayer({
|
|||||||
>
|
>
|
||||||
<div className="pointer-events-none absolute inset-x-0 top-0 z-10 h-[30%] w-full rounded-lg bg-gradient-to-b from-black/20 to-transparent md:rounded-2xl"></div>
|
<div className="pointer-events-none absolute inset-x-0 top-0 z-10 h-[30%] w-full rounded-lg bg-gradient-to-b from-black/20 to-transparent md:rounded-2xl"></div>
|
||||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 h-[10%] w-full rounded-lg bg-gradient-to-t from-black/20 to-transparent md:rounded-2xl"></div>
|
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 h-[10%] w-full rounded-lg bg-gradient-to-t from-black/20 to-transparent md:rounded-2xl"></div>
|
||||||
<div className="size-full">{player}</div>
|
<div className="size-full" ref={playerRef}>
|
||||||
|
{player}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
|
import { useBirdseyeLayout } from "@/api/ws";
|
||||||
import CameraFeatureToggle from "@/components/dynamic/CameraFeatureToggle";
|
import CameraFeatureToggle from "@/components/dynamic/CameraFeatureToggle";
|
||||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import BirdseyeLivePlayer from "@/components/player/BirdseyeLivePlayer";
|
import BirdseyeLivePlayer from "@/components/player/BirdseyeLivePlayer";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
isDesktop,
|
isDesktop,
|
||||||
isFirefox,
|
isFirefox,
|
||||||
@ -122,6 +124,72 @@ export default function LiveBirdseyeView({
|
|||||||
return "mse";
|
return "mse";
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
|
const birdseyeLayout = useBirdseyeLayout();
|
||||||
|
|
||||||
|
// Click overlay handling
|
||||||
|
|
||||||
|
const playerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const handleOverlayClick = useCallback(
|
||||||
|
(
|
||||||
|
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
|
||||||
|
) => {
|
||||||
|
let clientX;
|
||||||
|
let clientY;
|
||||||
|
if ("TouchEvent" in window && e.nativeEvent instanceof TouchEvent) {
|
||||||
|
clientX = e.nativeEvent.touches[0].clientX;
|
||||||
|
clientY = e.nativeEvent.touches[0].clientY;
|
||||||
|
} else if (e.nativeEvent instanceof MouseEvent) {
|
||||||
|
clientX = e.nativeEvent.clientX;
|
||||||
|
clientY = e.nativeEvent.clientY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
playerRef.current &&
|
||||||
|
clientX &&
|
||||||
|
clientY &&
|
||||||
|
config &&
|
||||||
|
birdseyeLayout?.payload
|
||||||
|
) {
|
||||||
|
const playerRect = playerRef.current.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Calculate coordinates relative to player div, accounting for offset
|
||||||
|
const rawX = clientX - playerRect.left;
|
||||||
|
const rawY = clientY - playerRect.top;
|
||||||
|
|
||||||
|
// Ensure click is within player bounds
|
||||||
|
if (
|
||||||
|
rawX < 0 ||
|
||||||
|
rawX > playerRect.width ||
|
||||||
|
rawY < 0 ||
|
||||||
|
rawY > playerRect.height
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale click coordinates to birdseye canvas resolution
|
||||||
|
const canvasX = rawX * (config.birdseye.width / playerRect.width);
|
||||||
|
const canvasY = rawY * (config.birdseye.height / playerRect.height);
|
||||||
|
|
||||||
|
for (const [cameraName, coords] of Object.entries(
|
||||||
|
birdseyeLayout.payload,
|
||||||
|
)) {
|
||||||
|
const parsedCoords =
|
||||||
|
typeof coords === "string" ? JSON.parse(coords) : coords;
|
||||||
|
if (
|
||||||
|
canvasX >= parsedCoords.x &&
|
||||||
|
canvasX < parsedCoords.x + parsedCoords.width &&
|
||||||
|
canvasY >= parsedCoords.y &&
|
||||||
|
canvasY < parsedCoords.y + parsedCoords.height
|
||||||
|
) {
|
||||||
|
navigate(`/#${cameraName}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[playerRef, config, birdseyeLayout, navigate],
|
||||||
|
);
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
}
|
}
|
||||||
@ -215,16 +283,21 @@ export default function LiveBirdseyeView({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={growClassName}
|
className={cn(
|
||||||
|
"flex flex-col items-center justify-center",
|
||||||
|
growClassName,
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
aspectRatio: constrainedAspectRatio,
|
aspectRatio: constrainedAspectRatio,
|
||||||
}}
|
}}
|
||||||
|
onClick={handleOverlayClick}
|
||||||
>
|
>
|
||||||
<BirdseyeLivePlayer
|
<BirdseyeLivePlayer
|
||||||
className={`${fullscreen ? "*:rounded-none" : ""}`}
|
className={`${fullscreen ? "*:rounded-none" : ""}`}
|
||||||
birdseyeConfig={config.birdseye}
|
birdseyeConfig={config.birdseye}
|
||||||
liveMode={preferredLiveMode}
|
liveMode={preferredLiveMode}
|
||||||
containerRef={containerRef}
|
containerRef={containerRef}
|
||||||
|
playerRef={playerRef}
|
||||||
pip={pip}
|
pip={pip}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user