{"_id":"@arijs/transfer-speed-graph","_rev":"5-1c0ebc7e4666bdef2971c2afd5a0e3df","name":"@arijs/transfer-speed-graph","dist-tags":{"readme":"0.1.1-0.readme","latest":"0.1.3"},"versions":{"0.1.0":{"name":"@arijs/transfer-speed-graph","version":"0.1.0","author":{"name":"rhengles@gmail.com"},"license":"MIT","_id":"@arijs/transfer-speed-graph@0.1.0","maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"dist":{"shasum":"7b539c0611f5926bbbacb5b779622aec469d987c","tarball":"https://registry.npmjs.org/@arijs/transfer-speed-graph/-/transfer-speed-graph-0.1.0.tgz","fileCount":9,"integrity":"sha512-+gSAnq9xxt9ZSU5Kf0evzOjgUoaDBmMjNro6TpkEBLmD86hVZcUDb0VGvpM1+G0TEdo1JXIpHVsGBWOgCxFwlQ==","signatures":[{"sig":"MEQCIGxVecDbRXnl4qLs2e2qq0imzL6zZM7SBxxndmKoTocqAiA5bZop6UCY4ZCM9GXZUp+mTrMcWGUrjvd7LcgrZCpWMg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74069},"main":"./dist/arijs-transfer-speed-graph.umd.cjs","type":"module","access":"public","module":"./dist/arijs-transfer-speed-graph.js","exports":{".":{"import":"./dist/arijs-transfer-speed-graph.js","require":"./dist/arijs-transfer-speed-graph.umd.cjs"}},"gitHead":"fad9daab67d7f167e47a143dc94cebc4789afa4d","_npmUser":{"name":"arijs","email":"arijs@arijs.org"},"_npmVersion":"11.6.2","description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/transfer-speed-graph_0.1.0_1779758294323_0.4247105832393403","host":"s3://npm-registry-packages-npm-production"}},"0.1.1-0.readme":{"name":"@arijs/transfer-speed-graph","version":"0.1.1-0.readme","author":{"name":"rhengles@gmail.com"},"license":"MIT","_id":"@arijs/transfer-speed-graph@0.1.1-0.readme","maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"dist":{"shasum":"ecd9a0c34c9f70035e2d1e40b072f8e4bbc00b2e","tarball":"https://registry.npmjs.org/@arijs/transfer-speed-graph/-/transfer-speed-graph-0.1.1-0.readme.tgz","fileCount":10,"integrity":"sha512-qBWindnOKIvxl7Cku1heSH7fDSSAVQz+omSuHHc4AsizK8Ggog+mzJWaK6KzGrxbw7hGL+lJIQy9/6YTpixK7A==","signatures":[{"sig":"MEYCIQCHlpQwfaBfK3KjW7eSb2mOhP1VfhgJ9Iur0WTkzAu/UwIhAJEg4m320VOaZhesnukygajCx1/zi7QJpi5NVBgERDmW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79050},"main":"./dist/arijs-transfer-speed-graph.umd.cjs","type":"module","access":"public","module":"./dist/arijs-transfer-speed-graph.js","exports":{".":{"import":"./dist/arijs-transfer-speed-graph.js","require":"./dist/arijs-transfer-speed-graph.umd.cjs"}},"gitHead":"ad3a738d744cc2811c1393b91eb7feb9f5e59874","_npmUser":{"name":"arijs","email":"arijs@arijs.org"},"_npmVersion":"11.6.2","description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/transfer-speed-graph_0.1.1-0.readme_1779758549345_0.8868564463647572","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@arijs/transfer-speed-graph","version":"0.1.1","author":{"name":"rhengles@gmail.com"},"license":"MIT","_id":"@arijs/transfer-speed-graph@0.1.1","maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"dist":{"shasum":"7581531a474293b08250e070accbadd288fec87a","tarball":"https://registry.npmjs.org/@arijs/transfer-speed-graph/-/transfer-speed-graph-0.1.1.tgz","fileCount":10,"integrity":"sha512-UB/PZ6xEo3ukyGRfLT0bu7xC7j+aFqHwbxZXbqnpGeino4vAAqUDDfmPsNA2uqJUewhXA5ff+gTsQX2AljmxzQ==","signatures":[{"sig":"MEQCIBYSnduMV3wxaLjOd8aUZ4ViP1coAFzcauULc8BM7CbNAiAKsUkDTDvJDyKrFs6/5vBRNZYkBWbdf2UDnZYXOoi1gg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79041},"main":"./dist/arijs-transfer-speed-graph.umd.cjs","type":"module","access":"public","module":"./dist/arijs-transfer-speed-graph.js","exports":{".":{"import":"./dist/arijs-transfer-speed-graph.js","require":"./dist/arijs-transfer-speed-graph.umd.cjs"}},"gitHead":"ce98c8f3094294e882dbb2627fb33014ab7da630","_npmUser":{"name":"arijs","email":"arijs@arijs.org"},"_npmVersion":"11.6.2","description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/transfer-speed-graph_0.1.1_1779758743633_0.32744876099040243","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@arijs/transfer-speed-graph","version":"0.1.2","author":{"name":"rhengles@gmail.com"},"license":"MIT","_id":"@arijs/transfer-speed-graph@0.1.2","maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"homepage":"https://github.com/rhengles/transfer-speed-graph","bugs":{"url":"https://github.com/rhengles/transfer-speed-graph/issues"},"dist":{"shasum":"3bce068bdabb8633fed84855f5eeecebad7812c8","tarball":"https://registry.npmjs.org/@arijs/transfer-speed-graph/-/transfer-speed-graph-0.1.2.tgz","fileCount":10,"integrity":"sha512-p3q6bU2D8ROi533CXhoq++vcYHj36taYK/OfVLV1JdNDmk9aV6Wf1xHgGyg1Je0DTeQeL/14eMhdlR50nnMFRQ==","signatures":[{"sig":"MEQCIEYeqx+u23y7XMEvnaEqQZjRoKcgZxO8WGh4L0CDmqwfAiAb2mLd0x2g2kYsG8D0wWxnHfE1cl/xz1UBySoPzhFbZg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79140},"main":"./dist/arijs-transfer-speed-graph.umd.cjs","type":"module","access":"public","module":"./dist/arijs-transfer-speed-graph.js","exports":{".":{"import":"./dist/arijs-transfer-speed-graph.js","require":"./dist/arijs-transfer-speed-graph.umd.cjs"}},"gitHead":"67ffd1e6107eb7633919ae9a51d5bebe4a1ec5b3","_npmUser":{"name":"arijs","email":"arijs@arijs.org"},"repository":{"url":"git+https://github.com/rhengles/transfer-speed-graph.git","type":"git","directory":"core"},"_npmVersion":"11.6.2","description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/transfer-speed-graph_0.1.2_1779797538747_0.5570586979458165","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@arijs/transfer-speed-graph","version":"0.1.3","description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","access":"public","type":"module","author":{"name":"rhengles@gmail.com"},"license":"MIT","homepage":"https://speed-transfer.arijs.org/","repository":{"type":"git","url":"git+https://github.com/rhengles/transfer-speed-graph.git","directory":"core"},"main":"./dist/arijs-transfer-speed-graph.umd.cjs","module":"./dist/arijs-transfer-speed-graph.js","exports":{".":{"import":"./dist/arijs-transfer-speed-graph.js","require":"./dist/arijs-transfer-speed-graph.umd.cjs"}},"gitHead":"859a00786a996d05ed14be3fc17ff431b25d493d","_id":"@arijs/transfer-speed-graph@0.1.3","bugs":{"url":"https://github.com/rhengles/transfer-speed-graph/issues"},"_nodeVersion":"20.20.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-OjoB/9ClwzTviAIlhKIUeP2VBUapD4HPz8n6oIe6w0MYFLeGiDA3/M+emeJ/EBZXXmMZlLab4PfqUlnV1ejVOA==","shasum":"1eb4b074f8f7e012fffb800ebeddfd668f3e250c","tarball":"https://registry.npmjs.org/@arijs/transfer-speed-graph/-/transfer-speed-graph-0.1.3.tgz","fileCount":10,"unpackedSize":99390,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEMCH0McrRyR4oZ1ObLA+yyQjiUv024APUTmhwoEppXikH0CIEXZ137vSv9C2gTOF/F7U6JgF9Lrx9fPPv2YvTr02PVZ"}]},"_npmUser":{"name":"arijs","email":"arijs@arijs.org"},"directories":{},"maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/transfer-speed-graph_0.1.3_1779842158290_0.3808902320000287"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-26T01:18:14.213Z","modified":"2026-05-27T00:35:58.543Z","0.1.0":"2026-05-26T01:18:14.493Z","0.1.1-0.readme":"2026-05-26T01:22:29.522Z","0.1.1":"2026-05-26T01:25:43.782Z","0.1.2":"2026-05-26T12:12:18.906Z","0.1.3":"2026-05-27T00:35:58.425Z"},"bugs":{"url":"https://github.com/rhengles/transfer-speed-graph/issues"},"author":{"name":"rhengles@gmail.com"},"license":"MIT","homepage":"https://speed-transfer.arijs.org/","repository":{"type":"git","url":"git+https://github.com/rhengles/transfer-speed-graph.git","directory":"core"},"description":"A lightweight, modular transfer speed graph inspired by the Windows 8 file transfer dialog, with support for: Real transfer integration (download/upload), Deterministic and random fake transfer simulation, Pause/cancel/finish states, and Highly configurab","maintainers":[{"name":"arijs","email":"arijs@arijs.org"}],"readme":"# Transfer Speed Graph\r\n\r\n![Transfer Speed Graph](img/artwork/github-preview-720.png)\r\n\r\n\r\n[Transfer Speed Graph homepage](https://speed-transfer.arijs.org/) / [NPM Package](https://npmjs.com/package/@arijs/transfer-speed-graph) ![NPM Version](https://img.shields.io/npm/v/%40arijs%2Ftransfer-speed-graph)\r\n\r\nA lightweight, modular transfer-speed graph inspired by the Windows 8 file transfer dialog, with support for:\r\n\r\n- Real transfer integration (download/upload)\r\n- Deterministic and random fake transfer simulation\r\n- Pause/cancel/finish states\r\n- Highly configurable graph smoothing and dynamic Y-scale behavior\r\n\r\n### Real Example\r\n\r\n![Deterministic transfer at 50%](img/screenshots/deterministic-50perc.png)\r\n\r\n## Quick Usage\r\n\r\n### Install\r\n\r\n```bash\r\nnpm install @arijs/transfer-speed-graph\r\n```\r\n\r\nThen use the object:\r\n\r\n```js\r\nimport { TransferGraph } from '@arijs/transfer-speed-graph'\r\n\r\nconst graph = new TransferGraph()\r\n```\r\n\r\n### CDN\r\n\r\nIf you prefer not to use a bundler, you can use either ES module imports or the UMD bundle.\r\n\r\nES module import via jsDelivr:\r\n\r\n```js\r\nimport { TransferGraph } from 'https://cdn.jsdelivr.net/npm/@arijs/transfer-speed-graph@latest/+esm'\r\n\r\nconst graph = new TransferGraph()\r\n```\r\n\r\nES module import via unpkg:\r\n\r\n```js\r\nimport { TransferGraph } from 'https://unpkg.com/@arijs/transfer-speed-graph@latest?module'\r\n\r\nconst graph = new TransferGraph()\r\n```\r\n\r\nUMD script via jsDelivr:\r\n\r\n```html\r\n<script src=\"https://cdn.jsdelivr.net/npm/@arijs/transfer-speed-graph@latest/dist/arijs-transfer-speed-graph.umd.js\"></script>\r\n```\r\n\r\nUMD script via unpkg:\r\n\r\n```html\r\n<script src=\"https://unpkg.com/@arijs/transfer-speed-graph@latest/dist/arijs-transfer-speed-graph.umd.js\"></script>\r\n```\r\n\r\n### HTML Script Tag\r\n\r\nAfter loading one of the CDN scripts above, you can initialize the graph with a minimal HTML snippet:\r\n\r\n```html\r\n<canvas id=\"graph\" width=\"416\" height=\"72\"></canvas>\r\n<script>\r\n  const graph = new TransferSpeedGraph.TransferGraph()\r\n  const canvasCtx = document.getElementById('graph').getContext('2d')\r\n\r\n  graph.setRendererOptions({\r\n    canvasCtx,\r\n    canvasWidth: 416,\r\n    canvasHeight: 72,\r\n  })\r\n\r\n  graph.startTransfer({ totalSize: 12 * 1024 * 1024 })\r\n</script>\r\n```\r\n\r\n### Download Example\r\n\r\n```js\r\nimport { TransferGraph } from '@arijs/transfer-speed-graph'\r\n\r\nconst controller = new TransferGraph()\r\ncontroller.setOnFrame((view) => {\r\n  // update your UI with view.progressInt, view.speedBps, etc.\r\n})\r\n\r\nconst downloadUrl = 'https://httpbin.org/bytes/12582912?seed=2026'\r\nconst fallbackTotalSize = 12 * 1024 * 1024\r\n\r\ncontroller.setRendererOptions({\r\n  canvasCtx,\r\n  canvasWidth: 416,\r\n  canvasHeight: 72,\r\n})\r\n\r\nfetch(downloadUrl).then(async (res) => {\r\n  if (!res.ok || !res.body) throw new Error('Download failed: ' + res.status)\r\n\r\n  const totalHeader = parseInt(res.headers.get('content-length') || '0', 10)\r\n  const totalSize = Number.isFinite(totalHeader) && totalHeader > 0\r\n    ? totalHeader\r\n    : fallbackTotalSize\r\n\r\n  const reader = res.body.getReader()\r\n  let transferredBytes = 0\r\n\r\n  controller.startTransfer({ totalSize })\r\n\r\n  while (true) {\r\n    const chunk = await reader.read()\r\n    if (chunk.done) break\r\n    transferredBytes += chunk.value.byteLength\r\n    controller.pushProgress({ transferredBytes, totalSize })\r\n  }\r\n\r\n  controller.finishTransfer({ transferredBytes, totalSize })\r\n}).catch((err) => {\r\n  console.warn(err)\r\n  controller.cancel()\r\n})\r\n```\r\n\r\nSource example: [real/download-example.js](https://github.com/rhengles/transfer-speed-graph/blob/master/real/download-example.js)\r\n\r\n### Upload Example\r\n\r\n```js\r\nimport { TransferGraph } from '@arijs/transfer-speed-graph'\r\n\r\nconst controller = new TransferGraph()\r\nconst uploadUrl = 'https://httpbin.org/post'\r\nconst uploadSize = 10 * 1024 * 1024\r\n\r\nconst xhr = new XMLHttpRequest()\r\nconst payload = new Blob([new Uint8Array(uploadSize)])\r\n\r\ncontroller.setRendererOptions({\r\n  canvasCtx,\r\n  canvasWidth: 416,\r\n  canvasHeight: 72,\r\n})\r\ncontroller.startTransfer({ totalSize: uploadSize })\r\n\r\nxhr.upload.addEventListener('progress', (ev) => {\r\n  if (!ev.lengthComputable) return\r\n  controller.pushProgress({\r\n    transferredBytes: ev.loaded,\r\n    totalSize: ev.total,\r\n  })\r\n})\r\n\r\nxhr.addEventListener('load', () => {\r\n  controller.finishTransfer({\r\n    transferredBytes: uploadSize,\r\n    totalSize: uploadSize,\r\n  })\r\n})\r\n\r\nxhr.addEventListener('error', () => {\r\n  console.warn('upload failed')\r\n  controller.cancel()\r\n})\r\n\r\nxhr.addEventListener('abort', () => {\r\n  controller.cancel()\r\n})\r\n\r\nxhr.open('POST', uploadUrl)\r\nxhr.send(payload)\r\n```\r\n\r\nSource example: [real/upload-example.js](https://github.com/rhengles/transfer-speed-graph/blob/master/real/upload-example.js)\r\n\r\n## State Showcase\r\n\r\nPaused state:\r\n\r\n![Paused transfer state](img/screenshots/deterministic-series16-67perc-paused.png)\r\n\r\nCancelled state:\r\n\r\n![Cancelled transfer state](img/screenshots/deterministic-series16-67perc-cancelled.png)\r\n\r\n## Why This Library Is Strong\r\n\r\n### Source Files\r\n\r\nThe published package is split by concern:\r\n\r\n- Graph core:\r\n  - [core/main.js](core/main.js)\r\n    public `TransferGraph` facade that coordinates model, renderer, and runtime APIs.\r\n  - [core/model.js](core/model.js)\r\n    transfer state machine plus series, timing, and control state management.\r\n  - [core/renderer.js](core/renderer.js)\r\n    renderer configuration layer that resolves options and delegates frame drawing.\r\n  - [core/frame.js](core/frame.js)\r\n    canvas frame rendering, graph geometry, and draw-hook execution.\r\n  - [core/speed-series.js](core/speed-series.js)\r\n    series utilities for averaging, speed calculations, and coordinate transforms.\r\n- Fake transfer subsystem:\r\n  - [fake/progress-source.js](fake/progress-source.js)\r\n    controller bridge that drives fake progress updates into the graph.\r\n  - [fake/simulation.js](fake/simulation.js)\r\n    deterministic/random simulation engine for timing and size progression.\r\n  - [fake/series.js](fake/series.js)\r\n    fake-series helpers and presets used by the simulator.\r\n- Real transfer examples:\r\n  - [real/download-example.js](real/download-example.js)\r\n    streaming download example wired to the graph controller.\r\n  - [real/upload-example.js](real/upload-example.js)\r\n    upload progress example wired to the graph controller.\r\n\r\nThat separation keeps rendering, state management, fake generation, and transport examples independent and easy to evolve.\r\n\r\n### High Configurability\r\n\r\nGraph behavior can be tuned at runtime with controls such as:\r\n\r\n- `pixelAverageWindow`\r\n- `maxSpeedDecay`\r\n- `maxSpeedHeadroom`\r\n- `ignoreTrailingSpeedSample`\r\n\r\nFake simulation is configurable through `simulationOptions`, including:\r\n\r\n- `minFrame`, `maxFrame`\r\n- `minFrameRepeat`, `maxFrameRepeat`\r\n- `minSizeInc`, `maxSizeInc`\r\n- `deterministicSeed`\r\n\r\nThis allows both realistic noisy profiles and stable deterministic test profiles.\r\n\r\n## Practical Runtime API\r\n\r\n`TransferGraph` gives a straightforward app-facing API:\r\n\r\n- `startTransfer`\r\n\r\n  Start a new transfer and reset the runtime state.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  startTransfer(config)\r\n  ```\r\n\r\n  - `config.totalSize`: required positive total size for the transfer.\r\n  - `config.nowMs`: optional timestamp used as the transfer start time.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.startTransfer({ totalSize: 12 * 1024 * 1024 })\r\n  ```\r\n\r\n- `pushProgress`\r\n\r\n  Append a new progress update to the active transfer.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  pushProgress(update)\r\n  ```\r\n\r\n  - `update.transferredBytes`: current transferred byte count.\r\n  - `update.totalSize`: optional total size override.\r\n  - `update.elapsedMs`: optional elapsed time override.\r\n  - `update.nowMs`: optional timestamp used to resolve elapsed time.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.pushProgress({ transferredBytes: 4 * 1024 * 1024 })\r\n  ```\r\n\r\n- `finishTransfer`\r\n\r\n  Mark the transfer as finished and capture the final point.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  finishTransfer(update)\r\n  ```\r\n\r\n  - `update.transferredBytes`: final transferred byte count.\r\n  - `update.totalSize`: optional total size override.\r\n  - `update.elapsedMs`: optional elapsed time override.\r\n  - `update.nowMs`: optional timestamp used to resolve elapsed time.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.finishTransfer({ transferredBytes: 12 * 1024 * 1024 })\r\n  ```\r\n\r\n- `cancel`\r\n\r\n  Cancel the active transfer and freeze it in a finished state.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  cancel()\r\n  ```\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.cancel()\r\n  ```\r\n\r\n- `reset`\r\n\r\n  Reset the model back to its initial state.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  reset()\r\n  ```\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.reset()\r\n  ```\r\n\r\n- `pause`\r\n\r\n  Pause elapsed-time tracking without clearing transfer progress.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  pause(nowMs)\r\n  ```\r\n\r\n  - `nowMs`: optional timestamp used to freeze elapsed-time calculations.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.pause()\r\n  ```\r\n\r\n- `resume`\r\n\r\n  Resume elapsed-time tracking after a pause.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  resume(nowMs)\r\n  ```\r\n\r\n  - `nowMs`: optional timestamp used to resume elapsed-time calculations.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.resume()\r\n  ```\r\n\r\n- `toggleFinishedPauseVisual`\r\n\r\n  Toggle the paused visual state that is shown after a transfer finishes.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  toggleFinishedPauseVisual()\r\n  ```\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.toggleFinishedPauseVisual()\r\n  ```\r\n\r\n- `refreshGraphScale`\r\n\r\n  Force the renderer to recalculate the speed scale on the next frame.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  refreshGraphScale()\r\n  ```\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.refreshGraphScale()\r\n  ```\r\n\r\n- `setPixelAverageWindow`\r\n\r\n  Change the rolling average window used by the renderer.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setPixelAverageWindow(nextWindow)\r\n  ```\r\n\r\n  - `nextWindow`: smoothing window size in rendered points.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setPixelAverageWindow(16)\r\n  ```\r\n\r\n- `setMaxSpeedDecay`\r\n\r\n  Change the decay factor used for the dynamic speed scale.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setMaxSpeedDecay(nextValue)\r\n  ```\r\n\r\n  - `nextValue`: new decay value, typically between `0.5` and `0.999`.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setMaxSpeedDecay(0.95)\r\n  ```\r\n\r\n- `setMaxSpeedHeadroom`\r\n\r\n  Change the headroom factor used for the dynamic speed scale.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setMaxSpeedHeadroom(nextValue)\r\n  ```\r\n\r\n  - `nextValue`: new headroom value, typically between `1` and `2`.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setMaxSpeedHeadroom(1.08)\r\n  ```\r\n\r\n- `setOnFrame`\r\n\r\n  Register a callback that receives the computed frame view model.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setOnFrame(onFrame)\r\n  ```\r\n\r\n  - `onFrame(view)`: receives the computed frame view model.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setOnFrame((view) => {\r\n  console.log(view.progressInt)\r\n  })\r\n  ```\r\n\r\n- `setOnControls`\r\n\r\n  Register a callback that receives the current controls state.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setOnControls(onControls)\r\n  ```\r\n\r\n  - `onControls(view)`: receives the current controls state.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setOnControls((controls) => {\r\n  console.log(controls.pixelAverageWindow)\r\n  })\r\n  ```\r\n\r\n- `setOnStateChange`\r\n\r\n  Register a callback that receives the raw state snapshot.\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  setOnStateChange(onStateChange)\r\n  ```\r\n\r\n  - `onStateChange(state)`: receives the raw state snapshot.\r\n\r\n  Example:\r\n\r\n  ```js\r\n  const graph = new TransferGraph()\r\n  graph.setOnStateChange((state) => {\r\n  console.log(state.started, state.finished)\r\n  })\r\n  ```\r\n\r\n## Canvas Drawing Hooks\r\n\r\n`TransferGraphRenderer` accepts optional draw hooks that let you customize the canvas output without replacing the whole renderer. If a hook is omitted, the default implementation reproduces the current visuals.\r\n\r\nProvide them through `new TransferGraph({ ... })` or `setRendererOptions({ ... })`:\r\n\r\n### Common argument properties\r\n\r\nEvery draw hook receives these shared properties:\r\n\r\n- `canvasCtx`: the active 2D canvas context for the current frame.\r\n- `canvasWidth`: the canvas width in pixels.\r\n- `canvasHeight`: the canvas height in pixels.\r\n\r\n- `drawProgressBar`\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  drawProgressBar({ canvasCtx, canvasWidth, canvasHeight, lastX, backgroundValue, createDefaultPath })\r\n  ```\r\n\r\n  - `lastX`: the resolved filled width of the progress bar in canvas coordinates.\r\n  - `backgroundValue`: the value used to compute the background fill width.\r\n  - `createDefaultPath()`: builds the current progress-bar path with `beginPath()` + `rect()`.\r\n\r\n  Default: the renderer calls `createDefaultPath()`, then `fill()` and `stroke()`.\r\n\r\n  ```js\r\n  const graph = new TransferGraph({\r\n  drawProgressBar({ canvasCtx, createDefaultPath }) {\r\n    createDefaultPath()\r\n    canvasCtx.fill()\r\n    canvasCtx.stroke()\r\n  },\r\n  })\r\n  ```\r\n\r\n- `drawGrid`\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  drawGrid({ canvasCtx, canvasWidth, canvasHeight, gridCols, gridRows, createDefaultPath })\r\n  ```\r\n\r\n  - `gridCols`: number of vertical grid divisions.\r\n  - `gridRows`: number of horizontal grid divisions.\r\n  - `createDefaultPath()`: builds the current grid paths for both directions.\r\n\r\n  Default: the renderer calls `createDefaultPath()`, then `stroke()`.\r\n\r\n  ```js\r\n  const graph = new TransferGraph({\r\n  drawGrid({ canvasCtx, createDefaultPath }) {\r\n    createDefaultPath()\r\n    canvasCtx.stroke()\r\n  },\r\n  })\r\n  ```\r\n\r\n- `drawSpeedOverlay`\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  drawSpeedOverlay({ canvasCtx, canvasWidth, canvasHeight, lastX, endX, avgWithSpeeds, renderPointCount, pixelsPerValue, maxAvgSpeed, createDefaultPath })\r\n  ```\r\n\r\n  - `lastX`: the resolved filled width of the progress area.\r\n  - `endX`: the right edge where the overlay path should continue until the filled progress ends.\r\n  - `avgWithSpeeds`: the calculated speed points used to draw the overlay.\r\n  - `renderPointCount`: number of points used when rendering the visible speed curve.\r\n  - `pixelsPerValue`: the conversion factor from value units to canvas X pixels.\r\n  - `maxAvgSpeed`: the resolved speed scale used to normalize the overlay height.\r\n  - `createDefaultPath()`: builds the current speed-area path and lets the default implementation resolve the current point position.\r\n\r\n  Default: the renderer calls `createDefaultPath()`, then `fill()`.\r\n\r\n  ```js\r\n  const graph = new TransferGraph({\r\n  drawSpeedOverlay({ canvasCtx, createDefaultPath }) {\r\n    createDefaultPath()\r\n    canvasCtx.fill()\r\n  },\r\n  })\r\n  ```\r\n\r\n- `drawSpeedLineLabel`\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  drawSpeedLineLabel({ canvasCtx, canvasWidth, canvasHeight, guideY, textX, labelBottomY, labelTopY, labelLeftX, labelWidth, labelPaddingX, labelPaddingY, speedLabel, speedLabelColor, speedLabelBackgroundColor, speedGuideColor, createDefaultLinePath, createDefaultLabelBackgroundPath, fillDefaultLabelText })\r\n  ```\r\n\r\n  - `guideY`: the Y position of the horizontal guide line.\r\n  - `textX`: the right-aligned X position used for the label text.\r\n  - `labelBottomY`: the baseline Y position for the label text.\r\n  - `labelTopY`: the top Y position of the background box.\r\n  - `labelLeftX`: the left X position of the background box.\r\n  - `labelWidth`: measured width of the label text.\r\n  - `labelPaddingX`: horizontal padding used by the default label box.\r\n  - `labelPaddingY`: vertical padding used by the default label box.\r\n  - `speedLabel`: the formatted label string.\r\n  - `speedLabelColor`: the current text color.\r\n  - `speedLabelBackgroundColor`: the current background fill color.\r\n  - `speedGuideColor`: the current guide-line stroke color.\r\n  - `createDefaultLinePath()`: builds the current guide-line path.\r\n  - `createDefaultLabelBackgroundPath()`: builds the current label background path with `beginPath()` + `rect()`.\r\n  - `fillDefaultLabelText(options)`: draws the current text using `fillText()`. Optional `options` can override fill style and text alignment for custom drawing.\r\n\r\n  Default: the renderer strokes the line path, fills the background path, and calls `fillDefaultLabelText()`.\r\n\r\n  ```js\r\n  const graph = new TransferGraph({\r\n  drawSpeedLineLabel({\r\n    canvasCtx,\r\n    createDefaultLinePath,\r\n    createDefaultLabelBackgroundPath,\r\n    fillDefaultLabelText,\r\n  }) {\r\n    createDefaultLinePath()\r\n    canvasCtx.stroke()\r\n    createDefaultLabelBackgroundPath()\r\n    canvasCtx.fill()\r\n    fillDefaultLabelText()\r\n  },\r\n  })\r\n  ```\r\n\r\n- `drawBorder`\r\n\r\n  Signature:\r\n\r\n  ```js\r\n  drawBorder({ canvasCtx, canvasWidth, canvasHeight, borderColor, createDefaultPath })\r\n  ```\r\n\r\n  - `borderColor`: the current border stroke color.\r\n  - `createDefaultPath()`: builds the current canvas border path with `beginPath()` + `rect()`.\r\n\r\n  Default: the renderer calls `createDefaultPath()`, then `stroke()`.\r\n\r\n  ```js\r\n  const graph = new TransferGraph({\r\n  drawBorder({ canvasCtx, createDefaultPath }) {\r\n    createDefaultPath()\r\n    canvasCtx.stroke()\r\n  },\r\n  })\r\n  ```\r\n\r\n\r\n## Development\r\n\r\nSee repo at https://github.com/rhengles/transfer-speed-graph\r\n","readmeFilename":"README.md"}