minerva-design 1.6.0 → 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.
Files changed (120) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/charts/engine/data.cjs +1 -1
  3. package/dist/charts/engine/data.cjs.map +1 -1
  4. package/dist/charts/engine/data.d.cts +2 -0
  5. package/dist/charts/engine/data.d.ts +2 -0
  6. package/dist/charts/engine/data.js +6 -4
  7. package/dist/charts/engine/data.js.map +1 -1
  8. package/dist/charts/engine/defaults.cjs +1 -1
  9. package/dist/charts/engine/defaults.cjs.map +1 -1
  10. package/dist/charts/engine/defaults.js +22 -18
  11. package/dist/charts/engine/defaults.js.map +1 -1
  12. package/dist/charts/engine/graph/chart.cjs +1 -1
  13. package/dist/charts/engine/graph/chart.cjs.map +1 -1
  14. package/dist/charts/engine/graph/chart.js +532 -493
  15. package/dist/charts/engine/graph/chart.js.map +1 -1
  16. package/dist/charts/engine/graph/geometry.cjs +1 -1
  17. package/dist/charts/engine/graph/geometry.cjs.map +1 -1
  18. package/dist/charts/engine/graph/geometry.d.cts +12 -2
  19. package/dist/charts/engine/graph/geometry.d.ts +12 -2
  20. package/dist/charts/engine/graph/geometry.js +35 -31
  21. package/dist/charts/engine/graph/geometry.js.map +1 -1
  22. package/dist/charts/engine/model.cjs +1 -1
  23. package/dist/charts/engine/model.cjs.map +1 -1
  24. package/dist/charts/engine/model.js +95 -74
  25. package/dist/charts/engine/model.js.map +1 -1
  26. package/dist/charts/engine/orderbook/field.cjs +1 -1
  27. package/dist/charts/engine/orderbook/field.cjs.map +1 -1
  28. package/dist/charts/engine/orderbook/field.d.cts +15 -2
  29. package/dist/charts/engine/orderbook/field.d.ts +15 -2
  30. package/dist/charts/engine/orderbook/field.js +21 -9
  31. package/dist/charts/engine/orderbook/field.js.map +1 -1
  32. package/dist/charts/engine/orderbook/heatmap.cjs +1 -1
  33. package/dist/charts/engine/orderbook/heatmap.cjs.map +1 -1
  34. package/dist/charts/engine/orderbook/heatmap.d.cts +29 -0
  35. package/dist/charts/engine/orderbook/heatmap.d.ts +29 -0
  36. package/dist/charts/engine/orderbook/heatmap.js +576 -453
  37. package/dist/charts/engine/orderbook/heatmap.js.map +1 -1
  38. package/dist/charts/engine/orderbook/types.d.cts +36 -11
  39. package/dist/charts/engine/orderbook/types.d.ts +36 -11
  40. package/dist/charts/engine/presets.cjs +1 -1
  41. package/dist/charts/engine/presets.cjs.map +1 -1
  42. package/dist/charts/engine/presets.d.cts +16 -3
  43. package/dist/charts/engine/presets.d.ts +16 -3
  44. package/dist/charts/engine/presets.js +42 -32
  45. package/dist/charts/engine/presets.js.map +1 -1
  46. package/dist/charts/engine/scene.cjs +1 -1
  47. package/dist/charts/engine/scene.cjs.map +1 -1
  48. package/dist/charts/engine/scene.d.cts +4 -2
  49. package/dist/charts/engine/scene.d.ts +4 -2
  50. package/dist/charts/engine/scene.js +185 -107
  51. package/dist/charts/engine/scene.js.map +1 -1
  52. package/dist/charts/engine/three-d/oit.cjs +119 -34
  53. package/dist/charts/engine/three-d/oit.cjs.map +1 -1
  54. package/dist/charts/engine/three-d/oit.d.cts +65 -10
  55. package/dist/charts/engine/three-d/oit.d.ts +65 -10
  56. package/dist/charts/engine/three-d/oit.js +119 -34
  57. package/dist/charts/engine/three-d/oit.js.map +1 -1
  58. package/dist/charts/engine/three-d/render-types.cjs.map +1 -1
  59. package/dist/charts/engine/three-d/render-types.d.cts +19 -0
  60. package/dist/charts/engine/three-d/render-types.d.ts +19 -0
  61. package/dist/charts/engine/three-d/render-types.js.map +1 -1
  62. package/dist/charts/engine/three-d/shaders.cjs +14 -6
  63. package/dist/charts/engine/three-d/shaders.cjs.map +1 -1
  64. package/dist/charts/engine/three-d/shaders.d.cts +6 -1
  65. package/dist/charts/engine/three-d/shaders.d.ts +6 -1
  66. package/dist/charts/engine/three-d/shaders.js +40 -26
  67. package/dist/charts/engine/three-d/shaders.js.map +1 -1
  68. package/dist/charts/engine/three-d/webgl.cjs +1 -1
  69. package/dist/charts/engine/three-d/webgl.cjs.map +1 -1
  70. package/dist/charts/engine/three-d/webgl.js +167 -125
  71. package/dist/charts/engine/three-d/webgl.js.map +1 -1
  72. package/dist/charts/engine/three-d/webgpu.cjs +1 -1
  73. package/dist/charts/engine/three-d/webgpu.cjs.map +1 -1
  74. package/dist/charts/engine/three-d/webgpu.js +169 -140
  75. package/dist/charts/engine/three-d/webgpu.js.map +1 -1
  76. package/dist/charts/engine/trading/chart.cjs +1 -1
  77. package/dist/charts/engine/trading/chart.cjs.map +1 -1
  78. package/dist/charts/engine/trading/chart.js +1149 -1023
  79. package/dist/charts/engine/trading/chart.js.map +1 -1
  80. package/dist/charts/engine/trading/labels.cjs +1 -1
  81. package/dist/charts/engine/trading/labels.cjs.map +1 -1
  82. package/dist/charts/engine/trading/labels.js +12 -0
  83. package/dist/charts/engine/trading/labels.js.map +1 -1
  84. package/dist/charts/engine/trading/layout.cjs +2 -0
  85. package/dist/charts/engine/trading/layout.cjs.map +1 -0
  86. package/dist/charts/engine/trading/layout.d.cts +37 -0
  87. package/dist/charts/engine/trading/layout.d.ts +37 -0
  88. package/dist/charts/engine/trading/layout.js +63 -0
  89. package/dist/charts/engine/trading/layout.js.map +1 -0
  90. package/dist/charts/engine/trading/types.d.cts +24 -7
  91. package/dist/charts/engine/trading/types.d.ts +24 -7
  92. package/dist/charts/engine/types.d.cts +21 -8
  93. package/dist/charts/engine/types.d.ts +21 -8
  94. package/dist/core/contracts.cjs +1 -1
  95. package/dist/core/contracts.cjs.map +1 -1
  96. package/dist/core/contracts.js +1 -1
  97. package/dist/core/contracts.js.map +1 -1
  98. package/dist/native/charts/src/engine/data.cjs +1 -1
  99. package/dist/native/charts/src/engine/data.cjs.map +1 -1
  100. package/dist/native/charts/src/engine/data.js +6 -4
  101. package/dist/native/charts/src/engine/data.js.map +1 -1
  102. package/dist/native/charts/src/engine/model.cjs +1 -1
  103. package/dist/native/charts/src/engine/model.cjs.map +1 -1
  104. package/dist/native/charts/src/engine/model.js +104 -83
  105. package/dist/native/charts/src/engine/model.js.map +1 -1
  106. package/dist/native/charts/src/engine/presets.cjs +1 -1
  107. package/dist/native/charts/src/engine/presets.cjs.map +1 -1
  108. package/dist/native/charts/src/engine/presets.js +42 -32
  109. package/dist/native/charts/src/engine/presets.js.map +1 -1
  110. package/dist/native/charts/src/engine/scene.cjs +1 -1
  111. package/dist/native/charts/src/engine/scene.cjs.map +1 -1
  112. package/dist/native/charts/src/engine/scene.js +185 -107
  113. package/dist/native/charts/src/engine/scene.js.map +1 -1
  114. package/dist/taro/index.js +1263 -1152
  115. package/dist/vue/components/Chart/OrderBookHeatmap.vue.d.ts +11 -0
  116. package/dist/vue/components/Chart/orderbook.d.ts +7 -0
  117. package/dist/vue/components/Chart/orderbook.js +2 -0
  118. package/dist/vue/components/Chart/orderbook.js.map +1 -1
  119. package/dist/weapp/charts/canvas.js +234 -58
  120. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"heatmap.js","names":["LUT_SIZE","MAX_TEXELS","SCALE_QUANTILE","HEAT_GAMMA","DARK_RAMP","LIGHT_RAMP","TAG_HEIGHT","BUBBLE_SPACING","LABELS","heatIntensity","size","max","r","contrast","scale","createOrderBookHeatmap","options","initial","store","createOrderBookStore","emitter","createEmitter","fmt","createFormatters","colors","lut","table","HEAT_TABLE_SIZE","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","createHost","container","refreshColors","root","texts","localeLabels","labels","applyTexts","interval","history","depth","nowTime","elapsed","perfNow","theme","sideColors","c","value","background","luminance","ramp","oklabRamp","heatTable","refreshFormat","decimalsOf","inferPriceDecimals","inferSizeDecimals","clearHistory","ensureTick","base","inferTickSize","mid","ratio","multiple","p","m","roundToStep","sampleBook","limit","bins","sizes","n","side","count","rows","i","bin","closeColumn","column","start","oldest","drop","advance","time","step","noteTime","columnAt","lo","hi","headSource","version","heatGrid","live","maxWidth","maxHeight","lastSeq","key","x0","x1","y0","y1","end","sources","buildHeatGrid","fixed","now","target","percentile","ease","dt","k","paintHeatGrid","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","toCss","index","color","pen","price","drawBubbles","bubbles","b","ref","maxD","sized","clamp","a","fontOf","fontSize","x","mixOklab","text","drawProfile","rowPx","maxSize","sides","levels","fineCeil","left","px","inner","profileW","f","gap","bar","top","bottom","w","s","best","tw","hoverCell","hx","hy","rowPrice","drawTag","align","filled","roundRect","draw","l","width","regular","bold","clock","dpr","height","sample","axisW","timeH","right","first","fitTimeRange","minSpan","fitPriceRange","t","floorCss","canvas","bw","bh","heat","sx","sy","rect","yTicks","linearTicks","xt","timeTicks","cell","hoverTime","formatClock","hoverHalf","half","last","pins","shownPins","hoverY","layout","layoutAxisLabels","at","pin","drawHover","fresh","bestBid","bestAsk","buyVolume","sellVolume","lv","ry","cx0","cx1","cy0","cy1","timeText","sideColor","tooltipHtml","doc","event","initRenderer","token","next","createHeatFieldRenderer","kind","exclude","unfollowDefault","followDefaultRenderer","setFollow","clampTime","range","span","onPointerDown","localPoint","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 { luminance, mixOklab, oklabRamp, toCss, type Rgba } 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/** Quantile of the visible sizes at the hottest color (auto scale) */\nconst SCALE_QUANTILE = 0.98;\n/** Gamma of the color curve (> 1: less noise at the cold end) */\nconst HEAT_GAMMA = 1.4;\n\n/**\n * Heat ramps, interpolated in OKLab; the first color is also the empty\n * field. Dark: from deep navy, lightness rises through blue, cyan and green\n * to yellow, then the hottest walls turn orange / red (the Bookmap\n * convention). Light: from a pale tint, lightness falls through blue and\n * violet to crimson.\n */\nconst DARK_RAMP = [\n \"#0a1830\",\n \"#0f2c57\",\n \"#134a8a\",\n \"#1670b4\",\n \"#1aa0bf\",\n \"#2fc3a0\",\n \"#8ad65a\",\n \"#e8dc3f\",\n \"#ffa733\",\n \"#ff5a2e\",\n];\nconst LIGHT_RAMP = [\n \"#eef4fb\",\n \"#cfe1f6\",\n \"#9fc2ee\",\n \"#679ee2\",\n \"#3a73cf\",\n \"#3f4bb0\",\n \"#62309a\",\n \"#9c2783\",\n \"#d12c52\",\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\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 \"sqrt\":\n return Math.sqrt(r);\n default:\n // one decade: a tenth of the hottest size is a fifth of the ramp\n return Math.log10(1 + 9 * 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 const ramp = (\n options.colors?.length ? options.colors : dark ? DARK_RAMP : LIGHT_RAMP\n ).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 const scale = options.colorScale ?? \"log\";\n // a mild gamma after the scale: the thin noise of the book stays near\n // the cold end, the walls stand out\n table = heatTable(lut, (r) => heatIntensity(r, 1, scale, 1) ** HEAT_GAMMA);\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 98th percentile of the visible sizes (eased), so the\n * whole ramp is used in light and dark themes alike\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 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 tick,\n ].join(\"|\");\n if (key !== gridKey) {\n const sources: HeatSource[] = live ? [...columns, live] : columns;\n grid = buildHeatGrid(\n { sources, step, tick, x0, x1, y0, y1, end, maxWidth, maxHeight },\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 /** Trade bubbles, area ∝ volume, the largest with their volume */\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) max = Math.max(max, b.volume);\n bubbleRef = bubbleRef > 0 ? Math.max(max, bubbleRef * 0.995) : max;\n const ref = options.bubbleVolume ?? bubbleRef;\n const maxD = Math.max(4, options.bubbleSize ?? 28);\n const sized = bubbles\n .map((b) => ({\n ...b,\n d: clamp(Math.sqrt(b.volume / ref) * maxD, 3, maxD),\n }))\n .sort((a, b) => a.d - b.d);\n clipPlot(ctx);\n ctx.lineWidth = 1.25;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.font = fontOf(host.theme, options, 600, Math.max(8, fontSize - 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, r, 0, Math.PI * 2);\n ctx.fillStyle = toCss(color, 0.62);\n ctx.fill();\n ctx.strokeStyle = toCss(mixOklab(color, [1, 1, 1, 1], 0.25));\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 = \"#fff\";\n ctx.fillText(text, x, y + 0.5);\n }\n }\n }\n ctx.restore();\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 ) => {\n const theme = host.theme;\n const [y0, y1] = viewY;\n const rowPx = Math.max(1, (tick / (y1 - y0)) * plot.h);\n let maxSize = 0;\n const sides = ([\"bid\", \"ask\"] as const).map((side) => {\n const levels = store.levels(side, { step: tick, limit: depth() });\n for (let i = 0; i < levels.count; i++) {\n const p = levels.price[i]!;\n if (p >= y0 && p <= y1) maxSize = Math.max(maxSize, levels.size[i]!);\n }\n return { side, ...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 price edges; a 1 px gap when tall\n const gap = rowPx >= 4 ? 1 : 0;\n const bar = (p: number, s: number) => {\n const top = Math.round(yOf(p + tick / 2));\n const bottom = Math.max(top + 1, Math.round(yOf(p - tick / 2)) - 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, price, size, count } of sides) {\n const color = side === \"bid\" ? colors.up : colors.down;\n ctx.beginPath();\n for (let i = 1; i < count; i++) {\n const p = price[i]!;\n if (p >= y0 - tick && p <= y1 + tick) bar(p, size[i]!);\n }\n ctx.fillStyle = toCss(color, dark ? 0.62 : 0.55);\n ctx.fill();\n // the best level, solid\n const best = price[0];\n if (count && best !== undefined && best >= y0 && best <= y1) {\n ctx.beginPath();\n bar(best, size[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 */\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 bin: number;\n rowPrice: number;\n }\n\n const hoverCell = (): 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 bin = Math.round(price / tick);\n const rowPrice = +(bin * tick).toFixed(Math.min(12, decimalsOf(tick) + 2));\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, bin, 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\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 // 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 // grid over the cells\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.text, dark ? 0.07 : 0.09);\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(plot.x, y);\n ctx.lineTo(right, 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);\n ctx.lineTo(x, plot.y + plot.h);\n }\n ctx.stroke();\n\n // best bid / ask, trades, the current book\n if (ready) {\n drawBest(ctx, visible, xOf, yOf, columnPx);\n if (options.bubbles !== false)\n drawBubbles(ctx, tradeBubbles(visible, columnPx), xOf, yOf, fontSize);\n if (profileW) drawProfile(ctx, px, profileW, yOf, fontSize);\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() : 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 ry: 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, bin, rowPrice } = cell;\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 (column.bins[i] === bin) size += column.sizes[i]!;\n }\n ({ bestBid, bestAsk, buyVolume, sellVolume } = column);\n } else if (Number.isFinite(start)) {\n const levels = ([\"bid\", \"ask\"] as const).map((side) =>\n store.levels(side, { step: tick, limit: depth() }),\n );\n for (const lv of levels) {\n for (let i = 0; i < lv.count; i++) {\n if (Math.round(lv.price[i]! / tick) === bin) size += lv.size[i]!;\n }\n }\n bestBid = store.bestBid();\n bestAsk = store.bestAsk();\n buyVolume = open.buyVolume;\n sellVolume = open.sellVolume;\n }\n const side: OrderBookSide | null =\n rowPrice <= bestBid ? \"bid\" : rowPrice >= 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, ry);\n ctx.lineTo(right, ry);\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(rowPrice + tick / 2);\n const cy1 = yOf(rowPrice - tick / 2);\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 ry,\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 [l.price, fmt.price(rowPrice)],\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}|${bin}|${size}|${buyVolume}|${sellVolume}`;\n if (key !== hoverKey) {\n hoverKey = key;\n const event: OrderBookHeatmapHoverEvent = {\n time: Number.isFinite(start) ? start : time,\n price: rowPrice,\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.js","names":["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","toOklab","i","k","t","p0","j","p1","a","b","packColor","fromOklab","rowBucket","tickPx","need","p","m","LABELS","heatIntensity","max","r","contrast","scale","CDF_BINS","rankOf","dist","x","f","sizeCdf","min","count","cells","v","bins","span","sum","heatCurve","absolute","base","rank","createOrderBookHeatmap","options","initial","store","createOrderBookStore","emitter","createEmitter","fmt","createFormatters","colors","table","HEAT_TABLE_SIZE","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","createHost","container","refreshColors","root","texts","localeLabels","labels","applyTexts","interval","history","depth","nowTime","elapsed","perfNow","theme","sideColors","value","background","luminance","ramp","oklabRamp","at","hex","parseColor","heatTable","refreshFormat","decimalsOf","inferPriceDecimals","inferSizeDecimals","withUnit","unit","text","clearHistory","ensureTick","inferTickSize","mid","ratio","multiple","roundToStep","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","buildHeatGrid","fixed","now","target","percentile","ease","dt","paint","paintHeatGrid","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","toCss","index","color","pen","price","drawBubbles","bubbles","ref","maxD","minD","sized","clamp","fontOf","fontSize","rim","mixOklab","bookBuckets","buckets","lastBin","ry","drawProfile","rowPx","lowOf","highOf","maxSize","sides","levels","fineCeil","left","px","inner","profileW","gap","bar","top","bottom","w","s","best","tw","hoverCell","hx","hy","bucket","digits","low","high","rowPrice","drawTag","align","filled","roundRect","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","fitTimeRange","minSpan","fitPriceRange","floorCss","canvas","bw","bh","heat","sx","sy","rect","yTicks","linearTicks","xt","timeTicks","cell","hoverTime","formatClock","hoverHalf","half","last","pins","shownPins","hoverY","layout","layoutAxisLabels","pin","drawHover","fresh","inBucket","bestBid","bestAsk","buyVolume","sellVolume","cx0","cx1","cy0","cy1","timeText","sideColor","tooltipHtml","doc","event","initRenderer","token","next","createHeatFieldRenderer","kind","exclude","unfollowDefault","followDefaultRenderer","setFollow","clampTime","range","onPointerDown","localPoint","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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"}
@@ -470,6 +470,8 @@ export interface OrderBookHeatmapLabels {
470
470
  bidSide: string;
471
471
  /** Side badge of a hovered ask row in the tooltip @default "Ask side" */
472
472
  askSide: string;
473
+ /** Legend row of the trades (bubbles) @default "Bubble area = trade size" */
474
+ bubbleHint: string;
473
475
  /** Accessible name (when `ariaLabel` is not set) @default "Liquidity heatmap" */
474
476
  name: string;
475
477
  }
@@ -502,19 +504,33 @@ export interface OrderBookHeatmapOptions extends OrderBookCommonOptions {
502
504
  /** Visible price span (top − bottom); fits the best bid / ask of the window when omitted */
503
505
  priceSpan?: number;
504
506
  /**
505
- * Scale from sizes to colors: `log` reveals thin liquidity next to walls
506
- * @default "log"
507
+ * Scale from sizes to colors: `sqrt` keeps typical levels dim and lets
508
+ * significant liquidity glow, `linear` shows only the walls, `log`
509
+ * reveals thin liquidity next to them
510
+ * @default "sqrt"
507
511
  */
508
512
  colorScale?: OrderBookHeatmapScale;
509
513
  /**
510
- * Multiplies the sizes before the scale: above 1 brightens thin liquidity,
511
- * below 1 keeps only the walls
514
+ * Unit of the sizes, shown after them in the legend and the tooltip
515
+ * (e.g. "BTC"); the numbers are not converted
516
+ */
517
+ sizeUnit?: string;
518
+ /**
519
+ * Legend of the color ramp (cold to hot, its size range) and of the
520
+ * trades, in the top-left corner of the plot
521
+ * @default true
522
+ */
523
+ legend?: boolean;
524
+ /**
525
+ * Multiplies the sizes before the scale: above 1 brightens thin liquidity
526
+ * (more of the field glows), below 1 keeps only the largest walls
512
527
  * @default 1
513
528
  */
514
529
  contrast?: number;
515
530
  /**
516
- * Size drawn with the hottest color; when omitted, the 98th percentile of
517
- * the visible sizes (eased), so the whole ramp is used
531
+ * Size drawn with the hottest color (larger sizes saturate); when
532
+ * omitted, the 99th percentile of the visible non-empty cells (eased), so
533
+ * typical levels stay dark and only the top liquidity glows
518
534
  */
519
535
  maxSize?: number;
520
536
  /**
@@ -530,11 +546,15 @@ export interface OrderBookHeatmapOptions extends OrderBookCommonOptions {
530
546
  */
531
547
  bubbles?: boolean;
532
548
  /**
533
- * Largest bubble diameter, in pixels
534
- * @default 28
549
+ * Diameter of the largest bubble, in pixels (area ∝ volume, the smallest
550
+ * are 3 px dots)
551
+ * @default 14
535
552
  */
536
553
  bubbleSize?: number;
537
- /** Trade volume of the largest bubble; follows the data when omitted */
554
+ /**
555
+ * Trade volume of the largest bubble; when omitted, the largest visible
556
+ * trade (eased)
557
+ */
538
558
  bubbleVolume?: number;
539
559
  /**
540
560
  * Best bid and ask lines
@@ -577,9 +597,14 @@ export interface OrderBookHeatmapOptions extends OrderBookCommonOptions {
577
597
  export interface OrderBookHeatmapHoverEvent {
578
598
  /** Start time of the hovered column */
579
599
  time: number;
580
- /** Price of the hovered row */
600
+ /**
601
+ * Price of the hovered row; its lowest price when rows are aggregated
602
+ * into price buckets (rows thinner than 2 px)
603
+ */
581
604
  price: number;
582
- /** Resting size of the cell */
605
+ /** Highest price of the hovered row (equals `price` without aggregation) */
606
+ priceHigh: number;
607
+ /** Resting size of the cell (summed over the bucket's prices) */
583
608
  size: number;
584
609
  /** Side of the cell (`null` inside the spread) */
585
610
  side: OrderBookSide | null;