{"version":3,"file":"touch.mjs","names":["CircularBuffer","HORIZON","HISTORY","kineticEnergyToVelocity","work","sqrt2","Math","sqrt","abs","calculateImpulseVelocity","samples","length","t","d","i","vprev","vcurr","useVelocity","touches","addMovement","e","Array","from","changedTouches","forEach","touch","_touches$touch$identi","identifier","push","timeStamp","endTouch","getVelocity","id","_touches$id","values","reverse","Error","concat","newest","x","y","_iterator","_createForOfIteratorHelper","_step","s","n","done","val","value","clientX","clientY","err","f","direction","_ref","absX","absY","oops"],"sources":["../../src/composables/touch.ts"],"sourcesContent":["// Utilities\nimport { CircularBuffer } from '@/utils'\n\nconst HORIZON = 100 // ms\nconst HISTORY = 20 // number of samples to keep\n\nexport interface Sample {\n  t: number\n  d: number\n}\n\n/** @see https://android.googlesource.com/platform/frameworks/native/+/master/libs/input/VelocityTracker.cpp */\nfunction kineticEnergyToVelocity(work: number) {\n  const sqrt2 = 1.41421356237\n  return (work < 0 ? -1.0 : 1.0) * Math.sqrt(Math.abs(work)) * sqrt2\n}\n\n/**\n * Returns pointer velocity in px/s\n */\nexport function calculateImpulseVelocity(samples: Sample[]) {\n  // The input should be in reversed time order (most recent sample at index i=0)\n  if (samples.length < 2) {\n    // if 0 or 1 points, velocity is zero\n    return 0\n  }\n  // if (samples[1].t > samples[0].t) {\n  //   // Algorithm will still work, but not perfectly\n  //   consoleWarn('Samples provided to calculateImpulseVelocity in the wrong order')\n  // }\n  if (samples.length === 2) {\n    // if 2 points, basic linear calculation\n    if (samples[1].t === samples[0].t) {\n      // consoleWarn(`Events have identical time stamps t=${samples[0].t}, setting velocity = 0`)\n      return 0\n    }\n    return (samples[1].d - samples[0].d) / (samples[1].t - samples[0].t)\n  }\n  // Guaranteed to have at least 3 points here\n  // start with the oldest sample and go forward in time\n  let work = 0\n  for (let i = samples.length - 1; i > 0; i--) {\n    if (samples[i].t === samples[i - 1].t) {\n      // consoleWarn(`Events have identical time stamps t=${samples[i].t}, skipping sample`)\n      continue\n    }\n    const vprev = kineticEnergyToVelocity(work) // v[i-1]\n    const vcurr =\n      (samples[i].d - samples[i - 1].d) / (samples[i].t - samples[i - 1].t) // v[i]\n    work += (vcurr - vprev) * Math.abs(vcurr)\n    if (i === samples.length - 1) {\n      work *= 0.5\n    }\n  }\n  return kineticEnergyToVelocity(work) * 1000\n}\n\nexport function useVelocity() {\n  const touches: Record<number, CircularBuffer<[number, Touch]> | undefined> =\n    {}\n\n  function addMovement(e: TouchEvent) {\n    Array.from(e.changedTouches).forEach((touch) => {\n      const samples =\n        touches[touch.identifier] ??\n        (touches[touch.identifier] = new CircularBuffer(HISTORY))\n      samples.push([e.timeStamp, touch])\n    })\n  }\n\n  function endTouch(e: TouchEvent) {\n    Array.from(e.changedTouches).forEach((touch) => {\n      delete touches[touch.identifier]\n    })\n  }\n\n  function getVelocity(id: number) {\n    const samples = touches[id]?.values().reverse()\n\n    if (!samples) {\n      throw new Error(`No samples for touch id ${id}`)\n    }\n\n    const newest = samples[0]\n    const x: Sample[] = []\n    const y: Sample[] = []\n    for (const val of samples) {\n      if (newest[0] - val[0] > HORIZON) break\n\n      x.push({ t: val[0], d: val[1].clientX })\n      y.push({ t: val[0], d: val[1].clientY })\n    }\n\n    return {\n      x: calculateImpulseVelocity(x),\n      y: calculateImpulseVelocity(y),\n      get direction() {\n        const { x, y } = this\n        const [absX, absY] = [Math.abs(x), Math.abs(y)]\n\n        return absX > absY && x >= 0\n          ? 'right'\n          : absX > absY && x <= 0\n          ? 'left'\n          : absY > absX && y >= 0\n          ? 'down'\n          : absY > absX && y <= 0\n          ? 'up'\n          : oops()\n      },\n    }\n  }\n\n  return { addMovement, endTouch, getVelocity }\n}\n\nfunction oops(): never {\n  throw new Error()\n}\n"],"mappings":"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"}