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.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. /**
  6. * Capture zoom gestures (pinches, wheels and pans) and send to the state.
  7. * @param ref
  8. * @returns
  9. */
  10. export default function useZoomEvents(
  11. ref: React.MutableRefObject<SVGSVGElement>
  12. ) {
  13. const rTouchDist = useRef(0)
  14. useEffect(() => {
  15. const element = ref.current
  16. if (!element) return
  17. function handleWheel(e: WheelEvent) {
  18. e.preventDefault()
  19. if (e.ctrlKey) {
  20. state.send("ZOOMED_CAMERA", {
  21. delta: e.deltaY,
  22. ...inputs.wheel(e),
  23. })
  24. return
  25. }
  26. state.send("PANNED_CAMERA", {
  27. delta: [e.deltaX, e.deltaY],
  28. ...inputs.wheel(e),
  29. })
  30. }
  31. function handleTouchMove(e: TouchEvent) {
  32. e.preventDefault()
  33. if (e.touches.length === 2) {
  34. const { clientX: x0, clientY: y0 } = e.touches[0]
  35. const { clientX: x1, clientY: y1 } = e.touches[1]
  36. const dist = vec.dist([x0, y0], [x1, y1])
  37. const point = vec.med([x0, y0], [x1, y1])
  38. state.send("WHEELED", {
  39. delta: dist - rTouchDist.current,
  40. point,
  41. })
  42. rTouchDist.current = dist
  43. }
  44. }
  45. element.addEventListener("wheel", handleWheel)
  46. element.addEventListener("touchstart", handleTouchMove)
  47. element.addEventListener("touchmove", handleTouchMove)
  48. return () => {
  49. element.removeEventListener("wheel", handleWheel)
  50. element.removeEventListener("touchstart", handleTouchMove)
  51. element.removeEventListener("touchmove", handleTouchMove)
  52. }
  53. }, [ref])
  54. return {}
  55. }