minerva-design 1.6.1 → 1.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"heatmap.cjs","names":["toOklab","packColor","fromOklab","createOrderBookStore","createEmitter","createFormatters","HEAT_TABLE_SIZE","createHost","localeLabels","sideColors","luminance","oklabRamp","parseColor","heatTable","decimalsOf","inferPriceDecimals","inferSizeDecimals","inferTickSize","roundToStep","buildHeatGrid","percentile","ease","toCss","clamp","fontOf","mixOklab","fineCeil","fitTimeRange","fitPriceRange","linearTicks","timeTicks","formatClock","layoutAxisLabels","createHeatFieldRenderer","followDefaultRenderer","localPoint","require_color","require_locale","require_scale","require_follow","require_time","require_book","require_format","require_host","require_field","require_layout","LUT_SIZE","MAX_TEXELS","SCALE_QUANTILE","MIN_ROW_PX","DARK_RAMP","LIGHT_RAMP","TAG_HEIGHT","BUBBLE_SPACING","BUBBLE_SIZE","BUBBLE_MIN","positionedRamp","lut","size","stops","lab","c","i","k","t","p0","j","p1","f","a","b","rowBucket","tickPx","need","p","m","LABELS","heatIntensity","max","r","contrast","scale","createOrderBookHeatmap","options","initial","store","emitter","fmt","colors","table","floor","dark","tick","columns","seq","openStart","open","lastTrade","dataTime","dataWall","scaleMax","scaleTarget","scaleAt","bubbleRef","profileMax","grid","gridKey","paintKey","head","renderer","rendererToken","destroyed","resolveReady","ready","resolve","follow","windowSpan","viewX","viewY","viewYReady","yTarget","ySpan","shownTime","lastFrame","plot","hoverAt","hoverKey","drag","host","container","refreshColors","root","texts","labels","applyTexts","interval","history","depth","nowTime","elapsed","perfNow","theme","value","background","ramp","at","hex","refreshFormat","clearHistory","ensureTick","base","mid","ratio","multiple","sampleBook","limit","bins","sizes","n","side","count","rows","bin","closeColumn","column","start","oldest","drop","advance","time","step","noteTime","columnAt","lo","hi","headSource","version","heatGrid","live","maxWidth","maxHeight","rowBins","y1","y0","lastSeq","key","x0","x1","end","sources","fixed","now","target","dt","visibleColumns","out","tradeBubbles","columnPx","group","t0","t1","sum","flush","add","g","id","flow","visible","clipPlot","ctx","drawBest","steps","xs","xa","xOf","row","xb","run","flushRun","y","yOf","bid","ask","index","color","pen","price","drawBubbles","bubbles","x","ref","maxD","minD","sized","fontSize","rim","text","bookBuckets","buckets","lastBin","ry","drawProfile","rowPx","lowOf","highOf","maxSize","sides","levels","left","px","inner","profileW","gap","bar","top","bottom","w","s","best","tw","hoverCell","hx","hy","bucket","digits","low","high","rowPrice","drawTag","align","filled","draw","l","width","regular","bold","clock","dpr","height","sample","axisW","timeH","right","first","minSpan","floorCss","canvas","bw","bh","heat","sx","sy","rect","yTicks","xt","cell","hoverTime","hoverHalf","half","last","pins","shownPins","hoverY","layout","pin","drawHover","fresh","inBucket","bestBid","bestAsk","buyVolume","sellVolume","cx0","cx1","cy0","cy1","timeText","sideColor","doc","event","initRenderer","token","next","kind","exclude","unfollowDefault","setFollow","clampTime","range","span","onPointerDown","onPointerMove","dx","dy","tx","ty","onPointerUp","onPointerLeave","zoomTime","factor","anchorX","zoomPrice","onWheel","onDoubleClick","instance","onKeyDown","d","applyOne","delta","snapshot","deltas","list","trades","trade","previous","handler"],"sources":["../../../../../charts/src/engine/orderbook/heatmap.ts"],"sourcesContent":["// createOrderBookHeatmap: Bookmap-style liquidity heatmap. The book is\n// sampled every `interval` ms into a column of price rows; the visible\n// columns are rasterized into one image (a texel per column and price row,\n// see field.ts) drawn with nearest filtering by a WebGPU / WebGL / Canvas2D\n// backend over the cold end of the ramp: a continuous field without seams.\n// The best bid / ask step lines, the spread band, the trade bubbles, the\n// grid, the axes, the book profile, the crosshair and the tooltip are drawn\n// on a Canvas2D layer above.\n\nimport {\n fromOklab,\n luminance,\n mixOklab,\n oklabRamp,\n packColor,\n parseColor,\n toCss,\n toOklab,\n type Rgba,\n} from \"../color\";\nimport { followDefaultRenderer } from \"../renderers/follow\";\nimport { linearTicks } from \"../scale\";\nimport { timeTicks } from \"../time\";\nimport type { ChartRendererKind } from \"../types\";\nimport {\n createOrderBookStore,\n decimalsOf,\n inferPriceDecimals,\n inferSizeDecimals,\n inferTickSize,\n roundToStep,\n} from \"./book\";\nimport {\n clamp,\n createFormatters,\n ease,\n fontOf,\n formatClock,\n roundRect,\n sideColors,\n type Formatters,\n} from \"./format\";\nimport { localeLabels, type LabelDictionary } from \"../locale\";\nimport {\n HEAT_TABLE_SIZE,\n buildHeatGrid,\n createHeatFieldRenderer,\n heatTable,\n paintHeatGrid,\n percentile,\n type HeatFieldRenderer,\n type HeatGrid,\n type HeatSource,\n} from \"./field\";\nimport { createEmitter, createHost, localPoint, tooltipHtml } from \"./host\";\nimport {\n fineCeil,\n fitPriceRange,\n fitTimeRange,\n layoutAxisLabels,\n type AxisLabel,\n} from \"./layout\";\nimport type {\n OrderBookDelta,\n OrderBookHeatmapEventMap,\n OrderBookHeatmapHoverEvent,\n OrderBookHeatmapInstance,\n OrderBookHeatmapLabels,\n OrderBookHeatmapOptions,\n OrderBookHeatmapScale,\n OrderBookSide,\n MarketTrade,\n} from \"./types\";\n\n/** Colors of the ramp lookup table */\nconst LUT_SIZE = 256;\n/** Largest heat image (texels per side) */\nconst MAX_TEXELS = 4096;\n/**\n * Quantile of the visible (non-empty) cells at the hottest color (auto\n * scale): typical levels stay dark, only the top 1 % of the liquidity glows\n */\nconst SCALE_QUANTILE = 0.99;\n/** Thinnest price row on screen (CSS px); thinner rows are bucketed */\nconst MIN_ROW_PX = 2;\n\n/** A ramp color at a position (0-1) */\ntype RampStop = readonly [number, string];\n\n/**\n * Heat ramps (positioned stops, interpolated in OKLab, lightness rising\n * monotonically with the size); the first color is also the empty field.\n * Dark: a long dark segment close to the panel (thin liquidity stays dim),\n * then blue, cyan, yellow, orange and a white-hot end for the walls (the\n * Bookmap convention). Light: the mirror, near white to deep blue, violet\n * and crimson.\n */\nconst DARK_RAMP: readonly RampStop[] = [\n [0, \"#0b1322\"],\n [0.3, \"#0e1c36\"],\n [0.5, \"#11306a\"],\n [0.63, \"#1556a8\"],\n [0.74, \"#1b95c8\"],\n [0.83, \"#59d6d0\"],\n [0.9, \"#f2e14b\"],\n [0.96, \"#ff8c2b\"],\n [1, \"#fff6e8\"],\n];\nconst LIGHT_RAMP: readonly RampStop[] = [\n [0, \"#f7f9fc\"],\n [0.3, \"#eef3fa\"],\n [0.5, \"#d6e3f5\"],\n [0.63, \"#9dbde9\"],\n [0.74, \"#4f86d6\"],\n [0.85, \"#2f4fb0\"],\n [0.93, \"#6a2a9c\"],\n [1, \"#c4173f\"],\n];\n/** Height of the price tags of the axis, in pixels */\nconst TAG_HEIGHT = 16;\n/** Smallest distance between two trade bubbles' columns, in pixels */\nconst BUBBLE_SPACING = 6;\n/** Diameter of the largest trade bubble (default), in pixels */\nconst BUBBLE_SIZE = 14;\n/** Diameter of the smallest trade bubble, in pixels */\nconst BUBBLE_MIN = 3;\n\n/**\n * Lookup table of a ramp with positioned stops (`[position 0-1, color]`,\n * ascending), interpolated in OKLab\n */\nexport const positionedRamp = (\n stops: readonly (readonly [number, Rgba])[],\n size = LUT_SIZE,\n): Uint32Array => {\n const lut = new Uint32Array(size);\n if (!stops.length) return lut;\n const lab = stops.map(([, c]) => toOklab(c));\n let i = 0;\n for (let k = 0; k < size; k++) {\n const t = k / Math.max(1, size - 1);\n while (i + 1 < stops.length - 1 && t > stops[i + 1]![0]) i++;\n const [p0] = stops[i]!;\n const j = Math.min(stops.length - 1, i + 1);\n const [p1] = stops[j]!;\n const f = p1 > p0 ? Math.min(1, Math.max(0, (t - p0) / (p1 - p0))) : 0;\n const a = lab[i]!;\n const b = lab[j]!;\n lut[k] = packColor(\n fromOklab([\n a[0] + (b[0] - a[0]) * f,\n a[1] + (b[1] - a[1]) * f,\n a[2] + (b[2] - a[2]) * f,\n 1,\n ]),\n );\n }\n return lut;\n};\n\n/**\n * Rows (ticks) per drawn price row: 1 while a tick is at least 2 px tall,\n * otherwise the smallest 1 / 2 / 5 × 10ⁿ bucket that is (Bookmap sums the\n * sizes within a price bucket)\n */\nexport const rowBucket = (tickPx: number): number => {\n if (!(tickPx > 0) || tickPx >= MIN_ROW_PX) return 1;\n const need = MIN_ROW_PX / tickPx;\n for (let p = 1; p < 1e12; p *= 10) {\n for (const m of [1, 2, 5]) if (m * p >= need) return m * p;\n }\n return 1;\n};\n\nconst LABELS: LabelDictionary<OrderBookHeatmapLabels> = {\n en: {\n time: \"Time\",\n price: \"Price\",\n liquidity: \"Liquidity\",\n buys: \"Buys\",\n sells: \"Sells\",\n bid: \"Bid\",\n ask: \"Ask\",\n bidSide: \"Bid side\",\n askSide: \"Ask side\",\n name: \"Liquidity heatmap\",\n },\n zh: {\n time: \"时间\",\n price: \"价格\",\n liquidity: \"挂单量\",\n buys: \"主动买入\",\n sells: \"主动卖出\",\n bid: \"买一\",\n ask: \"卖一\",\n bidSide: \"买盘\",\n askSide: \"卖盘\",\n name: \"订单簿热力图\",\n },\n ja: {\n time: \"時刻\",\n price: \"価格\",\n liquidity: \"指値量\",\n buys: \"買い約定\",\n sells: \"売り約定\",\n bid: \"最良買気配\",\n ask: \"最良売気配\",\n bidSide: \"買い板\",\n askSide: \"売り板\",\n name: \"板ヒートマップ\",\n },\n fr: {\n time: \"Heure\",\n price: \"Prix\",\n liquidity: \"Liquidité\",\n buys: \"Achats\",\n sells: \"Ventes\",\n bid: \"Meilleur achat\",\n ask: \"Meilleure vente\",\n bidSide: \"Côté achat\",\n askSide: \"Côté vente\",\n name: \"Carte de chaleur de la liquidité\",\n },\n};\n\ninterface Column extends HeatSource {\n /** Sequence number */\n seq: number;\n /** Start time */\n time: number;\n /** Price rows (price / tick, rounded) */\n bins: Float64Array;\n sizes: Float32Array;\n bestBid: number;\n bestAsk: number;\n buyVolume: number;\n buyNotional: number;\n sellVolume: number;\n sellNotional: number;\n}\n\n/** Normalized intensity (0-1) of a size */\nexport const heatIntensity = (\n size: number,\n max: number,\n scale: OrderBookHeatmapScale,\n contrast: number,\n): number => {\n if (!(size > 0) || !(max > 0)) return 0;\n const r = Math.min(1, (size * contrast) / max);\n switch (scale) {\n case \"linear\":\n return r;\n case \"log\":\n // one decade: a tenth of the hottest size is a fifth of the ramp\n return Math.log10(1 + 9 * r);\n default:\n return Math.sqrt(r);\n }\n};\n\n/**\n * Creates a liquidity heatmap in `container`: resting size over time and\n * price on the GPU, trades as bubbles, best bid / ask lines, the current\n * book profile, zoom / pan and a crosshair tooltip.\n */\nexport const createOrderBookHeatmap = (\n container: HTMLElement,\n initial: OrderBookHeatmapOptions = {},\n): OrderBookHeatmapInstance => {\n let options = initial;\n const store = createOrderBookStore();\n const emitter = createEmitter<OrderBookHeatmapEventMap>();\n let fmt: Formatters = createFormatters(options, 2, 4);\n let colors = { up: [0, 0, 0, 1] as Rgba, down: [0, 0, 0, 1] as Rgba };\n let lut: Uint32Array = new Uint32Array(LUT_SIZE);\n /** Size → color table of the current ramp and color scale */\n let table: Uint32Array = new Uint32Array(HEAT_TABLE_SIZE + 1);\n /** The empty field: the cold end of the ramp */\n let floor: Rgba = [0, 0, 0, 1];\n let dark = false;\n\n let tick = 0;\n let columns: Column[] = [];\n let seq = 0;\n /** Start of the open column (the live book), NaN before the first data */\n let openStart = NaN;\n const open = { buyVolume: 0, buyNotional: 0, sellVolume: 0, sellNotional: 0 };\n let lastTrade: MarketTrade | null = null;\n\n /** Time source: exchange times once any is given, the local clock otherwise */\n let dataTime = NaN;\n let dataWall = 0;\n\n /** Size at the hottest color (auto scale, eased) and its target */\n let scaleMax = 0;\n let scaleTarget = 0;\n let scaleAt = -Infinity;\n let bubbleRef = 0;\n /** Size at the full width of the profile */\n let profileMax = 0;\n /** The rasterized field and the inputs it was built from */\n let grid: HeatGrid | null = null;\n let gridKey = \"\";\n let paintKey = \"\";\n /** The live book as a column, cached by store version */\n let head: {\n version: number;\n bins: Float64Array;\n sizes: Float32Array;\n } | null = null;\n\n let renderer: HeatFieldRenderer | null = null;\n let rendererToken = 0;\n let destroyed = false;\n let resolveReady: (kind: ChartRendererKind | null) => void = () => {};\n const ready = new Promise<ChartRendererKind | null>((resolve) => {\n resolveReady = resolve;\n });\n\n /** View: time range and price range; follows the market unless panned */\n let follow = true;\n let windowSpan = NaN;\n let viewX: [number, number] = [0, 1];\n let viewY: [number, number] = [0, 1];\n /** `viewY` holds a fitted range (it eases toward `yTarget` afterwards) */\n let viewYReady = false;\n /** Price range the following view eases to */\n let yTarget: [number, number] | null = null;\n /** Price span chosen by the user (zoom), NaN for the auto fit */\n let ySpan = NaN;\n /** Monotonic clock of the view (no jitter back when data arrives) */\n let shownTime = NaN;\n let lastFrame = 0;\n let plot = { x: 0, y: 0, w: 0, h: 0 };\n let hoverAt: [number, number] | null = null;\n let hoverKey = \"\";\n let drag: {\n x: number;\n y: number;\n viewX: [number, number];\n viewY: [number, number];\n axis: boolean;\n span: number;\n } | null = null;\n\n const host = createHost(container, {\n className: \"minerva-orderbook-heatmap\",\n draw,\n onTheme: () => {\n refreshColors();\n host.invalidate();\n },\n });\n const { root, doc } = host;\n root.tabIndex = 0;\n root.setAttribute(\"role\", \"figure\");\n root.style.touchAction = \"none\";\n\n /** Texts in the locale, resolved on every option update */\n let texts = localeLabels(LABELS, options.locale, options.labels);\n const labels = () => texts;\n const applyTexts = () => {\n texts = localeLabels(LABELS, options.locale, options.labels);\n root.setAttribute(\"aria-label\", options.ariaLabel ?? texts.name);\n };\n const interval = () => Math.max(10, options.interval ?? 100);\n const history = () => Math.max(interval() * 4, options.history ?? 300_000);\n const depth = () => Math.max(4, Math.round(options.depth ?? 160));\n const nowTime = () => {\n if (!Number.isFinite(dataTime)) return Date.now();\n const elapsed = perfNow() - dataWall;\n return dataTime + Math.min(Math.max(0, elapsed), interval() * 3);\n };\n const perfNow = () =>\n typeof performance !== \"undefined\" ? performance.now() : Date.now();\n\n function refreshColors() {\n const theme = host.theme;\n colors = sideColors(theme, options);\n const resolve = (value: string) => {\n const c = theme.resolve\n ? theme.resolve(value, theme.primary)\n : theme.primary;\n return [c[0], c[1], c[2], 1] as Rgba;\n };\n const background: Rgba = [\n theme.background[0],\n theme.background[1],\n theme.background[2],\n 1,\n ];\n dark = theme.background[3] > 0 ? luminance(background) < 0.4 : false;\n if (options.colors?.length) {\n const ramp = options.colors.map(resolve);\n // the field is opaque: the empty color is the cold end of the ramp\n floor = ramp[0] ?? background;\n lut = oklabRamp(ramp.length > 1 ? ramp : [floor, floor], LUT_SIZE);\n } else {\n const stops = (dark ? DARK_RAMP : LIGHT_RAMP).map(\n ([at, hex]) => [at, parseColor(hex) ?? background] as const,\n );\n floor = stops[0]![1];\n lut = positionedRamp(stops, LUT_SIZE);\n }\n const scale = options.colorScale ?? \"sqrt\";\n table = heatTable(lut, (r) => heatIntensity(r, 1, scale, 1));\n paintKey = \"\";\n }\n\n const refreshFormat = () => {\n fmt = createFormatters(\n options,\n tick > 0\n ? Math.max(decimalsOf(tick), inferPriceDecimals(store))\n : inferPriceDecimals(store),\n inferSizeDecimals(store),\n );\n };\n\n const clearHistory = () => {\n columns = [];\n grid = null;\n gridKey = paintKey = \"\";\n head = null;\n openStart = NaN;\n scaleMax = scaleTarget = 0;\n scaleAt = -Infinity;\n bubbleRef = 0;\n profileMax = 0;\n shownTime = NaN;\n open.buyVolume = open.buyNotional = open.sellVolume = open.sellNotional = 0;\n };\n\n // --------------------------------------------------------------- columns\n\n const ensureTick = () => {\n if (tick > 0) return;\n const base = inferTickSize(store);\n const mid = store.mid();\n if (options.tickSize && options.tickSize > 0) tick = options.tickSize;\n else if (base > 0 && Number.isFinite(mid)) {\n // rows of about 0.1 basis point: a round multiple of the tick (BTC at\n // 64,000 with a 0.1 tick: 0.5 rows)\n const ratio = (mid * 1e-5) / base;\n let multiple = 1;\n for (let p = 1; p <= 1e9 && multiple < ratio * 0.75; p *= 10) {\n for (const m of [1, 2, 5]) {\n multiple = m * p;\n if (multiple >= ratio * 0.75) break;\n }\n }\n tick = roundToStep(base * multiple, base);\n } else tick = Number.isFinite(mid) ? Math.max(1e-8, mid * 1e-5) : 0;\n if (tick > 0) refreshFormat();\n };\n\n /** Samples the book into price rows */\n const sampleBook = () => {\n const limit = depth();\n const bins = new Float64Array(limit * 2);\n const sizes = new Float32Array(limit * 2);\n let n = 0;\n for (const side of [\"bid\", \"ask\"] as const) {\n const count = store.count(side);\n let rows = 0;\n for (let i = 0; i < count; i++) {\n const bin = Math.round(store.priceAt(side, i) / tick);\n const size = store.sizeAt(side, i);\n if (n > 0 && bins[n - 1] === bin && rows > 0) {\n sizes[n - 1] += size;\n continue;\n }\n if (rows >= limit) break;\n bins[n] = bin;\n sizes[n] = size;\n n++;\n rows++;\n }\n }\n return { bins: bins.slice(0, n), sizes: sizes.slice(0, n) };\n };\n\n /** Closes the open column at `start` with the current book */\n const closeColumn = (start: number) => {\n if (!(tick > 0)) return;\n const { bins, sizes } = sampleBook();\n const column: Column = {\n seq: seq++,\n time: start,\n bins,\n sizes,\n bestBid: store.bestBid(),\n bestAsk: store.bestAsk(),\n buyVolume: open.buyVolume,\n buyNotional: open.buyNotional,\n sellVolume: open.sellVolume,\n sellNotional: open.sellNotional,\n };\n open.buyVolume = open.buyNotional = open.sellVolume = open.sellNotional = 0;\n columns.push(column);\n // history\n const oldest = start - history();\n let drop = 0;\n while (drop < columns.length && columns[drop]!.time < oldest) drop++;\n if (drop) columns = columns.slice(drop);\n };\n\n /** Closes every column ending before `time` */\n const advance = (time: number) => {\n if (!Number.isFinite(time)) return;\n const step = interval();\n if (!Number.isFinite(openStart)) {\n openStart = Math.floor(time / step) * step;\n return;\n }\n if (time - openStart > history()) {\n // a long gap: one column, then jump\n closeColumn(openStart);\n openStart = Math.floor(time / step) * step;\n return;\n }\n while (time >= openStart + step) {\n closeColumn(openStart);\n openStart += step;\n }\n };\n\n const noteTime = (time: number | undefined) => {\n if (time === undefined || !Number.isFinite(time)) return Date.now();\n if (!Number.isFinite(dataTime) || time >= dataTime) {\n dataTime = time;\n dataWall = perfNow();\n }\n return time;\n };\n\n /**\n * Column showing a time: the last one starting at or before it (a column\n * lasts until the next one), `null` for the open one or before the data\n */\n const columnAt = (time: number): Column | null => {\n if (Number.isFinite(openStart) && time >= openStart) return null;\n let lo = 0;\n let hi = columns.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (columns[mid]!.time <= time) lo = mid + 1;\n else hi = mid;\n }\n return lo > 0 ? columns[lo - 1]! : null;\n };\n\n // ----------------------------------------------------------------- field\n\n /** The live book as a column (sampled once per store version) */\n const headSource = (): HeatSource | null => {\n if (!Number.isFinite(openStart) || !(tick > 0)) return null;\n const version = store.version();\n if (!head || head.version !== version) head = { version, ...sampleBook() };\n return { time: openStart, bins: head.bins, sizes: head.sizes };\n };\n\n /**\n * The heat image of the view, rebuilt when its inputs change; the color\n * scale follows the 99th percentile of the visible non-empty cells\n * (eased): typical levels stay dim, only significant liquidity glows\n */\n const heatGrid = (\n x0: number,\n x1: number,\n y0: number,\n y1: number,\n end: number,\n dt: number,\n ): HeatGrid | null => {\n const step = interval();\n const live = headSource();\n const maxWidth = Math.min(MAX_TEXELS, Math.ceil(plot.w));\n const maxHeight = Math.min(MAX_TEXELS, Math.ceil(plot.h));\n const rowBins = rowBucket((tick / (y1 - y0)) * plot.h);\n const lastSeq = columns.length ? columns[columns.length - 1]!.seq : -1;\n const key = [\n x0,\n x1,\n y0,\n y1,\n Math.floor(end / step),\n columns.length,\n lastSeq,\n head?.version ?? -1,\n maxWidth,\n maxHeight,\n rowBins,\n tick,\n ].join(\"|\");\n if (key !== gridKey) {\n const sources: HeatSource[] = live ? [...columns, live] : columns;\n grid = buildHeatGrid(\n {\n sources,\n step,\n tick,\n x0,\n x1,\n y0,\n y1,\n end,\n maxWidth,\n maxHeight,\n rowBins,\n },\n grid,\n );\n gridKey = key;\n paintKey = \"\";\n }\n if (!grid) return null;\n // auto scale: a robust \"hot\" size, sampled at most 4 times a second\n const fixed = options.maxSize;\n if (fixed !== undefined && fixed > 0) scaleMax = fixed;\n else {\n const now = perfNow();\n if (now - scaleAt > 250 || !(scaleTarget > 0)) {\n const target = percentile(grid.cells, SCALE_QUANTILE);\n if (target > 0) scaleTarget = target;\n scaleAt = now;\n }\n if (!(scaleMax > 0)) scaleMax = scaleTarget;\n else if (scaleTarget > 0 && Math.abs(scaleTarget / scaleMax - 1) > 1e-3)\n scaleMax += (scaleTarget - scaleMax) * ease(dt, 700);\n }\n const contrast = Math.max(0.01, options.contrast ?? 1);\n const k = scaleMax > 0 ? (HEAT_TABLE_SIZE * contrast) / scaleMax : 0;\n const paint = `${grid.version}|${k}`;\n if (paint !== paintKey) {\n paintHeatGrid(grid, table, k);\n paintKey = `${grid.version}|${k}`;\n }\n return grid;\n };\n\n const visibleColumns = () => {\n const step = interval();\n const out: Column[] = [];\n // binary search of the first visible column\n let lo = 0;\n let hi = columns.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (columns[mid]!.time + step < viewX[0]) lo = mid + 1;\n else hi = mid;\n }\n for (let i = lo; i < columns.length; i++) {\n const c = columns[i]!;\n if (c.time > viewX[1]) break;\n out.push(c);\n }\n return out;\n };\n\n /** Trade volumes of a group of columns */\n interface Bubble {\n time: number;\n price: number;\n volume: number;\n buy: boolean;\n }\n type Flow = Pick<\n Column,\n \"buyVolume\" | \"buyNotional\" | \"sellVolume\" | \"sellNotional\"\n >;\n\n /**\n * Trades of the visible columns as bubbles: columns are grouped (by their\n * sequence, so groups stay put while the view scrolls) until a group is\n * BUBBLE_SPACING px wide; one bubble per side at the average price\n */\n const tradeBubbles = (\n visible: readonly Column[],\n columnPx: number,\n ): Bubble[] => {\n const step = interval();\n const k = Math.max(1, Math.ceil(BUBBLE_SPACING / Math.max(1e-6, columnPx)));\n const out: Bubble[] = [];\n let group = NaN;\n let t0 = 0;\n let t1 = 0;\n const sum = { bv: 0, bn: 0, sv: 0, sn: 0 };\n const flush = () => {\n const time = (t0 + t1) / 2;\n if (sum.sv > 0)\n out.push({ time, price: sum.sn / sum.sv, volume: sum.sv, buy: false });\n if (sum.bv > 0)\n out.push({ time, price: sum.bn / sum.bv, volume: sum.bv, buy: true });\n sum.bv = sum.bn = sum.sv = sum.sn = 0;\n };\n const add = (id: number, start: number, flow: Flow) => {\n const g = Math.floor(id / k);\n if (g !== group) {\n if (Number.isFinite(group)) flush();\n group = g;\n t0 = start;\n }\n t1 = start + step;\n sum.bv += flow.buyVolume;\n sum.bn += flow.buyNotional;\n sum.sv += flow.sellVolume;\n sum.sn += flow.sellNotional;\n };\n for (const c of visible) add(c.seq, c.time, c);\n if (Number.isFinite(openStart) && openStart <= viewX[1])\n add(seq, openStart, open);\n if (Number.isFinite(group)) flush();\n return out;\n };\n\n const clipPlot = (ctx: CanvasRenderingContext2D) => {\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.w, plot.h);\n ctx.clip();\n };\n\n /** Best bid / ask step lines and the translucent spread band between them */\n const drawBest = (\n ctx: CanvasRenderingContext2D,\n visible: readonly Column[],\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n columnPx: number,\n ) => {\n if (options.bestLines === false) return;\n const step = interval();\n // [start, end, bid, ask]: a column lasts until the next one\n const rows: [number, number, number, number][] = visible.map((c) => [\n c.time,\n c.time + step,\n c.bestBid,\n c.bestAsk,\n ]);\n if (Number.isFinite(openStart))\n rows.push([\n openStart,\n openStart + step,\n store.bestBid(),\n store.bestAsk(),\n ]);\n if (!rows.length) return;\n for (let i = 0; i + 1 < rows.length; i++) rows[i]![1] = rows[i + 1]![0];\n // wide columns: steps; narrow ones: a line through the column centers\n const steps = columnPx >= 2;\n const xs = (row: readonly number[]): [number, number] => {\n const xa = xOf(row[0]!);\n const xb = xOf(row[1]!);\n return steps ? [xa, xb] : [(xa + xb) / 2, (xa + xb) / 2];\n };\n clipPlot(ctx);\n // the spread band: one polygon per run of valid columns (no overlapping\n // rectangles, so no seams where neighbours meet)\n ctx.beginPath();\n let run: (typeof rows)[number][] = [];\n const flushRun = () => {\n if (!run.length) return;\n run.forEach((row, i) => {\n const [xa, xb] = xs(row);\n const y = yOf(row[3]);\n if (i) ctx.lineTo(xa, y);\n else ctx.moveTo(xa, y);\n ctx.lineTo(xb, y);\n });\n for (let i = run.length - 1; i >= 0; i--) {\n const [xa, xb] = xs(run[i]!);\n const y = yOf(run[i]![2]);\n ctx.lineTo(xb, y);\n ctx.lineTo(xa, y);\n }\n ctx.closePath();\n run = [];\n };\n for (const row of rows) {\n const [, , bid, ask] = row;\n if (Number.isFinite(bid) && Number.isFinite(ask) && ask > bid)\n run.push(row);\n else flushRun();\n }\n flushRun();\n ctx.fillStyle = toCss(host.theme.text, dark ? 0.08 : 0.07);\n ctx.fill();\n ctx.lineJoin = \"round\";\n for (const [index, color] of [\n [2, colors.up],\n [3, colors.down],\n ] as const) {\n ctx.beginPath();\n let pen = false;\n for (const row of rows) {\n const price = row[index];\n if (!Number.isFinite(price)) {\n pen = false;\n continue;\n }\n const y = yOf(price);\n const [xa, xb] = xs(row);\n if (pen) ctx.lineTo(xa, y);\n else ctx.moveTo(xa, y);\n if (steps) ctx.lineTo(xb, y);\n pen = true;\n }\n // a dark halo keeps the line readable on hot cells\n ctx.strokeStyle = toCss(floor, 0.55);\n ctx.lineWidth = 3.5;\n ctx.stroke();\n ctx.strokeStyle = toCss(color);\n ctx.lineWidth = 1.5;\n ctx.stroke();\n }\n ctx.restore();\n };\n\n /**\n * Trade bubbles: area ∝ volume (relative to the largest visible trade,\n * eased), translucent with a thin outline; the largest with their volume\n */\n const drawBubbles = (\n ctx: CanvasRenderingContext2D,\n bubbles: Bubble[],\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n fontSize: number,\n ) => {\n if (!bubbles.length) return;\n let max = 0;\n for (const b of bubbles) {\n const x = xOf(b.time);\n if (x >= plot.x && x <= plot.x + plot.w) max = Math.max(max, b.volume);\n }\n // the reference follows the visible trades: fast up, slowly down\n if (max > 0)\n bubbleRef = bubbleRef > 0 ? Math.max(max, bubbleRef * 0.995) : max;\n const ref = options.bubbleVolume ?? bubbleRef;\n if (!(ref > 0)) return;\n const maxD = Math.max(BUBBLE_MIN, options.bubbleSize ?? BUBBLE_SIZE);\n const minD = Math.min(BUBBLE_MIN, maxD);\n const sized = bubbles\n .map((b) => ({\n ...b,\n d: clamp(Math.sqrt(b.volume / ref) * maxD, minD, maxD),\n }))\n .sort((a, b) => a.d - b.d);\n clipPlot(ctx);\n ctx.lineWidth = 1;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.font = fontOf(host.theme, options, 600, Math.max(8, fontSize - 1));\n const rim: Rgba = dark ? [1, 1, 1, 1] : [0, 0, 0, 1];\n for (const b of sized) {\n const x = xOf(b.time);\n const y = yOf(b.price);\n const r = b.d / 2;\n if (x < plot.x - r || x > plot.x + plot.w + r) continue;\n if (y < plot.y - r || y > plot.y + plot.h + r) continue;\n const color = b.buy ? colors.up : colors.down;\n ctx.beginPath();\n ctx.arc(x, y, Math.max(1, r - 0.5), 0, Math.PI * 2);\n ctx.fillStyle = toCss(color, 0.35);\n ctx.fill();\n ctx.strokeStyle = toCss(mixOklab(color, rim, 0.2), 0.9);\n ctx.stroke();\n if (b.d >= 26) {\n const text = fmt.compact(b.volume);\n if (ctx.measureText(text).width <= b.d - 6) {\n ctx.fillStyle = toCss(dark ? [1, 1, 1, 1] : [0.08, 0.08, 0.1, 1]);\n ctx.fillText(text, x, y + 0.5);\n }\n }\n }\n ctx.restore();\n };\n\n /**\n * Price buckets of `ry` rows of a side of the live book (the rows of the\n * field: bucket `b` holds the rows `b × ry` to `b × ry + ry - 1`), best first\n */\n const bookBuckets = (side: OrderBookSide, ry: number) => {\n const buckets: number[] = [];\n const sizes: number[] = [];\n const count = store.count(side);\n let rows = 0;\n let lastBin = NaN;\n for (let i = 0; i < count; i++) {\n const bin = Math.round(store.priceAt(side, i) / tick);\n if (bin !== lastBin) {\n if (++rows > depth()) break;\n lastBin = bin;\n }\n const b = Math.floor(bin / ry);\n const size = store.sizeAt(side, i);\n if (buckets.length && buckets[buckets.length - 1] === b)\n sizes[sizes.length - 1] += size;\n else {\n buckets.push(b);\n sizes.push(size);\n }\n }\n return { side, buckets, sizes };\n };\n\n /** The current book as horizontal bars right of the plot, with a size scale */\n const drawProfile = (\n ctx: CanvasRenderingContext2D,\n px: number,\n profileW: number,\n yOf: (p: number) => number,\n fontSize: number,\n ry: number,\n ) => {\n const theme = host.theme;\n const [y0, y1] = viewY;\n const rowPx = Math.max(1, ((tick * ry) / (y1 - y0)) * plot.h);\n // bucket b spans [(b ry - ½) tick, (b ry + ry - ½) tick)\n const lowOf = (b: number) => (b * ry - 0.5) * tick;\n const highOf = (b: number) => (b * ry + ry - 0.5) * tick;\n let maxSize = 0;\n const sides = ([\"bid\", \"ask\"] as const).map((side) => {\n const levels = bookBuckets(side, ry);\n levels.buckets.forEach((b, i) => {\n if (highOf(b) >= y0 && lowOf(b) <= y1)\n maxSize = Math.max(maxSize, levels.sizes[i]!);\n });\n return levels;\n });\n // a fine \"nice\" scale (the largest bar fills 75-100 % of the panel),\n // changed only on a clear change: no jumping bars\n if (maxSize > profileMax || maxSize < profileMax * 0.6 || !(profileMax > 0))\n profileMax = fineCeil(maxSize);\n if (!(profileMax > 0)) return;\n const left = px + 2;\n const inner = Math.max(4, profileW - 6);\n // faint guides at half and full scale\n ctx.strokeStyle = toCss(theme.text, 0.07);\n ctx.lineWidth = 1;\n ctx.setLineDash([2, 3]);\n ctx.beginPath();\n for (const f of [0.5, 1]) {\n const x = Math.round(left + inner * f) - 0.5;\n ctx.moveTo(x, plot.y);\n ctx.lineTo(x, plot.y + plot.h);\n }\n ctx.stroke();\n ctx.setLineDash([]);\n ctx.save();\n ctx.beginPath();\n ctx.rect(px, plot.y, profileW, plot.h);\n ctx.clip();\n // rows on whole pixels from the bucket edges; a 1 px gap when tall\n const gap = rowPx >= 4 ? 1 : 0;\n const bar = (b: number, s: number) => {\n const top = Math.round(yOf(highOf(b)));\n const bottom = Math.max(top + 1, Math.round(yOf(lowOf(b))) - gap);\n const w = Math.max(1, Math.min(inner, (s / profileMax) * inner));\n ctx.rect(left, top, w, bottom - top);\n };\n for (const { side, buckets, sizes } of sides) {\n const color = side === \"bid\" ? colors.up : colors.down;\n ctx.beginPath();\n for (let i = 1; i < buckets.length; i++) {\n const b = buckets[i]!;\n if (highOf(b) >= y0 && lowOf(b) <= y1) bar(b, sizes[i]!);\n }\n ctx.fillStyle = toCss(color, dark ? 0.62 : 0.55);\n ctx.fill();\n // the best bucket, solid\n const best = buckets[0];\n if (best !== undefined && highOf(best) >= y0 && lowOf(best) <= y1) {\n ctx.beginPath();\n bar(best, sizes[0]!);\n ctx.fillStyle = toCss(color);\n ctx.fill();\n }\n }\n ctx.restore();\n // size scale below the panel\n const y = Math.round(plot.y + plot.h + 4) + 0.5;\n ctx.strokeStyle = toCss(theme.textMuted, 0.7);\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(left + inner, y);\n for (const f of [0, 0.5, 1]) {\n const x = Math.round(left + inner * f) + 0.5;\n ctx.moveTo(x, y);\n ctx.lineTo(x, y + 3);\n }\n ctx.stroke();\n ctx.font = fontOf(theme, options, 400, Math.max(8, fontSize - 1));\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textBaseline = \"top\";\n const text = fmt.compact(profileMax);\n const tw = ctx.measureText(text).width;\n ctx.textAlign = \"right\";\n ctx.fillText(text, left + inner + 2, y + 4);\n if (tw + ctx.measureText(\"0\").width + 8 < inner) {\n ctx.textAlign = \"left\";\n ctx.fillText(\"0\", left - 1, y + 4);\n }\n };\n\n /** Hovered cell: pointer, time, price row (bucket of `ry` ticks) */\n interface HoverCell {\n hx: number;\n hy: number;\n /** Time under the pointer */\n time: number;\n /** Start of the hovered column (NaN outside the data) */\n start: number;\n column: Column | null;\n /** Bucket: rows `bucket × ry` to `bucket × ry + ry - 1` */\n bucket: number;\n ry: number;\n /** Lowest / highest row price of the bucket and its center */\n low: number;\n high: number;\n rowPrice: number;\n }\n\n const hoverCell = (ry: number): HoverCell | null => {\n if (!hoverAt || options.tooltip === false || !(tick > 0) || drag)\n return null;\n if (!viewYReady) return null;\n const [hx, hy] = hoverAt;\n if (\n hx < plot.x ||\n hx > plot.x + plot.w ||\n hy < plot.y ||\n hy > plot.y + plot.h\n )\n return null;\n const [x0, x1] = viewX;\n const [y0, y1] = viewY;\n const time = x0 + ((hx - plot.x) / plot.w) * (x1 - x0);\n const price = y0 + ((plot.y + plot.h - hy) / plot.h) * (y1 - y0);\n const bucket = Math.floor(Math.round(price / tick) / ry);\n const digits = Math.min(12, decimalsOf(tick) + 2);\n const low = +(bucket * ry * tick).toFixed(digits);\n const high = +((bucket * ry + ry - 1) * tick).toFixed(digits);\n const rowPrice = +((low + high) / 2).toFixed(digits);\n const column = columnAt(time);\n const start = column\n ? column.time\n : Number.isFinite(openStart) && time >= openStart\n ? openStart\n : NaN;\n return { hx, hy, time, start, column, bucket, ry, low, high, rowPrice };\n };\n\n /** Price / time tag: filled (best bid / ask, hover) or outlined (last trade) */\n const drawTag = (\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n maxWidth: number,\n color: Rgba,\n filled: boolean,\n align: \"left\" | \"center\" = \"left\",\n ) => {\n const w = Math.min(ctx.measureText(text).width + 10, maxWidth);\n const left = align === \"center\" ? x - w / 2 : x;\n ctx.fillStyle = filled ? toCss(color) : toCss(floor);\n roundRect(ctx, left, y - TAG_HEIGHT / 2, w, TAG_HEIGHT, 3);\n ctx.fill();\n if (!filled) {\n ctx.strokeStyle = toCss(color);\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n ctx.fillStyle = filled\n ? luminance(color) > 0.6\n ? \"#111\"\n : \"#fff\"\n : toCss(color);\n ctx.textAlign = align;\n ctx.textBaseline = \"middle\";\n ctx.fillText(text, align === \"center\" ? x : left + 5, y + 0.5);\n };\n\n // ---------------------------------------------------------------- draw\n\n function draw(now: number): boolean {\n const ctx = host.ctx;\n if (!ctx) return false;\n const { width, height, dpr, theme } = host;\n const dt = lastFrame ? now - lastFrame : 0;\n lastFrame = now;\n const l = labels();\n const fontSize = options.fontSize ?? (width < 420 ? 10 : 11);\n const regular = fontOf(theme, options, 400, fontSize);\n const bold = fontOf(theme, options, 600, fontSize);\n const step = interval();\n const live = !Number.isFinite(dataTime);\n if (live && store.count(\"bid\") + store.count(\"ask\") > 0)\n advance(Date.now());\n // a monotonic clock: the view never jumps back when data arrives late\n const clock = nowTime();\n shownTime =\n Number.isFinite(shownTime) && clock > shownTime - step * 4\n ? Math.max(shownTime, clock)\n : clock;\n const time = shownTime;\n\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, width, height);\n\n // layout\n ensureTick();\n const mid = store.mid();\n ctx.font = bold;\n const sample = fmt.price(Number.isFinite(mid) ? mid * 1.0001 : 0);\n const axisW = Math.ceil(ctx.measureText(sample).width) + 18;\n ctx.font = regular;\n const profileW =\n options.profile === false ? 0 : Math.round(clamp(width * 0.12, 56, 120));\n const timeH = fontSize + 12;\n plot = {\n x: 0,\n y: 0,\n w: Math.max(10, width - axisW - profileW),\n h: Math.max(10, height - timeH),\n };\n const px = plot.x + plot.w;\n const right = px + profileW;\n\n // view: the following view fits the data (history fills the plot from\n // the left) and keeps the price range while the market stays inside it\n if (!Number.isFinite(windowSpan))\n windowSpan = Math.max(step * 10, options.window ?? 60_000);\n if (follow) {\n const first = columns.length ? columns[0]!.time : openStart;\n // the view ends at the live time: the open column (the live book) is\n // cut by the right edge, so no gap opens while it is being sampled\n viewX = fitTimeRange(\n first,\n time,\n windowSpan,\n Math.min(windowSpan, step * 60),\n );\n let lo = store.bestBid();\n let hi = store.bestAsk();\n for (const c of visibleColumns()) {\n if (Number.isFinite(c.bestBid) && !(c.bestBid >= lo)) lo = c.bestBid;\n if (Number.isFinite(c.bestAsk) && !(c.bestAsk <= hi)) hi = c.bestAsk;\n }\n if (!Number.isFinite(lo)) lo = hi;\n if (!Number.isFinite(hi)) hi = lo;\n const minSpan = tick > 0 ? tick * Math.max(40, plot.h / 6) : 0;\n const fixed =\n options.priceSpan ?? (Number.isFinite(ySpan) ? ySpan : undefined);\n if (minSpan > 0 || fixed !== undefined) {\n yTarget = fitPriceRange(yTarget, lo, hi, minSpan, fixed);\n const [t0, t1] = yTarget;\n if (Number.isFinite(t0) && Number.isFinite(t1)) {\n if (!viewYReady) {\n viewY = [t0, t1];\n viewYReady = true;\n } else {\n const k = ease(dt, 280);\n viewY = [\n viewY[0] + (t0 - viewY[0]) * k,\n viewY[1] + (t1 - viewY[1]) * k,\n ];\n }\n }\n }\n }\n const [x0, x1] = viewX;\n const [y0, y1] = viewY;\n const xOf = (t: number) => plot.x + ((t - x0) / (x1 - x0)) * plot.w;\n const yOf = (p: number) =>\n plot.y + plot.h - ((p - y0) / (y1 - y0)) * plot.h;\n const ready = viewYReady && tick > 0;\n const visible = visibleColumns();\n const columnPx = (step / (x1 - x0)) * plot.w;\n /** Price rows per drawn row (bucketing of thin rows), as the field */\n let ry = ready ? rowBucket((tick / (y1 - y0)) * plot.h) : 1;\n\n // data layer: the heat field (an opaque image over the cold color)\n const floorCss = toCss(floor);\n if (renderer) {\n const canvas = renderer.canvas;\n canvas.style.left = `${plot.x}px`;\n canvas.style.top = `${plot.y}px`;\n canvas.style.width = `${plot.w}px`;\n canvas.style.height = `${plot.h}px`;\n const bw = Math.max(1, Math.round(plot.w * dpr));\n const bh = Math.max(1, Math.round(plot.h * dpr));\n if (canvas.width !== bw || canvas.height !== bh) renderer.resize(bw, bh);\n const heat =\n ready && Number.isFinite(openStart)\n ? heatGrid(x0, x1, y0, y1, time, dt)\n : null;\n if (heat) ry = heat.rowBins;\n // the image rectangle in device pixels of the plot canvas\n const sx = bw / plot.w;\n const sy = bh / plot.h;\n const rect: [number, number, number, number] = heat\n ? [\n (xOf(heat.t0) - plot.x) * sx,\n (yOf(heat.p1) - plot.y) * sy,\n (xOf(heat.t1) - plot.x) * sx,\n (yOf(heat.p0) - plot.y) * sy,\n ]\n : [0, 0, 0, 0];\n renderer.render(heat, rect, floor);\n } else {\n ctx.fillStyle = floorCss;\n ctx.fillRect(plot.x, plot.y, plot.w, plot.h);\n }\n\n // no grid inside the field (it would read as liquidity): short tick\n // marks on the time and price axes instead\n const yTicks = ready\n ? linearTicks(y0, y1, Math.max(2, Math.floor(plot.h / 44)))\n : [];\n const xt = timeTicks(\n x0,\n x1,\n Math.max(2, Math.floor(plot.w / 75)),\n undefined,\n options.timeZone ?? \"local\",\n );\n ctx.strokeStyle = toCss(theme.axis);\n ctx.lineWidth = 1;\n ctx.beginPath();\n for (const p of yTicks) {\n const y = Math.round(yOf(p)) + 0.5;\n ctx.moveTo(right, y);\n ctx.lineTo(right + 4, y);\n }\n for (const t of xt.values) {\n const x = Math.round(xOf(t)) + 0.5;\n if (x <= plot.x + 1 || x >= px - 1) continue;\n ctx.moveTo(x, plot.y + plot.h);\n ctx.lineTo(x, plot.y + plot.h + 4);\n }\n ctx.stroke();\n\n // trades, then the best bid / ask on top of them, the current book\n if (ready) {\n if (options.bubbles !== false)\n drawBubbles(ctx, tradeBubbles(visible, columnPx), xOf, yOf, fontSize);\n drawBest(ctx, visible, xOf, yOf, columnPx);\n if (profileW) drawProfile(ctx, px, profileW, yOf, fontSize, ry);\n }\n\n // frame\n ctx.strokeStyle = toCss(theme.axis);\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(0, Math.round(plot.y + plot.h) + 0.5);\n ctx.lineTo(width, Math.round(plot.y + plot.h) + 0.5);\n if (profileW) {\n ctx.moveTo(Math.round(px) + 0.5, plot.y);\n ctx.lineTo(Math.round(px) + 0.5, plot.y + plot.h);\n }\n ctx.moveTo(Math.round(right) + 0.5, plot.y);\n ctx.lineTo(Math.round(right) + 0.5, plot.y + plot.h);\n ctx.stroke();\n\n const cell = ready ? hoverCell(ry) : null;\n\n // time axis (the hover time tag hides the ticks it covers)\n ctx.font = regular;\n const hoverTime = cell\n ? formatClock(\n Number.isFinite(cell.start) ? cell.start : cell.time,\n step < 1000,\n options.timeZone,\n )\n : \"\";\n const hoverHalf = cell ? ctx.measureText(hoverTime).width / 2 + 8 : 0;\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"top\";\n for (const t of xt.values) {\n const x = xOf(t);\n const text = xt.format(t);\n const half = ctx.measureText(text).width / 2;\n // labels stay whole inside the plot\n if (x - half < plot.x + 2 || x + half > px - 2) continue;\n if (cell && Math.abs(x - cell.hx) < hoverHalf + half) continue;\n ctx.fillText(text, x, plot.y + plot.h + 6);\n }\n\n // price axis: pinned tags (best ask / bid, last trade) win over the\n // ticks, the hover tag over everything\n const last = lastTrade;\n const pins: { price: number; color: Rgba; filled: boolean }[] = [\n { price: store.bestAsk(), color: colors.down, filled: true },\n { price: store.bestBid(), color: colors.up, filled: true },\n ];\n if (\n last &&\n last.price !== store.bestBid() &&\n last.price !== store.bestAsk()\n )\n pins.push({\n price: last.price,\n color: last.side === \"buy\" ? colors.up : colors.down,\n filled: false,\n });\n const shownPins = ready\n ? pins.filter(\n (p) => Number.isFinite(p.price) && p.price >= y0 && p.price <= y1,\n )\n : [];\n const hoverY = cell ? Math.round(yOf(cell.rowPrice)) + 0.5 : NaN;\n const layout = layoutAxisLabels(\n shownPins.map((p): AxisLabel => ({ y: yOf(p.price), h: TAG_HEIGHT })),\n cell ? { y: hoverY, h: TAG_HEIGHT } : null,\n yTicks.map(yOf),\n fontSize + 2,\n [plot.y, plot.y + plot.h],\n );\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textAlign = \"left\";\n ctx.textBaseline = \"middle\";\n yTicks.forEach((p, i) => {\n if (layout.ticks[i]) ctx.fillText(fmt.price(p), right + 6, yOf(p));\n });\n ctx.font = bold;\n shownPins.forEach((pin, i) => {\n const y = layout.pinned[i];\n if (y === null || y === undefined) return;\n const at = yOf(pin.price);\n if (Math.abs(y - at) > 1) {\n // a moved tag points at its price\n ctx.strokeStyle = toCss(pin.color);\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(right - 4, at);\n ctx.lineTo(right + 1, y);\n ctx.stroke();\n }\n drawTag(\n ctx,\n fmt.price(pin.price),\n right + 1,\n y,\n width - right - 2,\n pin.color,\n pin.filled,\n );\n });\n\n // crosshair, hover tags and tooltip\n drawHover(ctx, xOf, yOf, right, l, cell, hoverY, hoverTime);\n ctx.font = regular;\n\n host.describe(\n `${options.ariaLabel ?? l.name}. ${l.bid} ${fmt.price(store.bestBid())}, ${l.ask} ${fmt.price(store.bestAsk())}.`,\n );\n // keep scrolling while following a live market\n const fresh = live || perfNow() - dataWall < 2000;\n return (\n (follow && fresh && Number.isFinite(openStart)) ||\n (viewYReady && yTarget !== null && Math.abs(viewY[0] - yTarget[0]) > 1e-9)\n );\n }\n\n function drawHover(\n ctx: CanvasRenderingContext2D,\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n right: number,\n l: OrderBookHeatmapLabels,\n cell: HoverCell | null,\n hoverY: number,\n timeText: string,\n ) {\n const { theme } = host;\n if (!cell) {\n host.tooltip.style.display = \"none\";\n if (hoverKey) {\n hoverKey = \"\";\n emitter.emit(\"hover\", null);\n }\n return;\n }\n const { hx, hy, time, start, column, bucket, ry, low, high, rowPrice } =\n cell;\n const inBucket = (bin: number) => Math.floor(bin / ry) === bucket;\n const step = interval();\n let size = 0;\n let bestBid = NaN;\n let bestAsk = NaN;\n let buyVolume = 0;\n let sellVolume = 0;\n if (column) {\n for (let i = 0; i < column.bins.length; i++) {\n if (inBucket(column.bins[i]!)) size += column.sizes[i]!;\n }\n ({ bestBid, bestAsk, buyVolume, sellVolume } = column);\n } else if (Number.isFinite(start)) {\n const live = headSource();\n if (live) {\n for (let i = 0; i < live.bins.length; i++) {\n if (inBucket(live.bins[i]!)) size += live.sizes[i]!;\n }\n }\n bestBid = store.bestBid();\n bestAsk = store.bestAsk();\n buyVolume = open.buyVolume;\n sellVolume = open.sellVolume;\n }\n // a bucket holding both sides (around the spread) has no side\n const side: OrderBookSide | null =\n high <= bestBid ? \"bid\" : low >= bestAsk ? \"ask\" : null;\n\n // crosshair\n ctx.strokeStyle = toCss(theme.text, 0.5);\n ctx.lineWidth = 1;\n ctx.setLineDash([3, 3]);\n ctx.beginPath();\n ctx.moveTo(Math.round(hx) + 0.5, plot.y);\n ctx.lineTo(Math.round(hx) + 0.5, plot.y + plot.h);\n ctx.moveTo(plot.x, hoverY);\n ctx.lineTo(right, hoverY);\n ctx.stroke();\n ctx.setLineDash([]);\n if (Number.isFinite(start)) {\n // outline of the hovered cell\n const cx0 = xOf(start);\n const cx1 = xOf(start + step);\n const cy0 = yOf((bucket * ry + ry - 0.5) * tick);\n const cy1 = yOf((bucket * ry - 0.5) * tick);\n ctx.strokeStyle = toCss(theme.text, 0.85);\n ctx.strokeRect(cx0, cy0, Math.max(2, cx1 - cx0), Math.max(2, cy1 - cy0));\n }\n // price and time tags\n ctx.font = fontOf(\n theme,\n options,\n 600,\n options.fontSize ?? (host.width < 420 ? 10 : 11),\n );\n drawTag(\n ctx,\n fmt.price(rowPrice),\n right + 1,\n hoverY,\n host.width - right - 2,\n theme.text,\n true,\n );\n drawTag(\n ctx,\n timeText,\n clamp(hx, plot.x + 40, plot.x + plot.w - 40),\n plot.y + plot.h + TAG_HEIGHT / 2 + 2,\n plot.w,\n theme.text,\n true,\n \"center\",\n );\n\n const sideColor =\n side === \"bid\" ? colors.up : side === \"ask\" ? colors.down : null;\n tooltipHtml(\n doc,\n host.tooltip,\n {\n text: formatClock(\n Number.isFinite(start) ? start : time,\n true,\n options.timeZone,\n ),\n color: undefined,\n // the side as a small colored badge (no accent border)\n badge:\n side && sideColor\n ? {\n text: side === \"bid\" ? l.bidSide : l.askSide,\n color: toCss(sideColor),\n }\n : undefined,\n },\n [\n [\n l.price,\n ry > 1\n ? `${fmt.price(low)} – ${fmt.price(high)}`\n : fmt.price(rowPrice),\n ],\n [l.liquidity, fmt.size(size)],\n [l.buys, fmt.size(buyVolume)],\n [l.sells, fmt.size(sellVolume)],\n ],\n );\n host.tooltip.style.display = \"block\";\n host.placeTooltip(\n host.tooltip,\n hx,\n hy,\n hx > plot.w * 0.6 ? \"left\" : \"right\",\n );\n\n const key = `${start}|${bucket}|${ry}|${size}|${buyVolume}|${sellVolume}`;\n if (key !== hoverKey) {\n hoverKey = key;\n const event: OrderBookHeatmapHoverEvent = {\n time: Number.isFinite(start) ? start : time,\n price: low,\n priceHigh: high,\n size,\n side,\n buyVolume,\n sellVolume,\n };\n emitter.emit(\"hover\", event);\n }\n }\n\n // ------------------------------------------------------------ renderer\n\n const initRenderer = async (exclude: Set<ChartRendererKind> = new Set()) => {\n const token = ++rendererToken;\n const next = await createHeatFieldRenderer(\n options.renderer ?? \"auto\",\n () => {\n const canvas = doc.createElement(\"canvas\");\n Object.assign(canvas.style, {\n position: \"absolute\",\n left: \"0\",\n top: \"0\",\n pointerEvents: \"none\",\n });\n canvas.setAttribute(\"aria-hidden\", \"true\");\n return canvas;\n },\n (kind) => {\n if (destroyed || renderer?.kind !== kind) return;\n renderer.destroy();\n renderer.canvas.remove();\n renderer = null;\n void initRenderer(new Set([...exclude, kind]));\n },\n exclude,\n );\n if (destroyed || token !== rendererToken) {\n next?.destroy();\n return;\n }\n if (renderer) {\n renderer.destroy();\n renderer.canvas.remove();\n }\n renderer = next;\n if (next) {\n root.dataset.renderer = next.kind;\n root.insertBefore(next.canvas, host.canvas);\n emitter.emit(\"renderer\", next.kind);\n } else delete root.dataset.renderer;\n resolveReady(next?.kind ?? null);\n host.invalidate();\n };\n const unfollowDefault = followDefaultRenderer(\n () => options.renderer,\n () => void initRenderer(),\n );\n\n // --------------------------------------------------------- interaction\n\n const setFollow = (value: boolean) => {\n if (follow === value) return;\n follow = value;\n emitter.emit(\"follow\", value);\n };\n\n /** Keeps a panned time range near the data (half a view of margin) */\n const clampTime = (range: [number, number]): [number, number] => {\n const first = columns.length ? columns[0]!.time : openStart;\n if (!Number.isFinite(first)) return range;\n const span = range[1] - range[0];\n const latest = Number.isFinite(shownTime) ? shownTime : nowTime();\n const max = latest + interval() + span / 2;\n const start = Math.max(first - span / 2, Math.min(range[0], max - span));\n return [start, start + span];\n };\n\n const onPointerDown = (event: PointerEvent) => {\n if (options.interactive === false) return;\n const [x, y] = localPoint(root, event);\n root.setPointerCapture?.(event.pointerId);\n drag = {\n x,\n y,\n viewX: [...viewX],\n viewY: [...viewY],\n axis: x > plot.x + plot.w,\n span: viewY[1] - viewY[0],\n };\n };\n const onPointerMove = (event: PointerEvent) => {\n const [x, y] = localPoint(root, event);\n hoverAt = [x, y];\n if (drag) {\n const dx = x - drag.x;\n const dy = y - drag.y;\n if (drag.axis) {\n // dragging the price axis scales the prices around the center\n const span = drag.span * Math.exp(dy * 0.006);\n const c = (drag.viewY[0] + drag.viewY[1]) / 2;\n ySpan = span;\n viewY = [c - span / 2, c + span / 2];\n yTarget = [viewY[0], viewY[1]];\n } else if (Math.abs(dx) + Math.abs(dy) > 3) {\n setFollow(false);\n const tx = ((drag.viewX[1] - drag.viewX[0]) / plot.w) * dx;\n const ty = ((drag.viewY[1] - drag.viewY[0]) / plot.h) * dy;\n viewX = clampTime([drag.viewX[0] - tx, drag.viewX[1] - tx]);\n viewY = [drag.viewY[0] + ty, drag.viewY[1] + ty];\n }\n }\n host.invalidate();\n };\n const onPointerUp = (event: PointerEvent) => {\n root.releasePointerCapture?.(event.pointerId);\n drag = null;\n host.invalidate();\n };\n const onPointerLeave = () => {\n if (drag) return;\n hoverAt = null;\n host.invalidate();\n };\n const zoomTime = (factor: number, anchorX: number) => {\n const [a, b] = viewX;\n const span = clamp(\n (follow ? windowSpan : b - a) * factor,\n interval() * 10,\n history(),\n );\n windowSpan = span;\n if (!follow) {\n const t = a + ((anchorX - plot.x) / plot.w) * (b - a);\n const r = (t - a) / (b - a);\n viewX = clampTime([t - span * r, t + span * (1 - r)]);\n }\n host.invalidate();\n };\n const zoomPrice = (factor: number) => {\n const span = clamp(\n (viewY[1] - viewY[0]) * factor,\n tick * 6 || 1e-9,\n Infinity,\n );\n const c = (viewY[0] + viewY[1]) / 2;\n ySpan = span;\n viewY = [c - span / 2, c + span / 2];\n yTarget = [viewY[0], viewY[1]];\n host.invalidate();\n };\n const onWheel = (event: WheelEvent) => {\n if (options.interactive === false || !(event.ctrlKey || event.metaKey))\n return;\n event.preventDefault();\n const [x] = localPoint(root, event);\n const factor = Math.exp(event.deltaY * 0.002);\n if (event.shiftKey || x > plot.x + plot.w) zoomPrice(factor);\n else zoomTime(factor, x);\n };\n const onDoubleClick = () => {\n if (options.interactive === false) return;\n instance.resetView();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (options.interactive === false) return;\n switch (event.key) {\n case \"+\":\n case \"=\":\n zoomTime(0.8, plot.x + plot.w);\n break;\n case \"-\":\n zoomTime(1.25, plot.x + plot.w);\n break;\n case \"ArrowUp\":\n case \"ArrowDown\": {\n if (event.shiftKey) {\n zoomPrice(event.key === \"ArrowUp\" ? 0.8 : 1.25);\n break;\n }\n setFollow(false);\n const d =\n (viewY[1] - viewY[0]) * 0.1 * (event.key === \"ArrowUp\" ? 1 : -1);\n viewY = [viewY[0] + d, viewY[1] + d];\n host.invalidate();\n break;\n }\n case \"ArrowLeft\":\n case \"ArrowRight\": {\n setFollow(false);\n const d =\n (viewX[1] - viewX[0]) * 0.1 * (event.key === \"ArrowLeft\" ? -1 : 1);\n viewX = clampTime([viewX[0] + d, viewX[1] + d]);\n host.invalidate();\n break;\n }\n case \"0\":\n case \"Home\":\n instance.resetView();\n break;\n default:\n return;\n }\n event.preventDefault();\n };\n\n root.addEventListener(\"pointerdown\", onPointerDown);\n root.addEventListener(\"pointermove\", onPointerMove);\n root.addEventListener(\"pointerup\", onPointerUp);\n root.addEventListener(\"pointercancel\", onPointerUp);\n root.addEventListener(\"pointerleave\", onPointerLeave);\n root.addEventListener(\"wheel\", onWheel, { passive: false });\n root.addEventListener(\"dblclick\", onDoubleClick);\n root.addEventListener(\"keydown\", onKeyDown);\n\n // ----------------------------------------------------------------- api\n\n const applyOne = (delta: OrderBookDelta) => {\n const time = noteTime(delta.time);\n if (store.count(\"bid\") + store.count(\"ask\") > 0) {\n ensureTick();\n advance(time);\n }\n store.applyDelta(delta);\n };\n\n const instance: OrderBookHeatmapInstance = {\n setBook(snapshot) {\n const time = noteTime(snapshot.time);\n if (store.count(\"bid\") + store.count(\"ask\") > 0) advance(time);\n store.setSnapshot(snapshot);\n ensureTick();\n refreshFormat();\n if (!Number.isFinite(openStart)) advance(time);\n host.invalidate();\n },\n applyDeltas(deltas) {\n if (Array.isArray(deltas)) {\n for (const d of deltas as readonly OrderBookDelta[]) applyOne(d);\n } else applyOne(deltas as OrderBookDelta);\n if (!Number.isFinite(openStart) && tick > 0) advance(nowTime());\n host.invalidate();\n },\n addTrades(trades) {\n const list: readonly MarketTrade[] = Array.isArray(trades)\n ? (trades as readonly MarketTrade[])\n : [trades as MarketTrade];\n for (const trade of list) {\n if (!(trade.size > 0) || !Number.isFinite(trade.price)) continue;\n if (Number.isFinite(dataTime)) {\n noteTime(trade.time);\n advance(trade.time);\n }\n const target =\n !Number.isFinite(openStart) || trade.time >= openStart\n ? open\n : columnAt(trade.time);\n if (target) {\n if (trade.side === \"buy\") {\n target.buyVolume += trade.size;\n target.buyNotional += trade.size * trade.price;\n } else {\n target.sellVolume += trade.size;\n target.sellNotional += trade.size * trade.price;\n }\n }\n if (!lastTrade || trade.time >= lastTrade.time) lastTrade = trade;\n }\n host.invalidate();\n },\n clear() {\n store.clear();\n clearHistory();\n lastTrade = null;\n dataTime = NaN;\n tick = 0;\n ySpan = NaN;\n yTarget = null;\n viewYReady = false;\n host.invalidate();\n },\n setOptions(next) {\n const previous = options;\n options = next;\n applyTexts();\n if (\n next.tickSize !== previous.tickSize ||\n (next.interval ?? 100) !== (previous.interval ?? 100)\n ) {\n clearHistory();\n tick = 0;\n ySpan = NaN;\n ensureTick();\n }\n if (next.window !== previous.window) windowSpan = NaN;\n if (next.priceSpan !== previous.priceSpan) ySpan = NaN;\n if ((next.renderer ?? \"auto\") !== (previous.renderer ?? \"auto\"))\n void initRenderer();\n refreshColors();\n refreshFormat();\n host.invalidate();\n },\n resetView() {\n windowSpan = NaN;\n ySpan = NaN;\n yTarget = null;\n setFollow(true);\n host.invalidate();\n },\n getRenderer: () => renderer?.kind ?? null,\n ready,\n getStore: () => store,\n on: (event, handler) => emitter.on(event, handler),\n resize() {\n host.invalidate();\n },\n destroy() {\n destroyed = true;\n unfollowDefault();\n root.removeEventListener(\"pointerdown\", onPointerDown);\n root.removeEventListener(\"pointermove\", onPointerMove);\n root.removeEventListener(\"pointerup\", onPointerUp);\n root.removeEventListener(\"pointercancel\", onPointerUp);\n root.removeEventListener(\"pointerleave\", onPointerLeave);\n root.removeEventListener(\"wheel\", onWheel);\n root.removeEventListener(\"dblclick\", onDoubleClick);\n root.removeEventListener(\"keydown\", onKeyDown);\n renderer?.destroy();\n renderer = null;\n emitter.clear();\n host.destroy();\n resolveReady(null);\n },\n };\n\n applyTexts();\n refreshColors();\n void initRenderer();\n return instance;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"heatmap.cjs","names":["toOklab","packColor","fromOklab","createOrderBookStore","createEmitter","createFormatters","HEAT_TABLE_SIZE","createHost","localeLabels","sideColors","luminance","oklabRamp","parseColor","heatTable","decimalsOf","inferPriceDecimals","inferSizeDecimals","inferTickSize","roundToStep","buildHeatGrid","percentile","ease","toCss","clamp","fontOf","mixOklab","fineCeil","fitTimeRange","fitPriceRange","linearTicks","timeTicks","formatClock","layoutAxisLabels","createHeatFieldRenderer","followDefaultRenderer","localPoint","require_color","require_locale","require_scale","require_follow","require_time","require_book","require_format","require_host","require_field","require_layout","LUT_SIZE","MAX_TEXELS","SCALE_QUANTILE","MIN_ROW_PX","DARK_RAMP","LIGHT_RAMP","TAG_HEIGHT","BUBBLE_SPACING","BUBBLE_SIZE","BUBBLE_MIN","positionedRamp","lut","size","stops","lab","c","i","k","t","p0","j","p1","f","a","b","rowBucket","tickPx","need","p","m","LABELS","heatIntensity","max","r","contrast","scale","CDF_BINS","rankOf","dist","x","sizeCdf","min","count","cells","v","bins","span","sum","heatCurve","absolute","base","rank","createOrderBookHeatmap","options","initial","store","emitter","fmt","colors","table","curve","floor","dark","tick","columns","seq","openStart","open","lastTrade","dataTime","dataWall","scaleMax","scaleTarget","scaleAt","bubbleRef","profileMax","grid","gridKey","paintKey","head","renderer","rendererToken","destroyed","resolveReady","ready","resolve","follow","windowSpan","viewX","viewY","viewYReady","yTarget","ySpan","shownTime","lastFrame","plot","hoverAt","hoverKey","drag","host","container","refreshColors","root","texts","labels","applyTexts","interval","history","depth","nowTime","elapsed","perfNow","theme","value","background","ramp","at","hex","refreshFormat","withUnit","unit","text","clearHistory","ensureTick","mid","ratio","multiple","sampleBook","limit","sizes","n","side","rows","bin","closeColumn","column","start","oldest","drop","advance","time","step","noteTime","columnAt","lo","hi","headSource","version","heatGrid","live","maxWidth","maxHeight","rowBins","y1","y0","lastSeq","key","x0","x1","end","sources","fixed","now","target","dt","paint","visibleColumns","out","tradeBubbles","columnPx","group","t0","t1","flush","add","g","id","flow","visible","clipPlot","ctx","drawBest","steps","xs","xa","xOf","row","xb","run","flushRun","y","yOf","bid","ask","index","color","pen","price","drawBubbles","bubbles","ref","maxD","minD","sized","fontSize","rim","bookBuckets","buckets","lastBin","ry","drawProfile","rowPx","lowOf","highOf","maxSize","sides","levels","left","px","inner","profileW","gap","bar","top","bottom","w","s","best","tw","hoverCell","hx","hy","bucket","digits","low","high","rowPrice","drawTag","align","filled","rampCss","packed","drawLegend","l","title","bold","regular","small","titleW","lowW","highW","hintW","dotsW","boxW","rowH","boxH","bx","by","rampY","gradient","labelY","hintY","dot","draw","width","clock","dpr","height","sample","axisW","timeH","right","first","minSpan","floorCss","canvas","bw","bh","heat","sx","sy","rect","yTicks","xt","cell","hoverTime","hoverHalf","half","last","pins","shownPins","hoverY","layout","pin","drawHover","fresh","inBucket","bestBid","bestAsk","buyVolume","sellVolume","cx0","cx1","cy0","cy1","timeText","sideColor","doc","event","initRenderer","token","next","kind","exclude","unfollowDefault","setFollow","clampTime","range","onPointerDown","onPointerMove","dx","dy","tx","ty","onPointerUp","onPointerLeave","zoomTime","factor","anchorX","zoomPrice","onWheel","onDoubleClick","instance","onKeyDown","d","applyOne","delta","snapshot","deltas","list","trades","trade","previous","handler"],"sources":["../../../../../charts/src/engine/orderbook/heatmap.ts"],"sourcesContent":["// createOrderBookHeatmap: Bookmap-style liquidity heatmap. The book is\n// sampled every `interval` ms into a column of price rows; the visible\n// columns are rasterized into one image (a texel per column and price row,\n// see field.ts) drawn with nearest filtering by a WebGPU / WebGL / Canvas2D\n// backend over the cold end of the ramp: a continuous field without seams.\n// The best bid / ask step lines, the spread band, the trade bubbles, the\n// grid, the axes, the book profile, the crosshair and the tooltip are drawn\n// on a Canvas2D layer above.\n\nimport {\n fromOklab,\n luminance,\n mixOklab,\n oklabRamp,\n packColor,\n parseColor,\n toCss,\n toOklab,\n type Rgba,\n} from \"../color\";\nimport { followDefaultRenderer } from \"../renderers/follow\";\nimport { linearTicks } from \"../scale\";\nimport { timeTicks } from \"../time\";\nimport type { ChartRendererKind } from \"../types\";\nimport {\n createOrderBookStore,\n decimalsOf,\n inferPriceDecimals,\n inferSizeDecimals,\n inferTickSize,\n roundToStep,\n} from \"./book\";\nimport {\n clamp,\n createFormatters,\n ease,\n fontOf,\n formatClock,\n roundRect,\n sideColors,\n type Formatters,\n} from \"./format\";\nimport { localeLabels, type LabelDictionary } from \"../locale\";\nimport {\n HEAT_TABLE_SIZE,\n buildHeatGrid,\n createHeatFieldRenderer,\n heatTable,\n paintHeatGrid,\n percentile,\n type HeatFieldRenderer,\n type HeatGrid,\n type HeatSource,\n} from \"./field\";\nimport { createEmitter, createHost, localPoint, tooltipHtml } from \"./host\";\nimport {\n fineCeil,\n fitPriceRange,\n fitTimeRange,\n layoutAxisLabels,\n type AxisLabel,\n} from \"./layout\";\nimport type {\n OrderBookDelta,\n OrderBookHeatmapEventMap,\n OrderBookHeatmapHoverEvent,\n OrderBookHeatmapInstance,\n OrderBookHeatmapLabels,\n OrderBookHeatmapOptions,\n OrderBookHeatmapScale,\n OrderBookSide,\n MarketTrade,\n} from \"./types\";\n\n/** Colors of the ramp lookup table */\nconst LUT_SIZE = 256;\n/** Largest heat image (texels per side) */\nconst MAX_TEXELS = 4096;\n/**\n * Quantile of the visible (non-empty) cells at the hottest color (auto\n * scale): typical levels stay dark, only the top 1 % of the liquidity glows\n */\nconst SCALE_QUANTILE = 0.99;\n/** Thinnest price row on screen (CSS px); thinner rows are bucketed */\nconst MIN_ROW_PX = 2;\n\n/** A ramp color at a position (0-1) */\ntype RampStop = readonly [number, string];\n\n/**\n * Heat ramps (positioned stops, interpolated in OKLab, lightness rising\n * monotonically with the size); the first color is also the empty field.\n * Dark: a long dark segment close to the panel (thin liquidity stays dim),\n * then blue, cyan, yellow, orange and a white-hot end for the walls (the\n * Bookmap convention). Light: the mirror, near white to deep blue, violet\n * and crimson.\n */\nconst DARK_RAMP: readonly RampStop[] = [\n [0, \"#0b1322\"],\n [0.3, \"#0d1a2e\"],\n [0.5, \"#102a4e\"],\n [0.65, \"#154a8a\"],\n [0.76, \"#1b86b8\"],\n [0.85, \"#3fc3c0\"],\n [0.91, \"#e8d84a\"],\n [0.96, \"#ff8c2b\"],\n [1, \"#ffe6c2\"],\n];\nconst LIGHT_RAMP: readonly RampStop[] = [\n [0, \"#fbfcfe\"],\n [0.3, \"#f3f6fc\"],\n [0.5, \"#dde7f7\"],\n [0.65, \"#a8c4ec\"],\n [0.76, \"#5b8bd6\"],\n [0.85, \"#2f4fb0\"],\n [0.93, \"#6a2a9c\"],\n [1, \"#c4173f\"],\n];\n/** Height of the price tags of the axis, in pixels */\nconst TAG_HEIGHT = 16;\n/** Smallest distance between two trade bubbles' columns, in pixels */\nconst BUBBLE_SPACING = 6;\n/** Diameter of the largest trade bubble (default), in pixels */\nconst BUBBLE_SIZE = 14;\n/** Diameter of the smallest trade bubble, in pixels */\nconst BUBBLE_MIN = 3;\n\n/**\n * Lookup table of a ramp with positioned stops (`[position 0-1, color]`,\n * ascending), interpolated in OKLab\n */\nexport const positionedRamp = (\n stops: readonly (readonly [number, Rgba])[],\n size = LUT_SIZE,\n): Uint32Array => {\n const lut = new Uint32Array(size);\n if (!stops.length) return lut;\n const lab = stops.map(([, c]) => toOklab(c));\n let i = 0;\n for (let k = 0; k < size; k++) {\n const t = k / Math.max(1, size - 1);\n while (i + 1 < stops.length - 1 && t > stops[i + 1]![0]) i++;\n const [p0] = stops[i]!;\n const j = Math.min(stops.length - 1, i + 1);\n const [p1] = stops[j]!;\n const f = p1 > p0 ? Math.min(1, Math.max(0, (t - p0) / (p1 - p0))) : 0;\n const a = lab[i]!;\n const b = lab[j]!;\n lut[k] = packColor(\n fromOklab([\n a[0] + (b[0] - a[0]) * f,\n a[1] + (b[1] - a[1]) * f,\n a[2] + (b[2] - a[2]) * f,\n 1,\n ]),\n );\n }\n return lut;\n};\n\n/**\n * Rows (ticks) per drawn price row: 1 while a tick is at least 2 px tall,\n * otherwise the smallest 1 / 2 / 5 × 10ⁿ bucket that is (Bookmap sums the\n * sizes within a price bucket)\n */\nexport const rowBucket = (tickPx: number): number => {\n if (!(tickPx > 0) || tickPx >= MIN_ROW_PX) return 1;\n const need = MIN_ROW_PX / tickPx;\n for (let p = 1; p < 1e12; p *= 10) {\n for (const m of [1, 2, 5]) if (m * p >= need) return m * p;\n }\n return 1;\n};\n\nconst LABELS: LabelDictionary<OrderBookHeatmapLabels> = {\n en: {\n time: \"Time\",\n price: \"Price\",\n liquidity: \"Liquidity\",\n buys: \"Buys\",\n sells: \"Sells\",\n bid: \"Bid\",\n ask: \"Ask\",\n bidSide: \"Bid side\",\n askSide: \"Ask side\",\n bubbleHint: \"Bubble area = trade size\",\n name: \"Liquidity heatmap\",\n },\n zh: {\n time: \"时间\",\n price: \"价格\",\n liquidity: \"挂单量\",\n buys: \"主动买入\",\n sells: \"主动卖出\",\n bid: \"买一\",\n ask: \"卖一\",\n bidSide: \"买盘\",\n askSide: \"卖盘\",\n bubbleHint: \"气泡面积 = 成交量\",\n name: \"订单簿热力图\",\n },\n ja: {\n time: \"時刻\",\n price: \"価格\",\n liquidity: \"指値量\",\n buys: \"買い約定\",\n sells: \"売り約定\",\n bid: \"最良買気配\",\n ask: \"最良売気配\",\n bidSide: \"買い板\",\n askSide: \"売り板\",\n bubbleHint: \"バブル面積 = 出来高\",\n name: \"板ヒートマップ\",\n },\n fr: {\n time: \"Heure\",\n price: \"Prix\",\n liquidity: \"Liquidité\",\n buys: \"Achats\",\n sells: \"Ventes\",\n bid: \"Meilleur achat\",\n ask: \"Meilleure vente\",\n bidSide: \"Côté achat\",\n askSide: \"Côté vente\",\n bubbleHint: \"Aire de la bulle = volume\",\n name: \"Carte de chaleur de la liquidité\",\n },\n};\n\ninterface Column extends HeatSource {\n /** Sequence number */\n seq: number;\n /** Start time */\n time: number;\n /** Price rows (price / tick, rounded) */\n bins: Float64Array;\n sizes: Float32Array;\n bestBid: number;\n bestAsk: number;\n buyVolume: number;\n buyNotional: number;\n sellVolume: number;\n sellNotional: number;\n}\n\n/** Normalized intensity (0-1) of a size */\nexport const heatIntensity = (\n size: number,\n max: number,\n scale: OrderBookHeatmapScale,\n contrast: number,\n): number => {\n if (!(size > 0) || !(max > 0)) return 0;\n const r = Math.min(1, (size * contrast) / max);\n switch (scale) {\n case \"linear\":\n return r;\n case \"log\":\n // one decade: a tenth of the hottest size is a fifth of the ramp\n return Math.pow(Math.log10(1 + 9 * r), 1.2);\n default:\n // square root: thin liquidity stays cool, walls reach the warm end\n return Math.sqrt(r);\n }\n};\n\n/**\n * Cumulative distribution of the visible sizes (a coarse log histogram):\n * the rank of a size among the cells on screen, 0-1. It spreads a field of\n * similar sizes over the ramp (no flat wash) while the biggest walls stay\n * at its hot end. `version` of the grid it was built from.\n */\nexport interface SizeCdf {\n version: number;\n min: number;\n max: number;\n /** Bins of equal width in log space */\n cdf: Float32Array;\n}\n\nconst CDF_BINS = 48;\n\n/** Rank (0-1) of a size in the visible cells, `0` below the smallest */\nconst rankOf = (dist: SizeCdf, size: number): number => {\n if (!(size >= dist.min) || !(dist.max > dist.min)) return 0;\n const t = Math.log(size / dist.min) / Math.log(dist.max / dist.min);\n const x = Math.min(CDF_BINS - 1e-6, Math.max(0, t * CDF_BINS));\n const i = Math.floor(x);\n const f = x - i;\n const a = dist.cdf[i] ?? 0;\n const b = dist.cdf[i + 1] ?? a;\n return a + (b - a) * f;\n};\n\n/** Cumulative distribution of the positive sizes of a grid */\nexport const sizeCdf = (cells: Float32Array, version = 0): SizeCdf | null => {\n let min = Infinity;\n let max = 0;\n let count = 0;\n for (let i = 0; i < cells.length; i++) {\n const v = cells[i]!;\n if (!(v > 0)) continue;\n count++;\n if (v < min) min = v;\n if (v > max) max = v;\n }\n if (!count || !(max > min)) return null;\n const bins = new Float32Array(CDF_BINS + 1);\n const span = Math.log(max / min);\n for (let i = 0; i < cells.length; i++) {\n const v = cells[i]!;\n if (!(v > 0)) continue;\n const t = Math.log(v / min) / span;\n bins[Math.min(CDF_BINS, Math.floor(t * CDF_BINS))]! += 1;\n }\n let sum = 0;\n for (let i = 0; i <= CDF_BINS; i++) {\n sum += bins[i]!;\n bins[i] = sum / count;\n }\n return { version, min, max, cdf: bins };\n};\n\n/** Mix of the absolute curve and the rank (0-1 → 0-1) */\nexport const heatCurve =\n (dist: SizeCdf | null, max: number, base: (r: number) => number) =>\n (r: number): number => {\n const absolute = Math.min(1, Math.max(0, base(r)));\n if (!dist || !(max > 0)) return absolute;\n const rank = rankOf(dist, r * max);\n // the absolute size keeps the meaning of the ramp, the rank spreads the\n // mid-range over it (a field of similar sizes is not a flat wash)\n return Math.min(1, 0.55 * absolute + 0.45 * rank);\n };\n\n/**\n * Creates a liquidity heatmap in `container`: resting size over time and\n * price on the GPU, trades as bubbles, best bid / ask lines, the current\n * book profile, zoom / pan and a crosshair tooltip.\n */\nexport const createOrderBookHeatmap = (\n container: HTMLElement,\n initial: OrderBookHeatmapOptions = {},\n): OrderBookHeatmapInstance => {\n let options = initial;\n const store = createOrderBookStore();\n const emitter = createEmitter<OrderBookHeatmapEventMap>();\n let fmt: Formatters = createFormatters(options, 2, 4);\n let colors = { up: [0, 0, 0, 1] as Rgba, down: [0, 0, 0, 1] as Rgba };\n let lut: Uint32Array = new Uint32Array(LUT_SIZE);\n /** Size → color table of the current ramp and color scale */\n let table: Uint32Array = new Uint32Array(HEAT_TABLE_SIZE + 1);\n /** Base intensity curve (0-1 → 0-1) of the color scale */\n let curve: (r: number) => number = (r) => Math.sqrt(r);\n /** Distribution of the visible sizes (rank blending), rebuilt with the grid */\n let dist: SizeCdf | null = null;\n /** The empty field: the cold end of the ramp */\n let floor: Rgba = [0, 0, 0, 1];\n let dark = false;\n\n let tick = 0;\n let columns: Column[] = [];\n let seq = 0;\n /** Start of the open column (the live book), NaN before the first data */\n let openStart = NaN;\n const open = { buyVolume: 0, buyNotional: 0, sellVolume: 0, sellNotional: 0 };\n let lastTrade: MarketTrade | null = null;\n\n /** Time source: exchange times once any is given, the local clock otherwise */\n let dataTime = NaN;\n let dataWall = 0;\n\n /** Size at the hottest color (auto scale, eased) and its target */\n let scaleMax = 0;\n let scaleTarget = 0;\n let scaleAt = -Infinity;\n let bubbleRef = 0;\n /** Size at the full width of the profile */\n let profileMax = 0;\n /** The rasterized field and the inputs it was built from */\n let grid: HeatGrid | null = null;\n let gridKey = \"\";\n let paintKey = \"\";\n /** The live book as a column, cached by store version */\n let head: {\n version: number;\n bins: Float64Array;\n sizes: Float32Array;\n } | null = null;\n\n let renderer: HeatFieldRenderer | null = null;\n let rendererToken = 0;\n let destroyed = false;\n let resolveReady: (kind: ChartRendererKind | null) => void = () => {};\n const ready = new Promise<ChartRendererKind | null>((resolve) => {\n resolveReady = resolve;\n });\n\n /** View: time range and price range; follows the market unless panned */\n let follow = true;\n let windowSpan = NaN;\n let viewX: [number, number] = [0, 1];\n let viewY: [number, number] = [0, 1];\n /** `viewY` holds a fitted range (it eases toward `yTarget` afterwards) */\n let viewYReady = false;\n /** Price range the following view eases to */\n let yTarget: [number, number] | null = null;\n /** Price span chosen by the user (zoom), NaN for the auto fit */\n let ySpan = NaN;\n /** Monotonic clock of the view (no jitter back when data arrives) */\n let shownTime = NaN;\n let lastFrame = 0;\n let plot = { x: 0, y: 0, w: 0, h: 0 };\n let hoverAt: [number, number] | null = null;\n let hoverKey = \"\";\n let drag: {\n x: number;\n y: number;\n viewX: [number, number];\n viewY: [number, number];\n axis: boolean;\n span: number;\n } | null = null;\n\n const host = createHost(container, {\n className: \"minerva-orderbook-heatmap\",\n draw,\n onTheme: () => {\n refreshColors();\n host.invalidate();\n },\n });\n const { root, doc } = host;\n root.tabIndex = 0;\n root.setAttribute(\"role\", \"figure\");\n root.style.touchAction = \"none\";\n\n /** Texts in the locale, resolved on every option update */\n let texts = localeLabels(LABELS, options.locale, options.labels);\n const labels = () => texts;\n const applyTexts = () => {\n texts = localeLabels(LABELS, options.locale, options.labels);\n root.setAttribute(\"aria-label\", options.ariaLabel ?? texts.name);\n };\n const interval = () => Math.max(10, options.interval ?? 100);\n const history = () => Math.max(interval() * 4, options.history ?? 300_000);\n const depth = () => Math.max(4, Math.round(options.depth ?? 160));\n const nowTime = () => {\n if (!Number.isFinite(dataTime)) return Date.now();\n const elapsed = perfNow() - dataWall;\n return dataTime + Math.min(Math.max(0, elapsed), interval() * 3);\n };\n const perfNow = () =>\n typeof performance !== \"undefined\" ? performance.now() : Date.now();\n\n function refreshColors() {\n const theme = host.theme;\n colors = sideColors(theme, options);\n const resolve = (value: string) => {\n const c = theme.resolve\n ? theme.resolve(value, theme.primary)\n : theme.primary;\n return [c[0], c[1], c[2], 1] as Rgba;\n };\n const background: Rgba = [\n theme.background[0],\n theme.background[1],\n theme.background[2],\n 1,\n ];\n dark = theme.background[3] > 0 ? luminance(background) < 0.4 : false;\n if (options.colors?.length) {\n const ramp = options.colors.map(resolve);\n // the field is opaque: the empty color is the cold end of the ramp\n floor = ramp[0] ?? background;\n lut = oklabRamp(ramp.length > 1 ? ramp : [floor, floor], LUT_SIZE);\n } else {\n const stops = (dark ? DARK_RAMP : LIGHT_RAMP).map(\n ([at, hex]) => [at, parseColor(hex) ?? background] as const,\n );\n floor = stops[0]![1];\n lut = positionedRamp(stops, LUT_SIZE);\n }\n const scale = options.colorScale ?? \"sqrt\";\n curve = (r) => heatIntensity(r, 1, scale, 1);\n table = heatTable(lut, curve);\n paintKey = \"\";\n }\n\n const refreshFormat = () => {\n fmt = createFormatters(\n options,\n tick > 0\n ? Math.max(decimalsOf(tick), inferPriceDecimals(store))\n : inferPriceDecimals(store),\n inferSizeDecimals(store),\n );\n };\n\n /** A size with its unit, when `sizeUnit` is set */\n const withUnit = (text: string) => {\n const unit = options.sizeUnit?.trim();\n return unit ? `${text} ${unit}` : text;\n };\n\n const clearHistory = () => {\n columns = [];\n grid = null;\n gridKey = paintKey = \"\";\n head = null;\n dist = null;\n openStart = NaN;\n scaleMax = scaleTarget = 0;\n scaleAt = -Infinity;\n bubbleRef = 0;\n profileMax = 0;\n shownTime = NaN;\n open.buyVolume = open.buyNotional = open.sellVolume = open.sellNotional = 0;\n };\n\n // --------------------------------------------------------------- columns\n\n const ensureTick = () => {\n if (tick > 0) return;\n const base = inferTickSize(store);\n const mid = store.mid();\n if (options.tickSize && options.tickSize > 0) tick = options.tickSize;\n else if (base > 0 && Number.isFinite(mid)) {\n // rows of about 0.1 basis point: a round multiple of the tick (BTC at\n // 64,000 with a 0.1 tick: 0.5 rows)\n const ratio = (mid * 1e-5) / base;\n let multiple = 1;\n for (let p = 1; p <= 1e9 && multiple < ratio * 0.75; p *= 10) {\n for (const m of [1, 2, 5]) {\n multiple = m * p;\n if (multiple >= ratio * 0.75) break;\n }\n }\n tick = roundToStep(base * multiple, base);\n } else tick = Number.isFinite(mid) ? Math.max(1e-8, mid * 1e-5) : 0;\n if (tick > 0) refreshFormat();\n };\n\n /** Samples the book into price rows */\n const sampleBook = () => {\n const limit = depth();\n const bins = new Float64Array(limit * 2);\n const sizes = new Float32Array(limit * 2);\n let n = 0;\n for (const side of [\"bid\", \"ask\"] as const) {\n const count = store.count(side);\n let rows = 0;\n for (let i = 0; i < count; i++) {\n const bin = Math.round(store.priceAt(side, i) / tick);\n const size = store.sizeAt(side, i);\n if (n > 0 && bins[n - 1] === bin && rows > 0) {\n sizes[n - 1] += size;\n continue;\n }\n if (rows >= limit) break;\n bins[n] = bin;\n sizes[n] = size;\n n++;\n rows++;\n }\n }\n return { bins: bins.slice(0, n), sizes: sizes.slice(0, n) };\n };\n\n /** Closes the open column at `start` with the current book */\n const closeColumn = (start: number) => {\n if (!(tick > 0)) return;\n const { bins, sizes } = sampleBook();\n const column: Column = {\n seq: seq++,\n time: start,\n bins,\n sizes,\n bestBid: store.bestBid(),\n bestAsk: store.bestAsk(),\n buyVolume: open.buyVolume,\n buyNotional: open.buyNotional,\n sellVolume: open.sellVolume,\n sellNotional: open.sellNotional,\n };\n open.buyVolume = open.buyNotional = open.sellVolume = open.sellNotional = 0;\n columns.push(column);\n // history\n const oldest = start - history();\n let drop = 0;\n while (drop < columns.length && columns[drop]!.time < oldest) drop++;\n if (drop) columns = columns.slice(drop);\n };\n\n /** Closes every column ending before `time` */\n const advance = (time: number) => {\n if (!Number.isFinite(time)) return;\n const step = interval();\n if (!Number.isFinite(openStart)) {\n openStart = Math.floor(time / step) * step;\n return;\n }\n if (time - openStart > history()) {\n // a long gap: one column, then jump\n closeColumn(openStart);\n openStart = Math.floor(time / step) * step;\n return;\n }\n while (time >= openStart + step) {\n closeColumn(openStart);\n openStart += step;\n }\n };\n\n const noteTime = (time: number | undefined) => {\n if (time === undefined || !Number.isFinite(time)) return Date.now();\n if (!Number.isFinite(dataTime) || time >= dataTime) {\n dataTime = time;\n dataWall = perfNow();\n }\n return time;\n };\n\n /**\n * Column showing a time: the last one starting at or before it (a column\n * lasts until the next one), `null` for the open one or before the data\n */\n const columnAt = (time: number): Column | null => {\n if (Number.isFinite(openStart) && time >= openStart) return null;\n let lo = 0;\n let hi = columns.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (columns[mid]!.time <= time) lo = mid + 1;\n else hi = mid;\n }\n return lo > 0 ? columns[lo - 1]! : null;\n };\n\n // ----------------------------------------------------------------- field\n\n /** The live book as a column (sampled once per store version) */\n const headSource = (): HeatSource | null => {\n if (!Number.isFinite(openStart) || !(tick > 0)) return null;\n const version = store.version();\n if (!head || head.version !== version) head = { version, ...sampleBook() };\n return { time: openStart, bins: head.bins, sizes: head.sizes };\n };\n\n /**\n * The heat image of the view, rebuilt when its inputs change; the color\n * scale follows the 99th percentile of the visible non-empty cells\n * (eased): typical levels stay dim, only significant liquidity glows\n */\n const heatGrid = (\n x0: number,\n x1: number,\n y0: number,\n y1: number,\n end: number,\n dt: number,\n ): HeatGrid | null => {\n const step = interval();\n const live = headSource();\n const maxWidth = Math.min(MAX_TEXELS, Math.ceil(plot.w));\n const maxHeight = Math.min(MAX_TEXELS, Math.ceil(plot.h));\n const rowBins = rowBucket((tick / (y1 - y0)) * plot.h);\n const lastSeq = columns.length ? columns[columns.length - 1]!.seq : -1;\n const key = [\n x0,\n x1,\n y0,\n y1,\n Math.floor(end / step),\n columns.length,\n lastSeq,\n head?.version ?? -1,\n maxWidth,\n maxHeight,\n rowBins,\n tick,\n ].join(\"|\");\n if (key !== gridKey) {\n const sources: HeatSource[] = live ? [...columns, live] : columns;\n grid = buildHeatGrid(\n {\n sources,\n step,\n tick,\n x0,\n x1,\n y0,\n y1,\n end,\n maxWidth,\n maxHeight,\n rowBins,\n },\n grid,\n );\n gridKey = key;\n paintKey = \"\";\n }\n if (!grid) return null;\n // auto scale: a robust \"hot\" size, sampled at most 4 times a second\n const fixed = options.maxSize;\n if (fixed !== undefined && fixed > 0) scaleMax = fixed;\n else {\n const now = perfNow();\n if (now - scaleAt > 250 || !(scaleTarget > 0)) {\n const target = percentile(grid.cells, SCALE_QUANTILE);\n if (target > 0) scaleTarget = target;\n scaleAt = now;\n dist = sizeCdf(grid.cells, grid.version);\n }\n if (!(scaleMax > 0)) scaleMax = scaleTarget;\n else if (scaleTarget > 0 && Math.abs(scaleTarget / scaleMax - 1) > 1e-3)\n scaleMax += (scaleTarget - scaleMax) * ease(dt, 700);\n }\n const contrast = Math.max(0.01, options.contrast ?? 1);\n const k = scaleMax > 0 ? (HEAT_TABLE_SIZE * contrast) / scaleMax : 0;\n const paint = `${grid.version}|${k}|${dist?.version ?? -1}`;\n if (paint !== paintKey) {\n // the table maps a size (through `k`) to the mix of its absolute\n // intensity and its rank among the visible cells\n table = heatTable(lut, heatCurve(dist, scaleMax / contrast, curve));\n paintHeatGrid(grid, table, k);\n paintKey = paint;\n }\n return grid;\n };\n\n const visibleColumns = () => {\n const step = interval();\n const out: Column[] = [];\n // binary search of the first visible column\n let lo = 0;\n let hi = columns.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (columns[mid]!.time + step < viewX[0]) lo = mid + 1;\n else hi = mid;\n }\n for (let i = lo; i < columns.length; i++) {\n const c = columns[i]!;\n if (c.time > viewX[1]) break;\n out.push(c);\n }\n return out;\n };\n\n /** Trade volumes of a group of columns */\n interface Bubble {\n time: number;\n price: number;\n volume: number;\n buy: boolean;\n }\n type Flow = Pick<\n Column,\n \"buyVolume\" | \"buyNotional\" | \"sellVolume\" | \"sellNotional\"\n >;\n\n /**\n * Trades of the visible columns as bubbles: columns are grouped (by their\n * sequence, so groups stay put while the view scrolls) until a group is\n * BUBBLE_SPACING px wide; one bubble per side at the average price\n */\n const tradeBubbles = (\n visible: readonly Column[],\n columnPx: number,\n ): Bubble[] => {\n const step = interval();\n const k = Math.max(1, Math.ceil(BUBBLE_SPACING / Math.max(1e-6, columnPx)));\n const out: Bubble[] = [];\n let group = NaN;\n let t0 = 0;\n let t1 = 0;\n const sum = { bv: 0, bn: 0, sv: 0, sn: 0 };\n const flush = () => {\n const time = (t0 + t1) / 2;\n if (sum.sv > 0)\n out.push({ time, price: sum.sn / sum.sv, volume: sum.sv, buy: false });\n if (sum.bv > 0)\n out.push({ time, price: sum.bn / sum.bv, volume: sum.bv, buy: true });\n sum.bv = sum.bn = sum.sv = sum.sn = 0;\n };\n const add = (id: number, start: number, flow: Flow) => {\n const g = Math.floor(id / k);\n if (g !== group) {\n if (Number.isFinite(group)) flush();\n group = g;\n t0 = start;\n }\n t1 = start + step;\n sum.bv += flow.buyVolume;\n sum.bn += flow.buyNotional;\n sum.sv += flow.sellVolume;\n sum.sn += flow.sellNotional;\n };\n for (const c of visible) add(c.seq, c.time, c);\n if (Number.isFinite(openStart) && openStart <= viewX[1])\n add(seq, openStart, open);\n if (Number.isFinite(group)) flush();\n return out;\n };\n\n const clipPlot = (ctx: CanvasRenderingContext2D) => {\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.w, plot.h);\n ctx.clip();\n };\n\n /** Best bid / ask step lines and the translucent spread band between them */\n const drawBest = (\n ctx: CanvasRenderingContext2D,\n visible: readonly Column[],\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n columnPx: number,\n ) => {\n if (options.bestLines === false) return;\n const step = interval();\n // [start, end, bid, ask]: a column lasts until the next one\n const rows: [number, number, number, number][] = visible.map((c) => [\n c.time,\n c.time + step,\n c.bestBid,\n c.bestAsk,\n ]);\n if (Number.isFinite(openStart))\n rows.push([\n openStart,\n openStart + step,\n store.bestBid(),\n store.bestAsk(),\n ]);\n if (!rows.length) return;\n for (let i = 0; i + 1 < rows.length; i++) rows[i]![1] = rows[i + 1]![0];\n // wide columns: steps; narrow ones: a line through the column centers\n const steps = columnPx >= 2;\n const xs = (row: readonly number[]): [number, number] => {\n const xa = xOf(row[0]!);\n const xb = xOf(row[1]!);\n return steps ? [xa, xb] : [(xa + xb) / 2, (xa + xb) / 2];\n };\n clipPlot(ctx);\n // the spread band: one polygon per run of valid columns (no overlapping\n // rectangles, so no seams where neighbours meet)\n ctx.beginPath();\n let run: (typeof rows)[number][] = [];\n const flushRun = () => {\n if (!run.length) return;\n run.forEach((row, i) => {\n const [xa, xb] = xs(row);\n const y = yOf(row[3]);\n if (i) ctx.lineTo(xa, y);\n else ctx.moveTo(xa, y);\n ctx.lineTo(xb, y);\n });\n for (let i = run.length - 1; i >= 0; i--) {\n const [xa, xb] = xs(run[i]!);\n const y = yOf(run[i]![2]);\n ctx.lineTo(xb, y);\n ctx.lineTo(xa, y);\n }\n ctx.closePath();\n run = [];\n };\n for (const row of rows) {\n const [, , bid, ask] = row;\n if (Number.isFinite(bid) && Number.isFinite(ask) && ask > bid)\n run.push(row);\n else flushRun();\n }\n flushRun();\n ctx.fillStyle = toCss(host.theme.text, dark ? 0.08 : 0.07);\n ctx.fill();\n ctx.lineJoin = \"round\";\n for (const [index, color] of [\n [2, colors.up],\n [3, colors.down],\n ] as const) {\n ctx.beginPath();\n let pen = false;\n for (const row of rows) {\n const price = row[index];\n if (!Number.isFinite(price)) {\n pen = false;\n continue;\n }\n const y = yOf(price);\n const [xa, xb] = xs(row);\n if (pen) ctx.lineTo(xa, y);\n else ctx.moveTo(xa, y);\n if (steps) ctx.lineTo(xb, y);\n pen = true;\n }\n // a dark halo keeps the line readable on hot cells\n ctx.strokeStyle = toCss(floor, 0.55);\n ctx.lineWidth = 3.5;\n ctx.stroke();\n ctx.strokeStyle = toCss(color);\n ctx.lineWidth = 1.5;\n ctx.stroke();\n }\n ctx.restore();\n };\n\n /**\n * Trade bubbles: area ∝ volume (relative to the largest visible trade,\n * eased), translucent with a thin outline; the largest with their volume\n */\n const drawBubbles = (\n ctx: CanvasRenderingContext2D,\n bubbles: Bubble[],\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n fontSize: number,\n ) => {\n if (!bubbles.length) return;\n let max = 0;\n for (const b of bubbles) {\n const x = xOf(b.time);\n if (x >= plot.x && x <= plot.x + plot.w) max = Math.max(max, b.volume);\n }\n // the reference follows the visible trades: fast up, slowly down\n if (max > 0)\n bubbleRef = bubbleRef > 0 ? Math.max(max, bubbleRef * 0.995) : max;\n const ref = options.bubbleVolume ?? bubbleRef;\n if (!(ref > 0)) return;\n const maxD = Math.max(BUBBLE_MIN, options.bubbleSize ?? BUBBLE_SIZE);\n const minD = Math.min(BUBBLE_MIN, maxD);\n const sized = bubbles\n .map((b) => ({\n ...b,\n d: clamp(Math.sqrt(b.volume / ref) * maxD, minD, maxD),\n }))\n .sort((a, b) => a.d - b.d);\n clipPlot(ctx);\n ctx.lineWidth = 1;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.font = fontOf(host.theme, options, 600, Math.max(8, fontSize - 1));\n const rim: Rgba = dark ? [1, 1, 1, 1] : [0, 0, 0, 1];\n for (const b of sized) {\n const x = xOf(b.time);\n const y = yOf(b.price);\n const r = b.d / 2;\n if (x < plot.x - r || x > plot.x + plot.w + r) continue;\n if (y < plot.y - r || y > plot.y + plot.h + r) continue;\n const color = b.buy ? colors.up : colors.down;\n ctx.beginPath();\n ctx.arc(x, y, Math.max(1, r - 0.5), 0, Math.PI * 2);\n ctx.fillStyle = toCss(color, 0.35);\n ctx.fill();\n ctx.strokeStyle = toCss(mixOklab(color, rim, 0.2), 0.9);\n ctx.stroke();\n if (b.d >= 26) {\n const text = fmt.compact(b.volume);\n if (ctx.measureText(text).width <= b.d - 6) {\n ctx.fillStyle = toCss(dark ? [1, 1, 1, 1] : [0.08, 0.08, 0.1, 1]);\n ctx.fillText(text, x, y + 0.5);\n }\n }\n }\n ctx.restore();\n };\n\n /**\n * Price buckets of `ry` rows of a side of the live book (the rows of the\n * field: bucket `b` holds the rows `b × ry` to `b × ry + ry - 1`), best first\n */\n const bookBuckets = (side: OrderBookSide, ry: number) => {\n const buckets: number[] = [];\n const sizes: number[] = [];\n const count = store.count(side);\n let rows = 0;\n let lastBin = NaN;\n for (let i = 0; i < count; i++) {\n const bin = Math.round(store.priceAt(side, i) / tick);\n if (bin !== lastBin) {\n if (++rows > depth()) break;\n lastBin = bin;\n }\n const b = Math.floor(bin / ry);\n const size = store.sizeAt(side, i);\n if (buckets.length && buckets[buckets.length - 1] === b)\n sizes[sizes.length - 1] += size;\n else {\n buckets.push(b);\n sizes.push(size);\n }\n }\n return { side, buckets, sizes };\n };\n\n /** The current book as horizontal bars right of the plot, with a size scale */\n const drawProfile = (\n ctx: CanvasRenderingContext2D,\n px: number,\n profileW: number,\n yOf: (p: number) => number,\n fontSize: number,\n ry: number,\n ) => {\n const theme = host.theme;\n const [y0, y1] = viewY;\n const rowPx = Math.max(1, ((tick * ry) / (y1 - y0)) * plot.h);\n // bucket b spans [(b ry - ½) tick, (b ry + ry - ½) tick)\n const lowOf = (b: number) => (b * ry - 0.5) * tick;\n const highOf = (b: number) => (b * ry + ry - 0.5) * tick;\n let maxSize = 0;\n const sides = ([\"bid\", \"ask\"] as const).map((side) => {\n const levels = bookBuckets(side, ry);\n levels.buckets.forEach((b, i) => {\n if (highOf(b) >= y0 && lowOf(b) <= y1)\n maxSize = Math.max(maxSize, levels.sizes[i]!);\n });\n return levels;\n });\n // a fine \"nice\" scale (the largest bar fills 75-100 % of the panel),\n // changed only on a clear change: no jumping bars\n if (maxSize > profileMax || maxSize < profileMax * 0.6 || !(profileMax > 0))\n profileMax = fineCeil(maxSize);\n if (!(profileMax > 0)) return;\n const left = px + 2;\n const inner = Math.max(4, profileW - 6);\n // faint guides at half and full scale\n ctx.strokeStyle = toCss(theme.text, 0.07);\n ctx.lineWidth = 1;\n ctx.setLineDash([2, 3]);\n ctx.beginPath();\n for (const f of [0.5, 1]) {\n const x = Math.round(left + inner * f) - 0.5;\n ctx.moveTo(x, plot.y);\n ctx.lineTo(x, plot.y + plot.h);\n }\n ctx.stroke();\n ctx.setLineDash([]);\n ctx.save();\n ctx.beginPath();\n ctx.rect(px, plot.y, profileW, plot.h);\n ctx.clip();\n // rows on whole pixels from the bucket edges; a 1 px gap when tall\n const gap = rowPx >= 4 ? 1 : 0;\n const bar = (b: number, s: number) => {\n const top = Math.round(yOf(highOf(b)));\n const bottom = Math.max(top + 1, Math.round(yOf(lowOf(b))) - gap);\n const w = Math.max(1, Math.min(inner, (s / profileMax) * inner));\n ctx.rect(left, top, w, bottom - top);\n };\n for (const { side, buckets, sizes } of sides) {\n const color = side === \"bid\" ? colors.up : colors.down;\n ctx.beginPath();\n for (let i = 1; i < buckets.length; i++) {\n const b = buckets[i]!;\n if (highOf(b) >= y0 && lowOf(b) <= y1) bar(b, sizes[i]!);\n }\n ctx.fillStyle = toCss(color, dark ? 0.62 : 0.55);\n ctx.fill();\n // the best bucket, solid\n const best = buckets[0];\n if (best !== undefined && highOf(best) >= y0 && lowOf(best) <= y1) {\n ctx.beginPath();\n bar(best, sizes[0]!);\n ctx.fillStyle = toCss(color);\n ctx.fill();\n }\n }\n ctx.restore();\n // size scale below the panel\n const y = Math.round(plot.y + plot.h + 4) + 0.5;\n ctx.strokeStyle = toCss(theme.textMuted, 0.7);\n ctx.beginPath();\n ctx.moveTo(left, y);\n ctx.lineTo(left + inner, y);\n for (const f of [0, 0.5, 1]) {\n const x = Math.round(left + inner * f) + 0.5;\n ctx.moveTo(x, y);\n ctx.lineTo(x, y + 3);\n }\n ctx.stroke();\n ctx.font = fontOf(theme, options, 400, Math.max(8, fontSize - 1));\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textBaseline = \"top\";\n const text = fmt.compact(profileMax);\n const tw = ctx.measureText(text).width;\n ctx.textAlign = \"right\";\n ctx.fillText(text, left + inner + 2, y + 4);\n if (tw + ctx.measureText(\"0\").width + 8 < inner) {\n ctx.textAlign = \"left\";\n ctx.fillText(\"0\", left - 1, y + 4);\n }\n };\n\n /** Hovered cell: pointer, time, price row (bucket of `ry` ticks) */\n interface HoverCell {\n hx: number;\n hy: number;\n /** Time under the pointer */\n time: number;\n /** Start of the hovered column (NaN outside the data) */\n start: number;\n column: Column | null;\n /** Bucket: rows `bucket × ry` to `bucket × ry + ry - 1` */\n bucket: number;\n ry: number;\n /** Lowest / highest row price of the bucket and its center */\n low: number;\n high: number;\n rowPrice: number;\n }\n\n const hoverCell = (ry: number): HoverCell | null => {\n if (!hoverAt || options.tooltip === false || !(tick > 0) || drag)\n return null;\n if (!viewYReady) return null;\n const [hx, hy] = hoverAt;\n if (\n hx < plot.x ||\n hx > plot.x + plot.w ||\n hy < plot.y ||\n hy > plot.y + plot.h\n )\n return null;\n const [x0, x1] = viewX;\n const [y0, y1] = viewY;\n const time = x0 + ((hx - plot.x) / plot.w) * (x1 - x0);\n const price = y0 + ((plot.y + plot.h - hy) / plot.h) * (y1 - y0);\n const bucket = Math.floor(Math.round(price / tick) / ry);\n const digits = Math.min(12, decimalsOf(tick) + 2);\n const low = +(bucket * ry * tick).toFixed(digits);\n const high = +((bucket * ry + ry - 1) * tick).toFixed(digits);\n const rowPrice = +((low + high) / 2).toFixed(digits);\n const column = columnAt(time);\n const start = column\n ? column.time\n : Number.isFinite(openStart) && time >= openStart\n ? openStart\n : NaN;\n return { hx, hy, time, start, column, bucket, ry, low, high, rowPrice };\n };\n\n /** Price / time tag: filled (best bid / ask, hover) or outlined (last trade) */\n const drawTag = (\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n maxWidth: number,\n color: Rgba,\n filled: boolean,\n align: \"left\" | \"center\" = \"left\",\n ) => {\n const w = Math.min(ctx.measureText(text).width + 10, maxWidth);\n const left = align === \"center\" ? x - w / 2 : x;\n ctx.fillStyle = filled ? toCss(color) : toCss(floor);\n roundRect(ctx, left, y - TAG_HEIGHT / 2, w, TAG_HEIGHT, 3);\n ctx.fill();\n if (!filled) {\n ctx.strokeStyle = toCss(color);\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n ctx.fillStyle = filled\n ? luminance(color) > 0.6\n ? \"#111\"\n : \"#fff\"\n : toCss(color);\n ctx.textAlign = align;\n ctx.textBaseline = \"middle\";\n ctx.fillText(text, align === \"center\" ? x : left + 5, y + 0.5);\n };\n\n // ---------------------------------------------------------------- draw\n\n /** A packed ramp color as CSS (`packColor`), alpha dropped */\n const rampCss = (packed: number) => {\n const r = packed & 255;\n const g = (packed >>> 8) & 255;\n const b = (packed >>> 16) & 255;\n return `rgb(${r}, ${g}, ${b})`;\n };\n\n /**\n * Legend in the top-left corner of the plot: the color ramp with the size\n * range it covers (cold = empty, hot = the largest size) and what the\n * bubbles are, so a color can be read as a size\n */\n const drawLegend = (ctx: CanvasRenderingContext2D, fontSize: number) => {\n if (plot.w < 200 || plot.h < 96) return;\n const theme = host.theme;\n const l = labels();\n const unit = options.sizeUnit?.trim();\n const title = unit ? `${l.liquidity} · ${unit}` : l.liquidity;\n const bold = fontOf(theme, options, 600, fontSize - 1);\n const regular = fontOf(theme, options, 400, fontSize - 1);\n const small = fontSize - 2;\n const barW = 76;\n const barH = 7;\n const max = scaleMax > 0 ? fmt.size(scaleMax) : \"–\";\n // measures\n ctx.font = bold;\n const titleW = ctx.measureText(title).width;\n ctx.font = fontOf(theme, options, 400, small);\n const lowW = ctx.measureText(\"0\").width;\n const highW = ctx.measureText(max).width;\n ctx.font = regular;\n const hintW = ctx.measureText(l.bubbleHint).width;\n const dotsW = small + 10;\n const innerW = Math.max(barW, titleW, hintW + dotsW);\n const pad = 7;\n const boxW = innerW + pad * 2;\n const rowH = fontSize - 1;\n const boxH = pad * 2 + rowH + 3 + barH + 2 + small + 6 + rowH;\n const bx = plot.x + 8;\n const by = plot.y + 8;\n if (bx + boxW > plot.x + plot.w - 8) return;\n // panel: a full subtle border, no accent edge\n ctx.fillStyle = toCss(theme.background, dark ? 0.82 : 0.88);\n ctx.strokeStyle = toCss(theme.axis, 0.6);\n ctx.lineWidth = 1;\n roundRect(ctx, bx + 0.5, by + 0.5, boxW, boxH, 6);\n ctx.fill();\n ctx.stroke();\n const left = bx + pad;\n ctx.textAlign = \"left\";\n ctx.textBaseline = \"middle\";\n // title\n ctx.font = bold;\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.fillText(title, left, by + pad + rowH / 2);\n // ramp\n const rampY = by + pad + rowH + 3;\n const gradient = ctx.createLinearGradient(left, rampY, left + barW, rampY);\n for (let i = 0; i <= 8; i++) {\n const t = i / 8;\n const packed = lut[Math.round(t * (lut.length - 1))] ?? 0;\n gradient.addColorStop(t, rampCss(packed));\n }\n ctx.fillStyle = gradient;\n roundRect(ctx, left, rampY, barW, barH, 2);\n ctx.fill();\n // its size range\n ctx.font = fontOf(theme, options, 400, small);\n ctx.fillStyle = toCss(theme.textMuted);\n const labelY = rampY + barH + 2 + small / 2;\n ctx.fillText(\"0\", left, labelY);\n ctx.textAlign = \"right\";\n ctx.fillText(max, left + Math.max(barW, highW + lowW), labelY);\n ctx.textAlign = \"left\";\n // trades\n const hintY = labelY + small / 2 + 6 + rowH / 2;\n const dot = small / 2;\n for (const [i, color] of [colors.up, colors.down].entries()) {\n ctx.fillStyle = toCss(color, 0.9);\n ctx.beginPath();\n ctx.arc(left + dot + i * (small + 4), hintY, dot, 0, Math.PI * 2);\n ctx.fill();\n }\n ctx.font = regular;\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.fillText(l.bubbleHint, left + dotsW, hintY);\n };\n\n function draw(now: number): boolean {\n const ctx = host.ctx;\n if (!ctx) return false;\n const { width, height, dpr, theme } = host;\n const dt = lastFrame ? now - lastFrame : 0;\n lastFrame = now;\n const l = labels();\n const fontSize = options.fontSize ?? (width < 420 ? 10 : 11);\n const regular = fontOf(theme, options, 400, fontSize);\n const bold = fontOf(theme, options, 600, fontSize);\n const step = interval();\n const live = !Number.isFinite(dataTime);\n if (live && store.count(\"bid\") + store.count(\"ask\") > 0)\n advance(Date.now());\n // a monotonic clock: the view never jumps back when data arrives late\n const clock = nowTime();\n shownTime =\n Number.isFinite(shownTime) && clock > shownTime - step * 4\n ? Math.max(shownTime, clock)\n : clock;\n const time = shownTime;\n\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, width, height);\n\n // layout\n ensureTick();\n const mid = store.mid();\n ctx.font = bold;\n const sample = fmt.price(Number.isFinite(mid) ? mid * 1.0001 : 0);\n const axisW = Math.ceil(ctx.measureText(sample).width) + 18;\n ctx.font = regular;\n const profileW =\n options.profile === false ? 0 : Math.round(clamp(width * 0.12, 56, 120));\n const timeH = fontSize + 12;\n plot = {\n x: 0,\n y: 0,\n w: Math.max(10, width - axisW - profileW),\n h: Math.max(10, height - timeH),\n };\n const px = plot.x + plot.w;\n const right = px + profileW;\n\n // view: the following view fits the data (history fills the plot from\n // the left) and keeps the price range while the market stays inside it\n if (!Number.isFinite(windowSpan))\n windowSpan = Math.max(step * 10, options.window ?? 60_000);\n if (follow) {\n const first = columns.length ? columns[0]!.time : openStart;\n // the view ends at the live time: the open column (the live book) is\n // cut by the right edge, so no gap opens while it is being sampled\n viewX = fitTimeRange(\n first,\n time,\n windowSpan,\n Math.min(windowSpan, step * 60),\n );\n let lo = store.bestBid();\n let hi = store.bestAsk();\n for (const c of visibleColumns()) {\n if (Number.isFinite(c.bestBid) && !(c.bestBid >= lo)) lo = c.bestBid;\n if (Number.isFinite(c.bestAsk) && !(c.bestAsk <= hi)) hi = c.bestAsk;\n }\n if (!Number.isFinite(lo)) lo = hi;\n if (!Number.isFinite(hi)) hi = lo;\n const minSpan = tick > 0 ? tick * Math.max(40, plot.h / 6) : 0;\n const fixed =\n options.priceSpan ?? (Number.isFinite(ySpan) ? ySpan : undefined);\n if (minSpan > 0 || fixed !== undefined) {\n yTarget = fitPriceRange(yTarget, lo, hi, minSpan, fixed);\n const [t0, t1] = yTarget;\n if (Number.isFinite(t0) && Number.isFinite(t1)) {\n if (!viewYReady) {\n viewY = [t0, t1];\n viewYReady = true;\n } else {\n const k = ease(dt, 280);\n viewY = [\n viewY[0] + (t0 - viewY[0]) * k,\n viewY[1] + (t1 - viewY[1]) * k,\n ];\n }\n }\n }\n }\n const [x0, x1] = viewX;\n const [y0, y1] = viewY;\n const xOf = (t: number) => plot.x + ((t - x0) / (x1 - x0)) * plot.w;\n const yOf = (p: number) =>\n plot.y + plot.h - ((p - y0) / (y1 - y0)) * plot.h;\n const ready = viewYReady && tick > 0;\n const visible = visibleColumns();\n const columnPx = (step / (x1 - x0)) * plot.w;\n /** Price rows per drawn row (bucketing of thin rows), as the field */\n let ry = ready ? rowBucket((tick / (y1 - y0)) * plot.h) : 1;\n\n // data layer: the heat field (an opaque image over the cold color)\n const floorCss = toCss(floor);\n if (renderer) {\n const canvas = renderer.canvas;\n canvas.style.left = `${plot.x}px`;\n canvas.style.top = `${plot.y}px`;\n canvas.style.width = `${plot.w}px`;\n canvas.style.height = `${plot.h}px`;\n const bw = Math.max(1, Math.round(plot.w * dpr));\n const bh = Math.max(1, Math.round(plot.h * dpr));\n if (canvas.width !== bw || canvas.height !== bh) renderer.resize(bw, bh);\n const heat =\n ready && Number.isFinite(openStart)\n ? heatGrid(x0, x1, y0, y1, time, dt)\n : null;\n if (heat) ry = heat.rowBins;\n // the image rectangle in device pixels of the plot canvas\n const sx = bw / plot.w;\n const sy = bh / plot.h;\n const rect: [number, number, number, number] = heat\n ? [\n (xOf(heat.t0) - plot.x) * sx,\n (yOf(heat.p1) - plot.y) * sy,\n (xOf(heat.t1) - plot.x) * sx,\n (yOf(heat.p0) - plot.y) * sy,\n ]\n : [0, 0, 0, 0];\n renderer.render(heat, rect, floor);\n } else {\n ctx.fillStyle = floorCss;\n ctx.fillRect(plot.x, plot.y, plot.w, plot.h);\n }\n\n // no grid inside the field (it would read as liquidity): short tick\n // marks on the time and price axes instead\n const yTicks = ready\n ? linearTicks(y0, y1, Math.max(2, Math.floor(plot.h / 44)))\n : [];\n const xt = timeTicks(\n x0,\n x1,\n Math.max(2, Math.floor(plot.w / 75)),\n undefined,\n options.timeZone ?? \"local\",\n );\n ctx.strokeStyle = toCss(theme.axis);\n ctx.lineWidth = 1;\n ctx.beginPath();\n for (const p of yTicks) {\n const y = Math.round(yOf(p)) + 0.5;\n ctx.moveTo(right, y);\n ctx.lineTo(right + 4, y);\n }\n for (const t of xt.values) {\n const x = Math.round(xOf(t)) + 0.5;\n if (x <= plot.x + 1 || x >= px - 1) continue;\n ctx.moveTo(x, plot.y + plot.h);\n ctx.lineTo(x, plot.y + plot.h + 4);\n }\n ctx.stroke();\n\n // trades, then the best bid / ask on top of them, the current book\n if (ready) {\n if (options.bubbles !== false)\n drawBubbles(ctx, tradeBubbles(visible, columnPx), xOf, yOf, fontSize);\n drawBest(ctx, visible, xOf, yOf, columnPx);\n if (profileW) drawProfile(ctx, px, profileW, yOf, fontSize, ry);\n }\n\n // frame\n ctx.strokeStyle = toCss(theme.axis);\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(0, Math.round(plot.y + plot.h) + 0.5);\n ctx.lineTo(width, Math.round(plot.y + plot.h) + 0.5);\n if (profileW) {\n ctx.moveTo(Math.round(px) + 0.5, plot.y);\n ctx.lineTo(Math.round(px) + 0.5, plot.y + plot.h);\n }\n ctx.moveTo(Math.round(right) + 0.5, plot.y);\n ctx.lineTo(Math.round(right) + 0.5, plot.y + plot.h);\n ctx.stroke();\n\n if (options.legend !== false) drawLegend(ctx, fontSize);\n\n const cell = ready ? hoverCell(ry) : null;\n\n // time axis (the hover time tag hides the ticks it covers)\n ctx.font = regular;\n const hoverTime = cell\n ? formatClock(\n Number.isFinite(cell.start) ? cell.start : cell.time,\n step < 1000,\n options.timeZone,\n )\n : \"\";\n const hoverHalf = cell ? ctx.measureText(hoverTime).width / 2 + 8 : 0;\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"top\";\n for (const t of xt.values) {\n const x = xOf(t);\n const text = xt.format(t);\n const half = ctx.measureText(text).width / 2;\n // labels stay whole inside the plot\n if (x - half < plot.x + 2 || x + half > px - 2) continue;\n if (cell && Math.abs(x - cell.hx) < hoverHalf + half) continue;\n ctx.fillText(text, x, plot.y + plot.h + 6);\n }\n\n // price axis: pinned tags (best ask / bid, last trade) win over the\n // ticks, the hover tag over everything\n const last = lastTrade;\n const pins: { price: number; color: Rgba; filled: boolean }[] = [\n { price: store.bestAsk(), color: colors.down, filled: true },\n { price: store.bestBid(), color: colors.up, filled: true },\n ];\n if (\n last &&\n last.price !== store.bestBid() &&\n last.price !== store.bestAsk()\n )\n pins.push({\n price: last.price,\n color: last.side === \"buy\" ? colors.up : colors.down,\n filled: false,\n });\n const shownPins = ready\n ? pins.filter(\n (p) => Number.isFinite(p.price) && p.price >= y0 && p.price <= y1,\n )\n : [];\n const hoverY = cell ? Math.round(yOf(cell.rowPrice)) + 0.5 : NaN;\n const layout = layoutAxisLabels(\n shownPins.map((p): AxisLabel => ({ y: yOf(p.price), h: TAG_HEIGHT })),\n cell ? { y: hoverY, h: TAG_HEIGHT } : null,\n yTicks.map(yOf),\n fontSize + 2,\n [plot.y, plot.y + plot.h],\n );\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.textAlign = \"left\";\n ctx.textBaseline = \"middle\";\n yTicks.forEach((p, i) => {\n if (layout.ticks[i]) ctx.fillText(fmt.price(p), right + 6, yOf(p));\n });\n ctx.font = bold;\n shownPins.forEach((pin, i) => {\n const y = layout.pinned[i];\n if (y === null || y === undefined) return;\n const at = yOf(pin.price);\n if (Math.abs(y - at) > 1) {\n // a moved tag points at its price\n ctx.strokeStyle = toCss(pin.color);\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.moveTo(right - 4, at);\n ctx.lineTo(right + 1, y);\n ctx.stroke();\n }\n drawTag(\n ctx,\n fmt.price(pin.price),\n right + 1,\n y,\n width - right - 2,\n pin.color,\n pin.filled,\n );\n });\n\n // crosshair, hover tags and tooltip\n drawHover(ctx, xOf, yOf, right, l, cell, hoverY, hoverTime);\n ctx.font = regular;\n\n host.describe(\n `${options.ariaLabel ?? l.name}. ${l.bid} ${fmt.price(store.bestBid())}, ${l.ask} ${fmt.price(store.bestAsk())}.`,\n );\n // keep scrolling while following a live market\n const fresh = live || perfNow() - dataWall < 2000;\n return (\n (follow && fresh && Number.isFinite(openStart)) ||\n (viewYReady && yTarget !== null && Math.abs(viewY[0] - yTarget[0]) > 1e-9)\n );\n }\n\n function drawHover(\n ctx: CanvasRenderingContext2D,\n xOf: (t: number) => number,\n yOf: (p: number) => number,\n right: number,\n l: OrderBookHeatmapLabels,\n cell: HoverCell | null,\n hoverY: number,\n timeText: string,\n ) {\n const { theme } = host;\n if (!cell) {\n host.tooltip.style.display = \"none\";\n if (hoverKey) {\n hoverKey = \"\";\n emitter.emit(\"hover\", null);\n }\n return;\n }\n const { hx, hy, time, start, column, bucket, ry, low, high, rowPrice } =\n cell;\n const inBucket = (bin: number) => Math.floor(bin / ry) === bucket;\n const step = interval();\n let size = 0;\n let bestBid = NaN;\n let bestAsk = NaN;\n let buyVolume = 0;\n let sellVolume = 0;\n if (column) {\n for (let i = 0; i < column.bins.length; i++) {\n if (inBucket(column.bins[i]!)) size += column.sizes[i]!;\n }\n ({ bestBid, bestAsk, buyVolume, sellVolume } = column);\n } else if (Number.isFinite(start)) {\n const live = headSource();\n if (live) {\n for (let i = 0; i < live.bins.length; i++) {\n if (inBucket(live.bins[i]!)) size += live.sizes[i]!;\n }\n }\n bestBid = store.bestBid();\n bestAsk = store.bestAsk();\n buyVolume = open.buyVolume;\n sellVolume = open.sellVolume;\n }\n // a bucket holding both sides (around the spread) has no side\n const side: OrderBookSide | null =\n high <= bestBid ? \"bid\" : low >= bestAsk ? \"ask\" : null;\n\n // crosshair\n ctx.strokeStyle = toCss(theme.text, 0.5);\n ctx.lineWidth = 1;\n ctx.setLineDash([3, 3]);\n ctx.beginPath();\n ctx.moveTo(Math.round(hx) + 0.5, plot.y);\n ctx.lineTo(Math.round(hx) + 0.5, plot.y + plot.h);\n ctx.moveTo(plot.x, hoverY);\n ctx.lineTo(right, hoverY);\n ctx.stroke();\n ctx.setLineDash([]);\n if (Number.isFinite(start)) {\n // outline of the hovered cell\n const cx0 = xOf(start);\n const cx1 = xOf(start + step);\n const cy0 = yOf((bucket * ry + ry - 0.5) * tick);\n const cy1 = yOf((bucket * ry - 0.5) * tick);\n ctx.strokeStyle = toCss(theme.text, 0.85);\n ctx.strokeRect(cx0, cy0, Math.max(2, cx1 - cx0), Math.max(2, cy1 - cy0));\n }\n // price and time tags\n ctx.font = fontOf(\n theme,\n options,\n 600,\n options.fontSize ?? (host.width < 420 ? 10 : 11),\n );\n drawTag(\n ctx,\n fmt.price(rowPrice),\n right + 1,\n hoverY,\n host.width - right - 2,\n theme.text,\n true,\n );\n drawTag(\n ctx,\n timeText,\n clamp(hx, plot.x + 40, plot.x + plot.w - 40),\n plot.y + plot.h + TAG_HEIGHT / 2 + 2,\n plot.w,\n theme.text,\n true,\n \"center\",\n );\n\n const sideColor =\n side === \"bid\" ? colors.up : side === \"ask\" ? colors.down : null;\n tooltipHtml(\n doc,\n host.tooltip,\n {\n text: formatClock(\n Number.isFinite(start) ? start : time,\n true,\n options.timeZone,\n ),\n color: undefined,\n // the side as a small colored badge (no accent border)\n badge:\n side && sideColor\n ? {\n text: side === \"bid\" ? l.bidSide : l.askSide,\n color: toCss(sideColor),\n }\n : undefined,\n },\n [\n [\n l.price,\n ry > 1\n ? `${fmt.price(low)} – ${fmt.price(high)}`\n : fmt.price(rowPrice),\n ],\n [l.liquidity, withUnit(fmt.size(size))],\n [l.buys, withUnit(fmt.size(buyVolume))],\n [l.sells, withUnit(fmt.size(sellVolume))],\n ],\n );\n host.tooltip.style.display = \"block\";\n host.placeTooltip(\n host.tooltip,\n hx,\n hy,\n hx > plot.w * 0.6 ? \"left\" : \"right\",\n );\n\n const key = `${start}|${bucket}|${ry}|${size}|${buyVolume}|${sellVolume}`;\n if (key !== hoverKey) {\n hoverKey = key;\n const event: OrderBookHeatmapHoverEvent = {\n time: Number.isFinite(start) ? start : time,\n price: low,\n priceHigh: high,\n size,\n side,\n buyVolume,\n sellVolume,\n };\n emitter.emit(\"hover\", event);\n }\n }\n\n // ------------------------------------------------------------ renderer\n\n const initRenderer = async (exclude: Set<ChartRendererKind> = new Set()) => {\n const token = ++rendererToken;\n const next = await createHeatFieldRenderer(\n options.renderer ?? \"auto\",\n () => {\n const canvas = doc.createElement(\"canvas\");\n Object.assign(canvas.style, {\n position: \"absolute\",\n left: \"0\",\n top: \"0\",\n pointerEvents: \"none\",\n });\n canvas.setAttribute(\"aria-hidden\", \"true\");\n return canvas;\n },\n (kind) => {\n if (destroyed || renderer?.kind !== kind) return;\n renderer.destroy();\n renderer.canvas.remove();\n renderer = null;\n void initRenderer(new Set([...exclude, kind]));\n },\n exclude,\n );\n if (destroyed || token !== rendererToken) {\n next?.destroy();\n return;\n }\n if (renderer) {\n renderer.destroy();\n renderer.canvas.remove();\n }\n renderer = next;\n if (next) {\n root.dataset.renderer = next.kind;\n root.insertBefore(next.canvas, host.canvas);\n emitter.emit(\"renderer\", next.kind);\n } else delete root.dataset.renderer;\n resolveReady(next?.kind ?? null);\n host.invalidate();\n };\n const unfollowDefault = followDefaultRenderer(\n () => options.renderer,\n () => void initRenderer(),\n );\n\n // --------------------------------------------------------- interaction\n\n const setFollow = (value: boolean) => {\n if (follow === value) return;\n follow = value;\n emitter.emit(\"follow\", value);\n };\n\n /** Keeps a panned time range near the data (half a view of margin) */\n const clampTime = (range: [number, number]): [number, number] => {\n const first = columns.length ? columns[0]!.time : openStart;\n if (!Number.isFinite(first)) return range;\n const span = range[1] - range[0];\n const latest = Number.isFinite(shownTime) ? shownTime : nowTime();\n const max = latest + interval() + span / 2;\n const start = Math.max(first - span / 2, Math.min(range[0], max - span));\n return [start, start + span];\n };\n\n const onPointerDown = (event: PointerEvent) => {\n if (options.interactive === false) return;\n const [x, y] = localPoint(root, event);\n root.setPointerCapture?.(event.pointerId);\n drag = {\n x,\n y,\n viewX: [...viewX],\n viewY: [...viewY],\n axis: x > plot.x + plot.w,\n span: viewY[1] - viewY[0],\n };\n };\n const onPointerMove = (event: PointerEvent) => {\n const [x, y] = localPoint(root, event);\n hoverAt = [x, y];\n if (drag) {\n const dx = x - drag.x;\n const dy = y - drag.y;\n if (drag.axis) {\n // dragging the price axis scales the prices around the center\n const span = drag.span * Math.exp(dy * 0.006);\n const c = (drag.viewY[0] + drag.viewY[1]) / 2;\n ySpan = span;\n viewY = [c - span / 2, c + span / 2];\n yTarget = [viewY[0], viewY[1]];\n } else if (Math.abs(dx) + Math.abs(dy) > 3) {\n setFollow(false);\n const tx = ((drag.viewX[1] - drag.viewX[0]) / plot.w) * dx;\n const ty = ((drag.viewY[1] - drag.viewY[0]) / plot.h) * dy;\n viewX = clampTime([drag.viewX[0] - tx, drag.viewX[1] - tx]);\n viewY = [drag.viewY[0] + ty, drag.viewY[1] + ty];\n }\n }\n host.invalidate();\n };\n const onPointerUp = (event: PointerEvent) => {\n root.releasePointerCapture?.(event.pointerId);\n drag = null;\n host.invalidate();\n };\n const onPointerLeave = () => {\n if (drag) return;\n hoverAt = null;\n host.invalidate();\n };\n const zoomTime = (factor: number, anchorX: number) => {\n const [a, b] = viewX;\n const span = clamp(\n (follow ? windowSpan : b - a) * factor,\n interval() * 10,\n history(),\n );\n windowSpan = span;\n if (!follow) {\n const t = a + ((anchorX - plot.x) / plot.w) * (b - a);\n const r = (t - a) / (b - a);\n viewX = clampTime([t - span * r, t + span * (1 - r)]);\n }\n host.invalidate();\n };\n const zoomPrice = (factor: number) => {\n const span = clamp(\n (viewY[1] - viewY[0]) * factor,\n tick * 6 || 1e-9,\n Infinity,\n );\n const c = (viewY[0] + viewY[1]) / 2;\n ySpan = span;\n viewY = [c - span / 2, c + span / 2];\n yTarget = [viewY[0], viewY[1]];\n host.invalidate();\n };\n const onWheel = (event: WheelEvent) => {\n if (options.interactive === false || !(event.ctrlKey || event.metaKey))\n return;\n event.preventDefault();\n const [x] = localPoint(root, event);\n const factor = Math.exp(event.deltaY * 0.002);\n if (event.shiftKey || x > plot.x + plot.w) zoomPrice(factor);\n else zoomTime(factor, x);\n };\n const onDoubleClick = () => {\n if (options.interactive === false) return;\n instance.resetView();\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (options.interactive === false) return;\n switch (event.key) {\n case \"+\":\n case \"=\":\n zoomTime(0.8, plot.x + plot.w);\n break;\n case \"-\":\n zoomTime(1.25, plot.x + plot.w);\n break;\n case \"ArrowUp\":\n case \"ArrowDown\": {\n if (event.shiftKey) {\n zoomPrice(event.key === \"ArrowUp\" ? 0.8 : 1.25);\n break;\n }\n setFollow(false);\n const d =\n (viewY[1] - viewY[0]) * 0.1 * (event.key === \"ArrowUp\" ? 1 : -1);\n viewY = [viewY[0] + d, viewY[1] + d];\n host.invalidate();\n break;\n }\n case \"ArrowLeft\":\n case \"ArrowRight\": {\n setFollow(false);\n const d =\n (viewX[1] - viewX[0]) * 0.1 * (event.key === \"ArrowLeft\" ? -1 : 1);\n viewX = clampTime([viewX[0] + d, viewX[1] + d]);\n host.invalidate();\n break;\n }\n case \"0\":\n case \"Home\":\n instance.resetView();\n break;\n default:\n return;\n }\n event.preventDefault();\n };\n\n root.addEventListener(\"pointerdown\", onPointerDown);\n root.addEventListener(\"pointermove\", onPointerMove);\n root.addEventListener(\"pointerup\", onPointerUp);\n root.addEventListener(\"pointercancel\", onPointerUp);\n root.addEventListener(\"pointerleave\", onPointerLeave);\n root.addEventListener(\"wheel\", onWheel, { passive: false });\n root.addEventListener(\"dblclick\", onDoubleClick);\n root.addEventListener(\"keydown\", onKeyDown);\n\n // ----------------------------------------------------------------- api\n\n const applyOne = (delta: OrderBookDelta) => {\n const time = noteTime(delta.time);\n if (store.count(\"bid\") + store.count(\"ask\") > 0) {\n ensureTick();\n advance(time);\n }\n store.applyDelta(delta);\n };\n\n const instance: OrderBookHeatmapInstance = {\n setBook(snapshot) {\n const time = noteTime(snapshot.time);\n if (store.count(\"bid\") + store.count(\"ask\") > 0) advance(time);\n store.setSnapshot(snapshot);\n ensureTick();\n refreshFormat();\n if (!Number.isFinite(openStart)) advance(time);\n host.invalidate();\n },\n applyDeltas(deltas) {\n if (Array.isArray(deltas)) {\n for (const d of deltas as readonly OrderBookDelta[]) applyOne(d);\n } else applyOne(deltas as OrderBookDelta);\n if (!Number.isFinite(openStart) && tick > 0) advance(nowTime());\n host.invalidate();\n },\n addTrades(trades) {\n const list: readonly MarketTrade[] = Array.isArray(trades)\n ? (trades as readonly MarketTrade[])\n : [trades as MarketTrade];\n for (const trade of list) {\n if (!(trade.size > 0) || !Number.isFinite(trade.price)) continue;\n if (Number.isFinite(dataTime)) {\n noteTime(trade.time);\n advance(trade.time);\n }\n const target =\n !Number.isFinite(openStart) || trade.time >= openStart\n ? open\n : columnAt(trade.time);\n if (target) {\n if (trade.side === \"buy\") {\n target.buyVolume += trade.size;\n target.buyNotional += trade.size * trade.price;\n } else {\n target.sellVolume += trade.size;\n target.sellNotional += trade.size * trade.price;\n }\n }\n if (!lastTrade || trade.time >= lastTrade.time) lastTrade = trade;\n }\n host.invalidate();\n },\n clear() {\n store.clear();\n clearHistory();\n lastTrade = null;\n dataTime = NaN;\n tick = 0;\n ySpan = NaN;\n yTarget = null;\n viewYReady = false;\n host.invalidate();\n },\n setOptions(next) {\n const previous = options;\n options = next;\n applyTexts();\n if (\n next.tickSize !== previous.tickSize ||\n (next.interval ?? 100) !== (previous.interval ?? 100)\n ) {\n clearHistory();\n tick = 0;\n ySpan = NaN;\n ensureTick();\n }\n if (next.window !== previous.window) windowSpan = NaN;\n if (next.priceSpan !== previous.priceSpan) ySpan = NaN;\n if ((next.renderer ?? \"auto\") !== (previous.renderer ?? \"auto\"))\n void initRenderer();\n refreshColors();\n refreshFormat();\n host.invalidate();\n },\n resetView() {\n windowSpan = NaN;\n ySpan = NaN;\n yTarget = null;\n setFollow(true);\n host.invalidate();\n },\n getRenderer: () => renderer?.kind ?? null,\n ready,\n getStore: () => store,\n on: (event, handler) => emitter.on(event, handler),\n resize() {\n host.invalidate();\n },\n destroy() {\n destroyed = true;\n unfollowDefault();\n root.removeEventListener(\"pointerdown\", onPointerDown);\n root.removeEventListener(\"pointermove\", onPointerMove);\n root.removeEventListener(\"pointerup\", onPointerUp);\n root.removeEventListener(\"pointercancel\", onPointerUp);\n root.removeEventListener(\"pointerleave\", onPointerLeave);\n root.removeEventListener(\"wheel\", onWheel);\n root.removeEventListener(\"dblclick\", onDoubleClick);\n root.removeEventListener(\"keydown\", onKeyDown);\n renderer?.destroy();\n renderer = null;\n emitter.clear();\n host.destroy();\n resolveReady(null);\n },\n };\n\n applyTexts();\n refreshColors();\n void initRenderer();\n return instance;\n};\n"],"mappings":"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"}
@@ -13,6 +13,23 @@ export declare const positionedRamp: (stops: readonly (readonly [number, Rgba])[
13
13
  export declare const rowBucket: (tickPx: number) => number;
14
14
  /** Normalized intensity (0-1) of a size */
15
15
  export declare const heatIntensity: (size: number, max: number, scale: OrderBookHeatmapScale, contrast: number) => number;
16
+ /**
17
+ * Cumulative distribution of the visible sizes (a coarse log histogram):
18
+ * the rank of a size among the cells on screen, 0-1. It spreads a field of
19
+ * similar sizes over the ramp (no flat wash) while the biggest walls stay
20
+ * at its hot end. `version` of the grid it was built from.
21
+ */
22
+ export interface SizeCdf {
23
+ version: number;
24
+ min: number;
25
+ max: number;
26
+ /** Bins of equal width in log space */
27
+ cdf: Float32Array;
28
+ }
29
+ /** Cumulative distribution of the positive sizes of a grid */
30
+ export declare const sizeCdf: (cells: Float32Array, version?: number) => SizeCdf | null;
31
+ /** Mix of the absolute curve and the rank (0-1 → 0-1) */
32
+ export declare const heatCurve: (dist: SizeCdf | null, max: number, base: (r: number) => number) => (r: number) => number;
16
33
  /**
17
34
  * Creates a liquidity heatmap in `container`: resting size over time and
18
35
  * price on the GPU, trades as bubbles, best bid / ask lines, the current
@@ -13,6 +13,23 @@ export declare const positionedRamp: (stops: readonly (readonly [number, Rgba])[
13
13
  export declare const rowBucket: (tickPx: number) => number;
14
14
  /** Normalized intensity (0-1) of a size */
15
15
  export declare const heatIntensity: (size: number, max: number, scale: OrderBookHeatmapScale, contrast: number) => number;
16
+ /**
17
+ * Cumulative distribution of the visible sizes (a coarse log histogram):
18
+ * the rank of a size among the cells on screen, 0-1. It spreads a field of
19
+ * similar sizes over the ramp (no flat wash) while the biggest walls stay
20
+ * at its hot end. `version` of the grid it was built from.
21
+ */
22
+ export interface SizeCdf {
23
+ version: number;
24
+ min: number;
25
+ max: number;
26
+ /** Bins of equal width in log space */
27
+ cdf: Float32Array;
28
+ }
29
+ /** Cumulative distribution of the positive sizes of a grid */
30
+ export declare const sizeCdf: (cells: Float32Array, version?: number) => SizeCdf | null;
31
+ /** Mix of the absolute curve and the rank (0-1 → 0-1) */
32
+ export declare const heatCurve: (dist: SizeCdf | null, max: number, base: (r: number) => number) => (r: number) => number;
16
33
  /**
17
34
  * Creates a liquidity heatmap in `container`: resting size over time and
18
35
  * price on the GPU, trades as bubbles, best bid / ask lines, the current