Skip to content

Commit

Permalink
update for the pinching gesture, design update for hub map for mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
piggydoughnut committed Feb 21, 2024
1 parent fc33ee1 commit 7311124
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 44 deletions.
101 changes: 72 additions & 29 deletions src/client/utils/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import config from '#client/config'
Expand Down Expand Up @@ -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) {
Expand All @@ -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<HTMLDivElement> = 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<HTMLDivElement> =
useCallback(() => {
setIsPanning(false)

const newPosition = {
x: positionRef.current.x,
y: positionRef.current.y,
}
setPosition(newPosition)
}, [positionRef])

const handleWheel: React.WheelEventHandler<HTMLDivElement> = useCallback(
(event) => {
Expand Down
17 changes: 14 additions & 3 deletions src/modules/hub-map/client/components/HubMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
/>
</div>
</div>
<div className="flex flex-row gap-2 overflow-hidden mt-6 sm:mt-2 items-center flex-wrap">
<div className="flex flex-row gap-3 sm:gap-2 overflow-hidden mt-6 sm:mt-2 items-center flex-wrap">
{!!visitors?.length &&
visitors.map((v) => {
return (
Expand All @@ -169,13 +169,24 @@ export const HubMap = () => {
</button>
)
})}
<div className="text-text-tertiary">
<div className="text-text-tertiary mb-4 sm:mb-0">
{userIsInOffce
? `You and ${visitorsNumber - 1}`
: visitorsNumber}{' '}
people in the {office?.name} hub
</div>
</div>
<Select
label=""
options={areas.map((x) => ({
label: x.name,
value: x.id,
}))}
value={area?.id}
onChange={onAreaChange}
placeholder={'Select area'}
containerClassName="w-full sm:w-auto mb-2 block sm:hidden"
/>
<div className="sm:max-w-[780px] h-[500px] sm:h-auto m-auto my-2 sm:my-10">
<OfficeFloorMap
area={area}
Expand Down
25 changes: 14 additions & 11 deletions src/modules/hub-map/client/components/ScheduledItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ const DateHeader = ({ dateValue }: { dateValue: string | Date }) => {
)
}

const Status = ({ status }: { status: string }) => (
<div className={cn('h-2 w-2 rounded-full ', StatusColor[status])}> </div>
)

export const ScheduledItem = ({
sheduledItem,
selected,
Expand Down Expand Up @@ -86,7 +90,7 @@ export const ScheduledItem = ({
}}
className={cn(
'transition-all',
'w-[224px] h-[192px] flex flex-col justify-between rounded-sm py-4 px-6 cursor-pointer',
' w-full sm:w-[224px] sm:h-[192px] flex flex-col justify-between rounded-sm px-4 py-4 sm:px-6 cursor-pointer',
ColorsBg[sheduledItem.type],
'border border-transparent',
iAmSelected && ColorsBorder[sheduledItem.type],
Expand All @@ -95,25 +99,24 @@ export const ScheduledItem = ({
>
<div className="flex flex-col gap-2">
<div className="overflow-hidden">
<DateHeader dateValue={sheduledItem.date} />
<div className="flex justify-between items-center">
<DateHeader dateValue={sheduledItem.date} />
{sheduledItem.status && <Status status={sheduledItem.status} />}
</div>
<div className="flex justify-between items-center mt-2">
<p className={cn('capitalize', iAmSelected && 'font-bold')}>
{sheduledItem.value.slice(0, 16)}
{sheduledItem.value.length > 16 && '...'}
<span className="sm:hidden text-text-tertiary text-sm break-all">
{' '}
{sheduledItem.description}
</span>
</p>
{sheduledItem.status && (
<div
className={cn(
'h-2 w-2 rounded-full',
StatusColor[sheduledItem.status]
)}
></div>
)}
</div>
<p className="text-text-secondary text-sm">
{sheduledItem.dateTime ? sheduledItem.dateTime : ''}
</p>
<p className="text-text-tertiary text-sm break-all">
<p className="hidden sm:block text-text-tertiary text-sm break-all">
{sheduledItem.description}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const ScheduledItemsList: React.FC<{
{office?.name}
</p>
)}
<div className="flex justify-start gap-4 overflow-x-auto max-w-[980px]">
<div className="flex justify-start flex-col sm:flex-row gap-2 sm:gap-4 overflow-x-auto max-w-[980px]">
{!!scheduledItems?.length &&
scheduledItems.map((item: ScheduledItemType, index) => (
<ScheduledItem
Expand Down

0 comments on commit 7311124

Please sign in to comment.