67 lines
2.3 KiB
JavaScript
67 lines
2.3 KiB
JavaScript
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
import { DEFAULT_MAP_SIZE, clampMapZoom } from "../lib/locationMapUtils";
|
|
|
|
const COMPACT_MAP_LAYOUT_QUERY = "(max-width: 839px)";
|
|
|
|
function getAutoFitKey(mapState, mapSize) {
|
|
return [
|
|
mapState?.location?.id || "",
|
|
mapState?.draft_map?.id || "",
|
|
mapState?.published_map?.id || "",
|
|
mapSize.width,
|
|
mapSize.height,
|
|
].join(":");
|
|
}
|
|
|
|
function getFitZoom(mapSize, scrollElement) {
|
|
const fallbackWidth = typeof window === "undefined" ? DEFAULT_MAP_SIZE.width : window.innerWidth;
|
|
const fallbackHeight = typeof window === "undefined" ? DEFAULT_MAP_SIZE.height : window.innerHeight;
|
|
const isCompactLayout = typeof window !== "undefined"
|
|
&& window.matchMedia(COMPACT_MAP_LAYOUT_QUERY).matches;
|
|
const minimumWidth = isCompactLayout ? 160 : 280;
|
|
const minimumHeight = isCompactLayout ? 120 : 220;
|
|
const availableWidth = Math.max(minimumWidth, (scrollElement?.clientWidth || fallbackWidth) - 24);
|
|
const availableHeight = Math.max(minimumHeight, (scrollElement?.clientHeight || fallbackHeight) - 24);
|
|
|
|
return Number(clampMapZoom(
|
|
Math.min(availableWidth / mapSize.width, availableHeight / mapSize.height)
|
|
).toFixed(2));
|
|
}
|
|
|
|
export default function useMobileMapAutoFit({
|
|
mapSize,
|
|
mapState,
|
|
mode,
|
|
setZoom,
|
|
svgRef,
|
|
}) {
|
|
const lastAutoFitKeyRef = useRef(null);
|
|
const autoFitKey = useMemo(
|
|
() => getAutoFitKey(mapState, mapSize),
|
|
[mapSize, mapState]
|
|
);
|
|
|
|
const fitMapToCanvas = useCallback(() => {
|
|
const scrollElement = svgRef.current?.closest(".location-map-scroll");
|
|
setZoom(getFitZoom(mapSize, scrollElement));
|
|
scrollElement?.scrollTo({ left: 0, top: 0 });
|
|
}, [mapSize, setZoom, svgRef]);
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return undefined;
|
|
if (!mapState || mode === "setup") return undefined;
|
|
if (!window.matchMedia(COMPACT_MAP_LAYOUT_QUERY).matches) return undefined;
|
|
if (lastAutoFitKeyRef.current === autoFitKey) return undefined;
|
|
|
|
const frameId = window.requestAnimationFrame(() => {
|
|
if (!svgRef.current) return;
|
|
lastAutoFitKeyRef.current = autoFitKey;
|
|
fitMapToCanvas();
|
|
});
|
|
|
|
return () => window.cancelAnimationFrame(frameId);
|
|
}, [autoFitKey, fitMapToCanvas, mapState, mode, svgRef]);
|
|
|
|
return fitMapToCanvas;
|
|
}
|