You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

useZoomEvents.ts 1.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import React, { useEffect, useRef } from 'react'
  2. import state from 'state'
  3. import inputs from 'state/inputs'
  4. import * as vec from 'utils/vec'
  5. import { useGesture } from 'react-use-gesture'
  6. /**
  7. * Capture zoom gestures (pinches, wheels and pans) and send to the state.
  8. * @param ref
  9. * @returns
  10. */
  11. export default function useZoomEvents(
  12. ref: React.MutableRefObject<SVGSVGElement>
  13. ) {
  14. const rPinchDa = useRef<number[] | undefined>(undefined)
  15. const rPinchPoint = useRef<number[] | undefined>(undefined)
  16. const bind = useGesture(
  17. {
  18. onWheel: ({ event, delta }) => {
  19. if (event.ctrlKey) {
  20. state.send('ZOOMED_CAMERA', {
  21. delta: delta[1],
  22. ...inputs.wheel(event as WheelEvent),
  23. })
  24. return
  25. }
  26. state.send('PANNED_CAMERA', {
  27. delta,
  28. ...inputs.wheel(event as WheelEvent),
  29. })
  30. },
  31. onPinch: ({ pinching, da, origin }) => {
  32. if (!pinching) {
  33. state.send('STOPPED_PINCHING')
  34. rPinchDa.current = undefined
  35. rPinchPoint.current = undefined
  36. return
  37. }
  38. if (rPinchPoint.current === undefined) {
  39. state.send('STARTED_PINCHING')
  40. rPinchDa.current = da
  41. rPinchPoint.current = origin
  42. }
  43. const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
  44. state.send('PINCHED', {
  45. delta: vec.sub(rPinchPoint.current, origin),
  46. point: origin,
  47. distanceDelta,
  48. angleDelta,
  49. })
  50. rPinchDa.current = da
  51. rPinchPoint.current = origin
  52. },
  53. },
  54. {
  55. domTarget: document.body,
  56. eventOptions: { passive: false },
  57. }
  58. )
  59. return { ...bind() }
  60. }