diff --git a/components/map-container.js b/components/map-container.js index fa2bcc5..d3f1c1c 100644 --- a/components/map-container.js +++ b/components/map-container.js @@ -3,7 +3,7 @@ import { Box } from 'theme-ui' import useStore from './data/store' -const MapContainer = ({ children, setMapProps }) => { +const MapContainer = ({ children, setMapProps, lockZoom }) => { const container = useRef(null) const moveListener = useRef(null) const [cursor, setCursor] = useState('grab') @@ -12,10 +12,32 @@ const MapContainer = ({ children, setMapProps }) => { const panMap = useCallback((offset) => { setMapProps((prev) => ({ ...prev, - translate: prev.translate.map((d, i) => d + offset[i]), + translate: + prev.scale <= 1 + ? prev.translate + : prev.translate.map((d, i) => d + offset[i]), })) }, []) + const zoomMap = useCallback( + (delta, offset = [0, 0]) => { + if (lockZoom) return + setMapProps((prev) => { + delta = delta * prev.scale + const updatedScale = + prev.scale + delta <= 1 ? prev.scale : prev.scale + delta + return { + ...prev, + scale: updatedScale, + translate: prev.translate.map( + (d, i) => offset[i] - ((offset[i] - d) / prev.scale) * updatedScale + ), + } + }) + }, + [lockZoom] + ) + const handler = useCallback( ({ key, keyCode, metaKey, ...rest }) => { if (document.activeElement !== container.current) { @@ -37,10 +59,16 @@ const MapContainer = ({ children, setMapProps }) => { } panMap(offset) + } else if (key === '=') { + // zoom in + zoomMap(1) + } else if (key === '-') { + // zoom out + zoomMap(-1) } } }, - [hasData, panMap] + [hasData, panMap, zoomMap] ) useEffect(() => { window.addEventListener('keydown', handler) @@ -78,6 +106,21 @@ const MapContainer = ({ children, setMapProps }) => { } }) + const handleWheel = useCallback( + (event) => { + const height = container.current.clientHeight + const width = container.current.clientWidth + const { x, y } = container.current.getBoundingClientRect() + const point = [event.clientX - x, event.clientY - y] + + const offset = [(point[0] / width) * 2 - 1, (point[1] / height) * 2 - 1] + const delta = event.deltaY / -150 + + zoomMap(delta, offset) + }, + [panMap, zoomMap] + ) + return ( { tabIndex={0} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} + onWheel={handleWheel} id='container' > {children} diff --git a/components/proxy-map.js b/components/proxy-map.js index 2a282a4..6a953a3 100644 --- a/components/proxy-map.js +++ b/components/proxy-map.js @@ -40,6 +40,7 @@ const ProxyMap = () => { scale: 1, translate: [0, 0], }) + const [lockZoom, setLockZoom] = useState(true) const mapPropsInitialized = useRef(0) useEffect(() => { @@ -50,7 +51,13 @@ const ProxyMap = () => { if (!mapPropsInitialized.current && chunkBounds) { const p = getMapProps(chunkBounds, projectionName) - setMapProps(p) + if (p.scale < 1.5) { + setMapProps({ ...p, scale: 1, translate: [0, 0] }) + setLockZoom(false) + } else { + setMapProps(p) + setLockZoom(true) + } mapPropsInitialized.current = true } }, [!!chunkBounds, projectionName]) @@ -75,7 +82,7 @@ const ProxyMap = () => { }, [mapProps]) return ( - + {plotMode === 'point' && } {plotMode === 'circle' && } @@ -131,6 +138,7 @@ const ProxyMap = () => { position: 'fixed', bottom: '18px', right: '18px', + opacity: lockZoom && mapProps.scale > 3 ? 1 : 0, transition: '0.1s', }} />