2021-05-28 16:25:43 +00:00
|
|
|
import React, { useEffect, useRef } from 'react'
|
|
|
|
import state from 'state'
|
|
|
|
import inputs from 'state/inputs'
|
|
|
|
import * as vec from 'utils/vec'
|
|
|
|
import { usePinch } from 'react-use-gesture'
|
2021-05-09 13:04:42 +00:00
|
|
|
|
2021-05-09 21:22:25 +00:00
|
|
|
/**
|
|
|
|
* Capture zoom gestures (pinches, wheels and pans) and send to the state.
|
|
|
|
* @param ref
|
|
|
|
* @returns
|
|
|
|
*/
|
2021-05-09 13:04:42 +00:00
|
|
|
export default function useZoomEvents(
|
|
|
|
ref: React.MutableRefObject<SVGSVGElement>
|
|
|
|
) {
|
|
|
|
const rTouchDist = useRef(0)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const element = ref.current
|
|
|
|
|
|
|
|
if (!element) return
|
|
|
|
|
|
|
|
function handleWheel(e: WheelEvent) {
|
|
|
|
e.preventDefault()
|
2021-05-28 16:25:43 +00:00
|
|
|
e.stopPropagation()
|
2021-05-09 13:04:42 +00:00
|
|
|
|
|
|
|
if (e.ctrlKey) {
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('ZOOMED_CAMERA', {
|
2021-05-09 13:04:42 +00:00
|
|
|
delta: e.deltaY,
|
2021-05-13 08:34:56 +00:00
|
|
|
...inputs.wheel(e),
|
2021-05-09 13:04:42 +00:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('PANNED_CAMERA', {
|
2021-05-09 13:04:42 +00:00
|
|
|
delta: [e.deltaX, e.deltaY],
|
2021-05-13 08:34:56 +00:00
|
|
|
...inputs.wheel(e),
|
2021-05-09 13:04:42 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleTouchMove(e: TouchEvent) {
|
2021-05-09 21:22:25 +00:00
|
|
|
e.preventDefault()
|
2021-05-28 16:25:43 +00:00
|
|
|
e.stopPropagation()
|
2021-05-09 13:04:42 +00:00
|
|
|
|
|
|
|
if (e.touches.length === 2) {
|
|
|
|
const { clientX: x0, clientY: y0 } = e.touches[0]
|
|
|
|
const { clientX: x1, clientY: y1 } = e.touches[1]
|
|
|
|
|
|
|
|
const dist = vec.dist([x0, y0], [x1, y1])
|
2021-05-09 21:22:25 +00:00
|
|
|
const point = vec.med([x0, y0], [x1, y1])
|
2021-05-09 13:04:42 +00:00
|
|
|
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('WHEELED', {
|
2021-05-09 21:22:25 +00:00
|
|
|
delta: dist - rTouchDist.current,
|
|
|
|
point,
|
|
|
|
})
|
2021-05-09 13:04:42 +00:00
|
|
|
|
|
|
|
rTouchDist.current = dist
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 16:25:43 +00:00
|
|
|
element.addEventListener('wheel', handleWheel, { passive: false })
|
|
|
|
element.addEventListener('touchstart', handleTouchMove, { passive: false })
|
|
|
|
element.addEventListener('touchmove', handleTouchMove, { passive: false })
|
2021-05-09 13:04:42 +00:00
|
|
|
|
|
|
|
return () => {
|
2021-05-28 16:25:43 +00:00
|
|
|
element.removeEventListener('wheel', handleWheel)
|
|
|
|
element.removeEventListener('touchstart', handleTouchMove)
|
|
|
|
element.removeEventListener('touchmove', handleTouchMove)
|
2021-05-09 13:04:42 +00:00
|
|
|
}
|
|
|
|
}, [ref])
|
|
|
|
|
2021-05-28 13:08:51 +00:00
|
|
|
const rPinchDa = useRef<number[] | undefined>(undefined)
|
|
|
|
const rPinchPoint = useRef<number[] | undefined>(undefined)
|
|
|
|
|
|
|
|
const bind = usePinch(({ pinching, da, origin }) => {
|
|
|
|
if (!pinching) {
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('STOPPED_PINCHING')
|
2021-05-28 13:08:51 +00:00
|
|
|
rPinchDa.current = undefined
|
|
|
|
rPinchPoint.current = undefined
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rPinchPoint.current === undefined) {
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('STARTED_PINCHING')
|
2021-05-28 13:08:51 +00:00
|
|
|
rPinchDa.current = da
|
|
|
|
rPinchPoint.current = origin
|
|
|
|
}
|
|
|
|
|
|
|
|
const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
|
|
|
|
|
2021-05-28 16:25:43 +00:00
|
|
|
state.send('PINCHED', {
|
2021-05-28 13:08:51 +00:00
|
|
|
delta: vec.sub(rPinchPoint.current, origin),
|
|
|
|
point: origin,
|
|
|
|
distanceDelta,
|
|
|
|
angleDelta,
|
|
|
|
})
|
|
|
|
|
|
|
|
rPinchDa.current = da
|
|
|
|
rPinchPoint.current = origin
|
|
|
|
})
|
|
|
|
|
|
|
|
return { ...bind() }
|
2021-05-09 13:04:42 +00:00
|
|
|
}
|