emberwick 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/README.md +14 -2
- package/index.d.ts +6 -0
- package/index.js +141 -44
- package/index.js.map +1 -1
- package/package.json +10 -1
- package/umd/emberwick.umd.js +1 -1
- package/umd/emberwick.umd.js.map +1 -1
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/chart/core/Layers.js","../src/chart/core/Loop.js","../src/chart/motion/Tween.js","../src/chart/core/TimeScale.js","../src/chart/core/PriceScale.js","../src/chart/core/palette.js","../src/chart/motion/LiveCandle.js","../src/chart/motion/Inertia.js","../src/chart/replay/Replay.js","../src/chart/core/formatters.js","../src/chart/render/grid.js","../src/chart/render/candles.js","../src/chart/render/crosshair.js","../src/chart/overlays/annotations.js","../src/chart/render/annotations.js","../src/chart/core/Chart.js","../src/chart/data/DataFeed.js","../src/chart/data/RandomFeed.js","../src/chart/index.js"],"sourcesContent":["/**\n * Layers — stacked canvases sharing one coordinate space.\n *\n * Why: the crosshair repaints on every pointer move, the candles do not.\n * Separate canvases mean moving the cursor never touches candle pixels.\n * All contexts are pre-scaled by devicePixelRatio, so every renderer draws\n * in CSS pixels and gets crisp output on retina.\n */\nexport class Layers {\n constructor(container, names) {\n this.container = container\n this.names = names\n this.canvas = {}\n this.ctx = {}\n this.width = 0\n this.height = 0\n this.dpr = 0\n this.onResize = null\n\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative'\n }\n\n names.forEach((name, i) => {\n const c = document.createElement('canvas')\n Object.assign(c.style, {\n position: 'absolute',\n left: '0',\n top: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: String(i + 1),\n })\n container.appendChild(c)\n this.canvas[name] = c\n this.ctx[name] = c.getContext('2d')\n })\n\n this._ro = new ResizeObserver(() => this.measure())\n this._ro.observe(container)\n this.measure()\n }\n\n measure() {\n const r = this.container.getBoundingClientRect()\n const w = Math.max(1, Math.floor(r.width))\n const h = Math.max(1, Math.floor(r.height))\n const dpr = Math.min(window.devicePixelRatio || 1, 2)\n if (w === this.width && h === this.height && dpr === this.dpr) return\n this.width = w\n this.height = h\n this.dpr = dpr\n for (const n of this.names) {\n const c = this.canvas[n]\n c.width = Math.floor(w * dpr)\n c.height = Math.floor(h * dpr)\n this.ctx[n].setTransform(dpr, 0, 0, dpr, 0, 0)\n }\n if (this.onResize) this.onResize(w, h)\n }\n\n /** Flatten all layers into a single canvas (for toImage/export). */\n composite() {\n const out = document.createElement('canvas')\n out.width = Math.floor(this.width * this.dpr)\n out.height = Math.floor(this.height * this.dpr)\n const c = out.getContext('2d')\n for (const n of this.names) c.drawImage(this.canvas[n], 0, 0)\n return out\n }\n\n destroy() {\n this._ro.disconnect()\n for (const n of this.names) this.canvas[n].remove()\n this.canvas = {}\n this.ctx = {}\n }\n}\n","/**\n * Loop — ONE requestAnimationFrame loop for the whole chart, driven by\n * dirty flags. 500 feed ticks between two frames still cost one repaint.\n *\n * The frame callback returns `true` while animation is in flight, which is\n * what keeps the loop running; otherwise it idles at zero CPU until something\n * calls invalidate().\n */\nexport class Loop {\n constructor(onFrame) {\n this.onFrame = onFrame\n this.fps = 0\n this._raf = 0\n this._dirty = new Set()\n this._last = 0\n this._running = false\n this._frames = 0\n this._fpsAt = 0\n this._tick = this._tick.bind(this)\n }\n\n invalidate(...layers) {\n if (!layers.length) this._dirty.add('all')\n else for (const l of layers) this._dirty.add(l)\n this._schedule()\n }\n\n start() {\n if (this._running) return\n this._running = true\n this._last = performance.now()\n this._fpsAt = this._last\n this.invalidate('all')\n }\n\n stop() {\n this._running = false\n if (this._raf) cancelAnimationFrame(this._raf)\n this._raf = 0\n }\n\n _schedule() {\n if (this._raf || !this._running) return\n this._raf = requestAnimationFrame(this._tick)\n }\n\n _tick(now) {\n this._raf = 0\n if (!this._running) return\n const dt = Math.min(Math.max(now - this._last, 1), 64)\n this._last = now\n\n this._frames++\n if (now - this._fpsAt >= 500) {\n this.fps = Math.round((this._frames * 1000) / (now - this._fpsAt))\n this._frames = 0\n this._fpsAt = now\n }\n\n const dirty = this._dirty\n this._dirty = new Set()\n\n let wantMore = false\n try {\n wantMore = this.onFrame(dirty, dt, now) === true\n } catch (e) {\n console.error('[Emberwick] frame error', e)\n }\n if (wantMore || this._dirty.size) this._schedule()\n }\n}\n","// Motion primitives. Everything animated in Emberwick goes through one of these\n// two classes so there is exactly one place that owns easing behaviour.\n\nexport const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3)\nexport const easeInOutCubic = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n\n/**\n * Smoothed — exponential smoothing toward a target that may move every frame.\n * Frame-rate independent: the same visual speed at 30fps and 144fps.\n * Use for values that are continuously re-targeted (autoscale, live candle, zoom).\n */\nexport class Smoothed {\n constructor(value = 0, tau = 90) {\n this.value = value\n this.target = value\n this.tau = tau\n }\n\n set(target) {\n this.target = target\n }\n\n /** Snap with no animation. */\n jump(v) {\n this.value = v\n this.target = v\n }\n\n get settled() {\n const eps = 1e-9 + Math.abs(this.target) * 1e-6\n return Math.abs(this.target - this.value) <= eps\n }\n\n /** @returns {boolean} true while still moving (caller keeps the loop alive) */\n tick(dt) {\n if (this.settled) {\n this.value = this.target\n return false\n }\n this.value += (this.target - this.value) * (1 - Math.exp(-dt / this.tau))\n return true\n }\n}\n\n/**\n * Tween — fixed-duration one-shot, for discrete events (a candle being born).\n */\nexport class Tween {\n constructor(duration = 200, ease = easeOutCubic) {\n this.duration = duration\n this.ease = ease\n this.t = duration\n }\n\n restart() {\n this.t = 0\n }\n\n get done() {\n return this.t >= this.duration\n }\n\n get progress() {\n return this.ease(Math.min(1, this.t / this.duration))\n }\n\n tick(dt) {\n if (this.done) return false\n this.t += dt\n return true\n }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * TimeScale — maps bar index <-> x pixels.\n *\n * Two smoothed values define the view:\n * spacing : px per bar (zoom)\n * right : float bar index sitting at the right edge of the plot\n *\n * Both are Smoothed, so a wheel zoom eases instead of stepping, and new bars\n * glide in rather than jumping. Dragging uses jump() so the chart stays glued\n * to the pointer — easing a drag feels like lag, not smoothness.\n */\nexport class TimeScale {\n constructor({ spacing = 9, minSpacing = 0.8, maxSpacing = 160, rightOffset = 12 } = {}) {\n this.minSpacing = minSpacing\n this.maxSpacing = maxSpacing\n this.rightOffset = rightOffset\n this.width = 0\n this.barCount = 0\n this.follow = true\n this.timeframeMs = 60000\n this._spacing = new Smoothed(spacing, 65)\n this._right = new Smoothed(rightOffset, 65)\n this._initial = spacing\n }\n\n get spacing() { return this._spacing.value }\n get right() { return this._right.value }\n\n resize(w) { this.width = Math.max(1, w) }\n\n setBarCount(n) {\n const grew = n > this.barCount\n this.barCount = n\n if (this.follow) {\n // target the new last bar; Smoothed turns this into a glide\n const t = n - 1 + this.rightOffset\n if (grew) this._right.set(t)\n else this._right.jump(t)\n }\n }\n\n x(i) { return this.width - (this._right.value - i) * this._spacing.value }\n\n /** Centre-x of bar i (bars are drawn centred on their slot). */\n index(x) { return this._right.value - (this.width - x) / this._spacing.value }\n\n barWidth() {\n const s = this._spacing.value\n // leave a gap between candles, but never thinner than a hairline\n return Math.max(1, Math.floor(s * 0.72))\n }\n\n visibleRange() {\n const first = Math.floor(this.index(0)) - 1\n const last = Math.ceil(this.index(this.width)) + 1\n return {\n from: clamp(first, 0, Math.max(0, this.barCount - 1)),\n to: clamp(last, 0, Math.max(0, this.barCount - 1)),\n }\n }\n\n _clampRight(v) {\n const max = this.barCount - 1 + this.rightOffset + this.width / this._spacing.target\n const min = Math.min(4, this.barCount - 1 + this.rightOffset)\n return clamp(v, min, max)\n }\n\n /** Immediate pan, in pixels. Positive dx drags content right (back in time). */\n panBy(dxPx) {\n if (!dxPx) return false\n const next = this._clampRight(this._right.value - dxPx / this._spacing.value)\n this._right.jump(next)\n this.follow = false\n return true\n }\n\n /** Zoom by `factor`, keeping the bar under `x` pinned. */\n zoomAt(x, factor) {\n const s0 = this._spacing.target\n const s1 = clamp(s0 * factor, this.minSpacing, this.maxSpacing)\n if (Math.abs(s1 - s0) < 1e-9) return false\n\n // While following realtime, pin the right edge instead of the cursor so the\n // latest candle stays put — that is what traders expect.\n const anchorX = this.follow ? this.width : x\n const r0 = this._right.target\n const idx = r0 - (this.width - anchorX) / s0\n const r1 = idx + (this.width - anchorX) / s1\n\n this._spacing.set(s1)\n this._right.set(this._clampRight(r1))\n return true\n }\n\n snapToRealtime() {\n this.follow = true\n this._right.set(this.barCount - 1 + this.rightOffset)\n }\n\n /**\n * Same anchor, no easing. Scrubbing re-targets the right edge many times a\n * second; easing each one reads as the chart lagging the scrubber, which is\n * the same reason a drag uses jump().\n */\n jumpToRealtime() {\n this.follow = true\n this._right.jump(this.barCount - 1 + this.rightOffset)\n }\n\n reset() {\n this._spacing.set(this._initial)\n this.snapToRealtime()\n }\n\n /** True while the view is still easing. */\n tick(dt) {\n const a = this._spacing.tick(dt)\n const b = this._right.tick(dt)\n return a || b\n }\n\n get settled() { return this._spacing.settled && this._right.settled }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * PriceScale — maps price <-> y pixels, with animated autoscale.\n *\n * Bounds live in *transformed* space (identity for linear, log for log), so\n * switching modes is a one-line change and the easing still behaves.\n * The whole point of smoothing here: when a spike arrives the range glides to\n * its new bounds instead of the chart snapping and losing the reader.\n */\nexport class PriceScale {\n constructor({ mode = 'linear', tau = 120, marginTop = 0.12, marginBottom = 0.12 } = {}) {\n this.mode = mode\n this.marginTop = marginTop\n this.marginBottom = marginBottom\n this.auto = true\n this.top = 0\n this.height = 1\n this._lo = new Smoothed(0, tau)\n this._hi = new Smoothed(1, tau)\n this._primed = false\n }\n\n _fwd(v) { return this.mode === 'log' ? Math.log(Math.max(v, 1e-9)) : v }\n _inv(v) { return this.mode === 'log' ? Math.exp(v) : v }\n\n setMode(mode) {\n if (mode === this.mode) return\n const lo = this._inv(this._lo.value)\n const hi = this._inv(this._hi.value)\n this.mode = mode\n this._lo.jump(this._fwd(lo))\n this._hi.jump(this._fwd(hi))\n }\n\n layout(top, height) {\n this.top = top\n this.height = Math.max(1, height)\n }\n\n get lo() { return this._inv(this._lo.value) }\n get hi() { return this._inv(this._hi.value) }\n\n y(price) {\n const a = this._lo.value\n const b = this._hi.value\n const t = (this._fwd(price) - a) / (b - a || 1)\n return this.top + this.height * (1 - t)\n }\n\n price(y) {\n const a = this._lo.value\n const b = this._hi.value\n const t = 1 - (y - this.top) / this.height\n return this._inv(a + t * (b - a))\n }\n\n /** Fit visible bars. `extra` lets the forming candle influence the range. */\n fit(bars, from, to, extra) {\n if (!this.auto || !bars.length) return\n let min = Infinity\n let max = -Infinity\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (!b) continue\n if (b.low < min) min = b.low\n if (b.high > max) max = b.high\n }\n if (extra) {\n if (extra.low < min) min = extra.low\n if (extra.high > max) max = extra.high\n }\n if (!isFinite(min) || !isFinite(max)) return\n\n let a = this._fwd(min)\n let b = this._fwd(max)\n let pad = (b - a) * this.marginTop\n if (!(pad > 0)) pad = Math.abs(b) * 0.01 || 1\n a -= pad\n b += (b - a) * 0 + pad\n\n this._lo.set(a)\n this._hi.set(b)\n if (!this._primed) {\n this._lo.jump(a)\n this._hi.jump(b)\n this._primed = true\n }\n }\n\n /** Manual axis-drag scaling around the vertical centre. */\n scaleBy(factor) {\n this.auto = false\n const a = this._lo.target\n const b = this._hi.target\n const mid = (a + b) / 2\n const half = ((b - a) / 2) * clamp(factor, 0.2, 5)\n this._lo.set(mid - half)\n this._hi.set(mid + half)\n }\n\n resetAuto() {\n this.auto = true\n }\n\n tick(dt) {\n const a = this._lo.tick(dt)\n const b = this._hi.tick(dt)\n return a || b\n }\n}\n","export const defaultTheme = {\n background: '#0b0e14',\n grid: 'rgba(255,255,255,0.045)',\n axisLine: 'rgba(255,255,255,0.10)',\n text: '#8b93a7',\n textStrong: '#e6e9ef',\n up: '#26a69a',\n down: '#ef5350',\n upFill: '#26a69a',\n downFill: '#ef5350',\n wickUp: '#26a69a',\n wickDown: '#ef5350',\n volumeUp: 'rgba(38,166,154,0.30)',\n volumeDown: 'rgba(239,83,80,0.30)',\n crosshair: 'rgba(255,255,255,0.32)',\n labelBg: '#2a3040',\n labelText: '#e6e9ef',\n tagText: '#06080d',\n font: '11px ui-sans-serif, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n priceAxisWidth: 68,\n timeAxisHeight: 26,\n}\n\nexport const lightTheme = {\n ...defaultTheme,\n background: '#ffffff',\n grid: 'rgba(0,0,0,0.06)',\n axisLine: 'rgba(0,0,0,0.14)',\n text: '#6b7280',\n textStrong: '#111827',\n labelBg: '#374151',\n volumeUp: 'rgba(38,166,154,0.25)',\n volumeDown: 'rgba(239,83,80,0.25)',\n crosshair: 'rgba(0,0,0,0.35)',\n tagText: '#ffffff',\n}\n","import { Smoothed, Tween } from './Tween.js'\n\n/**\n * LiveCandle — makes the forming (rightmost) candle *flow* instead of snapping.\n *\n * A raw feed tick replaces close/high/low instantly, which reads as a jitter.\n * Here every component eases toward the incoming value, and a brand new candle\n * plays a short grow-from-centre animation as it scrolls in.\n */\nexport class LiveCandle {\n constructor(tau = 55) {\n this.enabled = true\n this.o = new Smoothed(0, tau)\n this.h = new Smoothed(0, tau)\n this.l = new Smoothed(0, tau)\n this.c = new Smoothed(0, tau)\n this.vol = new Smoothed(0, tau * 2)\n this.spawn = new Tween(240)\n this._has = false\n this._time = null\n }\n\n setTarget(bar) {\n if (!bar) {\n this._has = false\n return\n }\n if (!this._has || bar.time !== this._time) {\n // New candle: start collapsed at its open, then animate outward.\n this.o.jump(bar.open)\n this.h.jump(bar.open)\n this.l.jump(bar.open)\n this.c.jump(bar.open)\n this.vol.jump(0)\n this.spawn.restart()\n this._time = bar.time\n this._has = true\n }\n this.o.set(bar.open)\n this.h.set(bar.high)\n this.l.set(bar.low)\n this.c.set(bar.close)\n this.vol.set(bar.volume || 0)\n }\n\n reset() {\n this._has = false\n this._time = null\n }\n\n /** @returns {boolean} true while animating */\n tick(dt) {\n if (!this._has) return false\n let moving = false\n if (this.o.tick(dt)) moving = true\n if (this.h.tick(dt)) moving = true\n if (this.l.tick(dt)) moving = true\n if (this.c.tick(dt)) moving = true\n if (this.vol.tick(dt)) moving = true\n if (this.spawn.tick(dt)) moving = true\n return moving\n }\n\n /** Interpolated view of `bar`, or `bar` itself when disabled. */\n read(bar) {\n if (!this._has || !this.enabled || bar.time !== this._time) return bar\n const o = this.o.value\n const c = this.c.value\n return {\n time: bar.time,\n open: o,\n close: c,\n // keep the wick consistent while values chase each other\n high: Math.max(this.h.value, o, c),\n low: Math.min(this.l.value, o, c),\n volume: this.vol.value,\n _spawn: this.spawn.progress,\n }\n }\n}\n","/**\n * Inertia — momentum panning with friction decay.\n * sample() while dragging, release() on pointer up, then tick() each frame\n * until it returns 0.\n */\nexport class Inertia {\n constructor({ friction = 0.92, min = 0.015 } = {}) {\n this.friction = friction\n this.min = min\n this.v = 0 // px per ms\n this.active = false\n }\n\n sample(dx, dt) {\n if (dt <= 0) return\n const instant = dx / dt\n // low-pass so one jittery frame doesn't define the throw\n this.v = this.v * 0.6 + instant * 0.4\n this.active = false\n }\n\n release() {\n if (Math.abs(this.v) > this.min) this.active = true\n }\n\n stop() {\n this.v = 0\n this.active = false\n }\n\n /** @returns {number} px to pan this frame (0 when idle) */\n tick(dt) {\n if (!this.active) return 0\n const dx = this.v * dt\n this.v *= Math.pow(this.friction, dt / 16.6667)\n if (Math.abs(this.v) < this.min) this.stop()\n return dx\n }\n}\n","/**\n * Replay — bar-by-bar playback over a fixed dataset.\n *\n * The chart is never put into a special \"replay mode\". This controller holds\n * the full dataset aside and hands the chart only the REVEALED PREFIX, so the\n * scales, annotations, crosshair and range events all behave exactly as they\n * do on live data that happens to end at the cursor. Nothing downstream needs\n * to know replay exists.\n *\n * Motion reuses the engine that is already there:\n *\n * - revealing the NEXT bar goes through `Chart.append()` — the same path a\n * feed tick takes — so the candle grows in and the time axis glides;\n * - scrubbing swaps the prefix and jumps, because easing a drag reads as lag\n * (the same rule the pan gesture follows).\n */\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/** Playback rate bounds, as a multiple of one bar per `baseInterval`. */\nexport const MIN_SPEED = 0.25\nexport const MAX_SPEED = 500\n\n/**\n * Ceiling on bars revealed in one frame. At 500× that is ~8 bars/frame, so\n * this only ever bites after a tab has been backgrounded and dt is huge.\n */\nconst MAX_STEPS_PER_FRAME = 240\n\nexport class Replay {\n constructor(chart, options = {}) {\n const src = Array.isArray(options.bars) ? options.bars : []\n\n this.chart = chart\n /** The full dataset. Never mutated. */\n this.source = src.slice()\n /** Real ms one bar takes at speed 1. Default: one bar per second. */\n this.baseInterval = Math.max(16, +options.baseInterval || 1000)\n this.speed = clamp(+options.speed || 1, MIN_SPEED, MAX_SPEED)\n /** Restart from the beginning instead of stopping at the end. */\n this.looping = options.loop === true\n /** Re-anchor the right edge on the cursor when scrubbing. */\n this.follow = options.follow !== false\n this.playing = false\n\n this._acc = 0\n this._markerKey = ''\n this._markerView = null\n\n // The scales infer the timeframe from the first PAIR of bars, so two bars\n // is the floor — the cursor never goes below index 1.\n this.minIndex = Math.min(1, this.lastIndex)\n\n const from = +options.from\n this.index = clamp(\n Number.isFinite(from) ? Math.round(from) : Math.floor(this.lastIndex / 2),\n this.minIndex,\n this.lastIndex,\n )\n\n this._apply('seek')\n }\n\n // ----------------------------------------------------------------- state --\n get length() { return this.source.length }\n get lastIndex() { return Math.max(0, this.source.length - 1) }\n get atEnd() { return this.index >= this.lastIndex }\n get bar() { return this.source[this.index] || null }\n get time() { return this.bar ? this.bar.time : null }\n\n /** 0 at the first playable bar, 1 at the last. */\n get progress() {\n const span = this.lastIndex - this.minIndex\n return span > 0 ? (this.index - this.minIndex) / span : 1\n }\n\n /** Real ms between bars at the current speed. */\n get interval() { return this.baseInterval / this.speed }\n\n /** Snapshot handed to `subscribe('replay', fn)`. */\n state() {\n return {\n active: true,\n playing: this.playing,\n index: this.index,\n length: this.length,\n progress: this.progress,\n speed: this.speed,\n time: this.time,\n bar: this.bar,\n atEnd: this.atEnd,\n }\n }\n\n // ------------------------------------------------------------- transport --\n play() {\n if (this.playing || this.length < 2) return this\n // Pressing play at the end restarts, rather than doing nothing.\n if (this.atEnd) {\n this.index = this.minIndex\n this._apply('seek')\n }\n this.playing = true\n this._acc = 0\n this._changed()\n return this\n }\n\n pause() {\n if (!this.playing) return this\n this.playing = false\n this._acc = 0\n this._changed()\n return this\n }\n\n toggle() { return this.playing ? this.pause() : this.play() }\n\n /** Multiplier on `baseInterval`. Clamped to 0.25×–500×. */\n setSpeed(speed) {\n const s = clamp(+speed || 1, MIN_SPEED, MAX_SPEED)\n if (s === this.speed) return this\n this.speed = s\n this._acc = 0 // no burst of bars when the rate jumps\n this._changed()\n return this\n }\n\n setLoop(on) {\n this.looping = !!on\n this._changed()\n return this\n }\n\n /** Move the cursor. Out-of-range values clamp; playback keeps running. */\n seek(index) {\n const next = clamp(Math.round(+index), this.minIndex, this.lastIndex)\n if (next === this.index) return this\n this.index = next\n this._acc = 0\n this._apply('seek')\n this._changed()\n return this\n }\n\n step(n = 1) { return this.seek(this.index + (n || 0)) }\n toStart() { return this.seek(this.minIndex) }\n toEnd() { return this.seek(this.lastIndex) }\n\n /**\n * Advance with wall-clock time. Called once per frame by the chart; returns\n * true while playback is in flight, which is what keeps the loop awake.\n */\n tick(dt) {\n if (!this.playing || this.length < 2) return false\n\n this._acc += dt * this.speed\n const steps = Math.floor(this._acc / this.baseInterval)\n if (steps <= 0) return true // playing, just not due for the next bar yet\n this._acc -= steps * this.baseInterval\n\n const last = this.lastIndex\n let next = this.index + Math.min(steps, MAX_STEPS_PER_FRAME)\n\n if (next > last) {\n if (this.looping) {\n this.index = this.minIndex\n this._apply('seek')\n this._changed()\n return true\n }\n next = last\n }\n\n const single = next === this.index + 1\n this.index = next\n this._apply(single ? 'step' : 'seek')\n if (this.atEnd && !this.looping) {\n this.playing = false\n this._acc = 0\n }\n this._changed()\n return this.playing\n }\n\n // --------------------------------------------------------------- markers --\n /**\n * Markers after the cursor are future information: hidden, not clamped.\n * Without this they would all pin to the newest revealed bar, because\n * time→index resolution snaps to the NEAREST bar.\n *\n * Cached on the cursor, so a paused chart allocates nothing per frame.\n */\n markerFilter(markers) {\n const t = this.time\n if (t == null) return markers\n const key = this.index + ':' + markers.length\n if (key !== this._markerKey || !this._markerView) {\n const cut = t + (this.chart.ts.timeframeMs || 0) / 2\n this._markerView = markers.filter((m) => m.time <= cut)\n this._markerKey = key\n }\n return this._markerView\n }\n\n /** Drop the cached slice — the marker set itself changed. */\n invalidateMarkers() {\n this._markerKey = ''\n this._markerView = null\n }\n\n // ---------------------------------------------------------------- private --\n /**\n * Push the revealed prefix into the chart.\n *\n * 'step' (exactly one bar forward) takes the live path so the new candle\n * animates; anything else swaps the prefix and re-anchors without easing.\n */\n _apply(mode) {\n const chart = this.chart\n if (mode === 'step' && chart.bars.length === this.index) {\n chart.append(this.source[this.index])\n return\n }\n chart._swapBars(this.source.slice(0, this.index + 1))\n if (this.follow) chart.ts.jumpToRealtime()\n }\n\n /** Any state change needs a frame: that frame is what emits 'replay'. */\n _changed() {\n this.chart.loop.invalidate('main')\n }\n}\n","/** \"Nice\" step size (1/2/5 x 10^n) covering `span` in about `count` steps. */\nexport function niceStep(span, count) {\n const raw = span / Math.max(1, count)\n if (!(raw > 0) || !isFinite(raw)) return 1\n const mag = Math.pow(10, Math.floor(Math.log10(raw)))\n const n = raw / mag\n const s = n < 1.5 ? 1 : n < 3 ? 2 : n < 7 ? 5 : 10\n return s * mag\n}\n\nexport function priceTicks(lo, hi, count) {\n const step = niceStep(hi - lo, count)\n const ticks = []\n const start = Math.ceil(lo / step) * step\n for (let v = start; v <= hi + step * 1e-9; v += step) ticks.push(v)\n return { ticks, step }\n}\n\nexport function decimalsFor(step) {\n if (!isFinite(step) || step <= 0) return 2\n if (step >= 100) return 0\n if (step >= 1) return 2\n return Math.min(8, Math.ceil(-Math.log10(step)) + 1)\n}\n\n/** Bar-index step that keeps time labels at least `minPx` apart. */\nexport function niceBarStep(minBars) {\n const opts = [1, 2, 5, 10, 15, 20, 30, 60, 120, 240, 480, 960, 1920, 3840, 7680]\n for (const o of opts) if (o >= minBars) return o\n return Math.ceil(minBars / 1000) * 1000\n}\n\nconst p2 = (n) => String(n).padStart(2, '0')\n\nexport function fmtAxisTime(ms, tfMs) {\n const d = new Date(ms)\n if (tfMs >= 864e5) return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n if (d.getHours() === 0 && d.getMinutes() === 0) {\n return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n }\n return `${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtDateTime(ms) {\n const d = new Date(ms)\n return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())} ${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtVolume(v) {\n if (!isFinite(v)) return '—'\n if (v >= 1e9) return (v / 1e9).toFixed(2) + 'B'\n if (v >= 1e6) return (v / 1e6).toFixed(2) + 'M'\n if (v >= 1e3) return (v / 1e3).toFixed(1) + 'K'\n return String(Math.round(v))\n}\n","import { priceTicks, decimalsFor, niceBarStep, fmtAxisTime } from '../core/formatters.js'\n\n/** Background, grid, and both axes. Repaints only when the view changes. */\nexport function drawGrid(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height } = s\n\n ctx.clearRect(0, 0, width, height)\n ctx.fillStyle = theme.background\n ctx.fillRect(0, 0, width, height)\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // ---- price grid + labels -------------------------------------------------\n const rows = Math.max(2, Math.floor(plot.h / 58))\n const { ticks, step } = priceTicks(ps.lo, ps.hi, rows)\n const dec = decimalsFor(step)\n\n ctx.strokeStyle = theme.grid\n ctx.lineWidth = 1\n ctx.beginPath()\n for (const v of ticks) {\n const y = Math.round(ps.y(v)) + 0.5\n if (y < plot.y || y > plot.y + plot.h) continue\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'left'\n for (const v of ticks) {\n const y = Math.round(ps.y(v))\n if (y < plot.y + 6 || y > plot.y + plot.h - 6) continue\n ctx.fillText(v.toFixed(dec), plot.w + 8, y)\n }\n\n // ---- time grid + labels --------------------------------------------------\n if (bars.length) {\n const minBars = Math.ceil(74 / Math.max(0.0001, ts.spacing))\n const stepBars = niceBarStep(minBars)\n const { from, to } = ts.visibleRange()\n const first = Math.ceil(from / stepBars) * stepBars\n\n ctx.strokeStyle = theme.grid\n ctx.beginPath()\n for (let i = first; i <= to; i += stepBars) {\n const x = Math.round(ts.x(i)) + 0.5\n if (x < 0 || x > plot.w) continue\n ctx.moveTo(x, 0)\n ctx.lineTo(x, plot.h)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'center'\n const ty = plot.h + theme.timeAxisHeight / 2\n for (let i = first; i <= to; i += stepBars) {\n const bar = bars[i]\n if (!bar) continue\n const x = Math.round(ts.x(i))\n if (x < 28 || x > plot.w - 28) continue\n ctx.fillText(fmtAxisTime(bar.time, ts.timeframeMs), x, ty)\n }\n }\n\n // ---- axis separators -----------------------------------------------------\n ctx.strokeStyle = theme.axisLine\n ctx.beginPath()\n ctx.moveTo(plot.w + 0.5, 0)\n ctx.lineTo(plot.w + 0.5, plot.h)\n ctx.moveTo(0, plot.h + 0.5)\n ctx.lineTo(width, plot.h + 0.5)\n ctx.stroke()\n}\n","import { decimalsFor, priceTicks } from '../core/formatters.js'\n\n/**\n * Candles + volume. Everything here is culled to the visible index range —\n * 500k bars loaded still costs only the ~200 on screen.\n */\nexport function drawCandles(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, live, volumeRatio } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!bars.length) return\n\n const { from, to } = ts.visibleRange()\n const bw = ts.barWidth()\n const half = bw / 2\n const thin = bw <= 2\n\n // ---- volume strip --------------------------------------------------------\n const volH = plot.h * volumeRatio\n const volTop = plot.y + plot.h - volH\n let vmax = 0\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (b && b.volume > vmax) vmax = b.volume\n }\n if (vmax > 0) {\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n if (live && i === bars.length - 1) b = live\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n const h = (b.volume / vmax) * volH * 0.9\n ctx.fillStyle = b.close >= b.open ? theme.volumeUp : theme.volumeDown\n ctx.fillRect(Math.round(x - half), volTop + (volH - h), Math.max(1, bw), h)\n }\n }\n\n // ---- candles -------------------------------------------------------------\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n const isLast = i === bars.length - 1\n if (live && isLast) b = live\n\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n\n const up = b.close >= b.open\n const color = up ? theme.up : theme.down\n const yO = ps.y(b.open)\n const yC = ps.y(b.close)\n const yH = ps.y(b.high)\n const yL = ps.y(b.low)\n\n // grow-from-centre on a freshly opened candle\n let scale = 1\n if (live && isLast && typeof b._spawn === 'number') scale = 0.35 + 0.65 * b._spawn\n\n const cx = Math.round(x) + (bw % 2 ? 0.5 : 0)\n\n // wick\n ctx.strokeStyle = up ? theme.wickUp : theme.wickDown\n ctx.lineWidth = Math.max(1, Math.min(2, bw * 0.16))\n ctx.beginPath()\n ctx.moveTo(cx, yH)\n ctx.lineTo(cx, yL)\n ctx.stroke()\n\n if (thin) continue\n\n // body\n const top = Math.min(yO, yC)\n const bodyH = Math.max(1, Math.abs(yC - yO))\n const w = Math.max(1, bw * scale)\n ctx.fillStyle = color\n ctx.fillRect(Math.round(x - w / 2), Math.round(top), Math.round(w), Math.round(bodyH))\n }\n\n // ---- last price line -----------------------------------------------------\n const lastBar = live || bars[bars.length - 1]\n if (lastBar) {\n const y = Math.round(ps.y(lastBar.close)) + 0.5\n if (y > plot.y && y < plot.y + plot.h) {\n const up = lastBar.close >= lastBar.open\n ctx.save()\n ctx.setLineDash([3, 3])\n ctx.strokeStyle = up ? theme.up : theme.down\n ctx.lineWidth = 1\n ctx.globalAlpha = 0.7\n ctx.beginPath()\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n ctx.stroke()\n ctx.restore()\n\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const label = lastBar.close.toFixed(decimalsFor(step))\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n ctx.textAlign = 'left'\n const tw = ctx.measureText(label).width\n ctx.fillStyle = up ? theme.up : theme.down\n ctx.fillRect(plot.w + 1, y - 9, tw + 14, 18)\n ctx.fillStyle = theme.tagText\n ctx.fillText(label, plot.w + 8, y)\n }\n }\n}\n","import { decimalsFor, priceTicks, fmtDateTime } from '../core/formatters.js'\n\n/**\n * Crosshair lives alone on the top canvas: moving the pointer repaints only\n * these few pixels, never the candles underneath.\n */\nexport function drawCrosshair(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, cursor, magnet } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!cursor || !bars.length) return\n if (cursor.x < 0 || cursor.x > plot.w || cursor.y < 0 || cursor.y > plot.h) return\n\n const i = Math.round(ts.index(cursor.x))\n const bar = bars[i]\n\n let x = cursor.x\n let y = cursor.y\n if (bar) {\n x = ts.x(i) // snap to the bar slot\n if (magnet) {\n // magnet to the nearest OHLC value\n const cands = [bar.open, bar.high, bar.low, bar.close]\n let best = null\n let bestD = Infinity\n for (const p of cands) {\n const py = ps.y(p)\n const d = Math.abs(py - cursor.y)\n if (d < bestD) { bestD = d; best = py }\n }\n if (bestD < 22) y = best\n }\n }\n\n ctx.save()\n ctx.setLineDash([4, 4])\n ctx.strokeStyle = theme.crosshair\n ctx.lineWidth = 1\n ctx.beginPath()\n ctx.moveTo(Math.round(x) + 0.5, 0)\n ctx.lineTo(Math.round(x) + 0.5, plot.h)\n ctx.moveTo(0, Math.round(y) + 0.5)\n ctx.lineTo(plot.w, Math.round(y) + 0.5)\n ctx.stroke()\n ctx.restore()\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // price tag\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const priceLabel = ps.price(y).toFixed(decimalsFor(step))\n ctx.textAlign = 'left'\n const pw = ctx.measureText(priceLabel).width\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(plot.w + 1, y - 9, pw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(priceLabel, plot.w + 8, y)\n\n // time tag\n if (bar) {\n const t = fmtDateTime(bar.time)\n ctx.textAlign = 'center'\n const tw = ctx.measureText(t).width\n const bx = Math.min(Math.max(x, tw / 2 + 6), plot.w - tw / 2 - 6)\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(bx - tw / 2 - 7, plot.h + 3, tw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(t, bx, plot.h + 12)\n }\n}\n\n","/**\n * Annotation model — normalisation, time→index resolution and collision\n * layout for markers.\n *\n * The geometry lives here rather than in the renderer so it can be reasoned\n * about (and tested) without a canvas, and out of Chart.js so the orchestrator\n * stays about orchestration.\n */\n\nexport const MARKER_SHAPES = [\n 'arrowUp',\n 'arrowDown',\n 'triangleUp',\n 'triangleDown',\n 'circle',\n 'square',\n 'diamond',\n 'flag',\n 'label',\n]\n\nconst SHAPE_SET = new Set(MARKER_SHAPES)\n\n/** Buys sit under the bar, sells over it — the convention traders expect. */\nconst DEFAULT_POSITION = {\n arrowUp: 'belowBar',\n triangleUp: 'belowBar',\n arrowDown: 'aboveBar',\n triangleDown: 'aboveBar',\n}\n\nconst POSITIONS = new Set(['aboveBar', 'belowBar', 'inBar', 'atPrice'])\n\nexport function normalizeMarker(raw, i) {\n if (!raw || !isFinite(raw.time)) return null\n const shape = SHAPE_SET.has(raw.shape) ? raw.shape : 'circle'\n const position = POSITIONS.has(raw.position)\n ? raw.position\n : DEFAULT_POSITION[shape] || 'aboveBar'\n return {\n id: raw.id != null ? String(raw.id) : `mk${i}`,\n time: +raw.time,\n price: isFinite(raw.price) ? +raw.price : null,\n shape,\n position,\n color: raw.color || null,\n textColor: raw.textColor || null,\n text: raw.text != null ? String(raw.text) : '',\n size: isFinite(raw.size) && raw.size > 0 ? +raw.size : 1,\n /** Anything the consumer wants handed back on hover/click. */\n data: raw.data,\n index: -1,\n }\n}\n\nexport function normalizeMarkers(list) {\n if (!Array.isArray(list)) return []\n const out = []\n for (let i = 0; i < list.length; i++) {\n const m = normalizeMarker(list[i], i)\n if (m) out.push(m)\n }\n out.sort((a, b) => a.time - b.time)\n return out\n}\n\n/**\n * Index of the bar closest in time to `time`; -1 with no bars.\n * Binary search — markers are resolved again whenever the bar array shifts\n * (a history page prepended in front of them moves every index).\n */\nexport function nearestIndex(bars, time) {\n const n = bars.length\n if (!n) return -1\n if (time <= bars[0].time) return 0\n if (time >= bars[n - 1].time) return n - 1\n\n let lo = 0\n let hi = n - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const t = bars[mid].time\n if (t === time) return mid\n if (t < time) lo = mid + 1\n else hi = mid - 1\n }\n const a = Math.max(0, hi)\n const b = Math.min(n - 1, lo)\n return Math.abs(bars[a].time - time) <= Math.abs(bars[b].time - time) ? a : b\n}\n\n/** Attach a bar index to every marker, in place. */\nexport function resolveMarkers(markers, bars) {\n for (let i = 0; i < markers.length; i++) {\n markers[i].index = nearestIndex(bars, markers[i].time)\n }\n return markers\n}\n\n/**\n * Place visible markers in screen space.\n *\n * Handles the two things that make markers look amateurish when skipped:\n * several markers on one bar overlapping, and thousands of them piling onto\n * the same pixels when zoomed out.\n */\nexport function layoutMarkers(markers, s) {\n const { ts, ps, plot, bars, live } = s\n if (!markers.length || !bars.length) return []\n\n const { from, to } = ts.visibleRange()\n const lastIdx = bars.length - 1\n const dense = ts.barWidth() <= 3\n const stacks = new Map()\n const placed = []\n let lastDenseX = -Infinity\n\n for (const m of markers) {\n const i = m.index\n if (i < 0 || i < from - 2 || i > to + 2) continue\n\n // the forming candle is interpolated, so anchor to the animated values\n const bar = live && i === lastIdx ? live : bars[i]\n if (!bar) continue\n\n const x = ts.x(i)\n if (x < -48 || x > plot.w + 48) continue\n\n // Zoomed far out, markers collapse onto the same pixels: drawing them all\n // costs frames and reads as noise. One per 4px is plenty.\n if (dense) {\n if (x - lastDenseX < 4) continue\n lastDenseX = x\n }\n\n const r = 5 * m.size\n let y\n let dir = 0\n\n if (m.position === 'atPrice' && m.price != null) {\n y = ps.y(m.price)\n } else if (m.position === 'inBar') {\n y = ps.y((bar.high + bar.low) / 2)\n } else if (m.position === 'belowBar') {\n y = ps.y(bar.low) + r + 7\n dir = 1\n } else {\n y = ps.y(bar.high) - r - 7\n dir = -1\n }\n\n // Two trades on one bar must not draw on top of each other.\n if (dir !== 0) {\n const key = i + m.position\n const n = stacks.get(key) || 0\n stacks.set(key, n + 1)\n y += dir * n * (r * 2 + 5)\n }\n\n placed.push({ m, x, y, r, dir })\n }\n\n return placed\n}\n","import { decimalsFor, priceTicks } from '../core/formatters.js'\nimport { nearestIndex } from '../overlays/annotations.js'\n\n/**\n * Annotation renderers: zones (behind the candles), price lines and markers\n * (in front of them). Each is a pure draw call over prepared state.\n */\n\nconst DASH = { solid: [], dashed: [6, 4], dotted: [1, 3] }\nconst DOWN_SHAPES = new Set(['arrowDown', 'triangleDown'])\n\nfunction roundRect(ctx, x, y, w, h, r) {\n const rr = Math.max(0, Math.min(r, h / 2, w / 2))\n ctx.beginPath()\n ctx.moveTo(x + rr, y)\n ctx.lineTo(x + w - rr, y)\n ctx.quadraticCurveTo(x + w, y, x + w, y + rr)\n ctx.lineTo(x + w, y + h - rr)\n ctx.quadraticCurveTo(x + w, y + h, x + w - rr, y + h)\n ctx.lineTo(x + rr, y + h)\n ctx.quadraticCurveTo(x, y + h, x, y + h - rr)\n ctx.lineTo(x, y + rr)\n ctx.quadraticCurveTo(x, y, x + rr, y)\n ctx.closePath()\n}\n\n/* ------------------------------------------------------------------ zones -- */\n/** Shaded regions. Drawn on the base layer, over the grid and under candles. */\nexport function drawZones(ctx, s) {\n const { zones, theme, ts, ps, plot, bars } = s\n if (!zones || !zones.length) return\n\n ctx.save()\n ctx.font = theme.font\n ctx.textBaseline = 'top'\n ctx.textAlign = 'left'\n\n for (const z of zones) {\n let x\n let y\n let w\n let h\n\n if (isFinite(z.from) && isFinite(z.to)) {\n // price band: spans the full width\n y = ps.y(Math.max(z.from, z.to))\n h = Math.max(1, ps.y(Math.min(z.from, z.to)) - y)\n x = 0\n w = plot.w\n } else if (isFinite(z.fromTime) && isFinite(z.toTime) && bars.length) {\n // time band: spans the full height\n const a = ts.x(nearestIndex(bars, Math.min(z.fromTime, z.toTime)))\n const b = ts.x(nearestIndex(bars, Math.max(z.fromTime, z.toTime)))\n x = a\n w = Math.max(1, b - a)\n y = 0\n h = plot.h\n } else {\n continue\n }\n\n if (x > plot.w || x + w < 0 || y > plot.h || y + h < 0) continue\n\n ctx.fillStyle = z.color || 'rgba(38,166,154,0.10)'\n ctx.fillRect(x, y, w, h)\n\n if (z.border) {\n ctx.strokeStyle = z.border\n ctx.lineWidth = 1\n ctx.strokeRect(Math.round(x) + 0.5, Math.round(y) + 0.5, Math.round(w), Math.round(h))\n }\n\n if (z.label) {\n ctx.fillStyle = z.labelColor || theme.text\n ctx.fillText(z.label, Math.max(6, x + 6), Math.max(4, y + 4))\n }\n }\n\n ctx.restore()\n}\n\n/* ------------------------------------------------------------- price lines -- */\n/** Horizontal lines with an optional left title pill and right axis tag. */\nexport function drawPriceLines(ctx, s) {\n const { priceLines, theme, ps, plot } = s\n if (!priceLines || !priceLines.length) return\n\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const dec = decimalsFor(step)\n\n ctx.save()\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n for (const L of priceLines) {\n if (!L || !isFinite(L.price)) continue\n const y = Math.round(ps.y(L.price)) + 0.5\n if (y < 0 || y > plot.h) continue\n\n const color = L.color || theme.textStrong\n\n ctx.setLineDash(DASH[L.lineStyle] || DASH.dashed)\n ctx.strokeStyle = color\n ctx.lineWidth = L.lineWidth || 1\n ctx.beginPath()\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n ctx.stroke()\n ctx.setLineDash([])\n\n if (L.title) {\n ctx.textAlign = 'left'\n const tw = ctx.measureText(L.title).width\n ctx.fillStyle = color\n roundRect(ctx, 6, y - 9, tw + 12, 18, 4)\n ctx.fill()\n ctx.fillStyle = L.titleColor || theme.tagText\n ctx.fillText(L.title, 12, y)\n }\n\n if (L.axisLabel !== false) {\n const label = L.price.toFixed(dec)\n ctx.textAlign = 'left'\n const lw = ctx.measureText(label).width\n ctx.fillStyle = color\n ctx.fillRect(plot.w + 1, y - 9, lw + 14, 18)\n ctx.fillStyle = L.tagTextColor || theme.tagText\n ctx.fillText(label, plot.w + 8, y)\n }\n }\n\n ctx.restore()\n}\n\n/* ---------------------------------------------------------------- markers -- */\nfunction shapePath(ctx, shape, x, y, r) {\n ctx.beginPath()\n switch (shape) {\n case 'arrowUp':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x + r * 0.45, y)\n ctx.lineTo(x + r * 0.45, y + r)\n ctx.lineTo(x - r * 0.45, y + r)\n ctx.lineTo(x - r * 0.45, y)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n case 'arrowDown':\n ctx.moveTo(x, y + r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x + r * 0.45, y)\n ctx.lineTo(x + r * 0.45, y - r)\n ctx.lineTo(x - r * 0.45, y - r)\n ctx.lineTo(x - r * 0.45, y)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n case 'triangleUp':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y + r)\n ctx.lineTo(x - r, y + r)\n ctx.closePath()\n break\n case 'triangleDown':\n ctx.moveTo(x, y + r)\n ctx.lineTo(x + r, y - r)\n ctx.lineTo(x - r, y - r)\n ctx.closePath()\n break\n case 'square':\n ctx.rect(x - r, y - r, r * 2, r * 2)\n break\n case 'diamond':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x, y + r)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n default:\n ctx.arc(x, y, r, 0, Math.PI * 2)\n }\n}\n\nfunction drawFlag(ctx, x, y, r, color) {\n ctx.fillStyle = color\n ctx.fillRect(x - r * 0.8, y - r, Math.max(1, r * 0.3), r * 2)\n ctx.beginPath()\n ctx.moveTo(x - r * 0.5, y - r)\n ctx.lineTo(x + r, y - r * 0.55)\n ctx.lineTo(x - r * 0.5, y - r * 0.1)\n ctx.closePath()\n ctx.fill()\n}\n\n/**\n * Draws placed markers and returns their hit circles, newest first, so the\n * chart can answer \"what is under the pointer?\" without re-deriving geometry.\n */\nexport function drawMarkers(ctx, s, placed, hoverId) {\n const hits = []\n if (!placed || !placed.length) return hits\n\n const { theme } = s\n ctx.save()\n ctx.font = theme.font\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n for (const p of placed) {\n const { m, x, y, r, dir } = p\n const color = m.color || (DOWN_SHAPES.has(m.shape) ? theme.down : theme.up)\n const hovered = hoverId != null && m.id === hoverId\n\n if (m.shape === 'label') {\n const text = m.text || '•'\n const w = ctx.measureText(text).width + 14\n const h = 18 * m.size\n roundRect(ctx, x - w / 2, y - h / 2, w, h, 4)\n ctx.fillStyle = color\n ctx.fill()\n if (hovered) {\n ctx.strokeStyle = theme.textStrong\n ctx.lineWidth = 1.5\n ctx.stroke()\n }\n ctx.fillStyle = m.textColor || theme.tagText\n ctx.fillText(text, x, y + 0.5)\n hits.push({ id: m.id, marker: m, x, y, r: Math.max(w, h) / 2 })\n continue\n }\n\n if (hovered) {\n ctx.beginPath()\n ctx.arc(x, y, r + 4, 0, Math.PI * 2)\n ctx.fillStyle = 'rgba(255,255,255,0.14)'\n ctx.fill()\n }\n\n if (m.shape === 'flag') {\n drawFlag(ctx, x, y, r, color)\n } else {\n shapePath(ctx, m.shape, x, y, r)\n ctx.fillStyle = color\n ctx.fill()\n }\n\n if (m.text) {\n ctx.fillStyle = m.textColor || theme.text\n ctx.fillText(m.text, x, dir >= 0 ? y + r + 9 : y - r - 9)\n }\n\n hits.push({ id: m.id, marker: m, x, y, r: r + 3 })\n }\n\n ctx.restore()\n return hits\n}\n","import { Layers } from './Layers.js'\nimport { Loop } from './Loop.js'\nimport { TimeScale } from './TimeScale.js'\nimport { PriceScale } from './PriceScale.js'\nimport { defaultTheme } from './palette.js'\nimport { LiveCandle } from '../motion/LiveCandle.js'\nimport { Inertia } from '../motion/Inertia.js'\nimport { Replay } from '../replay/Replay.js'\nimport { drawGrid } from '../render/grid.js'\nimport { drawCandles } from '../render/candles.js'\nimport { drawCrosshair } from '../render/crosshair.js'\nimport { drawZones, drawPriceLines, drawMarkers } from '../render/annotations.js'\nimport { normalizeMarkers, resolveMarkers, layoutMarkers } from '../overlays/annotations.js'\n\n/** The 'replay' payload when nothing is being replayed. */\nconst inactiveReplay = () => ({\n active: false,\n playing: false,\n index: -1,\n length: 0,\n progress: 0,\n speed: 1,\n time: null,\n bar: null,\n atEnd: false,\n})\n\n/**\n * Chart — the orchestrator. Owns the bar store, the scales, the input\n * handling and the frame composition. Framework-free by design: this file\n * touches nothing but DOM and Canvas, which is what lets the same core ship\n * as a React component, a Web Component, or a plain script tag.\n */\nexport class Chart {\n constructor(container, options = {}) {\n if (!container) throw new Error('Chart: container element is required')\n\n this.container = container\n this.theme = { ...defaultTheme, ...(options.theme || {}) }\n this.options = {\n volumeRatio: 0.18,\n magnet: true,\n animate: true,\n ...options,\n }\n\n this.bars = []\n this.feed = null\n this._unsub = null\n this._loadingHistory = false\n this._exhausted = false\n this._replay = null\n // Every async feed read is stamped with the generation current when it\n // STARTED. setFeed/detachFeed/destroy bump the counter, so a slow earlier\n // request that resolves second recognises itself as stale and drops its\n // result instead of writing over the newer feed's bars.\n this._feedGen = 0\n this._destroyed = false\n this._listeners = {\n crosshair: new Set(),\n visibleRange: new Set(),\n markerClick: new Set(),\n markerHover: new Set(),\n replay: new Set(),\n error: new Set(),\n }\n\n // ---- annotations --------------------------------------------------\n // Markers carry a `time`; the renderer needs an index. Resolving is a\n // binary search per marker, so it is redone only when the bar array\n // actually shifts (a prepended history page moves every index).\n this._markers = normalizeMarkers(options.markers)\n this.priceLines = Array.isArray(options.priceLines) ? options.priceLines.slice() : []\n this.zones = Array.isArray(options.zones) ? options.zones.slice() : []\n this._markerHits = []\n this._hoverMarkerId = null\n this._resolveKey = ''\n\n this.layers = new Layers(container, ['base', 'main', 'overlay'])\n this.ts = new TimeScale(options.timeScale)\n this.ps = new PriceScale(options.priceScale)\n this.live = new LiveCandle()\n this.live.enabled = this.options.animate !== false\n this.inertia = new Inertia()\n\n this.cursor = null\n this.plot = { x: 0, y: 0, w: 1, h: 1 }\n\n this.loop = new Loop((dirty, dt) => this._frame(dirty, dt))\n this.layers.onResize = () => {\n this._layout()\n this.loop.invalidate('all')\n }\n\n this._layout()\n this._bindEvents()\n this.loop.start()\n }\n\n // ---------------------------------------------------------------- layout --\n _layout() {\n const { width, height } = this.layers\n const w = Math.max(1, width - this.theme.priceAxisWidth)\n const h = Math.max(1, height - this.theme.timeAxisHeight)\n this.plot = { x: 0, y: 0, w, h }\n this.ts.resize(w)\n this.ps.layout(0, h)\n }\n\n // ------------------------------------------------------------------ data --\n setData(bars) {\n // New data means the dataset being replayed no longer exists.\n if (this._replay) this._replay = null\n this.bars = Array.isArray(bars) ? bars.slice() : []\n this._exhausted = false\n if (this.bars.length > 1) {\n this.ts.timeframeMs = this.bars[1].time - this.bars[0].time\n }\n this.ts.setBarCount(this.bars.length)\n this.ts.snapToRealtime()\n this.live.reset()\n this.ps._primed = false\n this.loop.invalidate('all')\n }\n\n /**\n * Replace the bar array WITHOUT re-anchoring the view — the deliberate\n * difference from setData(), which snaps to the right edge and re-primes\n * the price scale. Replay swaps its revealed prefix through here on every\n * scrub, so a snap would fight the user's zoom and the price scale would\n * pop instead of easing between windows.\n */\n _swapBars(bars) {\n this.bars = Array.isArray(bars) ? bars : []\n if (this.bars.length > 1) {\n this.ts.timeframeMs = this.bars[1].time - this.bars[0].time\n }\n this.ts.setBarCount(this.bars.length)\n this.live.reset()\n this._resolveKey = '' // the prefix changed length: every index re-resolves\n this.loop.invalidate('all')\n }\n\n /** Merge a tick into the forming candle (animated). */\n update(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && this.bars[n - 1].time === bar.time) {\n this.bars[n - 1] = bar\n } else {\n this.append(bar)\n return\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n /** Open a new candle; the previous one is now closed. */\n append(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && bar.time <= this.bars[n - 1].time) {\n this.bars[n - 1] = bar\n } else {\n this.bars.push(bar)\n this.ts.setBarCount(this.bars.length)\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n async setFeed(feed) {\n this.detachFeed()\n this.feed = feed\n if (!feed) return\n const gen = ++this._feedGen\n this.ts.timeframeMs = feed.timeframe || this.ts.timeframeMs\n let bars\n try {\n bars = await feed.getBars({\n symbol: feed.symbol,\n timeframe: feed.timeframe,\n to: null,\n limit: this.options.initialBars || 1500,\n })\n } catch (err) {\n if (gen !== this._feedGen || this._destroyed) return\n this._emitError(err, 'setFeed')\n return\n }\n // Another setFeed(), a detachFeed() or a destroy() landed while we were\n // awaiting: this result belongs to a chart state that no longer exists.\n if (gen !== this._feedGen || this._destroyed) return\n this.setData(bars)\n // Read back the SANITISED array rather than the raw return value:\n // setData() has already coerced a non-array to [], and prime() is\n // documented as taking Bar | undefined.\n if (typeof feed.prime === 'function') feed.prime(this.bars[this.bars.length - 1])\n this._unsub = feed.subscribe((msg) => {\n if (!msg || !msg.bar) return\n // A subscription that outlived its generation must never write bars —\n // two feeds on one timeframe otherwise target the same forming candle.\n if (gen !== this._feedGen || this._destroyed) return\n // During replay the feed is the FUTURE arriving: let it run, ignore it.\n if (this._replay) return\n if (msg.type === 'append') this.append(msg.bar)\n else this.update(msg.bar)\n })\n }\n\n detachFeed() {\n // Bumping the generation is what cancels in-flight work: neither\n // getBars() promise can be aborted, so instead they resolve into no-ops.\n this._feedGen++\n this._loadingHistory = false\n if (this._unsub) this._unsub()\n this._unsub = null\n this.feed = null\n }\n\n async _maybeLoadHistory() {\n // Replay owns the bar array; a page prepended underneath it would\n // renumber the cursor mid-playback.\n if (this._replay) return\n if (this._loadingHistory || this._exhausted || !this.feed) return\n const { from } = this.ts.visibleRange()\n if (from > 80 || !this.bars.length) return\n\n this._loadingHistory = true\n // Bind this page to the feed that asked for it. Everything after the await\n // must prove it still belongs to that feed before touching shared state —\n // including _exhausted, which a stale page could otherwise latch on a\n // fresh symbol that still has years of history.\n const gen = this._feedGen\n const feed = this.feed\n try {\n const older = await feed.getBars({\n symbol: feed.symbol,\n timeframe: feed.timeframe,\n to: this.bars[0].time,\n limit: 1000,\n })\n if (gen !== this._feedGen || this._destroyed) return\n if (!this.bars.length) return\n if (!older || !older.length) {\n this._exhausted = true\n return\n }\n // Re-read the boundary AFTER the await. Filtering against the stale\n // pre-await value can splice a page into the middle of the array and\n // break the ascending-by-time invariant that nearestIndex()'s binary\n // search and the candle draw order both depend on.\n const boundary = this.bars[0].time\n const added = older.filter((b) => b.time < boundary)\n if (!added.length) {\n this._exhausted = true\n return\n }\n this.bars = added.concat(this.bars)\n // Keep the view pinned to the same bars: every index shifted right.\n // Smoothed.jump() writes BOTH value and target, so it alone pins the\n // view. The set() that used to follow re-read the already-shifted\n // target and added the page size a SECOND time, easing the viewport\n // past the newest bar — which pushed `from` above the 80-bar threshold\n // and disabled lazy paging permanently.\n this.ts.barCount = this.bars.length\n this.ts._right.jump(this.ts._right.value + added.length)\n this.loop.invalidate('all')\n } catch (err) {\n if (gen !== this._feedGen || this._destroyed) return\n this._exhausted = true\n this._emitError(err, 'loadHistory')\n } finally {\n // Only the generation that owns the latch may release it, or a stale\n // request finishing late would unlock a load already in progress.\n if (gen === this._feedGen) this._loadingHistory = false\n }\n }\n\n /**\n * Feed failures are delivered as an 'error' event so an adapter can react.\n * With no subscriber they still reach the console rather than vanishing.\n */\n _emitError(err, phase) {\n const set = this._listeners.error\n if (!set.size) {\n console.error(`[Emberwick] ${phase} failed`, err)\n return\n }\n for (const fn of set) fn(err)\n }\n\n // ---------------------------------------------------------------- events --\n _bindEvents() {\n const el = this.container\n el.style.touchAction = 'none'\n el.style.cursor = 'crosshair'\n\n let dragging = false\n let mode = null\n let lastX = 0\n let lastY = 0\n let lastT = 0\n let moved = false\n const pointers = new Map()\n let pinchDist = 0\n\n const localPos = (e) => {\n const r = el.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n }\n\n this._onDown = (e) => {\n pointers.set(e.pointerId, localPos(e))\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n pinchDist = Math.hypot(a.x - b.x, a.y - b.y)\n dragging = false\n return\n }\n const p = localPos(e)\n dragging = true\n moved = false\n mode = p.x > this.plot.w ? 'price' : p.y > this.plot.h ? 'time' : 'pan'\n lastX = p.x\n lastY = p.y\n lastT = performance.now()\n this.inertia.stop()\n el.setPointerCapture(e.pointerId)\n }\n\n this._onMove = (e) => {\n const p = localPos(e)\n if (pointers.has(e.pointerId)) pointers.set(e.pointerId, p)\n\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n const d = Math.hypot(a.x - b.x, a.y - b.y)\n if (pinchDist > 0 && d > 0) {\n const mid = (a.x + b.x) / 2\n this.ts.zoomAt(mid, d / pinchDist)\n this.loop.invalidate('all')\n }\n pinchDist = d\n return\n }\n\n this.cursor = p\n this._emitCrosshair(p)\n this.loop.invalidate('overlay')\n\n if (!dragging) return\n const now = performance.now()\n const dt = now - lastT\n const dx = p.x - lastX\n const dy = p.y - lastY\n if (Math.abs(dx) > 1 || Math.abs(dy) > 1) moved = true\n\n if (mode === 'pan') {\n this.ts.panBy(dx)\n this.inertia.sample(dx, dt)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n } else if (mode === 'price') {\n this.ps.scaleBy(1 + dy / 220)\n this.loop.invalidate('all')\n } else if (mode === 'time') {\n this.ts.zoomAt(this.plot.w, 1 - dx / 260)\n this.loop.invalidate('all')\n }\n\n lastX = p.x\n lastY = p.y\n lastT = now\n }\n\n this._onUp = (e) => {\n pointers.delete(e.pointerId)\n if (pointers.size < 2) pinchDist = 0\n if (dragging && mode === 'pan' && moved) {\n this.inertia.release()\n this.loop.invalidate('all')\n }\n dragging = false\n mode = null\n try { el.releasePointerCapture(e.pointerId) } catch (_) {}\n }\n\n this._onLeave = () => {\n this.cursor = null\n this._emitCrosshair(null)\n this.loop.invalidate('overlay')\n }\n\n this._onWheel = (e) => {\n e.preventDefault()\n const r = el.getBoundingClientRect()\n const x = e.clientX - r.left\n const factor = Math.pow(0.999, e.deltaY)\n this.ts.zoomAt(x, factor)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n }\n\n this._onDbl = () => {\n this.ts.reset()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n this._onKey = (e) => {\n const step = e.shiftKey ? 120 : 40\n if (e.key === 'ArrowLeft') { this.ts.panBy(step); this.loop.invalidate('all'); this._maybeLoadHistory() }\n else if (e.key === 'ArrowRight') { this.ts.panBy(-step); this.loop.invalidate('all') }\n else if (e.key === '+' || e.key === '=') { this.ts.zoomAt(this.plot.w / 2, 1.2); this.loop.invalidate('all') }\n else if (e.key === '-' || e.key === '_') { this.ts.zoomAt(this.plot.w / 2, 0.8); this.loop.invalidate('all') }\n else return\n e.preventDefault()\n }\n\n this._onClick = (e) => {\n // `moved` is still set from the gesture that just ended — a pan that\n // happens to finish over a marker must not read as a click on it.\n if (moved) return\n if (!this._listeners.markerClick.size) return\n const p = localPos(e)\n const hit = this.markerAt(p.x, p.y)\n if (hit) for (const fn of this._listeners.markerClick) fn(hit)\n }\n\n el.addEventListener('click', this._onClick)\n el.addEventListener('pointerdown', this._onDown)\n el.addEventListener('pointermove', this._onMove)\n el.addEventListener('pointerup', this._onUp)\n el.addEventListener('pointercancel', this._onUp)\n el.addEventListener('pointerleave', this._onLeave)\n el.addEventListener('wheel', this._onWheel, { passive: false })\n el.addEventListener('dblclick', this._onDbl)\n el.addEventListener('keydown', this._onKey)\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '0')\n }\n\n _emitCrosshair(p) {\n if (this._listeners.crosshair.size) {\n let payload = null\n if (p && this.bars.length && p.x <= this.plot.w && p.y <= this.plot.h) {\n const i = Math.round(this.ts.index(p.x))\n const bar = this.bars[i]\n if (bar) payload = { index: i, bar, price: this.ps.price(p.y) }\n }\n for (const fn of this._listeners.crosshair) fn(payload)\n }\n this._updateHover(p)\n }\n\n /**\n * Topmost marker whose hit circle contains the point, else null.\n * Hit circles come from the last render, so this costs nothing but a loop.\n */\n markerAt(x, y) {\n const hits = this._markerHits\n for (let i = hits.length - 1; i >= 0; i--) {\n const h = hits[i]\n const dx = x - h.x\n const dy = y - h.y\n if (dx * dx + dy * dy <= h.r * h.r) return h.marker\n }\n return null\n }\n\n _updateHover(p) {\n const hit = p ? this.markerAt(p.x, p.y) : null\n const id = hit ? hit.id : null\n if (id === this._hoverMarkerId) return\n this._hoverMarkerId = id\n this.container.style.cursor = hit ? 'pointer' : 'crosshair'\n // the hover ring is drawn with the markers, so that layer must repaint\n this.loop.invalidate('main')\n for (const fn of this._listeners.markerHover) fn(hit)\n }\n\n subscribe(event, fn) {\n const set = this._listeners[event]\n if (!set) throw new Error(`Chart: unknown event \"${event}\"`)\n set.add(fn)\n // 'visibleRange' is a state event, not a notification: a new subscriber is\n // told the CURRENT window straight away, so it never has to wait for the\n // user to pan before it knows what is on screen.\n if (event === 'visibleRange') {\n const payload = this.visibleRange()\n this._rangeKey = this._rangeIdentity(payload)\n fn(payload)\n }\n // 'replay' is a state event for the same reason: a transport UI can render\n // itself from the first call instead of waiting for the first tick.\n if (event === 'replay') {\n const payload = this.replayState()\n this._replayKey = this._replayIdentity(payload)\n fn(payload)\n }\n return () => set.delete(fn)\n }\n\n // ------------------------------------------------------------------ range --\n /**\n * The window currently on screen. Cheap enough to poll, though\n * subscribe('visibleRange', fn) is the better way to track it.\n */\n visibleRange() {\n const { from, to } = this.ts.visibleRange()\n return this._rangePayload(from, to)\n }\n\n _rangePayload(from, to) {\n const n = this.bars.length\n return {\n from,\n to,\n fromTime: n ? this.bars[from].time : null,\n toTime: n ? this.bars[to].time : null,\n barCount: n,\n spacing: this.ts.spacing,\n settled: this.ts.settled,\n }\n }\n\n _rangeIdentity(p) {\n return `${p.from}:${p.to}:${p.fromTime}:${p.toTime}:${p.settled ? 1 : 0}`\n }\n\n /**\n * Fires only when the window actually changed, so a consumer can hang a\n * fetch off it without debouncing. Two deliberate choices:\n *\n * - `spacing` is NOT part of the identity. It is a float that moves on every\n * frame of an eased zoom, so keying on it would make this a 60/sec\n * firehose. It is still reported, for level-of-detail decisions.\n * - `settled` IS part of the identity, so the final event of a gesture\n * always arrives with settled:true. Without it, code that defers expensive\n * work until the view stops moving would wait forever.\n */\n _emitVisibleRange(from, to) {\n const set = this._listeners.visibleRange\n if (!set.size) return\n const payload = this._rangePayload(from, to)\n const key = this._rangeIdentity(payload)\n if (key === this._rangeKey) return // undefined on the first frame, so it emits\n this._rangeKey = key\n for (const fn of set) fn(payload)\n }\n\n // ----------------------------------------------------------------- replay --\n /**\n * Start bar-by-bar playback over a fixed dataset.\n *\n * With no `bars`, the chart's CURRENT data becomes the dataset — the usual\n * case: load history, then replay it. The chart is not switched into a\n * special mode; it is simply handed the revealed prefix, so scales,\n * annotations, the crosshair and visibleRange all keep behaving normally.\n *\n * chart.startReplay({ from: 200, speed: 4 })\n * chart.replay.play()\n *\n * @param {object} [options]\n * @param {Bar[]} [options.bars] dataset (defaults to current bars)\n * @param {number} [options.from] starting index (default: midpoint)\n * @param {number} [options.speed] rate multiplier, 0.25–500\n * @param {number} [options.baseInterval] real ms per bar at 1× (default 1000)\n * @param {boolean} [options.loop] restart at the end\n * @param {boolean} [options.follow] re-anchor the right edge on scrub\n * @returns {Replay|null} null if there are fewer than two bars to replay\n */\n startReplay(options = {}) {\n const source =\n Array.isArray(options.bars) && options.bars.length\n ? options.bars\n : this._replay\n ? this._replay.source\n : this.bars\n if (!source || source.length < 2) return null\n // Snapshot BEFORE the controller starts swapping prefixes in, otherwise\n // the dataset would be the live array it is about to shorten.\n const dataset = source.slice()\n this._replay = new Replay(this, { ...options, bars: dataset })\n return this._replay\n }\n\n /** Leave replay and reveal the whole dataset again. */\n stopReplay() {\n if (!this._replay) return\n const full = this._replay.source\n this._replay = null\n this.setData(full) // snaps back to the right edge, like any fresh data\n }\n\n /** The active controller, or null. */\n get replay() {\n return this._replay\n }\n\n /** Current playback state; `{ active: false, ... }` when not replaying. */\n replayState() {\n return this._replay ? this._replay.state() : inactiveReplay()\n }\n\n _replayIdentity(p) {\n return `${p.active ? 1 : 0}:${p.playing ? 1 : 0}:${p.index}:${p.length}:${p.speed}`\n }\n\n /**\n * Emitted from the frame, like visibleRange, so a handler can safely touch\n * the chart. Keyed on cursor + transport, not on the payload object, so a\n * paused replay emits nothing at all.\n */\n _emitReplay() {\n const set = this._listeners.replay\n if (!set.size) return\n const payload = this.replayState()\n const key = this._replayIdentity(payload)\n if (key === this._replayKey) return\n this._replayKey = key\n for (const fn of set) fn(payload)\n }\n\n // ----------------------------------------------------------- annotations --\n /** Replace every marker. Each `time` is resolved to its nearest bar. */\n setMarkers(markers) {\n this._markers = normalizeMarkers(markers)\n this._resolveKey = '' // force re-resolution on the next frame\n if (this._replay) this._replay.invalidateMarkers()\n this.loop.invalidate('main')\n }\n\n /** The current markers, normalised, each with its resolved bar index. */\n getMarkers() {\n return this._markers.slice()\n }\n\n addMarker(marker) {\n this.setMarkers(this._markers.concat([marker]))\n }\n\n removeMarker(id) {\n const key = String(id)\n this.setMarkers(this._markers.filter((m) => m.id !== key))\n }\n\n clearMarkers() {\n this.setMarkers([])\n }\n\n /** Horizontal lines — entries, stops, targets, alerts. */\n setPriceLines(lines) {\n this.priceLines = Array.isArray(lines) ? lines.slice() : []\n this.loop.invalidate('main')\n }\n\n /** Shaded regions: a price band ({from,to}) or a time band ({fromTime,toTime}). */\n setZones(zones) {\n this.zones = Array.isArray(zones) ? zones.slice() : []\n this.loop.invalidate('all')\n }\n\n // ----------------------------------------------------------------- frame --\n _frame(dirty, dt) {\n let animating = false\n\n // First: replay may append or swap bars, and everything below reads them.\n // It returns true while playing, which both keeps the loop awake and\n // forces the full redraw the newly revealed bar needs.\n if (this._replay && this._replay.tick(dt)) animating = true\n\n if (this.ts.tick(dt)) animating = true\n\n const dx = this.inertia.tick(dt)\n if (dx) {\n this.ts.panBy(dx)\n animating = true\n this._maybeLoadHistory()\n }\n\n if (this.live.tick(dt)) animating = true\n\n const { from, to } = this.ts.visibleRange()\n const lastIdx = this.bars.length - 1\n const liveBar = this.bars.length ? this.live.read(this.bars[lastIdx]) : null\n const liveVisible = liveBar && to >= lastIdx ? liveBar : null\n\n this.ps.fit(this.bars, from, to, liveVisible)\n if (this.ps.tick(dt)) animating = true\n\n const redrawAll = animating || dirty.has('all') || dirty.has('base') || dirty.has('main')\n const state = {\n theme: this.theme,\n ts: this.ts,\n ps: this.ps,\n plot: this.plot,\n bars: this.bars,\n width: this.layers.width,\n height: this.layers.height,\n live: liveVisible,\n volumeRatio: this.options.volumeRatio,\n cursor: this.cursor,\n magnet: this.options.magnet,\n priceLines: this.priceLines,\n zones: this.zones,\n }\n\n // Markers past the replay cursor are future information — hidden, not\n // clamped, because time→index resolution snaps to the NEAREST bar and\n // would otherwise pile them all onto the newest revealed candle.\n let markers = this._markers\n if (this._replay && markers.length) markers = this._replay.markerFilter(markers)\n\n // Marker indices only go stale when the bar array shifts: a prepended\n // history page renumbers every bar, an append does not.\n if (markers.length) {\n const key =\n markers.length + ':' + this.bars.length + ':' + (this.bars.length ? this.bars[0].time : 0)\n if (key !== this._resolveKey) {\n resolveMarkers(markers, this.bars)\n this._resolveKey = key\n }\n }\n\n if (redrawAll) {\n drawGrid(this.layers.ctx.base, state)\n drawZones(this.layers.ctx.base, state)\n drawCandles(this.layers.ctx.main, state)\n drawPriceLines(this.layers.ctx.main, state)\n this._markerHits = drawMarkers(\n this.layers.ctx.main,\n state,\n layoutMarkers(markers, state),\n this._hoverMarkerId,\n )\n }\n if (redrawAll || dirty.has('overlay')) {\n drawCrosshair(this.layers.ctx.overlay, state)\n }\n\n // Emitted after drawing, deliberately: a handler is free to call\n // setData() or setMarkers(), and by this point the renderers have\n // finished reading the state it would mutate.\n this._emitVisibleRange(from, to)\n this._emitReplay()\n\n return animating\n }\n\n // ------------------------------------------------------------------- api --\n get fps() { return this.loop.fps }\n\n setTheme(theme) {\n this.theme = { ...this.theme, ...theme }\n this._layout()\n this.loop.invalidate('all')\n }\n\n setPriceMode(mode) {\n this.ps.setMode(mode)\n this.loop.invalidate('all')\n }\n\n setAnimate(on) {\n this.live.enabled = !!on\n this.loop.invalidate('all')\n }\n\n setMagnet(on) {\n this.options.magnet = !!on\n this.loop.invalidate('overlay')\n }\n\n snapToRealtime() {\n this.ts.snapToRealtime()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n toImage() {\n return this.layers.composite().toDataURL('image/png')\n }\n\n destroy() {\n // Idempotent: Layers.destroy() throws on an already-emptied canvas map,\n // and both framework adapters can unmount twice (React StrictMode).\n if (this._destroyed) return\n this._destroyed = true\n const el = this.container\n el.removeEventListener('pointerdown', this._onDown)\n el.removeEventListener('pointermove', this._onMove)\n el.removeEventListener('pointerup', this._onUp)\n el.removeEventListener('pointercancel', this._onUp)\n el.removeEventListener('pointerleave', this._onLeave)\n el.removeEventListener('wheel', this._onWheel)\n el.removeEventListener('dblclick', this._onDbl)\n el.removeEventListener('keydown', this._onKey)\n el.removeEventListener('click', this._onClick)\n this.detachFeed()\n this.loop.stop()\n this.layers.destroy()\n for (const set of Object.values(this._listeners)) set.clear()\n this._replay = null\n this._markers = []\n this._markerHits = []\n this.priceLines = []\n this.zones = []\n this.bars = []\n }\n}\n\n","/**\n * DataFeed — THE seam of this library.\n *\n * The chart core never knows where bars come from. Anything that implements\n * this interface can drive it: a REST endpoint, a WebSocket, a Lambda behind\n * API Gateway, a CSV in memory, or the bundled RandomFeed.\n *\n * Bar shape (the only contract that matters):\n * { time: number (ms epoch), open, high, low, close, volume }\n * Bars MUST be ascending by time and de-duplicated by the feed.\n *\n * Implement:\n * getBars({ symbol, timeframe, to, limit }) -> Promise<Bar[]>\n * Historical bars ENDING at `to` (exclusive). Return [] when exhausted;\n * the chart stops asking for more history once it sees an empty page.\n * subscribe(handler) -> unsubscribe fn\n * handler({ type: 'update'|'append', bar }) where\n * 'update' = the forming candle changed (animates)\n * 'append' = a new candle opened (previous one is now closed)\n */\nexport class DataFeed {\n constructor({ symbol = 'DEMO', timeframe = 60000 } = {}) {\n this.symbol = symbol\n this.timeframe = timeframe\n }\n\n // eslint-disable-next-line no-unused-vars\n async getBars({ symbol, timeframe, to, limit }) {\n throw new Error('DataFeed.getBars() not implemented')\n }\n\n // eslint-disable-next-line no-unused-vars\n subscribe(handler) {\n return () => {}\n }\n\n destroy() {}\n}\n\n/** Deterministic PRNG so a given seed always renders the same chart. */\nexport function mulberry32(seed) {\n let a = seed >>> 0\n return function () {\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { DataFeed, mulberry32 } from './DataFeed.js'\n\n/**\n * RandomFeed — a plausible synthetic market. One implementation of DataFeed,\n * nothing more: swapping in a real provider is writing another class, with\n * zero changes to the chart core.\n *\n * Generates a GBM-ish random walk with volatility clustering and a volume\n * profile, then drives a live forming candle from sub-bar ticks.\n */\nexport class RandomFeed extends DataFeed {\n constructor({\n symbol = 'EMBR',\n timeframe = 60000,\n seed = 7,\n start = 100,\n volatility = 0.0022,\n drift = 0.00002,\n ticksPerSecond = 8,\n speed = 1,\n } = {}) {\n super({ symbol, timeframe })\n this.seed = seed\n this.start = start\n this.volatility = volatility\n this.drift = drift\n this.ticksPerSecond = ticksPerSecond\n this.speed = speed\n\n this._rnd = mulberry32(seed)\n this._handlers = new Set()\n this._timer = null\n this._forming = null\n this._last = start\n this._vol = volatility\n this._anchorTime = Math.floor(Date.now() / timeframe) * timeframe\n }\n\n _gauss() {\n // Box-Muller\n let u = 0\n let v = 0\n while (u === 0) u = this._rnd()\n while (v === 0) v = this._rnd()\n return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v)\n }\n\n _step(price) {\n // volatility clusters: vol mean-reverts but gets kicked by shocks\n const shock = this._gauss()\n this._vol += (this.volatility - this._vol) * 0.02 + Math.abs(shock) * this.volatility * 0.015\n this._vol = Math.min(this._vol, this.volatility * 6)\n return Math.max(0.01, price * (1 + this.drift + shock * this._vol))\n }\n\n _makeBar(time, open) {\n let c = open\n const n = 14\n let hi = open\n let lo = open\n for (let i = 0; i < n; i++) {\n c = this._step(c)\n if (c > hi) hi = c\n if (c < lo) lo = c\n }\n const range = Math.max(1e-9, hi - lo)\n const volume = Math.round(\n (300 + this._rnd() * 900) * (1 + (range / open) * 260)\n )\n return { time, open, high: hi, low: lo, close: c, volume }\n }\n\n /**\n * Historical bars ending just before `to`. Walks BACKWARDS from a synthetic\n * anchor, so paging further left keeps producing coherent history.\n */\n async getBars({ to, limit = 1500, timeframe = this.timeframe } = {}) {\n const end = to == null ? this._anchorTime : to\n const bars = []\n // generate forward from an earlier point for realistic shape, then slice\n const startTime = end - limit * timeframe\n const gen = mulberry32(this.seed ^ Math.floor(startTime / timeframe))\n const saved = this._rnd\n this._rnd = gen\n\n let price = this.start * (1 + (gen() - 0.5) * 0.04)\n for (let i = 0; i < limit; i++) {\n const t = startTime + i * timeframe\n const bar = this._makeBar(t, price)\n price = bar.close\n bars.push(bar)\n }\n this._rnd = saved\n\n if (to == null) {\n this._last = bars.length ? bars[bars.length - 1].close : this.start\n }\n return bars\n }\n\n subscribe(handler) {\n this._handlers.add(handler)\n if (!this._timer) this._start()\n return () => {\n this._handlers.delete(handler)\n if (!this._handlers.size) this.stop()\n }\n }\n\n _emit(msg) {\n for (const h of this._handlers) h(msg)\n }\n\n _start() {\n const interval = Math.max(16, 1000 / this.ticksPerSecond)\n this._timer = setInterval(() => this._tick(), interval)\n }\n\n /** Seed the live candle from wherever history ended. */\n prime(lastBar) {\n if (lastBar) {\n this._last = lastBar.close\n this._forming = { ...lastBar }\n }\n }\n\n _tick() {\n const tf = this.timeframe / this.speed\n const now = Date.now()\n const slot = Math.floor(now / tf) * tf\n\n if (!this._forming || this._forming.time !== slot) {\n const open = this._last\n this._forming = { time: slot, open, high: open, low: open, close: open, volume: 0 }\n this._emit({ type: 'append', bar: { ...this._forming } })\n return\n }\n\n const next = this._step(this._last)\n this._last = next\n const f = this._forming\n f.close = next\n if (next > f.high) f.high = next\n if (next < f.low) f.low = next\n f.volume += Math.round(20 + this._rnd() * 120)\n this._emit({ type: 'update', bar: { ...f } })\n }\n\n setSpeed(s) { this.speed = s }\n\n setTicksPerSecond(n) {\n this.ticksPerSecond = n\n if (this._timer) { this.stop(); this._start() }\n }\n\n setPaused(paused) {\n if (paused) this.stop()\n else if (!this._timer && this._handlers.size) this._start()\n }\n\n get paused() { return !this._timer }\n\n stop() {\n if (this._timer) clearInterval(this._timer)\n this._timer = null\n }\n\n destroy() {\n this.stop()\n this._handlers.clear()\n }\n}\n","/**\n * Emberwick — public API surface.\n *\n * This file is the future package entry point. Nothing below imports a\n * framework, so the same build drops into React, Vue, Svelte or a script tag.\n *\n * import { createChart, RandomFeed } from './chart/index.js'\n * const chart = createChart(el, { theme: { background: '#000' } })\n * await chart.setFeed(new RandomFeed({ timeframe: 60000 }))\n */\nexport { Chart } from './core/Chart.js'\nexport { TimeScale } from './core/TimeScale.js'\nexport { PriceScale } from './core/PriceScale.js'\nexport { defaultTheme, lightTheme } from './core/palette.js'\nexport { DataFeed, mulberry32 } from './data/DataFeed.js'\nexport { RandomFeed } from './data/RandomFeed.js'\nexport { Smoothed, Tween, easeOutCubic, easeInOutCubic } from './motion/Tween.js'\nexport { Inertia } from './motion/Inertia.js'\nexport { LiveCandle } from './motion/LiveCandle.js'\nexport { Replay, MIN_SPEED, MAX_SPEED } from './replay/Replay.js'\n\nimport { Chart } from './core/Chart.js'\n\n/** Preferred entry point. */\nexport function createChart(container, options) {\n return new Chart(container, options)\n}\n\nexport const version = '0.4.1'\n\n"],"names":["clamp","b"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/chart/core/Layers.js","../src/chart/core/Loop.js","../src/chart/motion/Tween.js","../src/chart/core/TimeScale.js","../src/chart/core/PriceScale.js","../src/chart/core/palette.js","../src/chart/motion/LiveCandle.js","../src/chart/motion/Inertia.js","../src/chart/replay/Replay.js","../src/chart/core/formatters.js","../src/chart/render/grid.js","../src/chart/render/candles.js","../src/chart/render/crosshair.js","../src/chart/overlays/annotations.js","../src/chart/render/annotations.js","../src/chart/core/Chart.js","../src/chart/data/DataFeed.js","../src/chart/data/RandomFeed.js","../src/chart/index.js"],"sourcesContent":["/**\n * Layers — stacked canvases sharing one coordinate space.\n *\n * Why: the crosshair repaints on every pointer move, the candles do not.\n * Separate canvases mean moving the cursor never touches candle pixels.\n * All contexts are pre-scaled by devicePixelRatio, so every renderer draws\n * in CSS pixels and gets crisp output on retina.\n */\nexport class Layers {\n constructor(container, names) {\n this.container = container\n this.names = names\n this.canvas = {}\n this.ctx = {}\n this.width = 0\n this.height = 0\n this.dpr = 0\n this.onResize = null\n\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative'\n }\n\n names.forEach((name, i) => {\n const c = document.createElement('canvas')\n Object.assign(c.style, {\n position: 'absolute',\n left: '0',\n top: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: String(i + 1),\n })\n container.appendChild(c)\n this.canvas[name] = c\n this.ctx[name] = c.getContext('2d')\n })\n\n this._ro = new ResizeObserver(() => this.measure())\n this._ro.observe(container)\n this.measure()\n }\n\n measure() {\n const r = this.container.getBoundingClientRect()\n const w = Math.max(1, Math.floor(r.width))\n const h = Math.max(1, Math.floor(r.height))\n const dpr = Math.min(window.devicePixelRatio || 1, 2)\n if (w === this.width && h === this.height && dpr === this.dpr) return\n this.width = w\n this.height = h\n this.dpr = dpr\n for (const n of this.names) {\n const c = this.canvas[n]\n c.width = Math.floor(w * dpr)\n c.height = Math.floor(h * dpr)\n this.ctx[n].setTransform(dpr, 0, 0, dpr, 0, 0)\n }\n if (this.onResize) this.onResize(w, h)\n }\n\n /** Flatten all layers into a single canvas (for toImage/export). */\n composite() {\n const out = document.createElement('canvas')\n out.width = Math.floor(this.width * this.dpr)\n out.height = Math.floor(this.height * this.dpr)\n const c = out.getContext('2d')\n for (const n of this.names) c.drawImage(this.canvas[n], 0, 0)\n return out\n }\n\n destroy() {\n this._ro.disconnect()\n for (const n of this.names) this.canvas[n].remove()\n this.canvas = {}\n this.ctx = {}\n }\n}\n","/**\n * Loop — ONE requestAnimationFrame loop for the whole chart, driven by\n * dirty flags. 500 feed ticks between two frames still cost one repaint.\n *\n * The frame callback returns `true` while animation is in flight, which is\n * what keeps the loop running; otherwise it idles at zero CPU until something\n * calls invalidate().\n */\n\n/**\n * Consecutive throwing frames tolerated before the loop gives up. A transient\n * error should heal; a permanent one must not spin at 60fps forever.\n */\nconst MAX_FRAME_ERRORS = 10\n\nexport class Loop {\n constructor(onFrame) {\n this.onFrame = onFrame\n this._frameErrors = 0\n this.fps = 0\n this._raf = 0\n this._dirty = new Set()\n this._last = 0\n this._running = false\n this._frames = 0\n this._fpsAt = 0\n this._tick = this._tick.bind(this)\n }\n\n invalidate(...layers) {\n if (!layers.length) this._dirty.add('all')\n else for (const l of layers) this._dirty.add(l)\n this._schedule()\n }\n\n start() {\n if (this._running) return\n this._running = true\n this._last = performance.now()\n this._fpsAt = this._last\n this.invalidate('all')\n }\n\n stop() {\n this._running = false\n if (this._raf) cancelAnimationFrame(this._raf)\n this._raf = 0\n }\n\n _schedule() {\n if (this._raf || !this._running) return\n this._raf = requestAnimationFrame(this._tick)\n }\n\n _tick(now) {\n this._raf = 0\n if (!this._running) return\n const dt = Math.min(Math.max(now - this._last, 1), 64)\n this._last = now\n\n this._frames++\n if (now - this._fpsAt >= 500) {\n this.fps = Math.round((this._frames * 1000) / (now - this._fpsAt))\n this._frames = 0\n this._fpsAt = now\n }\n\n const dirty = this._dirty\n this._dirty = new Set()\n\n let wantMore = false\n try {\n wantMore = this.onFrame(dirty, dt, now) === true\n this._frameErrors = 0\n } catch (e) {\n // The dirty set was swapped out before the call, so without putting it\n // back a single throw loses the pending layers AND leaves wantMore\n // false — nothing reschedules and the chart freezes for good.\n for (const l of dirty) this._dirty.add(l)\n if (++this._frameErrors >= MAX_FRAME_ERRORS) {\n console.error(\n `[Emberwick] frame error — stopping after ${MAX_FRAME_ERRORS} consecutive failures`, e)\n this._dirty.clear()\n this.stop()\n return\n }\n console.error('[Emberwick] frame error', e)\n }\n if (wantMore || this._dirty.size) this._schedule()\n }\n}\n","// Motion primitives. Everything animated in Emberwick goes through one of these\n// two classes so there is exactly one place that owns easing behaviour.\n\nexport const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3)\nexport const easeInOutCubic = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n\n/**\n * Smoothed — exponential smoothing toward a target that may move every frame.\n * Frame-rate independent: the same visual speed at 30fps and 144fps.\n * Use for values that are continuously re-targeted (autoscale, live candle, zoom).\n */\nexport class Smoothed {\n constructor(value = 0, tau = 90) {\n this.value = value\n this.target = value\n this.tau = tau\n }\n\n set(target) {\n this.target = target\n }\n\n /** Snap with no animation. */\n jump(v) {\n this.value = v\n this.target = v\n }\n\n get settled() {\n const eps = 1e-9 + Math.abs(this.target) * 1e-6\n return Math.abs(this.target - this.value) <= eps\n }\n\n /** @returns {boolean} true while still moving (caller keeps the loop alive) */\n tick(dt) {\n if (this.settled) {\n this.value = this.target\n return false\n }\n this.value += (this.target - this.value) * (1 - Math.exp(-dt / this.tau))\n return true\n }\n}\n\n/**\n * Tween — fixed-duration one-shot, for discrete events (a candle being born).\n */\nexport class Tween {\n constructor(duration = 200, ease = easeOutCubic) {\n this.duration = duration\n this.ease = ease\n this.t = duration\n }\n\n restart() {\n this.t = 0\n }\n\n get done() {\n return this.t >= this.duration\n }\n\n get progress() {\n return this.ease(Math.min(1, this.t / this.duration))\n }\n\n tick(dt) {\n if (this.done) return false\n this.t += dt\n return true\n }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * TimeScale — maps bar index <-> x pixels.\n *\n * Two smoothed values define the view:\n * spacing : px per bar (zoom)\n * right : float bar index sitting at the right edge of the plot\n *\n * Both are Smoothed, so a wheel zoom eases instead of stepping, and new bars\n * glide in rather than jumping. Dragging uses jump() so the chart stays glued\n * to the pointer — easing a drag feels like lag, not smoothness.\n */\nexport class TimeScale {\n constructor({ spacing = 9, minSpacing = 0.8, maxSpacing = 160, rightOffset = 12 } = {}) {\n this.minSpacing = minSpacing\n this.maxSpacing = maxSpacing\n this.rightOffset = rightOffset\n this.width = 0\n this.barCount = 0\n this.follow = true\n this.timeframeMs = 60000\n this._spacing = new Smoothed(spacing, 65)\n this._right = new Smoothed(rightOffset, 65)\n this._initial = spacing\n }\n\n get spacing() { return this._spacing.value }\n get right() { return this._right.value }\n\n resize(w) { this.width = Math.max(1, w) }\n\n setBarCount(n) {\n const grew = n > this.barCount\n this.barCount = n\n if (this.follow) {\n // target the new last bar; Smoothed turns this into a glide\n const t = n - 1 + this.rightOffset\n if (grew) this._right.set(t)\n else this._right.jump(t)\n }\n }\n\n x(i) { return this.width - (this._right.value - i) * this._spacing.value }\n\n /** Centre-x of bar i (bars are drawn centred on their slot). */\n index(x) { return this._right.value - (this.width - x) / this._spacing.value }\n\n barWidth() {\n const s = this._spacing.value\n // leave a gap between candles, but never thinner than a hairline\n return Math.max(1, Math.floor(s * 0.72))\n }\n\n visibleRange() {\n const first = Math.floor(this.index(0)) - 1\n const last = Math.ceil(this.index(this.width)) + 1\n return {\n from: clamp(first, 0, Math.max(0, this.barCount - 1)),\n to: clamp(last, 0, Math.max(0, this.barCount - 1)),\n }\n }\n\n _clampRight(v) {\n const max = this.barCount - 1 + this.rightOffset + this.width / this._spacing.target\n const min = Math.min(4, this.barCount - 1 + this.rightOffset)\n return clamp(v, min, max)\n }\n\n /** Immediate pan, in pixels. Positive dx drags content right (back in time). */\n panBy(dxPx) {\n if (!dxPx) return false\n const next = this._clampRight(this._right.value - dxPx / this._spacing.value)\n this._right.jump(next)\n this.follow = false\n return true\n }\n\n /** Zoom by `factor`, keeping the bar under `x` pinned. */\n zoomAt(x, factor) {\n const s0 = this._spacing.target\n const s1 = clamp(s0 * factor, this.minSpacing, this.maxSpacing)\n if (Math.abs(s1 - s0) < 1e-9) return false\n\n // While following realtime, pin the right edge instead of the cursor so the\n // latest candle stays put — that is what traders expect.\n const anchorX = this.follow ? this.width : x\n const r0 = this._right.target\n const idx = r0 - (this.width - anchorX) / s0\n const r1 = idx + (this.width - anchorX) / s1\n\n this._spacing.set(s1)\n this._right.set(this._clampRight(r1))\n return true\n }\n\n snapToRealtime() {\n this.follow = true\n this._right.set(this.barCount - 1 + this.rightOffset)\n }\n\n /**\n * Same anchor, no easing. Scrubbing re-targets the right edge many times a\n * second; easing each one reads as the chart lagging the scrubber, which is\n * the same reason a drag uses jump().\n */\n jumpToRealtime() {\n this.follow = true\n this._right.jump(this.barCount - 1 + this.rightOffset)\n }\n\n reset() {\n this._spacing.set(this._initial)\n this.snapToRealtime()\n }\n\n /** True while the view is still easing. */\n tick(dt) {\n const a = this._spacing.tick(dt)\n const b = this._right.tick(dt)\n return a || b\n }\n\n get settled() { return this._spacing.settled && this._right.settled }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * PriceScale — maps price <-> y pixels, with animated autoscale.\n *\n * Bounds live in *transformed* space (identity for linear, log for log), so\n * switching modes is a one-line change and the easing still behaves.\n * The whole point of smoothing here: when a spike arrives the range glides to\n * its new bounds instead of the chart snapping and losing the reader.\n */\nexport class PriceScale {\n constructor({ mode = 'linear', tau = 120, marginTop = 0.12, marginBottom = 0.12 } = {}) {\n this.mode = mode\n this.marginTop = marginTop\n this.marginBottom = marginBottom\n this.auto = true\n this.top = 0\n this.height = 1\n this._lo = new Smoothed(0, tau)\n this._hi = new Smoothed(1, tau)\n this._primed = false\n }\n\n _fwd(v) { return this.mode === 'log' ? Math.log(Math.max(v, 1e-9)) : v }\n _inv(v) { return this.mode === 'log' ? Math.exp(v) : v }\n\n setMode(mode) {\n if (mode === this.mode) return\n const lo = this._inv(this._lo.value)\n const hi = this._inv(this._hi.value)\n this.mode = mode\n this._lo.jump(this._fwd(lo))\n this._hi.jump(this._fwd(hi))\n }\n\n layout(top, height) {\n this.top = top\n this.height = Math.max(1, height)\n }\n\n get lo() { return this._inv(this._lo.value) }\n get hi() { return this._inv(this._hi.value) }\n\n y(price) {\n const a = this._lo.value\n const b = this._hi.value\n const t = (this._fwd(price) - a) / (b - a || 1)\n return this.top + this.height * (1 - t)\n }\n\n price(y) {\n const a = this._lo.value\n const b = this._hi.value\n const t = 1 - (y - this.top) / this.height\n return this._inv(a + t * (b - a))\n }\n\n /**\n * Is this a price this scale can actually plot?\n *\n * `isFinite(null)` is TRUE — null numifies to 0 — so a bar carrying a null\n * low used to sail through the old isFinite() guard and drag the minimum to\n * zero, flattening every candle into the top of the plot. Log mode has the\n * same problem from the other end: log(0) is -Infinity, and the clamp to\n * 1e-9 turns one zero tick into a ~20-decade range.\n */\n _plottable(v) {\n return typeof v === 'number' && isFinite(v) && (this.mode !== 'log' || v > 0)\n }\n\n /** Fit visible bars. `extra` lets the forming candle influence the range. */\n fit(bars, from, to, extra) {\n if (!this.auto || !bars.length) return\n let min = Infinity\n let max = -Infinity\n const consider = (lo, hi) => {\n if (this._plottable(lo) && lo < min) min = lo\n if (this._plottable(hi) && hi > max) max = hi\n }\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (!b) continue\n consider(b.low, b.high)\n }\n if (extra) consider(extra.low, extra.high)\n if (!isFinite(min) || !isFinite(max)) return\n\n let a = this._fwd(min)\n let b = this._fwd(max)\n // marginTop pads the high side, marginBottom the low side. They used to\n // share one `pad` computed from marginTop, which made the documented and\n // typed `marginBottom` option inert.\n const span = b - a\n let padTop = span * this.marginTop\n let padBottom = span * this.marginBottom\n if (!(padTop > 0)) padTop = Math.abs(b) * 0.01 || 1\n if (!(padBottom > 0)) padBottom = Math.abs(a) * 0.01 || 1\n a -= padBottom\n b += padTop\n\n this._lo.set(a)\n this._hi.set(b)\n if (!this._primed) {\n this._lo.jump(a)\n this._hi.jump(b)\n this._primed = true\n }\n }\n\n /** Manual axis-drag scaling around the vertical centre. */\n scaleBy(factor) {\n this.auto = false\n const a = this._lo.target\n const b = this._hi.target\n const mid = (a + b) / 2\n const half = ((b - a) / 2) * clamp(factor, 0.2, 5)\n this._lo.set(mid - half)\n this._hi.set(mid + half)\n }\n\n resetAuto() {\n this.auto = true\n }\n\n tick(dt) {\n const a = this._lo.tick(dt)\n const b = this._hi.tick(dt)\n return a || b\n }\n}\n","export const defaultTheme = {\n background: '#0b0e14',\n grid: 'rgba(255,255,255,0.045)',\n axisLine: 'rgba(255,255,255,0.10)',\n text: '#8b93a7',\n textStrong: '#e6e9ef',\n up: '#26a69a',\n down: '#ef5350',\n upFill: '#26a69a',\n downFill: '#ef5350',\n wickUp: '#26a69a',\n wickDown: '#ef5350',\n volumeUp: 'rgba(38,166,154,0.30)',\n volumeDown: 'rgba(239,83,80,0.30)',\n crosshair: 'rgba(255,255,255,0.32)',\n labelBg: '#2a3040',\n labelText: '#e6e9ef',\n tagText: '#06080d',\n font: '11px ui-sans-serif, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n priceAxisWidth: 68,\n timeAxisHeight: 26,\n}\n\nexport const lightTheme = {\n ...defaultTheme,\n background: '#ffffff',\n grid: 'rgba(0,0,0,0.06)',\n axisLine: 'rgba(0,0,0,0.14)',\n text: '#6b7280',\n textStrong: '#111827',\n labelBg: '#374151',\n volumeUp: 'rgba(38,166,154,0.25)',\n volumeDown: 'rgba(239,83,80,0.25)',\n crosshair: 'rgba(0,0,0,0.35)',\n tagText: '#ffffff',\n}\n","import { Smoothed, Tween } from './Tween.js'\n\n/**\n * LiveCandle — makes the forming (rightmost) candle *flow* instead of snapping.\n *\n * A raw feed tick replaces close/high/low instantly, which reads as a jitter.\n * Here every component eases toward the incoming value, and a brand new candle\n * plays a short grow-from-centre animation as it scrolls in.\n */\nexport class LiveCandle {\n constructor(tau = 55) {\n this.enabled = true\n this.o = new Smoothed(0, tau)\n this.h = new Smoothed(0, tau)\n this.l = new Smoothed(0, tau)\n this.c = new Smoothed(0, tau)\n this.vol = new Smoothed(0, tau * 2)\n this.spawn = new Tween(240)\n this._has = false\n this._time = null\n }\n\n setTarget(bar) {\n if (!bar) {\n this._has = false\n return\n }\n if (!this._has || bar.time !== this._time) {\n // New candle: start collapsed at its open, then animate outward.\n this.o.jump(bar.open)\n this.h.jump(bar.open)\n this.l.jump(bar.open)\n this.c.jump(bar.open)\n this.vol.jump(0)\n this.spawn.restart()\n this._time = bar.time\n this._has = true\n }\n this.o.set(bar.open)\n this.h.set(bar.high)\n this.l.set(bar.low)\n this.c.set(bar.close)\n this.vol.set(bar.volume || 0)\n }\n\n reset() {\n this._has = false\n this._time = null\n }\n\n /** @returns {boolean} true while animating */\n tick(dt) {\n if (!this._has) return false\n let moving = false\n if (this.o.tick(dt)) moving = true\n if (this.h.tick(dt)) moving = true\n if (this.l.tick(dt)) moving = true\n if (this.c.tick(dt)) moving = true\n if (this.vol.tick(dt)) moving = true\n if (this.spawn.tick(dt)) moving = true\n return moving\n }\n\n /** Interpolated view of `bar`, or `bar` itself when disabled. */\n read(bar) {\n if (!this._has || !this.enabled || bar.time !== this._time) return bar\n const o = this.o.value\n const c = this.c.value\n return {\n time: bar.time,\n open: o,\n close: c,\n // keep the wick consistent while values chase each other\n high: Math.max(this.h.value, o, c),\n low: Math.min(this.l.value, o, c),\n volume: this.vol.value,\n _spawn: this.spawn.progress,\n }\n }\n}\n","/**\n * Inertia — momentum panning with friction decay.\n * sample() while dragging, release() on pointer up, then tick() each frame\n * until it returns 0.\n */\nexport class Inertia {\n constructor({ friction = 0.92, min = 0.015 } = {}) {\n this.friction = friction\n this.min = min\n this.v = 0 // px per ms\n this.active = false\n }\n\n sample(dx, dt) {\n if (dt <= 0) return\n const instant = dx / dt\n // low-pass so one jittery frame doesn't define the throw\n this.v = this.v * 0.6 + instant * 0.4\n this.active = false\n }\n\n release() {\n if (Math.abs(this.v) > this.min) this.active = true\n }\n\n stop() {\n this.v = 0\n this.active = false\n }\n\n /** @returns {number} px to pan this frame (0 when idle) */\n tick(dt) {\n if (!this.active) return 0\n const dx = this.v * dt\n this.v *= Math.pow(this.friction, dt / 16.6667)\n if (Math.abs(this.v) < this.min) this.stop()\n return dx\n }\n}\n","/**\n * Replay — bar-by-bar playback over a fixed dataset.\n *\n * The chart is never put into a special \"replay mode\". This controller holds\n * the full dataset aside and hands the chart only the REVEALED PREFIX, so the\n * scales, annotations, crosshair and range events all behave exactly as they\n * do on live data that happens to end at the cursor. Nothing downstream needs\n * to know replay exists.\n *\n * Motion reuses the engine that is already there:\n *\n * - revealing the NEXT bar goes through `Chart.append()` — the same path a\n * feed tick takes — so the candle grows in and the time axis glides;\n * - scrubbing swaps the prefix and jumps, because easing a drag reads as lag\n * (the same rule the pan gesture follows).\n */\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/** Playback rate bounds, as a multiple of one bar per `baseInterval`. */\nexport const MIN_SPEED = 0.25\nexport const MAX_SPEED = 500\n\n/**\n * Ceiling on bars revealed in one frame. At 500× that is ~8 bars/frame, so\n * this only ever bites after a tab has been backgrounded and dt is huge.\n */\nconst MAX_STEPS_PER_FRAME = 240\n\nexport class Replay {\n constructor(chart, options = {}) {\n const src = Array.isArray(options.bars) ? options.bars : []\n\n this.chart = chart\n /** The full dataset. Never mutated. */\n this.source = src.slice()\n /** Real ms one bar takes at speed 1. Default: one bar per second. */\n this.baseInterval = Math.max(16, +options.baseInterval || 1000)\n this.speed = clamp(+options.speed || 1, MIN_SPEED, MAX_SPEED)\n /** Restart from the beginning instead of stopping at the end. */\n this.looping = options.loop === true\n /** Re-anchor the right edge on the cursor when scrubbing. */\n this.follow = options.follow !== false\n this.playing = false\n\n this._acc = 0\n this._markerKey = ''\n this._markerView = null\n /**\n * A controller replaced by a second startReplay() is no longer ticked by\n * the chart, but the caller still holds the object returned by the first\n * call — and its transport methods would happily keep swapping bars into\n * a chart that has moved on. Detaching neuters it.\n */\n this._detached = false\n\n // The scales infer the timeframe from the first PAIR of bars, so two bars\n // is the floor — the cursor never goes below index 1.\n this.minIndex = Math.min(1, this.lastIndex)\n\n const from = +options.from\n this.index = clamp(\n Number.isFinite(from) ? Math.round(from) : Math.floor(this.lastIndex / 2),\n this.minIndex,\n this.lastIndex,\n )\n\n this._apply('seek')\n }\n\n // ----------------------------------------------------------------- state --\n get length() { return this.source.length }\n get lastIndex() { return Math.max(0, this.source.length - 1) }\n get atEnd() { return this.index >= this.lastIndex }\n get bar() { return this.source[this.index] || null }\n get time() { return this.bar ? this.bar.time : null }\n\n /** 0 at the first playable bar, 1 at the last. */\n get progress() {\n const span = this.lastIndex - this.minIndex\n return span > 0 ? (this.index - this.minIndex) / span : 1\n }\n\n /** Real ms between bars at the current speed. */\n get interval() { return this.baseInterval / this.speed }\n\n /** Snapshot handed to `subscribe('replay', fn)`. */\n state() {\n return {\n active: true,\n playing: this.playing,\n index: this.index,\n length: this.length,\n progress: this.progress,\n speed: this.speed,\n time: this.time,\n bar: this.bar,\n atEnd: this.atEnd,\n }\n }\n\n // ------------------------------------------------------------- transport --\n /** Stop this controller from ever touching the chart again. Idempotent. */\n detach() {\n this._detached = true\n this.playing = false\n return this\n }\n\n play() {\n if (this._detached || this.playing || this.length < 2) return this\n // Pressing play at the end restarts, rather than doing nothing.\n if (this.atEnd) {\n this.index = this.minIndex\n this._apply('seek')\n }\n this.playing = true\n this._acc = 0\n this._changed()\n return this\n }\n\n pause() {\n if (!this.playing) return this\n this.playing = false\n this._acc = 0\n this._changed()\n return this\n }\n\n toggle() { return this.playing ? this.pause() : this.play() }\n\n /** Multiplier on `baseInterval`. Clamped to 0.25×–500×. */\n setSpeed(speed) {\n const s = clamp(+speed || 1, MIN_SPEED, MAX_SPEED)\n if (s === this.speed) return this\n this.speed = s\n this._acc = 0 // no burst of bars when the rate jumps\n this._changed()\n return this\n }\n\n setLoop(on) {\n this.looping = !!on\n this._changed()\n return this\n }\n\n /** Move the cursor. Out-of-range values clamp; playback keeps running. */\n seek(index) {\n const n = Math.round(+index)\n // clamp() compares with < and >, and every comparison against NaN is\n // false, so NaN passes straight through and slice(0, NaN) blanks the\n // chart. Every other numeric entry point here is already defensive.\n if (!Number.isFinite(n)) return this\n const next = clamp(n, this.minIndex, this.lastIndex)\n if (this._detached || next === this.index) return this\n this.index = next\n this._acc = 0\n this._apply('seek')\n this._changed()\n return this\n }\n\n step(n = 1) { return this.seek(this.index + (n || 0)) }\n toStart() { return this.seek(this.minIndex) }\n toEnd() { return this.seek(this.lastIndex) }\n\n /**\n * Advance with wall-clock time. Called once per frame by the chart; returns\n * true while playback is in flight, which is what keeps the loop awake.\n */\n tick(dt) {\n if (this._detached || !this.playing || this.length < 2) return false\n\n this._acc += dt * this.speed\n const steps = Math.floor(this._acc / this.baseInterval)\n if (steps <= 0) return true // playing, just not due for the next bar yet\n this._acc -= steps * this.baseInterval\n\n const last = this.lastIndex\n let next = this.index + Math.min(steps, MAX_STEPS_PER_FRAME)\n\n if (next > last) {\n if (this.looping) {\n this.index = this.minIndex\n this._apply('seek')\n this._changed()\n return true\n }\n next = last\n }\n\n const single = next === this.index + 1\n this.index = next\n this._apply(single ? 'step' : 'seek')\n if (this.atEnd && !this.looping) {\n this.playing = false\n this._acc = 0\n }\n this._changed()\n return this.playing\n }\n\n // --------------------------------------------------------------- markers --\n /**\n * Markers after the cursor are future information: hidden, not clamped.\n * Without this they would all pin to the newest revealed bar, because\n * time→index resolution snaps to the NEAREST bar.\n *\n * Cached on the cursor, so a paused chart allocates nothing per frame.\n */\n markerFilter(markers) {\n const t = this.time\n if (t == null) return markers\n const key = this.index + ':' + markers.length\n if (key !== this._markerKey || !this._markerView) {\n const cut = t + (this.chart.ts.timeframeMs || 0) / 2\n this._markerView = markers.filter((m) => m.time <= cut)\n this._markerKey = key\n }\n return this._markerView\n }\n\n /** Drop the cached slice — the marker set itself changed. */\n invalidateMarkers() {\n this._markerKey = ''\n this._markerView = null\n }\n\n // ---------------------------------------------------------------- private --\n /**\n * Push the revealed prefix into the chart.\n *\n * 'step' (exactly one bar forward) takes the live path so the new candle\n * animates; anything else swaps the prefix and re-anchors without easing.\n */\n _apply(mode) {\n // The single gate on touching the chart: a detached controller must not\n // swap bars underneath whatever replaced it.\n if (this._detached) return\n const chart = this.chart\n if (mode === 'step' && chart.bars.length === this.index) {\n chart.append(this.source[this.index])\n return\n }\n chart._swapBars(this.source.slice(0, this.index + 1))\n if (this.follow) chart.ts.jumpToRealtime()\n }\n\n /** Any state change needs a frame: that frame is what emits 'replay'. */\n _changed() {\n if (this._detached) return\n this.chart.loop.invalidate('main')\n }\n}\n","/** \"Nice\" step size (1/2/5 x 10^n) covering `span` in about `count` steps. */\nexport function niceStep(span, count) {\n const raw = span / Math.max(1, count)\n if (!(raw > 0) || !isFinite(raw)) return 1\n const mag = Math.pow(10, Math.floor(Math.log10(raw)))\n const n = raw / mag\n const s = n < 1.5 ? 1 : n < 3 ? 2 : n < 7 ? 5 : 10\n return s * mag\n}\n\n/** Hard ceiling on tick count — a guard, never reached by a sane range. */\nconst MAX_TICKS = 1000\n\nexport function priceTicks(lo, hi, count) {\n const step = niceStep(hi - lo, count)\n // A non-finite bound makes niceStep fall back to 1 and `start` become\n // -Infinity, and `v += step` never moves off -Infinity: the loop below\n // would spin forever inside a frame. Bail instead.\n if (!isFinite(lo) || !isFinite(hi) || hi < lo) return { ticks: [], step }\n const start = Math.ceil(lo / step) * step\n const ticks = []\n // Multiply rather than accumulate: repeated += step drifts on floats.\n for (let i = 0; i < MAX_TICKS; i++) {\n const v = start + i * step\n if (v > hi + step * 1e-9) break\n ticks.push(v)\n }\n return { ticks, step }\n}\n\nexport function decimalsFor(step) {\n if (!isFinite(step) || step <= 0) return 2\n if (step >= 100) return 0\n if (step >= 1) return 2\n return Math.min(8, Math.ceil(-Math.log10(step)) + 1)\n}\n\n/** Bar-index step that keeps time labels at least `minPx` apart. */\nexport function niceBarStep(minBars) {\n const opts = [1, 2, 5, 10, 15, 20, 30, 60, 120, 240, 480, 960, 1920, 3840, 7680]\n for (const o of opts) if (o >= minBars) return o\n return Math.ceil(minBars / 1000) * 1000\n}\n\nconst p2 = (n) => String(n).padStart(2, '0')\n\nexport function fmtAxisTime(ms, tfMs) {\n const d = new Date(ms)\n if (tfMs >= 864e5) return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n if (d.getHours() === 0 && d.getMinutes() === 0) {\n return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n }\n return `${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtDateTime(ms) {\n const d = new Date(ms)\n return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())} ${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtVolume(v) {\n if (!isFinite(v)) return '—'\n if (v >= 1e9) return (v / 1e9).toFixed(2) + 'B'\n if (v >= 1e6) return (v / 1e6).toFixed(2) + 'M'\n if (v >= 1e3) return (v / 1e3).toFixed(1) + 'K'\n return String(Math.round(v))\n}\n","import { priceTicks, decimalsFor, niceBarStep, fmtAxisTime } from '../core/formatters.js'\n\n/** Background, grid, and both axes. Repaints only when the view changes. */\nexport function drawGrid(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height } = s\n\n ctx.clearRect(0, 0, width, height)\n ctx.fillStyle = theme.background\n ctx.fillRect(0, 0, width, height)\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // ---- price grid + labels -------------------------------------------------\n const rows = Math.max(2, Math.floor(plot.h / 58))\n const { ticks, step } = priceTicks(ps.lo, ps.hi, rows)\n const dec = decimalsFor(step)\n\n ctx.strokeStyle = theme.grid\n ctx.lineWidth = 1\n ctx.beginPath()\n for (const v of ticks) {\n const y = Math.round(ps.y(v)) + 0.5\n if (y < plot.y || y > plot.y + plot.h) continue\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'left'\n for (const v of ticks) {\n const y = Math.round(ps.y(v))\n if (y < plot.y + 6 || y > plot.y + plot.h - 6) continue\n ctx.fillText(v.toFixed(dec), plot.w + 8, y)\n }\n\n // ---- time grid + labels --------------------------------------------------\n if (bars.length) {\n const minBars = Math.ceil(74 / Math.max(0.0001, ts.spacing))\n const stepBars = niceBarStep(minBars)\n const { from, to } = ts.visibleRange()\n const first = Math.ceil(from / stepBars) * stepBars\n\n ctx.strokeStyle = theme.grid\n ctx.beginPath()\n for (let i = first; i <= to; i += stepBars) {\n const x = Math.round(ts.x(i)) + 0.5\n if (x < 0 || x > plot.w) continue\n ctx.moveTo(x, 0)\n ctx.lineTo(x, plot.h)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'center'\n const ty = plot.h + theme.timeAxisHeight / 2\n for (let i = first; i <= to; i += stepBars) {\n const bar = bars[i]\n if (!bar) continue\n const x = Math.round(ts.x(i))\n if (x < 28 || x > plot.w - 28) continue\n ctx.fillText(fmtAxisTime(bar.time, ts.timeframeMs), x, ty)\n }\n }\n\n // ---- axis separators -----------------------------------------------------\n ctx.strokeStyle = theme.axisLine\n ctx.beginPath()\n ctx.moveTo(plot.w + 0.5, 0)\n ctx.lineTo(plot.w + 0.5, plot.h)\n ctx.moveTo(0, plot.h + 0.5)\n ctx.lineTo(width, plot.h + 0.5)\n ctx.stroke()\n}\n","import { decimalsFor, priceTicks } from '../core/formatters.js'\n\n/**\n * Candles + volume. Everything here is culled to the visible index range —\n * 500k bars loaded still costs only the ~200 on screen.\n */\nexport function drawCandles(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, live, volumeRatio } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!bars.length) return\n\n const { from, to } = ts.visibleRange()\n const bw = ts.barWidth()\n const half = bw / 2\n const thin = bw <= 2\n\n // ---- volume strip --------------------------------------------------------\n const volH = plot.h * volumeRatio\n const volTop = plot.y + plot.h - volH\n let vmax = 0\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (b && b.volume > vmax) vmax = b.volume\n }\n if (vmax > 0) {\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n if (live && i === bars.length - 1) b = live\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n const h = (b.volume / vmax) * volH * 0.9\n ctx.fillStyle = b.close >= b.open ? theme.volumeUp : theme.volumeDown\n ctx.fillRect(Math.round(x - half), volTop + (volH - h), Math.max(1, bw), h)\n }\n }\n\n // ---- candles -------------------------------------------------------------\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n const isLast = i === bars.length - 1\n if (live && isLast) b = live\n\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n\n const up = b.close >= b.open\n const color = up ? theme.up : theme.down\n const yO = ps.y(b.open)\n const yC = ps.y(b.close)\n const yH = ps.y(b.high)\n const yL = ps.y(b.low)\n\n // grow-from-centre on a freshly opened candle\n let scale = 1\n if (live && isLast && typeof b._spawn === 'number') scale = 0.35 + 0.65 * b._spawn\n\n const cx = Math.round(x) + (bw % 2 ? 0.5 : 0)\n\n // wick\n ctx.strokeStyle = up ? theme.wickUp : theme.wickDown\n ctx.lineWidth = Math.max(1, Math.min(2, bw * 0.16))\n ctx.beginPath()\n ctx.moveTo(cx, yH)\n ctx.lineTo(cx, yL)\n ctx.stroke()\n\n if (thin) continue\n\n // body\n const top = Math.min(yO, yC)\n const bodyH = Math.max(1, Math.abs(yC - yO))\n const w = Math.max(1, bw * scale)\n ctx.fillStyle = color\n ctx.fillRect(Math.round(x - w / 2), Math.round(top), Math.round(w), Math.round(bodyH))\n }\n\n // ---- last price line -----------------------------------------------------\n const lastBar = live || bars[bars.length - 1]\n if (lastBar) {\n const y = Math.round(ps.y(lastBar.close)) + 0.5\n if (y > plot.y && y < plot.y + plot.h) {\n const up = lastBar.close >= lastBar.open\n ctx.save()\n ctx.setLineDash([3, 3])\n ctx.strokeStyle = up ? theme.up : theme.down\n ctx.lineWidth = 1\n ctx.globalAlpha = 0.7\n ctx.beginPath()\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n ctx.stroke()\n ctx.restore()\n\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const label = lastBar.close.toFixed(decimalsFor(step))\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n ctx.textAlign = 'left'\n const tw = ctx.measureText(label).width\n ctx.fillStyle = up ? theme.up : theme.down\n ctx.fillRect(plot.w + 1, y - 9, tw + 14, 18)\n ctx.fillStyle = theme.tagText\n ctx.fillText(label, plot.w + 8, y)\n }\n }\n}\n","import { decimalsFor, priceTicks, fmtDateTime } from '../core/formatters.js'\n\n/**\n * Crosshair lives alone on the top canvas: moving the pointer repaints only\n * these few pixels, never the candles underneath.\n */\nexport function drawCrosshair(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, cursor, magnet } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!cursor || !bars.length) return\n if (cursor.x < 0 || cursor.x > plot.w || cursor.y < 0 || cursor.y > plot.h) return\n\n const i = Math.round(ts.index(cursor.x))\n const bar = bars[i]\n\n let x = cursor.x\n let y = cursor.y\n if (bar) {\n x = ts.x(i) // snap to the bar slot\n if (magnet) {\n // magnet to the nearest OHLC value\n const cands = [bar.open, bar.high, bar.low, bar.close]\n let best = null\n let bestD = Infinity\n for (const p of cands) {\n const py = ps.y(p)\n const d = Math.abs(py - cursor.y)\n if (d < bestD) { bestD = d; best = py }\n }\n if (bestD < 22) y = best\n }\n }\n\n ctx.save()\n ctx.setLineDash([4, 4])\n ctx.strokeStyle = theme.crosshair\n ctx.lineWidth = 1\n ctx.beginPath()\n ctx.moveTo(Math.round(x) + 0.5, 0)\n ctx.lineTo(Math.round(x) + 0.5, plot.h)\n ctx.moveTo(0, Math.round(y) + 0.5)\n ctx.lineTo(plot.w, Math.round(y) + 0.5)\n ctx.stroke()\n ctx.restore()\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // price tag\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const priceLabel = ps.price(y).toFixed(decimalsFor(step))\n ctx.textAlign = 'left'\n const pw = ctx.measureText(priceLabel).width\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(plot.w + 1, y - 9, pw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(priceLabel, plot.w + 8, y)\n\n // time tag\n if (bar) {\n const t = fmtDateTime(bar.time)\n ctx.textAlign = 'center'\n const tw = ctx.measureText(t).width\n const bx = Math.min(Math.max(x, tw / 2 + 6), plot.w - tw / 2 - 6)\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(bx - tw / 2 - 7, plot.h + 3, tw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(t, bx, plot.h + 12)\n }\n}\n\n","/**\n * Annotation model — normalisation, time→index resolution and collision\n * layout for markers.\n *\n * The geometry lives here rather than in the renderer so it can be reasoned\n * about (and tested) without a canvas, and out of Chart.js so the orchestrator\n * stays about orchestration.\n */\n\nexport const MARKER_SHAPES = [\n 'arrowUp',\n 'arrowDown',\n 'triangleUp',\n 'triangleDown',\n 'circle',\n 'square',\n 'diamond',\n 'flag',\n 'label',\n]\n\nconst SHAPE_SET = new Set(MARKER_SHAPES)\n\n/**\n * Monotonic, so generated ids are unique for the life of the module. Keying\n * them off the array index meant removing a marker and adding another handed\n * the newcomer an id the survivor might already own, and removeMarker(id)\n * would then take the wrong one.\n */\nlet autoId = 0\n\n/** Buys sit under the bar, sells over it — the convention traders expect. */\nconst DEFAULT_POSITION = {\n arrowUp: 'belowBar',\n triangleUp: 'belowBar',\n arrowDown: 'aboveBar',\n triangleDown: 'aboveBar',\n}\n\nconst POSITIONS = new Set(['aboveBar', 'belowBar', 'inBar', 'atPrice'])\n\n// eslint-disable-next-line no-unused-vars\nexport function normalizeMarker(raw, i) {\n if (!raw || !isFinite(raw.time)) return null\n const shape = SHAPE_SET.has(raw.shape) ? raw.shape : 'circle'\n const position = POSITIONS.has(raw.position)\n ? raw.position\n : DEFAULT_POSITION[shape] || 'aboveBar'\n return {\n id: raw.id != null ? String(raw.id) : `mk${++autoId}`,\n time: +raw.time,\n price: isFinite(raw.price) ? +raw.price : null,\n shape,\n position,\n color: raw.color || null,\n textColor: raw.textColor || null,\n text: raw.text != null ? String(raw.text) : '',\n size: isFinite(raw.size) && raw.size > 0 ? +raw.size : 1,\n /** Anything the consumer wants handed back on hover/click. */\n data: raw.data,\n index: -1,\n }\n}\n\nexport function normalizeMarkers(list) {\n if (!Array.isArray(list)) return []\n const out = []\n for (let i = 0; i < list.length; i++) {\n const m = normalizeMarker(list[i], i)\n if (m) out.push(m)\n }\n out.sort((a, b) => a.time - b.time)\n return out\n}\n\n/**\n * Index of the bar closest in time to `time`; -1 with no bars.\n * Binary search — markers are resolved again whenever the bar array shifts\n * (a history page prepended in front of them moves every index).\n */\nexport function nearestIndex(bars, time) {\n const n = bars.length\n if (!n) return -1\n if (time <= bars[0].time) return 0\n if (time >= bars[n - 1].time) return n - 1\n\n let lo = 0\n let hi = n - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const t = bars[mid].time\n if (t === time) return mid\n if (t < time) lo = mid + 1\n else hi = mid - 1\n }\n const a = Math.max(0, hi)\n const b = Math.min(n - 1, lo)\n return Math.abs(bars[a].time - time) <= Math.abs(bars[b].time - time) ? a : b\n}\n\n/**\n * Attach a bar index to every marker, in place.\n *\n * `toleranceMs` is how far outside the loaded range a marker may sit and\n * still snap to the nearest end bar — one timeframe, normally. Beyond that it\n * resolves to -1 and is not drawn. Without this, nearestIndex() clamps, so a\n * trade from six months before the loaded window pins itself to bar 0 and\n * reads as an event that happened at the left edge of the chart. Omit the\n * argument for the old clamping behaviour.\n */\nexport function resolveMarkers(markers, bars, toleranceMs) {\n const n = bars.length\n const tol = isFinite(toleranceMs) && toleranceMs > 0 ? toleranceMs : Infinity\n const first = n ? bars[0].time - tol : 0\n const last = n ? bars[n - 1].time + tol : 0\n for (let i = 0; i < markers.length; i++) {\n const t = markers[i].time\n markers[i].index = !n || t < first || t > last ? -1 : nearestIndex(bars, t)\n }\n return markers\n}\n\n/**\n * Place visible markers in screen space.\n *\n * Handles the two things that make markers look amateurish when skipped:\n * several markers on one bar overlapping, and thousands of them piling onto\n * the same pixels when zoomed out.\n */\nexport function layoutMarkers(markers, s) {\n const { ts, ps, plot, bars, live } = s\n if (!markers.length || !bars.length) return []\n\n const { from, to } = ts.visibleRange()\n const lastIdx = bars.length - 1\n const dense = ts.barWidth() <= 3\n const stacks = new Map()\n const placed = []\n let lastDenseX = -Infinity\n\n for (const m of markers) {\n const i = m.index\n if (i < 0 || i < from - 2 || i > to + 2) continue\n\n // the forming candle is interpolated, so anchor to the animated values\n const bar = live && i === lastIdx ? live : bars[i]\n if (!bar) continue\n\n const x = ts.x(i)\n if (x < -48 || x > plot.w + 48) continue\n\n // Zoomed far out, markers collapse onto the same pixels: drawing them all\n // costs frames and reads as noise. One per 4px is plenty.\n if (dense) {\n if (x - lastDenseX < 4) continue\n lastDenseX = x\n }\n\n const r = 5 * m.size\n let y\n let dir = 0\n\n if (m.position === 'atPrice' && m.price != null) {\n y = ps.y(m.price)\n } else if (m.position === 'inBar') {\n y = ps.y((bar.high + bar.low) / 2)\n } else if (m.position === 'belowBar') {\n y = ps.y(bar.low) + r + 7\n dir = 1\n } else {\n y = ps.y(bar.high) - r - 7\n dir = -1\n }\n\n // Two trades on one bar must not draw on top of each other.\n if (dir !== 0) {\n const key = i + m.position\n const n = stacks.get(key) || 0\n stacks.set(key, n + 1)\n y += dir * n * (r * 2 + 5)\n }\n\n placed.push({ m, x, y, r, dir })\n }\n\n return placed\n}\n","import { decimalsFor, priceTicks } from '../core/formatters.js'\nimport { nearestIndex } from '../overlays/annotations.js'\n\n/**\n * Annotation renderers: zones (behind the candles), price lines and markers\n * (in front of them). Each is a pure draw call over prepared state.\n */\n\nconst DASH = { solid: [], dashed: [6, 4], dotted: [1, 3] }\nconst DOWN_SHAPES = new Set(['arrowDown', 'triangleDown'])\n\nfunction roundRect(ctx, x, y, w, h, r) {\n const rr = Math.max(0, Math.min(r, h / 2, w / 2))\n ctx.beginPath()\n ctx.moveTo(x + rr, y)\n ctx.lineTo(x + w - rr, y)\n ctx.quadraticCurveTo(x + w, y, x + w, y + rr)\n ctx.lineTo(x + w, y + h - rr)\n ctx.quadraticCurveTo(x + w, y + h, x + w - rr, y + h)\n ctx.lineTo(x + rr, y + h)\n ctx.quadraticCurveTo(x, y + h, x, y + h - rr)\n ctx.lineTo(x, y + rr)\n ctx.quadraticCurveTo(x, y, x + rr, y)\n ctx.closePath()\n}\n\n/* ------------------------------------------------------------------ zones -- */\n/** Shaded regions. Drawn on the base layer, over the grid and under candles. */\nexport function drawZones(ctx, s) {\n const { zones, theme, ts, ps, plot, bars } = s\n if (!zones || !zones.length) return\n\n ctx.save()\n ctx.font = theme.font\n ctx.textBaseline = 'top'\n ctx.textAlign = 'left'\n\n for (const z of zones) {\n let x\n let y\n let w\n let h\n\n if (isFinite(z.from) && isFinite(z.to)) {\n // price band: spans the full width\n y = ps.y(Math.max(z.from, z.to))\n h = Math.max(1, ps.y(Math.min(z.from, z.to)) - y)\n x = 0\n w = plot.w\n } else if (isFinite(z.fromTime) && isFinite(z.toTime) && bars.length) {\n // time band: spans the full height\n const a = ts.x(nearestIndex(bars, Math.min(z.fromTime, z.toTime)))\n const b = ts.x(nearestIndex(bars, Math.max(z.fromTime, z.toTime)))\n x = a\n w = Math.max(1, b - a)\n y = 0\n h = plot.h\n } else {\n continue\n }\n\n if (x > plot.w || x + w < 0 || y > plot.h || y + h < 0) continue\n\n ctx.fillStyle = z.color || 'rgba(38,166,154,0.10)'\n ctx.fillRect(x, y, w, h)\n\n if (z.border) {\n ctx.strokeStyle = z.border\n ctx.lineWidth = 1\n ctx.strokeRect(Math.round(x) + 0.5, Math.round(y) + 0.5, Math.round(w), Math.round(h))\n }\n\n if (z.label) {\n ctx.fillStyle = z.labelColor || theme.text\n ctx.fillText(z.label, Math.max(6, x + 6), Math.max(4, y + 4))\n }\n }\n\n ctx.restore()\n}\n\n/* ------------------------------------------------------------- price lines -- */\n/** Horizontal lines with an optional left title pill and right axis tag. */\nexport function drawPriceLines(ctx, s) {\n const { priceLines, theme, ps, plot } = s\n if (!priceLines || !priceLines.length) return\n\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const dec = decimalsFor(step)\n\n ctx.save()\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n for (const L of priceLines) {\n if (!L || !isFinite(L.price)) continue\n const y = Math.round(ps.y(L.price)) + 0.5\n if (y < 0 || y > plot.h) continue\n\n const color = L.color || theme.textStrong\n\n ctx.setLineDash(DASH[L.lineStyle] || DASH.dashed)\n ctx.strokeStyle = color\n ctx.lineWidth = L.lineWidth || 1\n ctx.beginPath()\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n ctx.stroke()\n ctx.setLineDash([])\n\n if (L.title) {\n ctx.textAlign = 'left'\n const tw = ctx.measureText(L.title).width\n ctx.fillStyle = color\n roundRect(ctx, 6, y - 9, tw + 12, 18, 4)\n ctx.fill()\n ctx.fillStyle = L.titleColor || theme.tagText\n ctx.fillText(L.title, 12, y)\n }\n\n if (L.axisLabel !== false) {\n const label = L.price.toFixed(dec)\n ctx.textAlign = 'left'\n const lw = ctx.measureText(label).width\n ctx.fillStyle = color\n ctx.fillRect(plot.w + 1, y - 9, lw + 14, 18)\n ctx.fillStyle = L.tagTextColor || theme.tagText\n ctx.fillText(label, plot.w + 8, y)\n }\n }\n\n ctx.restore()\n}\n\n/* ---------------------------------------------------------------- markers -- */\nfunction shapePath(ctx, shape, x, y, r) {\n ctx.beginPath()\n switch (shape) {\n case 'arrowUp':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x + r * 0.45, y)\n ctx.lineTo(x + r * 0.45, y + r)\n ctx.lineTo(x - r * 0.45, y + r)\n ctx.lineTo(x - r * 0.45, y)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n case 'arrowDown':\n ctx.moveTo(x, y + r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x + r * 0.45, y)\n ctx.lineTo(x + r * 0.45, y - r)\n ctx.lineTo(x - r * 0.45, y - r)\n ctx.lineTo(x - r * 0.45, y)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n case 'triangleUp':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y + r)\n ctx.lineTo(x - r, y + r)\n ctx.closePath()\n break\n case 'triangleDown':\n ctx.moveTo(x, y + r)\n ctx.lineTo(x + r, y - r)\n ctx.lineTo(x - r, y - r)\n ctx.closePath()\n break\n case 'square':\n ctx.rect(x - r, y - r, r * 2, r * 2)\n break\n case 'diamond':\n ctx.moveTo(x, y - r)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x, y + r)\n ctx.lineTo(x - r, y)\n ctx.closePath()\n break\n default:\n ctx.arc(x, y, r, 0, Math.PI * 2)\n }\n}\n\nfunction drawFlag(ctx, x, y, r, color) {\n ctx.fillStyle = color\n ctx.fillRect(x - r * 0.8, y - r, Math.max(1, r * 0.3), r * 2)\n ctx.beginPath()\n ctx.moveTo(x - r * 0.5, y - r)\n ctx.lineTo(x + r, y - r * 0.55)\n ctx.lineTo(x - r * 0.5, y - r * 0.1)\n ctx.closePath()\n ctx.fill()\n}\n\n/**\n * Draws placed markers and returns their hit circles, newest first, so the\n * chart can answer \"what is under the pointer?\" without re-deriving geometry.\n */\nexport function drawMarkers(ctx, s, placed, hoverId) {\n const hits = []\n if (!placed || !placed.length) return hits\n\n const { theme } = s\n ctx.save()\n ctx.font = theme.font\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n for (const p of placed) {\n const { m, x, y, r, dir } = p\n const color = m.color || (DOWN_SHAPES.has(m.shape) ? theme.down : theme.up)\n const hovered = hoverId != null && m.id === hoverId\n\n if (m.shape === 'label') {\n const text = m.text || '•'\n const w = ctx.measureText(text).width + 14\n const h = 18 * m.size\n roundRect(ctx, x - w / 2, y - h / 2, w, h, 4)\n ctx.fillStyle = color\n ctx.fill()\n if (hovered) {\n ctx.strokeStyle = theme.textStrong\n ctx.lineWidth = 1.5\n ctx.stroke()\n }\n ctx.fillStyle = m.textColor || theme.tagText\n ctx.fillText(text, x, y + 0.5)\n hits.push({ id: m.id, marker: m, x, y, r: Math.max(w, h) / 2 })\n continue\n }\n\n if (hovered) {\n ctx.beginPath()\n ctx.arc(x, y, r + 4, 0, Math.PI * 2)\n ctx.fillStyle = 'rgba(255,255,255,0.14)'\n ctx.fill()\n }\n\n if (m.shape === 'flag') {\n drawFlag(ctx, x, y, r, color)\n } else {\n shapePath(ctx, m.shape, x, y, r)\n ctx.fillStyle = color\n ctx.fill()\n }\n\n if (m.text) {\n ctx.fillStyle = m.textColor || theme.text\n ctx.fillText(m.text, x, dir >= 0 ? y + r + 9 : y - r - 9)\n }\n\n hits.push({ id: m.id, marker: m, x, y, r: r + 3 })\n }\n\n ctx.restore()\n return hits\n}\n","import { Layers } from './Layers.js'\nimport { Loop } from './Loop.js'\nimport { TimeScale } from './TimeScale.js'\nimport { PriceScale } from './PriceScale.js'\nimport { defaultTheme } from './palette.js'\nimport { LiveCandle } from '../motion/LiveCandle.js'\nimport { Inertia } from '../motion/Inertia.js'\nimport { Replay } from '../replay/Replay.js'\nimport { drawGrid } from '../render/grid.js'\nimport { drawCandles } from '../render/candles.js'\nimport { drawCrosshair } from '../render/crosshair.js'\nimport { drawZones, drawPriceLines, drawMarkers } from '../render/annotations.js'\nimport { normalizeMarkers, resolveMarkers, layoutMarkers } from '../overlays/annotations.js'\n\n/** The 'replay' payload when nothing is being replayed. */\nconst inactiveReplay = () => ({\n active: false,\n playing: false,\n index: -1,\n length: 0,\n progress: 0,\n speed: 1,\n time: null,\n bar: null,\n atEnd: false,\n})\n\n/**\n * Chart — the orchestrator. Owns the bar store, the scales, the input\n * handling and the frame composition. Framework-free by design: this file\n * touches nothing but DOM and Canvas, which is what lets the same core ship\n * as a React component, a Web Component, or a plain script tag.\n */\n/** Consecutive gaps sampled when inferring the timeframe. */\nconst TF_SAMPLES = 200\n\n/**\n * Consecutive failing history pages before paging gives up. One transient 500\n * must not permanently disable lazy history, but a feed that is reliably\n * failing must not be re-asked on every pan either.\n */\nconst MAX_HISTORY_ERRORS = 3\n\n/**\n * Bar duration, taken as the MEDIAN gap between consecutive bars rather than\n * simply `bars[1].time - bars[0].time`.\n *\n * Any exchange with a trading session puts a large gap between the last bar\n * of one day and the first of the next — NSE closes at 15:30 and reopens at\n * 09:15, so on minute data the very first pair can read as 17.75 HOURS. That\n * one number then drives axis label density and, worse, Replay's future-marker\n * cut-off. The median survives session breaks, weekends and holidays for as\n * long as most bars are consecutive, which is the normal case.\n *\n * Gaps are sampled at a stride so a 500k-bar dataset costs the same as a\n * small one, and each sample is still a genuine adjacent pair.\n */\nexport function inferTimeframe(bars, fallback = 60000) {\n const n = bars.length\n if (n < 2) return fallback\n const stride = Math.max(1, Math.floor(n / TF_SAMPLES))\n const gaps = []\n for (let i = 1; i < n; i += stride) {\n const d = bars[i].time - bars[i - 1].time\n if (d > 0) gaps.push(d)\n }\n if (!gaps.length) return fallback\n gaps.sort((a, b) => a - b)\n return gaps[gaps.length >> 1]\n}\n\nexport class Chart {\n constructor(container, options = {}) {\n if (!container) throw new Error('Chart: container element is required')\n\n this.container = container\n this.theme = { ...defaultTheme, ...(options.theme || {}) }\n this.options = {\n volumeRatio: 0.18,\n magnet: true,\n animate: true,\n ...options,\n }\n\n this.bars = []\n this.feed = null\n this._unsub = null\n this._loadingHistory = false\n this._exhausted = false\n this._historyErrors = 0\n this._replay = null\n // Every async feed read is stamped with the generation current when it\n // STARTED. setFeed/detachFeed/destroy bump the counter, so a slow earlier\n // request that resolves second recognises itself as stale and drops its\n // result instead of writing over the newer feed's bars.\n this._feedGen = 0\n this._destroyed = false\n this._listeners = {\n crosshair: new Set(),\n visibleRange: new Set(),\n markerClick: new Set(),\n markerHover: new Set(),\n replay: new Set(),\n error: new Set(),\n }\n\n // ---- annotations --------------------------------------------------\n // Markers carry a `time`; the renderer needs an index. Resolving is a\n // binary search per marker, so it is redone only when the bar array\n // actually shifts (a prepended history page moves every index).\n this._markers = normalizeMarkers(options.markers)\n this.priceLines = Array.isArray(options.priceLines) ? options.priceLines.slice() : []\n this.zones = Array.isArray(options.zones) ? options.zones.slice() : []\n this._markerHits = []\n this._hoverMarkerId = null\n this._resolveKey = ''\n // Per-listener dedupe. A single shared key let a LATE subscriber record\n // the current state as \"already sent\", so the next emit compared equal\n // and every EXISTING listener silently missed that update.\n this._stateKeys = { visibleRange: new Map(), replay: new Map() }\n\n this.layers = new Layers(container, ['base', 'main', 'overlay'])\n this.ts = new TimeScale(options.timeScale)\n this.ps = new PriceScale(options.priceScale)\n this.live = new LiveCandle()\n this.live.enabled = this.options.animate !== false\n this.inertia = new Inertia()\n\n this.cursor = null\n this.plot = { x: 0, y: 0, w: 1, h: 1 }\n\n this.loop = new Loop((dirty, dt) => this._frame(dirty, dt))\n this.layers.onResize = () => {\n this._layout()\n this.loop.invalidate('all')\n }\n\n this._layout()\n this._bindEvents()\n this.loop.start()\n }\n\n // ---------------------------------------------------------------- layout --\n _layout() {\n const { width, height } = this.layers\n const w = Math.max(1, width - this.theme.priceAxisWidth)\n const h = Math.max(1, height - this.theme.timeAxisHeight)\n this.plot = { x: 0, y: 0, w, h }\n this.ts.resize(w)\n this.ps.layout(0, h)\n }\n\n // ------------------------------------------------------------------ data --\n setData(bars) {\n // New data means the dataset being replayed no longer exists.\n if (this._replay) {\n this._replay.detach()\n this._replay = null\n }\n this.bars = Array.isArray(bars) ? bars.slice() : []\n this._exhausted = false\n this._historyErrors = 0\n this._resolveKey = '' // new bars, so every marker index must re-resolve\n if (this.bars.length > 1) {\n this.ts.timeframeMs = inferTimeframe(this.bars, this.ts.timeframeMs)\n }\n this.ts.setBarCount(this.bars.length)\n this.ts.snapToRealtime()\n this.live.reset()\n this.ps._primed = false\n this.loop.invalidate('all')\n }\n\n /**\n * Replace the bar array WITHOUT re-anchoring the view — the deliberate\n * difference from setData(), which snaps to the right edge and re-primes\n * the price scale. Replay swaps its revealed prefix through here on every\n * scrub, so a snap would fight the user's zoom and the price scale would\n * pop instead of easing between windows.\n */\n _swapBars(bars) {\n this.bars = Array.isArray(bars) ? bars : []\n if (this.bars.length > 1) {\n this.ts.timeframeMs = inferTimeframe(this.bars, this.ts.timeframeMs)\n }\n this.ts.setBarCount(this.bars.length)\n this.live.reset()\n this._resolveKey = '' // the prefix changed length: every index re-resolves\n this.loop.invalidate('all')\n }\n\n /** Merge a tick into the forming candle (animated). */\n update(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && this.bars[n - 1].time === bar.time) {\n this.bars[n - 1] = bar\n } else {\n this.append(bar)\n return\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n /**\n * Open a new candle; the previous one is now closed.\n *\n * A bar OLDER than the newest one is dropped rather than applied. It used\n * to overwrite the last element — so a late tick silently deleted the\n * newest candle and left a duplicate timestamp behind, which breaks the\n * ascending-by-time invariant that marker resolution's binary search\n * depends on. Feeds are documented as ascending and de-duplicated\n * (data/DataFeed.js); this is the guard for the ones that are not.\n */\n append(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && bar.time < this.bars[n - 1].time) return\n // Equal timestamps ARE a replace: that is an idempotent re-send of the\n // forming candle, which is the common case on a chatty feed.\n if (n && bar.time === this.bars[n - 1].time) {\n this.bars[n - 1] = bar\n } else {\n this.bars.push(bar)\n this.ts.setBarCount(this.bars.length)\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n async setFeed(feed) {\n this.detachFeed()\n this.feed = feed\n if (!feed) return\n const gen = ++this._feedGen\n this.ts.timeframeMs = feed.timeframe || this.ts.timeframeMs\n let bars\n try {\n bars = await feed.getBars({\n symbol: feed.symbol,\n timeframe: feed.timeframe,\n to: null,\n limit: this.options.initialBars || 1500,\n })\n } catch (err) {\n if (gen !== this._feedGen || this._destroyed) return\n this._emitError(err, 'setFeed')\n return\n }\n // Another setFeed(), a detachFeed() or a destroy() landed while we were\n // awaiting: this result belongs to a chart state that no longer exists.\n if (gen !== this._feedGen || this._destroyed) return\n this.setData(bars)\n // Read back the SANITISED array rather than the raw return value:\n // setData() has already coerced a non-array to [], and prime() is\n // documented as taking Bar | undefined.\n if (typeof feed.prime === 'function') feed.prime(this.bars[this.bars.length - 1])\n this._unsub = feed.subscribe((msg) => {\n if (!msg || !msg.bar) return\n // A subscription that outlived its generation must never write bars —\n // two feeds on one timeframe otherwise target the same forming candle.\n if (gen !== this._feedGen || this._destroyed) return\n // During replay the feed is the FUTURE arriving: let it run, ignore it.\n if (this._replay) return\n if (msg.type === 'append') this.append(msg.bar)\n else this.update(msg.bar)\n })\n }\n\n detachFeed() {\n // Bumping the generation is what cancels in-flight work: neither\n // getBars() promise can be aborted, so instead they resolve into no-ops.\n this._feedGen++\n this._loadingHistory = false\n this._historyErrors = 0\n if (this._unsub) this._unsub()\n this._unsub = null\n this.feed = null\n }\n\n async _maybeLoadHistory() {\n // Replay owns the bar array; a page prepended underneath it would\n // renumber the cursor mid-playback.\n if (this._replay) return\n if (this._loadingHistory || this._exhausted || !this.feed) return\n const { from } = this.ts.visibleRange()\n if (from > 80 || !this.bars.length) return\n\n this._loadingHistory = true\n // Bind this page to the feed that asked for it. Everything after the await\n // must prove it still belongs to that feed before touching shared state —\n // including _exhausted, which a stale page could otherwise latch on a\n // fresh symbol that still has years of history.\n const gen = this._feedGen\n const feed = this.feed\n try {\n const older = await feed.getBars({\n symbol: feed.symbol,\n timeframe: feed.timeframe,\n to: this.bars[0].time,\n limit: 1000,\n })\n if (gen !== this._feedGen || this._destroyed) return\n if (!this.bars.length) return\n if (!older || !older.length) {\n this._exhausted = true\n return\n }\n // Re-read the boundary AFTER the await. Filtering against the stale\n // pre-await value can splice a page into the middle of the array and\n // break the ascending-by-time invariant that nearestIndex()'s binary\n // search and the candle draw order both depend on.\n const boundary = this.bars[0].time\n const added = older.filter((b) => b.time < boundary)\n if (!added.length) {\n this._exhausted = true\n return\n }\n this._historyErrors = 0\n this.bars = added.concat(this.bars)\n // Keep the view pinned to the same bars: every index shifted right.\n // Smoothed.jump() writes BOTH value and target, so it alone pins the\n // view. The set() that used to follow re-read the already-shifted\n // target and added the page size a SECOND time, easing the viewport\n // past the newest bar — which pushed `from` above the 80-bar threshold\n // and disabled lazy paging permanently.\n this.ts.barCount = this.bars.length\n this.ts._right.jump(this.ts._right.value + added.length)\n this.loop.invalidate('all')\n } catch (err) {\n if (gen !== this._feedGen || this._destroyed) return\n // Retry on the next pan; latch only once the feed looks properly dead.\n if (++this._historyErrors >= MAX_HISTORY_ERRORS) this._exhausted = true\n this._emitError(err, 'loadHistory')\n } finally {\n // Only the generation that owns the latch may release it, or a stale\n // request finishing late would unlock a load already in progress.\n if (gen === this._feedGen) this._loadingHistory = false\n }\n }\n\n /**\n * Feed failures are delivered as an 'error' event so an adapter can react.\n * With no subscriber they still reach the console rather than vanishing.\n */\n _emitError(err, phase) {\n const set = this._listeners.error\n if (!set.size) {\n console.error(`[Emberwick] ${phase} failed`, err)\n return\n }\n for (const fn of set) fn(err)\n }\n\n // ---------------------------------------------------------------- events --\n _bindEvents() {\n const el = this.container\n el.style.touchAction = 'none'\n el.style.cursor = 'crosshair'\n\n let dragging = false\n let mode = null\n let lastX = 0\n let lastY = 0\n let lastT = 0\n let moved = false\n const pointers = new Map()\n let pinchDist = 0\n\n const localPos = (e) => {\n const r = el.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n }\n\n this._onDown = (e) => {\n pointers.set(e.pointerId, localPos(e))\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n pinchDist = Math.hypot(a.x - b.x, a.y - b.y)\n dragging = false\n return\n }\n const p = localPos(e)\n dragging = true\n moved = false\n mode = p.x > this.plot.w ? 'price' : p.y > this.plot.h ? 'time' : 'pan'\n lastX = p.x\n lastY = p.y\n lastT = performance.now()\n this.inertia.stop()\n el.setPointerCapture(e.pointerId)\n }\n\n this._onMove = (e) => {\n const p = localPos(e)\n if (pointers.has(e.pointerId)) pointers.set(e.pointerId, p)\n\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n const d = Math.hypot(a.x - b.x, a.y - b.y)\n if (pinchDist > 0 && d > 0) {\n const mid = (a.x + b.x) / 2\n this.ts.zoomAt(mid, d / pinchDist)\n this.loop.invalidate('all')\n }\n pinchDist = d\n return\n }\n\n this.cursor = p\n this._emitCrosshair(p)\n this.loop.invalidate('overlay')\n\n if (!dragging) return\n const now = performance.now()\n const dt = now - lastT\n const dx = p.x - lastX\n const dy = p.y - lastY\n if (Math.abs(dx) > 1 || Math.abs(dy) > 1) moved = true\n\n if (mode === 'pan') {\n this.ts.panBy(dx)\n this.inertia.sample(dx, dt)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n } else if (mode === 'price') {\n this.ps.scaleBy(1 + dy / 220)\n this.loop.invalidate('all')\n } else if (mode === 'time') {\n this.ts.zoomAt(this.plot.w, 1 - dx / 260)\n this.loop.invalidate('all')\n }\n\n lastX = p.x\n lastY = p.y\n lastT = now\n }\n\n this._onUp = (e) => {\n pointers.delete(e.pointerId)\n if (pointers.size < 2) pinchDist = 0\n if (dragging && mode === 'pan' && moved) {\n this.inertia.release()\n this.loop.invalidate('all')\n }\n dragging = false\n mode = null\n try { el.releasePointerCapture(e.pointerId) } catch (_) {}\n }\n\n this._onLeave = () => {\n this.cursor = null\n this._emitCrosshair(null)\n this.loop.invalidate('overlay')\n }\n\n this._onWheel = (e) => {\n e.preventDefault()\n const r = el.getBoundingClientRect()\n const x = e.clientX - r.left\n const factor = Math.pow(0.999, e.deltaY)\n this.ts.zoomAt(x, factor)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n }\n\n this._onDbl = () => {\n this.ts.reset()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n this._onKey = (e) => {\n const step = e.shiftKey ? 120 : 40\n if (e.key === 'ArrowLeft') { this.ts.panBy(step); this.loop.invalidate('all'); this._maybeLoadHistory() }\n else if (e.key === 'ArrowRight') { this.ts.panBy(-step); this.loop.invalidate('all') }\n else if (e.key === '+' || e.key === '=') { this.ts.zoomAt(this.plot.w / 2, 1.2); this.loop.invalidate('all') }\n else if (e.key === '-' || e.key === '_') { this.ts.zoomAt(this.plot.w / 2, 0.8); this.loop.invalidate('all') }\n else return\n e.preventDefault()\n }\n\n this._onClick = (e) => {\n // `moved` is still set from the gesture that just ended — a pan that\n // happens to finish over a marker must not read as a click on it.\n if (moved) return\n if (!this._listeners.markerClick.size) return\n const p = localPos(e)\n const hit = this.markerAt(p.x, p.y)\n if (hit) for (const fn of this._listeners.markerClick) fn(hit)\n }\n\n el.addEventListener('click', this._onClick)\n el.addEventListener('pointerdown', this._onDown)\n el.addEventListener('pointermove', this._onMove)\n el.addEventListener('pointerup', this._onUp)\n el.addEventListener('pointercancel', this._onUp)\n el.addEventListener('pointerleave', this._onLeave)\n el.addEventListener('wheel', this._onWheel, { passive: false })\n el.addEventListener('dblclick', this._onDbl)\n el.addEventListener('keydown', this._onKey)\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '0')\n }\n\n _emitCrosshair(p) {\n if (this._listeners.crosshair.size) {\n let payload = null\n if (p && this.bars.length && p.x <= this.plot.w && p.y <= this.plot.h) {\n const i = Math.round(this.ts.index(p.x))\n const bar = this.bars[i]\n if (bar) payload = { index: i, bar, price: this.ps.price(p.y) }\n }\n for (const fn of this._listeners.crosshair) fn(payload)\n }\n this._updateHover(p)\n }\n\n /**\n * Topmost marker whose hit circle contains the point, else null.\n * Hit circles come from the last render, so this costs nothing but a loop.\n */\n markerAt(x, y) {\n const hits = this._markerHits\n for (let i = hits.length - 1; i >= 0; i--) {\n const h = hits[i]\n const dx = x - h.x\n const dy = y - h.y\n if (dx * dx + dy * dy <= h.r * h.r) return h.marker\n }\n return null\n }\n\n _updateHover(p) {\n const hit = p ? this.markerAt(p.x, p.y) : null\n const id = hit ? hit.id : null\n if (id === this._hoverMarkerId) return\n this._hoverMarkerId = id\n this.container.style.cursor = hit ? 'pointer' : 'crosshair'\n // the hover ring is drawn with the markers, so that layer must repaint\n this.loop.invalidate('main')\n for (const fn of this._listeners.markerHover) fn(hit)\n }\n\n subscribe(event, fn) {\n const set = this._listeners[event]\n if (!set) throw new Error(`Chart: unknown event \"${event}\"`)\n set.add(fn)\n // 'visibleRange' is a state event, not a notification: a new subscriber is\n // told the CURRENT window straight away, so it never has to wait for the\n // user to pan before it knows what is on screen.\n if (event === 'visibleRange') {\n const payload = this.visibleRange()\n this._stateKeys.visibleRange.set(fn, this._rangeIdentity(payload))\n fn(payload)\n }\n // 'replay' is a state event for the same reason: a transport UI can render\n // itself from the first call instead of waiting for the first tick.\n if (event === 'replay') {\n const payload = this.replayState()\n this._stateKeys.replay.set(fn, this._replayIdentity(payload))\n fn(payload)\n }\n return () => {\n set.delete(fn)\n const keys = this._stateKeys[event]\n if (keys) keys.delete(fn)\n }\n }\n\n // ------------------------------------------------------------------ range --\n /**\n * The window currently on screen. Cheap enough to poll, though\n * subscribe('visibleRange', fn) is the better way to track it.\n */\n visibleRange() {\n const { from, to } = this.ts.visibleRange()\n return this._rangePayload(from, to)\n }\n\n _rangePayload(from, to) {\n const n = this.bars.length\n return {\n from,\n to,\n fromTime: n ? this.bars[from].time : null,\n toTime: n ? this.bars[to].time : null,\n barCount: n,\n spacing: this.ts.spacing,\n settled: this.ts.settled,\n }\n }\n\n _rangeIdentity(p) {\n return `${p.from}:${p.to}:${p.fromTime}:${p.toTime}:${p.settled ? 1 : 0}`\n }\n\n /**\n * Fires only when the window actually changed, so a consumer can hang a\n * fetch off it without debouncing. Two deliberate choices:\n *\n * - `spacing` is NOT part of the identity. It is a float that moves on every\n * frame of an eased zoom, so keying on it would make this a 60/sec\n * firehose. It is still reported, for level-of-detail decisions.\n * - `settled` IS part of the identity, so the final event of a gesture\n * always arrives with settled:true. Without it, code that defers expensive\n * work until the view stops moving would wait forever.\n */\n _emitVisibleRange(from, to) {\n this._emitState('visibleRange', this._rangePayload(from, to), this._rangeIdentity)\n }\n\n /**\n * Deliver a state event to every listener that has not already seen this\n * exact state. Keys are per-listener, so one subscriber can never suppress\n * another's update, and a brand-new listener (no key yet) always gets one.\n */\n _emitState(event, payload, identity) {\n const set = this._listeners[event]\n if (!set.size) return\n const key = identity.call(this, payload)\n const keys = this._stateKeys[event]\n for (const fn of set) {\n if (keys.get(fn) === key) continue\n keys.set(fn, key)\n fn(payload)\n }\n }\n\n // ----------------------------------------------------------------- replay --\n /**\n * Start bar-by-bar playback over a fixed dataset.\n *\n * With no `bars`, the chart's CURRENT data becomes the dataset — the usual\n * case: load history, then replay it. The chart is not switched into a\n * special mode; it is simply handed the revealed prefix, so scales,\n * annotations, the crosshair and visibleRange all keep behaving normally.\n *\n * chart.startReplay({ from: 200, speed: 4 })\n * chart.replay.play()\n *\n * @param {object} [options]\n * @param {Bar[]} [options.bars] dataset (defaults to current bars)\n * @param {number} [options.from] starting index (default: midpoint)\n * @param {number} [options.speed] rate multiplier, 0.25–500\n * @param {number} [options.baseInterval] real ms per bar at 1× (default 1000)\n * @param {boolean} [options.loop] restart at the end\n * @param {boolean} [options.follow] re-anchor the right edge on scrub\n * @returns {Replay|null} null if there are fewer than two bars to replay\n */\n startReplay(options = {}) {\n const source =\n Array.isArray(options.bars) && options.bars.length\n ? options.bars\n : this._replay\n ? this._replay.source\n : this.bars\n if (!source || source.length < 2) return null\n // Snapshot BEFORE the controller starts swapping prefixes in, otherwise\n // the dataset would be the live array it is about to shorten.\n const dataset = source.slice()\n // The caller still holds whatever the previous startReplay() returned;\n // without detaching, its transport methods keep driving this chart.\n if (this._replay) this._replay.detach()\n this._replay = new Replay(this, { ...options, bars: dataset })\n return this._replay\n }\n\n /** Leave replay and reveal the whole dataset again. */\n stopReplay() {\n if (!this._replay) return\n const full = this._replay.source\n this._replay.detach()\n this._replay = null\n this.setData(full) // snaps back to the right edge, like any fresh data\n }\n\n /** The active controller, or null. */\n get replay() {\n return this._replay\n }\n\n /** Current playback state; `{ active: false, ... }` when not replaying. */\n replayState() {\n return this._replay ? this._replay.state() : inactiveReplay()\n }\n\n _replayIdentity(p) {\n return `${p.active ? 1 : 0}:${p.playing ? 1 : 0}:${p.index}:${p.length}:${p.speed}`\n }\n\n /**\n * Emitted from the frame, like visibleRange, so a handler can safely touch\n * the chart. Keyed on cursor + transport, not on the payload object, so a\n * paused replay emits nothing at all.\n */\n _emitReplay() {\n this._emitState('replay', this.replayState(), this._replayIdentity)\n }\n\n // ----------------------------------------------------------- annotations --\n /** Replace every marker. Each `time` is resolved to its nearest bar. */\n setMarkers(markers) {\n this._markers = normalizeMarkers(markers)\n this._resolveKey = '' // force re-resolution on the next frame\n if (this._replay) this._replay.invalidateMarkers()\n this.loop.invalidate('main')\n }\n\n /** The current markers, normalised, each with its resolved bar index. */\n getMarkers() {\n return this._markers.slice()\n }\n\n addMarker(marker) {\n this.setMarkers(this._markers.concat([marker]))\n }\n\n removeMarker(id) {\n const key = String(id)\n this.setMarkers(this._markers.filter((m) => m.id !== key))\n }\n\n clearMarkers() {\n this.setMarkers([])\n }\n\n /** Horizontal lines — entries, stops, targets, alerts. */\n setPriceLines(lines) {\n this.priceLines = Array.isArray(lines) ? lines.slice() : []\n this.loop.invalidate('main')\n }\n\n /** Shaded regions: a price band ({from,to}) or a time band ({fromTime,toTime}). */\n setZones(zones) {\n this.zones = Array.isArray(zones) ? zones.slice() : []\n this.loop.invalidate('all')\n }\n\n // ----------------------------------------------------------------- frame --\n _frame(dirty, dt) {\n let animating = false\n\n // First: replay may append or swap bars, and everything below reads them.\n // It returns true while playing, which both keeps the loop awake and\n // forces the full redraw the newly revealed bar needs.\n if (this._replay && this._replay.tick(dt)) animating = true\n\n if (this.ts.tick(dt)) animating = true\n\n const dx = this.inertia.tick(dt)\n if (dx) {\n this.ts.panBy(dx)\n animating = true\n this._maybeLoadHistory()\n }\n\n if (this.live.tick(dt)) animating = true\n\n const { from, to } = this.ts.visibleRange()\n const lastIdx = this.bars.length - 1\n const liveBar = this.bars.length ? this.live.read(this.bars[lastIdx]) : null\n const liveVisible = liveBar && to >= lastIdx ? liveBar : null\n\n this.ps.fit(this.bars, from, to, liveVisible)\n if (this.ps.tick(dt)) animating = true\n\n const redrawAll = animating || dirty.has('all') || dirty.has('base') || dirty.has('main')\n const state = {\n theme: this.theme,\n ts: this.ts,\n ps: this.ps,\n plot: this.plot,\n bars: this.bars,\n width: this.layers.width,\n height: this.layers.height,\n live: liveVisible,\n volumeRatio: this.options.volumeRatio,\n cursor: this.cursor,\n magnet: this.options.magnet,\n priceLines: this.priceLines,\n zones: this.zones,\n }\n\n // Markers past the replay cursor are future information — hidden, not\n // clamped, because time→index resolution snaps to the NEAREST bar and\n // would otherwise pile them all onto the newest revealed candle.\n let markers = this._markers\n if (this._replay && markers.length) markers = this._replay.markerFilter(markers)\n\n // Marker indices only go stale when the bar array shifts: a prepended\n // history page renumbers every bar, an append does not.\n if (markers.length) {\n const key =\n markers.length + ':' + this.bars.length + ':' + (this.bars.length ? this.bars[0].time : 0)\n if (key !== this._resolveKey) {\n // One timeframe of slack: a marker further outside the loaded range\n // than that resolves to -1 and is hidden, rather than clamping onto\n // the first or last bar as if it happened there.\n resolveMarkers(markers, this.bars, this.ts.timeframeMs)\n this._resolveKey = key\n }\n }\n\n if (redrawAll) {\n drawGrid(this.layers.ctx.base, state)\n drawZones(this.layers.ctx.base, state)\n drawCandles(this.layers.ctx.main, state)\n drawPriceLines(this.layers.ctx.main, state)\n this._markerHits = drawMarkers(\n this.layers.ctx.main,\n state,\n layoutMarkers(markers, state),\n this._hoverMarkerId,\n )\n }\n if (redrawAll || dirty.has('overlay')) {\n drawCrosshair(this.layers.ctx.overlay, state)\n }\n\n // Emitted after drawing, deliberately: a handler is free to call\n // setData() or setMarkers(), and by this point the renderers have\n // finished reading the state it would mutate.\n this._emitVisibleRange(from, to)\n this._emitReplay()\n\n return animating\n }\n\n // ------------------------------------------------------------------- api --\n get fps() { return this.loop.fps }\n\n setTheme(theme) {\n this.theme = { ...this.theme, ...theme }\n this._layout()\n this.loop.invalidate('all')\n }\n\n setPriceMode(mode) {\n this.ps.setMode(mode)\n this.loop.invalidate('all')\n }\n\n setAnimate(on) {\n this.live.enabled = !!on\n this.loop.invalidate('all')\n }\n\n setMagnet(on) {\n this.options.magnet = !!on\n this.loop.invalidate('overlay')\n }\n\n snapToRealtime() {\n this.ts.snapToRealtime()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n toImage() {\n return this.layers.composite().toDataURL('image/png')\n }\n\n destroy() {\n // Idempotent: Layers.destroy() throws on an already-emptied canvas map,\n // and both framework adapters can unmount twice (React StrictMode).\n if (this._destroyed) return\n this._destroyed = true\n const el = this.container\n el.removeEventListener('pointerdown', this._onDown)\n el.removeEventListener('pointermove', this._onMove)\n el.removeEventListener('pointerup', this._onUp)\n el.removeEventListener('pointercancel', this._onUp)\n el.removeEventListener('pointerleave', this._onLeave)\n el.removeEventListener('wheel', this._onWheel)\n el.removeEventListener('dblclick', this._onDbl)\n el.removeEventListener('keydown', this._onKey)\n el.removeEventListener('click', this._onClick)\n this.detachFeed()\n this.loop.stop()\n this.layers.destroy()\n for (const set of Object.values(this._listeners)) set.clear()\n for (const keys of Object.values(this._stateKeys)) keys.clear()\n if (this._replay) this._replay.detach()\n this._replay = null\n this._markers = []\n this._markerHits = []\n this.priceLines = []\n this.zones = []\n this.bars = []\n }\n}\n\n","/**\n * DataFeed — THE seam of this library.\n *\n * The chart core never knows where bars come from. Anything that implements\n * this interface can drive it: a REST endpoint, a WebSocket, a Lambda behind\n * API Gateway, a CSV in memory, or the bundled RandomFeed.\n *\n * Bar shape (the only contract that matters):\n * { time: number (ms epoch), open, high, low, close, volume }\n * Bars MUST be ascending by time and de-duplicated by the feed.\n *\n * Implement:\n * getBars({ symbol, timeframe, to, limit }) -> Promise<Bar[]>\n * Historical bars ENDING at `to` (exclusive). Return [] when exhausted;\n * the chart stops asking for more history once it sees an empty page.\n * subscribe(handler) -> unsubscribe fn\n * handler({ type: 'update'|'append', bar }) where\n * 'update' = the forming candle changed (animates)\n * 'append' = a new candle opened (previous one is now closed)\n */\nexport class DataFeed {\n constructor({ symbol = 'DEMO', timeframe = 60000 } = {}) {\n this.symbol = symbol\n this.timeframe = timeframe\n }\n\n // eslint-disable-next-line no-unused-vars\n async getBars({ symbol, timeframe, to, limit }) {\n throw new Error('DataFeed.getBars() not implemented')\n }\n\n // eslint-disable-next-line no-unused-vars\n subscribe(handler) {\n return () => {}\n }\n\n destroy() {}\n}\n\n/** Deterministic PRNG so a given seed always renders the same chart. */\nexport function mulberry32(seed) {\n let a = seed >>> 0\n return function () {\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { DataFeed, mulberry32 } from './DataFeed.js'\n\n/**\n * RandomFeed — a plausible synthetic market. One implementation of DataFeed,\n * nothing more: swapping in a real provider is writing another class, with\n * zero changes to the chart core.\n *\n * Generates a GBM-ish random walk with volatility clustering and a volume\n * profile, then drives a live forming candle from sub-bar ticks.\n */\nexport class RandomFeed extends DataFeed {\n constructor({\n symbol = 'EMBR',\n timeframe = 60000,\n seed = 7,\n start = 100,\n volatility = 0.0022,\n drift = 0.00002,\n ticksPerSecond = 8,\n speed = 1,\n } = {}) {\n super({ symbol, timeframe })\n this.seed = seed\n this.start = start\n this.volatility = volatility\n this.drift = drift\n this.ticksPerSecond = ticksPerSecond\n this.speed = speed\n\n this._rnd = mulberry32(seed)\n this._handlers = new Set()\n this._timer = null\n this._forming = null\n this._last = start\n this._vol = volatility\n this._anchorTime = Math.floor(Date.now() / timeframe) * timeframe\n }\n\n _gauss() {\n // Box-Muller\n let u = 0\n let v = 0\n while (u === 0) u = this._rnd()\n while (v === 0) v = this._rnd()\n return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v)\n }\n\n _step(price) {\n // volatility clusters: vol mean-reverts but gets kicked by shocks\n const shock = this._gauss()\n this._vol += (this.volatility - this._vol) * 0.02 + Math.abs(shock) * this.volatility * 0.015\n this._vol = Math.min(this._vol, this.volatility * 6)\n return Math.max(0.01, price * (1 + this.drift + shock * this._vol))\n }\n\n _makeBar(time, open) {\n let c = open\n const n = 14\n let hi = open\n let lo = open\n for (let i = 0; i < n; i++) {\n c = this._step(c)\n if (c > hi) hi = c\n if (c < lo) lo = c\n }\n const range = Math.max(1e-9, hi - lo)\n const volume = Math.round(\n (300 + this._rnd() * 900) * (1 + (range / open) * 260)\n )\n return { time, open, high: hi, low: lo, close: c, volume }\n }\n\n /**\n * Historical bars ending just before `to`. Walks BACKWARDS from a synthetic\n * anchor, so paging further left keeps producing coherent history.\n */\n async getBars({ to, limit = 1500, timeframe = this.timeframe } = {}) {\n const end = to == null ? this._anchorTime : to\n const bars = []\n // generate forward from an earlier point for realistic shape, then slice\n const startTime = end - limit * timeframe\n const gen = mulberry32(this.seed ^ Math.floor(startTime / timeframe))\n const saved = this._rnd\n this._rnd = gen\n\n let price = this.start * (1 + (gen() - 0.5) * 0.04)\n for (let i = 0; i < limit; i++) {\n const t = startTime + i * timeframe\n const bar = this._makeBar(t, price)\n price = bar.close\n bars.push(bar)\n }\n this._rnd = saved\n\n if (to == null) {\n this._last = bars.length ? bars[bars.length - 1].close : this.start\n }\n return bars\n }\n\n subscribe(handler) {\n this._handlers.add(handler)\n if (!this._timer) this._start()\n return () => {\n this._handlers.delete(handler)\n if (!this._handlers.size) this.stop()\n }\n }\n\n _emit(msg) {\n for (const h of this._handlers) h(msg)\n }\n\n _start() {\n const interval = Math.max(16, 1000 / this.ticksPerSecond)\n this._timer = setInterval(() => this._tick(), interval)\n }\n\n /** Seed the live candle from wherever history ended. */\n prime(lastBar) {\n if (lastBar) {\n this._last = lastBar.close\n this._forming = { ...lastBar }\n }\n }\n\n _tick() {\n const tf = this.timeframe / this.speed\n const now = Date.now()\n const slot = Math.floor(now / tf) * tf\n\n if (!this._forming || this._forming.time !== slot) {\n const open = this._last\n this._forming = { time: slot, open, high: open, low: open, close: open, volume: 0 }\n this._emit({ type: 'append', bar: { ...this._forming } })\n return\n }\n\n const next = this._step(this._last)\n this._last = next\n const f = this._forming\n f.close = next\n if (next > f.high) f.high = next\n if (next < f.low) f.low = next\n f.volume += Math.round(20 + this._rnd() * 120)\n this._emit({ type: 'update', bar: { ...f } })\n }\n\n setSpeed(s) { this.speed = s }\n\n setTicksPerSecond(n) {\n this.ticksPerSecond = n\n if (this._timer) { this.stop(); this._start() }\n }\n\n setPaused(paused) {\n if (paused) this.stop()\n else if (!this._timer && this._handlers.size) this._start()\n }\n\n get paused() { return !this._timer }\n\n stop() {\n if (this._timer) clearInterval(this._timer)\n this._timer = null\n }\n\n destroy() {\n this.stop()\n this._handlers.clear()\n }\n}\n","/**\n * Emberwick — public API surface.\n *\n * This file is the future package entry point. Nothing below imports a\n * framework, so the same build drops into React, Vue, Svelte or a script tag.\n *\n * import { createChart, RandomFeed } from './chart/index.js'\n * const chart = createChart(el, { theme: { background: '#000' } })\n * await chart.setFeed(new RandomFeed({ timeframe: 60000 }))\n */\nexport { Chart } from './core/Chart.js'\nexport { TimeScale } from './core/TimeScale.js'\nexport { PriceScale } from './core/PriceScale.js'\nexport { defaultTheme, lightTheme } from './core/palette.js'\nexport { DataFeed, mulberry32 } from './data/DataFeed.js'\nexport { RandomFeed } from './data/RandomFeed.js'\nexport { Smoothed, Tween, easeOutCubic, easeInOutCubic } from './motion/Tween.js'\nexport { Inertia } from './motion/Inertia.js'\nexport { LiveCandle } from './motion/LiveCandle.js'\nexport { Replay, MIN_SPEED, MAX_SPEED } from './replay/Replay.js'\n\nimport { Chart } from './core/Chart.js'\n\n/** Preferred entry point. */\nexport function createChart(container, options) {\n return new Chart(container, options)\n}\n\nexport const version = '0.5.0'\n\n"],"names":["clamp","b"],"mappings":"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"}
|