fix(web): make camera latest.jpg responsive

This commit is contained in:
Paul Armstrong 2021-01-25 09:49:00 -08:00 committed by Blake Blackshear
parent 2beb44b591
commit f0f3764992
5 changed files with 63 additions and 23 deletions

View File

@ -1,6 +1,7 @@
import { h } from 'preact';
import Box from './components/Box';
import Button from './components/Button';
import CameraImage from './components/CameraImage';
import Heading from './components/Heading';
import Switch from './components/Switch';
import { route } from 'preact-router';
@ -27,14 +28,26 @@ export default function CameraMasks({ camera, url }) {
zones,
} = cameraConfig;
const resizeObserver = useMemo(
() =>
new ResizeObserver((entries) => {
window.requestAnimationFrame(() => {
if (Array.isArray(entries) && entries.length) {
const scaledWidth = entries[0].contentRect.width;
const scale = scaledWidth / width;
setImageScale(scale);
}
});
}),
[camera, width, setImageScale]
);
useEffect(() => {
if (!imageRef.current) {
return;
}
const scaledWidth = imageRef.current.width;
const scale = scaledWidth / width;
setImageScale(scale);
}, [imageRef.current, setImageScale]);
resizeObserver.observe(imageRef.current);
}, [resizeObserver, imageRef.current]);
const [motionMaskPoints, setMotionMaskPoints] = useState(
Array.isArray(motionMask)
@ -226,7 +239,7 @@ ${Object.keys(objectMaskPoints)
<Box className="space-y-4">
<div className="relative">
<img ref={imageRef} className="w-full" src={`${apiHost}/api/${camera}/latest.jpg`} />
<CameraImage imageRef={imageRef} camera={camera} />
<EditableMask
onChange={handleUpdateEditable}
points={editing.subkey ? editing.set[editing.key][editing.subkey] : editing.set[editing.key]}

View File

@ -1,5 +1,6 @@
import { h } from 'preact';
import Box from './components/Box';
import CameraImage from './components/CameraImage';
import Events from './Events';
import Heading from './components/Heading';
import { route } from 'preact-router';
@ -23,7 +24,6 @@ export default function Cameras() {
}
function Camera({ name }) {
const apiHost = useContext(ApiHost);
const href = `/cameras/${name}`;
return (
@ -32,7 +32,7 @@ function Camera({ name }) {
href={href}
>
<Heading size="base">{name}</Heading>
<img className="w-full" src={`${apiHost}/api/${name}/latest.jpg`} />
<CameraImage camera={name} />
</Box>
);
}

View File

@ -1,11 +1,10 @@
import { h } from 'preact';
import CameraImage from './CameraImage';
import { ApiHost, Config } from '../context';
import { useCallback, useEffect, useContext, useState } from 'preact/hooks';
export default function AutoUpdatingCameraImage({ camera, searchParams }) {
const config = useContext(Config);
const apiHost = useContext(ApiHost);
const cameraConfig = config.cameras[camera];
const [key, setKey] = useState(Date.now());
useEffect(() => {
@ -17,11 +16,5 @@ export default function AutoUpdatingCameraImage({ camera, searchParams }) {
};
}, [key, searchParams]);
return (
<img
className="w-full"
src={`${apiHost}/api/${camera}/latest.jpg?cache=${key}&${searchParams}`}
alt={`Auto-updating ${camera} image`}
/>
);
return <CameraImage camera={camera} searchParams={`cache=${key}&${searchParams}`} />;
}

View File

@ -0,0 +1,38 @@
import { h } from 'preact';
import { ApiHost, Config } from '../context';
import { useCallback, useEffect, useContext, useState } from 'preact/hooks';
export default function CameraImage({ camera, searchParams = '', imageRef }) {
const config = useContext(Config);
const apiHost = useContext(ApiHost);
const { name, width, height } = config.cameras[camera];
const aspectRatio = width / height;
const innerWidth = parseInt(window.innerWidth, 10);
const responsiveWidths = [640, 768, 1024, 1280];
if (innerWidth > responsiveWidths[responsiveWidths.length - 1]) {
responsiveWidths.push(innerWidth);
}
const src = `${apiHost}/api/${camera}/latest.jpg`;
const { srcset, sizes } = responsiveWidths.reduce(
(memo, w, i) => {
memo.srcset.push(`${src}?h=${Math.ceil(w / aspectRatio)}&${searchParams} ${w}w`);
memo.sizes.push(`(max-width: ${w}) ${Math.ceil((w / innerWidth) * 100)}vw`);
return memo;
},
{ srcset: [], sizes: [] }
);
return (
<img
className="w-full"
srcset={srcset.join(', ')}
sizes={sizes.join(', ')}
src={`${srcset[srcset.length - 1]}`}
alt={name}
ref={imageRef}
/>
);
}

View File

@ -2,13 +2,9 @@ import { h } from 'preact';
import { useCallback, useState } from 'preact/hooks';
export default function Switch({ checked, label, id, onChange }) {
const handleChange = useCallback(
(event) => {
console.log(event.target.checked, !checked);
onChange(id, !checked);
},
[id, onChange, checked]
);
const handleChange = useCallback(() => {
onChange(id, !checked);
}, [id, onChange, checked]);
return (
<label for={id} className="flex items-center cursor-pointer">