{"version":3,"sources":["../src/createZoomImageWheel.ts"],"names":[],"mappings":"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","sourcesContent":["import { createStore } from \"@namnode/store\"\nimport type { PointerPosition } from \"./utils\"\nimport { clamp, computeZoomGesture, disableScroll, enableScroll, makeMaybeCallFunction } from \"./utils\"\n\nexport type ZoomImageWheelOptions = {\n  maxZoom?: number\n  wheelZoomRatio?: number\n  dblTapAnimationDuration?: number\n  initialState?: Partial<ZoomImageWheelStateUpdate>\n  shouldZoomOnSingleTouch?: () => boolean\n  zoomTarget?: HTMLElement | null\n}\n\n/* The delta values are not consistent across browsers.\n * We need to normalize them to a consistent value.\n * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaY\n */\nconst ZOOM_DELTA = 0.5\n\nexport type ZoomImageWheelState = {\n  currentRotation: number\n  currentZoom: number\n  enable: boolean\n  currentPositionX: number\n  currentPositionY: number\n}\n\nexport type ZoomImageWheelStateUpdate = Partial<{\n  enable: boolean\n  currentZoom: number\n  currentRotation: number\n  zoomTarget: HTMLElement | null\n}>\n\nconst defaultInitialState: ZoomImageWheelState = {\n  currentZoom: 1,\n  enable: true,\n  currentPositionX: 0,\n  currentPositionY: 0,\n  currentRotation: 0,\n}\n\nconst defaultShouldZoomOnSingleTouch = () => true\n\nexport function createZoomImageWheel(container: HTMLElement, options: ZoomImageWheelOptions = {}) {\n  const finalOptions: Required<ZoomImageWheelOptions> = {\n    maxZoom: options.maxZoom || 4,\n    wheelZoomRatio: options.wheelZoomRatio || 0.1,\n    dblTapAnimationDuration: options.dblTapAnimationDuration || 300,\n    initialState: { ...defaultInitialState, ...options.initialState },\n    shouldZoomOnSingleTouch: options.shouldZoomOnSingleTouch || defaultShouldZoomOnSingleTouch,\n    zoomTarget: options.zoomTarget === undefined ? container.querySelector(\"img\") : options.zoomTarget,\n  }\n\n  const store = createStore<ZoomImageWheelState>(finalOptions.initialState as ZoomImageWheelState)\n\n  const checkDimensionSwitched = () => {\n    return [90, 270].includes(store.getState().currentRotation % 360)\n  }\n\n  const calculatePositionX = (newPositionX: number, currentZoom: number, isDimensionSwitched: boolean) => {\n    if (newPositionX > 0) return 0\n\n    const width = isDimensionSwitched ? container.clientHeight : container.clientWidth\n    if (newPositionX + width * currentZoom < width) return -width * (currentZoom - 1)\n    return newPositionX\n  }\n\n  const calculatePositionY = (newPositionY: number, currentZoom: number, isDimensionSwitched: boolean) => {\n    if (newPositionY > 0) return 0\n\n    const height = isDimensionSwitched ? container.clientWidth : container.clientHeight\n    if (newPositionY + height * currentZoom < height) return -height * (currentZoom - 1)\n    return newPositionY\n  }\n\n  const updateStateOnNewZoom = (currentZoom: number) => {\n    const zoomPointX = container.clientWidth / 2\n    const zoomPointY = container.clientHeight / 2\n    const currentState = store.getState()\n    const zoomTargetX = (zoomPointX - currentState.currentPositionX) / currentState.currentZoom\n    const zoomTargetY = (zoomPointY - currentState.currentPositionY) / currentState.currentZoom\n\n    store.setState({\n      currentZoom,\n      currentPositionX: calculatePositionX(-zoomTargetX * currentZoom + zoomPointX, currentZoom, false),\n      currentPositionY: calculatePositionY(-zoomTargetY * currentZoom + zoomPointY, currentZoom, false),\n    })\n  }\n\n  // last pair of coordinates of a touch with two fingers\n  let prevTwoPositions: [PointerPosition, PointerPosition] | null = null\n  let enabledScroll = true\n  const pointerMap = new Map<number, PointerPosition>()\n\n  let lastPositionX = 0\n  let lastPositionY = 0\n  let startX = 0\n  let startY = 0\n\n  container.style.overflow = \"hidden\"\n\n  let zoomTarget = finalOptions.zoomTarget\n\n  function updateZoom() {\n    const currentState = store.getState()\n    if (zoomTarget) {\n      zoomTarget.style.transformOrigin = \"0 0\"\n      zoomTarget.style.transform = `translate(${currentState.currentPositionX}px, ${currentState.currentPositionY}px) scale(${currentState.currentZoom})`\n      container.style.rotate = `${currentState.currentRotation}deg`\n    }\n  }\n\n  function setState(newState: ZoomImageWheelStateUpdate) {\n    if (\"zoomTarget\" in newState) {\n      zoomTarget = newState.zoomTarget ?? null\n    }\n\n    store.batch(() => {\n      const currentState = store.getState()\n      if (typeof newState.enable === \"boolean\" && newState.enable !== currentState.enable) {\n        store.setState({\n          enable: newState.enable,\n        })\n\n        if (!newState.enable) {\n          return\n        }\n      }\n\n      if (typeof newState.currentRotation === \"number\") {\n        const newCurrentRotation = newState.currentRotation\n        store.setState({\n          currentRotation: newCurrentRotation,\n        })\n      }\n\n      if (typeof newState.currentZoom === \"number\" && newState.currentZoom !== currentState.currentZoom) {\n        const newCurrentZoom = clamp(newState.currentZoom, 1, finalOptions.maxZoom)\n\n        if (newCurrentZoom === currentState.currentZoom) {\n          return\n        }\n\n        updateStateOnNewZoom(newCurrentZoom)\n      }\n    })\n\n    updateZoom()\n  }\n\n  function processZoomWheel({ delta, x, y }: { delta: number; x: number; y: number }) {\n    const containerRect = container.getBoundingClientRect()\n    const currentState = store.getState()\n    const isDimensionSwitched = checkDimensionSwitched()\n\n    let zoomPointX = -1\n    let zoomPointY = -1\n\n    switch (currentState.currentRotation % 360) {\n      case 0:\n        zoomPointX = x - containerRect.left\n        zoomPointY = y - containerRect.top\n        break\n      case 90:\n        zoomPointX = Math.abs(x - containerRect.right)\n        zoomPointY = Math.abs(y - containerRect.top)\n        break\n      case 180:\n        zoomPointX = Math.abs(x - containerRect.right)\n        zoomPointY = Math.abs(y - containerRect.bottom)\n        break\n      case 270:\n        zoomPointX = Math.abs(x - containerRect.left)\n        zoomPointY = Math.abs(y - containerRect.bottom)\n        break\n    }\n\n    const zoomX = isDimensionSwitched ? currentState.currentPositionY : currentState.currentPositionX\n    const zoomY = isDimensionSwitched ? currentState.currentPositionX : currentState.currentPositionY\n\n    const zoomTargetX = (zoomPointX - zoomX) / currentState.currentZoom\n    const zoomTargetY = (zoomPointY - zoomY) / currentState.currentZoom\n\n    const newCurrentZoom = clamp(\n      currentState.currentZoom + delta * finalOptions.wheelZoomRatio * currentState.currentZoom,\n      1,\n      finalOptions.maxZoom,\n    )\n\n    const newX = calculatePositionX(-zoomTargetX * newCurrentZoom + zoomPointX, newCurrentZoom, isDimensionSwitched)\n    const newY = calculatePositionY(-zoomTargetY * newCurrentZoom + zoomPointY, newCurrentZoom, isDimensionSwitched)\n\n    store.setState({\n      currentZoom: newCurrentZoom,\n      currentPositionX: isDimensionSwitched ? newY : newX,\n      currentPositionY: isDimensionSwitched ? newX : newY,\n    })\n  }\n\n  function updatePositionsForSinglePointerFlow() {\n    if (pointerMap.size === 1) {\n      const { x, y } = pointerMap.values().next().value as PointerPosition\n      const isDimensionSwitched = checkDimensionSwitched()\n      startX = isDimensionSwitched ? y : x\n      startY = isDimensionSwitched ? x : y\n    }\n\n    const currentState = store.getState()\n    lastPositionX = currentState.currentPositionX\n    lastPositionY = currentState.currentPositionY\n  }\n\n  function _handleWheel(event: WheelEvent) {\n    event.preventDefault()\n\n    if (store.getState().currentZoom === finalOptions.maxZoom && event.deltaY < 0) {\n      return\n    }\n\n    const delta = -clamp(event.deltaY, -ZOOM_DELTA, ZOOM_DELTA)\n    processZoomWheel({ delta, x: event.clientX, y: event.clientY })\n    updateZoom()\n\n    updatePositionsForSinglePointerFlow()\n  }\n\n  function _handlePointerMove(event: PointerEvent) {\n    event.preventDefault()\n    const { clientX, clientY, pointerId } = event\n    for (const [cachedPointerId] of pointerMap.entries()) {\n      if (cachedPointerId === pointerId) {\n        pointerMap.set(cachedPointerId, { x: clientX, y: clientY })\n      }\n    }\n\n    const { currentZoom, currentRotation } = store.getState()\n    if (pointerMap.size === 1 && currentZoom !== 1) {\n      const isDimensionSwitched = checkDimensionSwitched()\n      const normalizedClientX = isDimensionSwitched ? clientY : clientX\n      const normalizedClientY = isDimensionSwitched ? clientX : clientY\n\n      let offsetX = -1\n      let offsetY = -1\n\n      switch (currentRotation % 360) {\n        case 0:\n          offsetX = normalizedClientX - startX\n          offsetY = normalizedClientY - startY\n          break\n        case 90:\n          offsetX = normalizedClientX - startX\n          offsetY = startY - normalizedClientY\n          break\n        case 180:\n          offsetX = startX - normalizedClientX\n          offsetY = startY - normalizedClientY\n          break\n        case 270:\n          offsetX = startX - normalizedClientX\n          offsetY = normalizedClientY - startY\n          break\n      }\n\n      store.setState({\n        currentPositionX: calculatePositionX(lastPositionX + offsetX, currentZoom, false),\n        currentPositionY: calculatePositionY(lastPositionY + offsetY, currentZoom, false),\n      })\n      updateZoom()\n    }\n  }\n\n  const animationState = {\n    startTimestamp: null as DOMHighResTimeStamp | null,\n    // the state at the start of the zoom animation\n    start: { x: 0, y: 0, zoom: 0 },\n    // the target state at the end of the zoom animation\n    target: { x: 0, y: 0, zoom: 0 },\n  }\n\n  function animateZoom(touchCoordinate: { x: number; y: number }) {\n    // the `touchCoordinate` should be relative to the container\n    const currentState = store.getState()\n\n    animationState.startTimestamp = null\n    animationState.start = {\n      x: currentState.currentPositionX,\n      y: currentState.currentPositionY,\n      zoom: currentState.currentZoom,\n    }\n\n    if (currentState.currentZoom > 1) {\n      animationState.target = {\n        x: 0,\n        y: 0,\n        zoom: 1,\n      }\n    } else {\n      animationState.target = {\n        zoom: finalOptions.maxZoom,\n        x: touchCoordinate.x * (1 - finalOptions.maxZoom),\n        y: touchCoordinate.y * (1 - finalOptions.maxZoom),\n      }\n    }\n\n    function lerp(a: number, b: number, t: number): number {\n      return a * (1 - t) + b * t\n    }\n\n    function frame(timestamp: DOMHighResTimeStamp) {\n      if (animationState.startTimestamp === null) {\n        animationState.startTimestamp = timestamp\n      }\n\n      // interpolation parameter that linearly goes from 0 to 1 during the animation\n      let t = (timestamp - animationState.startTimestamp) / finalOptions.dblTapAnimationDuration\n      if (t > 1) {\n        t = 1\n      }\n\n      store.setState({\n        currentPositionX: lerp(animationState.start.x, animationState.target.x, t),\n        currentPositionY: lerp(animationState.start.y, animationState.target.y, t),\n        currentZoom: lerp(animationState.start.zoom, animationState.target.zoom, t),\n      })\n      updateZoom()\n\n      if (t < 1) {\n        requestAnimationFrame(frame)\n      }\n    }\n\n    requestAnimationFrame(frame)\n  }\n\n  // These variables are used for zooming on double tap\n  let touchTimer: NodeJS.Timeout | null = null\n  const durationBetweenTap = 300\n\n  function _handleTouchStart(event: TouchEvent) {\n    if (event.touches.length > 1) {\n      return\n    }\n\n    if (touchTimer === null) {\n      touchTimer = setTimeout(() => {\n        touchTimer = null\n      }, durationBetweenTap)\n    } else {\n      clearTimeout(touchTimer)\n      touchTimer = null\n\n      const rect = container.getBoundingClientRect()\n      const touch = event.touches[0]\n      animateZoom({\n        x: touch.clientX - rect.left,\n        y: touch.clientY - rect.top,\n      })\n      return\n    }\n  }\n\n  function _handleTouchMove(event: TouchEvent) {\n    if (finalOptions.shouldZoomOnSingleTouch()) event.preventDefault()\n    if (event.touches.length > 1) {\n      event.preventDefault()\n      const currentTwoPositions = [...event.touches].map((t) => ({ x: t.clientX, y: t.clientY })) as [\n        PointerPosition,\n        PointerPosition,\n      ]\n\n      if (prevTwoPositions !== null) {\n        const { scale, center } = computeZoomGesture(prevTwoPositions, currentTwoPositions)\n        processZoomWheel({ delta: Math.log(scale) / finalOptions.wheelZoomRatio, ...center })\n      }\n      // Store the current two pointer positions for the next move event\n      prevTwoPositions = currentTwoPositions\n      updateZoom()\n      return\n    }\n  }\n\n  function _handlePointerDown(event: PointerEvent) {\n    if (event.pointerType === \"touch\" && !finalOptions.shouldZoomOnSingleTouch()) return\n    event.preventDefault()\n    if (pointerMap.size === 2) {\n      return\n    }\n\n    if (enabledScroll) {\n      disableScroll()\n      enabledScroll = false\n    }\n\n    const { clientX, clientY, pointerId } = event\n\n    const currentState = store.getState()\n    lastPositionX = currentState.currentPositionX\n    lastPositionY = currentState.currentPositionY\n\n    const isDimensionSwitched = checkDimensionSwitched()\n    startX = isDimensionSwitched ? clientY : clientX\n    startY = isDimensionSwitched ? clientX : clientY\n    pointerMap.set(pointerId, { x: clientX, y: clientY })\n  }\n\n  function _handlePointerUp(event: PointerEvent) {\n    pointerMap.delete(event.pointerId)\n\n    // Reset the distance as soon as one of the pointers is released\n    if (pointerMap.size < 2) {\n      prevTwoPositions = null\n    }\n\n    if (pointerMap.size === 0 && !enabledScroll) {\n      enableScroll()\n      enabledScroll = true\n    }\n\n    updatePositionsForSinglePointerFlow()\n  }\n\n  function _handlePointerLeave(event: PointerEvent) {\n    event.preventDefault()\n    pointerMap.delete(event.pointerId)\n    prevTwoPositions = null\n    if (!enabledScroll) {\n      enableScroll()\n      enabledScroll = true\n    }\n  }\n\n  function checkZoomEnabled() {\n    return store.getState().enable\n  }\n\n  const handleWheel = makeMaybeCallFunction(checkZoomEnabled, _handleWheel)\n  const handlePointerDown = makeMaybeCallFunction(checkZoomEnabled, _handlePointerDown)\n  const handlePointerLeave = makeMaybeCallFunction(checkZoomEnabled, _handlePointerLeave)\n  const handlePointerMove = makeMaybeCallFunction(checkZoomEnabled, _handlePointerMove)\n  const handlePointerUp = makeMaybeCallFunction(checkZoomEnabled, _handlePointerUp)\n  const handleTouchStart = makeMaybeCallFunction(checkZoomEnabled, _handleTouchStart)\n  const handleTouchMove = makeMaybeCallFunction(checkZoomEnabled, _handleTouchMove)\n\n  const controller = new AbortController()\n  const { signal } = controller\n  container.addEventListener(\"wheel\", handleWheel, { signal })\n  container.addEventListener(\"touchstart\", handleTouchStart, { signal })\n  container.addEventListener(\"touchmove\", handleTouchMove, { signal })\n  container.addEventListener(\"pointerdown\", handlePointerDown, { signal })\n  container.addEventListener(\"pointerleave\", handlePointerLeave, { signal })\n  container.addEventListener(\"pointermove\", handlePointerMove, { signal })\n  container.addEventListener(\"pointerup\", handlePointerUp, { signal })\n  container.addEventListener(\n    \"touchend\",\n    () => {\n      enabledScroll = true\n      enableScroll()\n    },\n    { signal },\n  )\n\n  // Kick things off in case we have initial zoom other than 1\n  if (store.getState().currentZoom !== defaultInitialState.currentZoom) {\n    updateStateOnNewZoom(store.getState().currentZoom)\n    updateZoom()\n  }\n\n  return {\n    cleanup() {\n      controller.abort()\n      store.cleanup()\n    },\n    subscribe: store.subscribe,\n    setState,\n    getState: store.getState,\n  }\n}\n"]}