diff --git a/src/client/utils/hooks.ts b/src/client/utils/hooks.ts index 127d4b68..32e366bc 100644 --- a/src/client/utils/hooks.ts +++ b/src/client/utils/hooks.ts @@ -3,6 +3,7 @@ import React, { useCallback, useEffect, useMemo, + useRef, useState, } from 'react' import config from '#client/config' @@ -172,6 +173,16 @@ export function usePanZoom( height: 0, width: 0, }) + const [initialPinchDistance, setInitialPinchDistance] = useState(0) + + const getDistanceBetweenTouches = (touches) => { + const touch1 = touches[0] + const touch2 = touches[1] + return Math.sqrt( + Math.pow(touch2.clientX - touch1.clientX, 2) + + Math.pow(touch2.clientY - touch1.clientY, 2) + ) + } useEffect(() => { if (containerRef.current && imageRef.current) { @@ -196,63 +207,95 @@ export function usePanZoom( y: touch.clientY, }) setIsPanning(true) + } else if (event.touches.length === 2) { + const distance = getDistanceBetweenTouches(event.touches) + setInitialPinchDistance(distance) } }, [] ) const updatePositionWithinBounds = (newX: number, newY: number) => { - const boundary = 100 - const xBoundaryRight = - containerDimension.width - - boundary * (containerDimension.width / containerDimension.height) - const xBoundaryLeft = -imageDimensions.width + 50 * scale - const yBoundaryBottom = - containerDimension.height - - boundary * (containerDimension.height / containerDimension.width) - const yBoundaryTop = -imageDimensions.height + 50 * scale + const xBoundaryRight = containerDimension.width + const xBoundaryLeft = -imageDimensions.width + const yBoundaryBottom = containerDimension.height + const yBoundaryTop = -imageDimensions.height + + const outOfViewX = newX > xBoundaryRight || newX < xBoundaryLeft + const outOfViewY = newY > yBoundaryBottom || newY < yBoundaryTop + const outOfView = outOfViewX || outOfViewY + + const newPosition = outOfView + ? initialPosition + : { + x: Math.min(Math.max(newX, xBoundaryLeft), xBoundaryRight), + y: Math.min(Math.max(newY, yBoundaryTop), yBoundaryBottom), + } + return { - x: - newX > 0 - ? Math.min(newX, xBoundaryRight) - : Math.max(newX, xBoundaryLeft), - y: - newY > 0 - ? Math.min(newY, yBoundaryBottom) - : Math.max(newY, yBoundaryTop), + newPosition: newPosition, + outOfView: outOfView, } } const resetScale = () => { setScale(1) - setPosition({ x: 0, y: 0 }) + setPosition(initialPosition) + positionRef.current = initialPosition } + const positionRef = useRef(position) const handleTouchMove: React.TouchEventHandler = useCallback( (event) => { if (isPanning && event.touches.length === 1) { + event.preventDefault() const touch = event.touches[0] const deltaX = touch.clientX - touchStart.x const deltaY = touch.clientY - touchStart.y - setPosition((prevPosition) => { - const newX = prevPosition.x + deltaX - const newY = prevPosition.y + deltaY - return updatePositionWithinBounds(newX, newY) - }) - - setTouchStart({ + const newTouchStart = { x: touch.clientX, y: touch.clientY, + } + setTouchStart(newTouchStart) + + const newPosition = { + x: positionRef.current.x + deltaX, + y: positionRef.current.y + deltaY, + } + positionRef.current = newPosition + + requestAnimationFrame(() => { + setPosition(newPosition) }) } + + if (event.touches.length === 2) { + event.preventDefault() + const distance = getDistanceBetweenTouches(event.touches) + if (initialPinchDistance != null) { + const scaleChange = distance / initialPinchDistance + setScale((prevScale) => { + const newScale = prevScale * scaleChange + return Math.max(1, newScale < MAX_ZOOM ? newScale : MAX_ZOOM) + }) + setInitialPinchDistance(distance) + } + } }, - [isPanning, touchStart] + [isPanning, touchStart, initialPinchDistance] ) - const handleTouchEnd = useCallback(() => { - setIsPanning(false) - }, []) + const handleTouchEnd: React.TouchEventHandler = + useCallback(() => { + setIsPanning(false) + + const newPosition = { + x: positionRef.current.x, + y: positionRef.current.y, + } + setPosition(newPosition) + }, [positionRef]) const handleWheel: React.WheelEventHandler = useCallback( (event) => { diff --git a/src/modules/hub-map/client/components/HubMap.tsx b/src/modules/hub-map/client/components/HubMap.tsx index 9cfb86fd..022b0820 100644 --- a/src/modules/hub-map/client/components/HubMap.tsx +++ b/src/modules/hub-map/client/components/HubMap.tsx @@ -148,11 +148,11 @@ export const HubMap = () => { value={area?.id} onChange={onAreaChange} placeholder={'Select area'} - containerClassName="w-full sm:w-auto mb-2" + containerClassName="w-full sm:w-auto mb-2 hidden sm:block" /> -
+
{!!visitors?.length && visitors.map((v) => { return ( @@ -169,13 +169,24 @@ export const HubMap = () => { ) })} -
+
{userIsInOffce ? `You and ${visitorsNumber - 1}` : visitorsNumber}{' '} people in the {office?.name} hub
+