@tldraw/utils
Version:
tldraw infinite canvas SDK (private utilities).
8 lines (7 loc) • 4.87 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/lib/throttle.ts"],
"sourcesContent": ["const isTest = () =>\n\ttypeof process !== 'undefined' &&\n\tprocess.env.NODE_ENV === 'test' &&\n\t// @ts-expect-error\n\t!globalThis.__FORCE_RAF_IN_TESTS__\n\nconst fpsQueue: Array<() => void> = []\nconst targetFps = 60\nconst targetTimePerFrame = Math.floor(1000 / targetFps) * 0.9 // ~15ms - we allow for some variance as browsers aren't that precise.\nlet frameRaf: undefined | number\nlet flushRaf: undefined | number\nlet lastFlushTime = -targetTimePerFrame\n\nconst flush = () => {\n\tconst queue = fpsQueue.splice(0, fpsQueue.length)\n\tfor (const fn of queue) {\n\t\tfn()\n\t}\n}\n\nfunction tick(isOnNextFrame = false) {\n\tif (frameRaf) return\n\n\tconst now = Date.now()\n\tconst elapsed = now - lastFlushTime\n\n\tif (elapsed < targetTimePerFrame) {\n\t\t// If we're too early to flush, we need to wait until the next frame to try and flush again.\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tframeRaf = requestAnimationFrame(() => {\n\t\t\tframeRaf = undefined\n\t\t\ttick(true)\n\t\t})\n\t\treturn\n\t}\n\n\tif (isOnNextFrame) {\n\t\t// If we've already waited for the next frame to run the tick, then we can flush immediately\n\t\tif (flushRaf) return // ...though if there's a flush raf, that means we'll be flushing on this frame already, so we can do nothing here.\n\t\tlastFlushTime = now\n\t\tflush()\n\t} else {\n\t\t// If we haven't already waited for the next frame to run the tick, we need to wait until the next frame to flush.\n\t\tif (flushRaf) return // ...though if there's a flush raf, that means we'll be flushing on the next frame already, so we can do nothing here.\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tflushRaf = requestAnimationFrame(() => {\n\t\t\tflushRaf = undefined\n\t\t\tlastFlushTime = now\n\t\t\tflush()\n\t\t})\n\t}\n}\n\n/**\n * Returns a throttled version of the function that will only be called max once per frame.\n * The target frame rate is 60fps.\n * @param fn - the fun to return a throttled version of\n * @returns\n * @internal\n */\nexport function fpsThrottle(fn: { (): void; cancel?(): void }): {\n\t(): void\n\tcancel?(): void\n} {\n\tif (isTest()) {\n\t\tfn.cancel = () => {\n\t\t\tif (frameRaf) {\n\t\t\t\tcancelAnimationFrame(frameRaf)\n\t\t\t\tframeRaf = undefined\n\t\t\t}\n\t\t\tif (flushRaf) {\n\t\t\t\tcancelAnimationFrame(flushRaf)\n\t\t\t\tflushRaf = undefined\n\t\t\t}\n\t\t}\n\t\treturn fn\n\t}\n\n\tconst throttledFn = () => {\n\t\tif (fpsQueue.includes(fn)) {\n\t\t\treturn\n\t\t}\n\t\tfpsQueue.push(fn)\n\t\ttick()\n\t}\n\tthrottledFn.cancel = () => {\n\t\tconst index = fpsQueue.indexOf(fn)\n\t\tif (index > -1) {\n\t\t\tfpsQueue.splice(index, 1)\n\t\t}\n\t}\n\treturn throttledFn\n}\n\n/**\n * Calls the function on the next frame. The target frame rate is 60fps.\n * If the same fn is passed again before the next frame, it will still be called only once.\n * @param fn - the fun to call on the next frame\n * @returns a function that will cancel the call if called before the next frame\n * @internal\n */\nexport function throttleToNextFrame(fn: () => void): () => void {\n\tif (isTest()) {\n\t\tfn()\n\t\treturn () => void null // noop\n\t}\n\n\tif (!fpsQueue.includes(fn)) {\n\t\tfpsQueue.push(fn)\n\t\ttick()\n\t}\n\n\treturn () => {\n\t\tconst index = fpsQueue.indexOf(fn)\n\t\tif (index > -1) {\n\t\t\tfpsQueue.splice(index, 1)\n\t\t}\n\t}\n}\n"],
"mappings": "AAAA,MAAM,SAAS,MACd,OAAO,YAAY,eACnB,QAAQ,IAAI,aAAa;AAEzB,CAAC,WAAW;AAEb,MAAM,WAA8B,CAAC;AACrC,MAAM,YAAY;AAClB,MAAM,qBAAqB,KAAK,MAAM,MAAO,SAAS,IAAI;AAC1D,IAAI;AACJ,IAAI;AACJ,IAAI,gBAAgB,CAAC;AAErB,MAAM,QAAQ,MAAM;AACnB,QAAM,QAAQ,SAAS,OAAO,GAAG,SAAS,MAAM;AAChD,aAAW,MAAM,OAAO;AACvB,OAAG;AAAA,EACJ;AACD;AAEA,SAAS,KAAK,gBAAgB,OAAO;AACpC,MAAI,SAAU;AAEd,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,UAAU,MAAM;AAEtB,MAAI,UAAU,oBAAoB;AAGjC,eAAW,sBAAsB,MAAM;AACtC,iBAAW;AACX,WAAK,IAAI;AAAA,IACV,CAAC;AACD;AAAA,EACD;AAEA,MAAI,eAAe;AAElB,QAAI,SAAU;AACd,oBAAgB;AAChB,UAAM;AAAA,EACP,OAAO;AAEN,QAAI,SAAU;AAEd,eAAW,sBAAsB,MAAM;AACtC,iBAAW;AACX,sBAAgB;AAChB,YAAM;AAAA,IACP,CAAC;AAAA,EACF;AACD;AASO,SAAS,YAAY,IAG1B;AACD,MAAI,OAAO,GAAG;AACb,OAAG,SAAS,MAAM;AACjB,UAAI,UAAU;AACb,6BAAqB,QAAQ;AAC7B,mBAAW;AAAA,MACZ;AACA,UAAI,UAAU;AACb,6BAAqB,QAAQ;AAC7B,mBAAW;AAAA,MACZ;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAEA,QAAM,cAAc,MAAM;AACzB,QAAI,SAAS,SAAS,EAAE,GAAG;AAC1B;AAAA,IACD;AACA,aAAS,KAAK,EAAE;AAChB,SAAK;AAAA,EACN;AACA,cAAY,SAAS,MAAM;AAC1B,UAAM,QAAQ,SAAS,QAAQ,EAAE;AACjC,QAAI,QAAQ,IAAI;AACf,eAAS,OAAO,OAAO,CAAC;AAAA,IACzB;AAAA,EACD;AACA,SAAO;AACR;AASO,SAAS,oBAAoB,IAA4B;AAC/D,MAAI,OAAO,GAAG;AACb,OAAG;AACH,WAAO,MAAM;AAAA,EACd;AAEA,MAAI,CAAC,SAAS,SAAS,EAAE,GAAG;AAC3B,aAAS,KAAK,EAAE;AAChB,SAAK;AAAA,EACN;AAEA,SAAO,MAAM;AACZ,UAAM,QAAQ,SAAS,QAAQ,EAAE;AACjC,QAAI,QAAQ,IAAI;AACf,eAAS,OAAO,OAAO,CAAC;AAAA,IACzB;AAAA,EACD;AACD;",
"names": []
}