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
@@ -25,36 +25,48 @@ var o = 1024, s = (e, t) => {
25
25
  }, l = (e, t) => {
26
26
  let { sources: n, step: r, tick: i, x0: a, x1: o, y0: s, y1: c, end: l } = e;
27
27
  if (!(r > 0) || !(i > 0) || !(o > a) || !(c > s) || !Number.isFinite(a + o + s + c)) return null;
28
- let u = r * Math.max(1, Math.ceil((o - a) / r / Math.max(1, e.maxWidth))), d = Math.floor(a / u) * u, f = Math.max(1, Math.ceil((o - d) / u)), p = Math.round(s / i), m = Math.round(c / i), h = Math.max(1, Math.ceil((m - p + 1) / Math.max(1, e.maxHeight))), g = Math.floor(p / h) * h, _ = Math.max(1, Math.ceil((m + 1 - g) / h)), v = f * _, y = t && t.cells.length === v ? t.cells.fill(0) : new Float32Array(v), b = (e, t) => {
28
+ let u = r * Math.max(1, Math.ceil((o - a) / r / Math.max(1, e.maxWidth))), d = Math.floor(a / u) * u, f = Math.max(1, Math.ceil((o - d) / u)), p = Math.round(s / i), m = Math.round(c / i), h = Math.max(1, Math.round(e.rowBins ?? 1) || 1, Math.ceil((m - p + 1) / Math.max(1, e.maxHeight))), g = Math.floor(p / h) * h, _ = Math.max(1, Math.ceil((m + 1 - g) / h)), v = f * _, y = t && t.cells.length === v ? t.cells.fill(0) : new Float32Array(v), b = h > 1 ? new Float32Array(_) : null, x = [], S = (e, t) => {
29
29
  let { bins: n, sizes: r } = e;
30
30
  for (let e = 0; e < r.length; e++) {
31
31
  let i = r[e];
32
32
  if (!(i > 0)) continue;
33
33
  let a = Math.floor((n[e] - g) / h);
34
34
  if (a < 0 || a >= _) continue;
35
+ if (b) {
36
+ b[a] || x.push(a), b[a] += i;
37
+ continue;
38
+ }
35
39
  let o = (_ - 1 - a) * f + t;
36
40
  i > y[o] && (y[o] = i);
37
41
  }
38
- }, x = (e) => {
42
+ if (b) {
43
+ for (let e of x) {
44
+ let n = (_ - 1 - e) * f + t;
45
+ b[e] > y[n] && (y[n] = b[e]), b[e] = 0;
46
+ }
47
+ x.length = 0;
48
+ }
49
+ }, C = (e) => {
39
50
  for (let t = 0, n = e; t < _; t++, n += f) y[n] = y[n - 1];
40
- }, S = 0, C = n.length;
41
- for (; S < C;) {
42
- let e = S + C >>> 1;
43
- n[e].time < d ? S = e + 1 : C = e;
51
+ }, w = 0, T = n.length;
52
+ for (; w < T;) {
53
+ let e = w + T >>> 1;
54
+ n[e].time < d ? w = e + 1 : T = e;
44
55
  }
45
- let w = S, T = S > 0 ? n[S - 1] : null;
56
+ let E = w, D = w > 0 ? n[w - 1] : null;
46
57
  for (let e = 0; e < f; e++) {
47
58
  let t = d + e * u;
48
59
  if (t >= l) break;
49
60
  let r = t + u, i = !1;
50
- for (; w < n.length && n[w].time < r;) b(n[w], e), T = n[w], i = !0, w++;
51
- !i && T && (e === 0 ? b(T, 0) : x(e));
61
+ for (; E < n.length && n[E].time < r;) S(n[E], e), D = n[E], i = !0, E++;
62
+ !i && D && (e === 0 ? S(D, 0) : C(e));
52
63
  }
53
64
  return {
54
65
  width: f,
55
66
  height: _,
56
67
  pixels: t && t.pixels.length === v ? t.pixels : new Uint32Array(v),
57
68
  cells: y,
69
+ rowBins: h,
58
70
  t0: d,
59
71
  t1: d + f * u,
60
72
  p0: (g - .5) * i,
@@ -1 +1 @@
1
- {"version":3,"file":"field.js","names":["HEAT_TABLE_SIZE","heatTable","table","last","lut","j","t","curve","percentile","len","values","m","limit","prime","value","n","sorted","k","v","at","q","lo","hi","buildHeatGrid","input","step","tick","x1","x0","y1","y0","g","gs","width","binLo","binHi","ry","base","height","count","cells","reuse","plot","source","sizes","s","r","bins","idx","i","repeat","sources","mid","previous","start","end","stop","hit","paintHeatGrid","grid","cold","scale","GLSL_VERTEX","GLSL_FRAGMENT","clipRect","rect","bytesOf","createGlHeatField","attributes","glContextAttributes","requireHardware","gl","canvas","kind","reject","isSoftwareRenderer","setup","program","compileProgram","corners","texture","objects","uploaded","uploadedVersion","size","destroyed","lost","forget","slot","claimGlSlot","draw","onLost","w","h","clear","textureAt","rectAt","WGSL","STAGE_VERTEX","STAGE_FRAGMENT","createWebGpuHeatField","gpu","adapter","info","device","context","format","layout","module","pipeline","sampler","uniform","bindGroup","encoder","pass","createCanvasHeatField","ctx","image","imageCtx","data","createHeatFieldRenderer","preference","resolveRendererPreference","requested","rendererCandidates","exclude","field","makeCanvas"],"sources":["../../../../../charts/src/engine/orderbook/field.ts"],"sourcesContent":["// Heat field of the order book heatmap. The liquidity of the visible\n// window is rasterized on the CPU into a small image, one texel per column\n// (sampling interval) and price row (tick), and drawn as ONE textured quad\n// with nearest filtering over a clear of the coldest color:\n// - rows and columns abut by construction (every device pixel samples\n// exactly one texel), so there are no anti-aliased seams between cells;\n// - a column fills until the next snapshot (gaps repeat the last book) and\n// the live one fills to the right edge;\n// - empty cells are the cold end of the ramp, never a transparent hole;\n// - the output is opaque (no blending), the same on every backend.\n// The backends mirror the chart engine's (WebGPU -> WebGL2 -> WebGL ->\n// Canvas2D, software GPUs skipped with `auto`), but with their own tiny\n// pipelines: a canvas only ever holds one context type.\n\nimport { resolveRendererPreference } from \"../defaults\";\nimport type { Rgba } from \"../color\";\nimport { rendererCandidates } from \"../renderers/detect\";\nimport {\n compileProgram,\n glContextAttributes,\n isSoftwareRenderer,\n type GlContext,\n} from \"../renderers/gl\";\nimport { claimGlSlot } from \"../renderers/gl-budget\";\nimport type { ChartRendererKind, ChartRendererPreference } from \"../types\";\n\n/** One sampled book: price rows (price / tick) and their resting sizes */\nexport interface HeatSource {\n /** Start time of the column */\n time: number;\n bins: ArrayLike<number>;\n sizes: ArrayLike<number>;\n}\n\n/** The rasterized field: packed RGBA texels, row 0 at the top (highest prices) */\nexport interface HeatGrid {\n width: number;\n height: number;\n pixels: Uint32Array;\n /** Resting size of every texel (max-pooled), same layout as `pixels` */\n cells: Float32Array;\n /** Times at the left / right edges of the image */\n t0: number;\n t1: number;\n /** Prices at the bottom / top edges of the image */\n p0: number;\n p1: number;\n /** Bumped on every rebuild (uploads are skipped while unchanged) */\n version: number;\n}\n\nexport interface HeatGridInput {\n /** Columns sorted by time (the live book last) */\n sources: readonly HeatSource[];\n /** Sampling interval (ms) */\n step: number;\n /** Price row height */\n tick: number;\n /** Visible time / price ranges */\n x0: number;\n x1: number;\n y0: number;\n y1: number;\n /** End of the data (the live time): texels starting later stay cold */\n end: number;\n /** Largest image (texels); denser data is max-pooled, walls stay visible */\n maxWidth: number;\n maxHeight: number;\n}\n\n/** Entries of a heat table (resolution of the size → color mapping) */\nexport const HEAT_TABLE_SIZE = 1024;\n\n/**\n * Size → color table of a ramp: entry `j` is the color of the relative size\n * `j / HEAT_TABLE_SIZE` through `curve` (0-1 → 0-1). Entry 0 is the cold end.\n */\nexport const heatTable = (\n lut: Uint32Array,\n curve: (r: number) => number,\n): Uint32Array => {\n const table = new Uint32Array(HEAT_TABLE_SIZE + 1);\n const last = lut.length - 1;\n for (let j = 0; j <= HEAT_TABLE_SIZE; j++) {\n const t = Math.min(1, Math.max(0, curve(j / HEAT_TABLE_SIZE)));\n table[j] = lut[Math.round(t * last)] ?? 0;\n }\n return table;\n};\n\n/**\n * `q`-quantile (0-1) of the positive values, NaN without any. Arrays longer\n * than `limit` are sampled (a prime stride, so a grid's rows and columns\n * are both covered).\n */\nexport const percentile = (\n values: ArrayLike<number>,\n q: number,\n limit = 16384,\n): number => {\n const len = values.length;\n const m = Math.min(len, Math.max(1, limit));\n const prime = len % 7919 ? 7919 : 7907;\n const value = (j: number) => values[m === len ? j : (j * prime) % len]!;\n let n = 0;\n for (let j = 0; j < m; j++) if (value(j) > 0) n++;\n if (!n) return NaN;\n const sorted = new Float64Array(n);\n let k = 0;\n for (let j = 0; j < m; j++) {\n const v = value(j);\n if (v > 0) sorted[k++] = v;\n }\n sorted.sort();\n const at = Math.min(n - 1, Math.max(0, q * (n - 1)));\n const lo = Math.floor(at);\n const hi = Math.min(n - 1, lo + 1);\n return sorted[lo]! + (sorted[hi]! - sorted[lo]!) * (at - lo);\n};\n\n/**\n * Rasterizes the visible liquidity into `cells` (the colors are set by\n * `paintHeatGrid`). Pass the previous grid as `reuse` to recycle its\n * buffers. Returns `null` without a valid range.\n */\nexport const buildHeatGrid = (\n input: HeatGridInput,\n reuse?: HeatGrid | null,\n): HeatGrid | null => {\n const { sources, step, tick, x0, x1, y0, y1, end } = input;\n if (\n !(step > 0) ||\n !(tick > 0) ||\n !(x1 > x0) ||\n !(y1 > y0) ||\n !Number.isFinite(x0 + x1 + y0 + y1)\n )\n return null;\n // time texels: `cx` columns each\n const cx = Math.max(\n 1,\n Math.ceil((x1 - x0) / step / Math.max(1, input.maxWidth)),\n );\n const g = step * cx;\n const gs = Math.floor(x0 / g) * g;\n const width = Math.max(1, Math.ceil((x1 - gs) / g));\n // price texels: `ry` rows each; a row covers [bin - ½, bin + ½) × tick\n const binLo = Math.round(y0 / tick);\n const binHi = Math.round(y1 / tick);\n const ry = Math.max(\n 1,\n Math.ceil((binHi - binLo + 1) / Math.max(1, input.maxHeight)),\n );\n const base = Math.floor(binLo / ry) * ry;\n const height = Math.max(1, Math.ceil((binHi + 1 - base) / ry));\n const count = width * height;\n\n const cells =\n reuse && reuse.cells.length === count\n ? reuse.cells.fill(0)\n : new Float32Array(count);\n const plot = (source: HeatSource, i: number) => {\n const { bins, sizes } = source;\n for (let k = 0; k < sizes.length; k++) {\n const s = sizes[k]!;\n if (!(s > 0)) continue;\n const r = Math.floor((bins[k]! - base) / ry);\n if (r < 0 || r >= height) continue;\n const idx = (height - 1 - r) * width + i;\n if (s > cells[idx]!) cells[idx] = s;\n }\n };\n const repeat = (i: number) => {\n for (let r = 0, idx = i; r < height; r++, idx += width)\n cells[idx] = cells[idx - 1]!;\n };\n\n // first source inside the image, and the one before (filled forward)\n let lo = 0;\n let hi = sources.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (sources[mid]!.time < gs) lo = mid + 1;\n else hi = mid;\n }\n let s = lo;\n let previous: HeatSource | null = lo > 0 ? sources[lo - 1]! : null;\n for (let i = 0; i < width; i++) {\n const start = gs + i * g;\n if (start >= end) break;\n const stop = start + g;\n let hit = false;\n while (s < sources.length && sources[s]!.time < stop) {\n plot(sources[s]!, i);\n previous = sources[s]!;\n hit = true;\n s++;\n }\n if (hit || !previous) continue;\n if (i === 0) plot(previous, 0);\n else repeat(i);\n }\n\n const pixels =\n reuse && reuse.pixels.length === count\n ? reuse.pixels\n : new Uint32Array(count);\n return {\n width,\n height,\n pixels,\n cells,\n t0: gs,\n t1: gs + width * g,\n p0: (base - 0.5) * tick,\n p1: (base + height * ry - 0.5) * tick,\n version: (reuse?.version ?? 0) + 1,\n };\n};\n\n/**\n * Colors the cells of a grid: `table[min(last, floor(size × scale))]`\n * (see `heatTable`), empty cells the cold end. Bumps the version.\n */\nexport const paintHeatGrid = (\n grid: HeatGrid,\n table: Uint32Array,\n scale: number,\n): void => {\n const { cells, pixels } = grid;\n const last = table.length - 1;\n const cold = table[0] ?? 0;\n const k = scale > 0 && Number.isFinite(scale) ? scale : 0;\n for (let idx = 0; idx < cells.length; idx++) {\n const v = cells[idx]! * k;\n pixels[idx] = v > 0 ? table[v >= last ? last : v | 0]! : cold;\n }\n grid.version++;\n};\n\n// ------------------------------------------------------------- renderers\n\n/** Draws heat grids on its own canvas (sized and placed by the caller) */\nexport interface HeatFieldRenderer {\n readonly kind: ChartRendererKind;\n readonly canvas: HTMLCanvasElement;\n /** Sets the size of the drawing buffer (device pixels) */\n resize(width: number, height: number): void;\n /**\n * Clears to `clear` (opaque) and draws `grid` stretched over `rect`\n * ([left, top, right, bottom] in device pixels, y down)\n */\n render(\n grid: HeatGrid | null,\n rect: readonly [number, number, number, number],\n clear: Rgba,\n ): void;\n destroy(): void;\n}\n\nconst GLSL_VERTEX = `\nattribute vec2 a_corner;\nuniform vec4 u_rect;\nvarying vec2 v_uv;\nvoid main() {\n v_uv = a_corner;\n gl_Position = vec4(mix(u_rect.x, u_rect.z, a_corner.x), mix(u_rect.y, u_rect.w, a_corner.y), 0.0, 1.0);\n}`;\nconst GLSL_FRAGMENT = `\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\nuniform sampler2D u_texture;\nvarying vec2 v_uv;\nvoid main() {\n gl_FragColor = vec4(texture2D(u_texture, v_uv).rgb, 1.0);\n}`;\n\n/** Clip-space rectangle of a pixel rectangle (y up) */\nconst clipRect = (\n rect: readonly [number, number, number, number],\n width: number,\n height: number,\n): [number, number, number, number] => [\n (rect[0] / width) * 2 - 1,\n 1 - (rect[1] / height) * 2,\n (rect[2] / width) * 2 - 1,\n 1 - (rect[3] / height) * 2,\n];\n\nconst bytesOf = (grid: HeatGrid) =>\n new Uint8Array(\n grid.pixels.buffer,\n grid.pixels.byteOffset,\n grid.width * grid.height * 4,\n );\n\n/** WebGL2 / WebGL backend (GLSL ES 1.00 runs on both) */\nexport const createGlHeatField = (\n canvas: HTMLCanvasElement,\n kind: \"webgl2\" | \"webgl\",\n onLost: () => void,\n requireHardware = false,\n): HeatFieldRenderer | null => {\n const attributes: WebGLContextAttributes = {\n ...glContextAttributes(requireHardware),\n alpha: false,\n premultipliedAlpha: false,\n };\n const gl = canvas.getContext(kind, attributes) as GlContext | null;\n if (!gl) return null;\n // a rejected context is freed now, not at garbage collection\n const reject = () => {\n gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n return null;\n };\n if (requireHardware && isSoftwareRenderer(gl)) return reject();\n\n /** Program, quad and texture: built again when a suspended context returns */\n const setup = () => {\n const program = compileProgram(\n gl,\n { vertex: GLSL_VERTEX, fragment: GLSL_FRAGMENT },\n [\"a_corner\"],\n );\n if (!program) return null;\n const corners = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, corners);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]),\n gl.STATIC_DRAW,\n );\n const texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n return {\n program,\n rectAt: gl.getUniformLocation(program.program, \"u_rect\"),\n textureAt: gl.getUniformLocation(program.program, \"u_texture\"),\n corners,\n texture,\n };\n };\n let objects = setup();\n if (!objects) return reject();\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n let size = [0, 0];\n let destroyed = false;\n let lost = false;\n let last: {\n grid: HeatGrid | null;\n rect: readonly [number, number, number, number];\n clear: Rgba;\n } | null = null;\n\n const forget = () => {\n objects = null;\n uploaded = null;\n uploadedVersion = -1;\n size = [0, 0];\n };\n // past the page-wide context budget the context may be suspended while\n // off-screen: its GPU objects go, and come back (with the last frame)\n // when it is restored\n const slot = claimGlSlot(canvas, gl, {\n suspend: forget,\n restore: () => {\n forget();\n objects = setup();\n if (!objects) {\n lost = true;\n if (!destroyed) onLost();\n } else if (last) draw(last.grid, last.rect, last.clear);\n },\n lost: () => {\n lost = true;\n if (!destroyed) onLost();\n },\n });\n\n const draw = (\n grid: HeatGrid | null,\n rect: readonly [number, number, number, number],\n clear: Rgba,\n ) => {\n if (!objects) return;\n const { program, rectAt, textureAt, corners, texture } = objects;\n const w = canvas.width;\n const h = canvas.height;\n gl.viewport(0, 0, w, h);\n gl.disable(gl.BLEND);\n gl.clearColor(clear[0], clear[1], clear[2], 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n if (!grid) return;\n gl.useProgram(program.program);\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n if (grid !== uploaded || grid.version !== uploadedVersion) {\n gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);\n if (size[0] === grid.width && size[1] === grid.height) {\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n grid.width,\n grid.height,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n bytesOf(grid),\n );\n } else {\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n grid.width,\n grid.height,\n 0,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n bytesOf(grid),\n );\n size = [grid.width, grid.height];\n }\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n gl.uniform1i(textureAt, 0);\n gl.uniform4fv(rectAt, clipRect(rect, w, h));\n gl.bindBuffer(gl.ARRAY_BUFFER, corners);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n };\n\n return {\n kind,\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n if (destroyed) return;\n last = { grid, rect, clear };\n if (lost || !slot.use() || gl.isContextLost()) return;\n draw(grid, rect, clear);\n },\n destroy() {\n destroyed = true;\n last = null;\n slot.release();\n if (objects && !gl.isContextLost()) {\n gl.deleteTexture(objects.texture);\n gl.deleteBuffer(objects.corners);\n gl.deleteProgram(objects.program.program);\n // frees the context now instead of at garbage collection\n gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n }\n objects = null;\n },\n };\n};\n\nconst WGSL = `\nstruct Uniforms { rect: vec4f };\n@group(0) @binding(0) var<uniform> u: Uniforms;\n@group(0) @binding(1) var heat: texture_2d<f32>;\n@group(0) @binding(2) var nearest: sampler;\nstruct Varyings {\n @builtin(position) position: vec4f,\n @location(0) uv: vec2f,\n};\n@vertex fn vs(@builtin(vertex_index) i: u32) -> Varyings {\n let c = vec2f(f32(i & 1u), f32(i >> 1u));\n var out: Varyings;\n out.position = vec4f(mix(u.rect.x, u.rect.z, c.x), mix(u.rect.y, u.rect.w, c.y), 0.0, 1.0);\n out.uv = c;\n return out;\n}\n@fragment fn fs(v: Varyings) -> @location(0) vec4f {\n return vec4f(textureSample(heat, nearest, v.uv).rgb, 1.0);\n}`;\n\ntype GpuNavigator = Navigator & { gpu?: GPU };\n\n// lib.dom has the WebGPU interfaces but not these constant objects\nconst BUFFER_UNIFORM = 0x40;\nconst BUFFER_COPY_DST = 0x08;\nconst TEXTURE_COPY_DST = 0x02;\nconst TEXTURE_BINDING = 0x04;\nconst STAGE_VERTEX = 0x1;\nconst STAGE_FRAGMENT = 0x2;\n\n/** WebGPU backend */\nexport const createWebGpuHeatField = async (\n canvas: HTMLCanvasElement,\n onLost: () => void,\n requireHardware = false,\n): Promise<HeatFieldRenderer | null> => {\n const gpu =\n typeof navigator !== \"undefined\"\n ? (navigator as GpuNavigator).gpu\n : undefined;\n if (!gpu) return null;\n const adapter = await gpu.requestAdapter();\n if (!adapter) return null;\n const info = adapter as GPUAdapter & {\n isFallbackAdapter?: boolean;\n info?: { isFallbackAdapter?: boolean };\n };\n if (\n requireHardware &&\n (info.info?.isFallbackAdapter || info.isFallbackAdapter)\n )\n return null;\n const device = await adapter.requestDevice();\n const context = canvas.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!context) {\n device.destroy();\n return null;\n }\n const format = gpu.getPreferredCanvasFormat();\n context.configure({ device, format, alphaMode: \"opaque\" });\n let destroyed = false;\n void device.lost.then(() => {\n if (!destroyed) onLost();\n });\n\n const layout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: STAGE_VERTEX, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: STAGE_FRAGMENT, texture: {} },\n { binding: 2, visibility: STAGE_FRAGMENT, sampler: {} },\n ],\n });\n const module = device.createShaderModule({ code: WGSL });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),\n vertex: { module, entryPoint: \"vs\" },\n fragment: { module, entryPoint: \"fs\", targets: [{ format }] },\n primitive: { topology: \"triangle-strip\" },\n });\n const sampler = device.createSampler({\n magFilter: \"nearest\",\n minFilter: \"nearest\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n });\n const uniform = device.createBuffer({\n size: 16,\n usage: BUFFER_UNIFORM | BUFFER_COPY_DST,\n });\n let texture: GPUTexture | null = null;\n let bindGroup: GPUBindGroup | null = null;\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n\n return {\n kind: \"webgpu\",\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n if (destroyed) return;\n if (grid && (grid !== uploaded || grid.version !== uploadedVersion)) {\n if (\n !texture ||\n texture.width !== grid.width ||\n texture.height !== grid.height\n ) {\n texture?.destroy();\n texture = device.createTexture({\n size: { width: grid.width, height: grid.height },\n format: \"rgba8unorm\",\n usage: TEXTURE_COPY_DST | TEXTURE_BINDING,\n });\n bindGroup = device.createBindGroup({\n layout,\n entries: [\n { binding: 0, resource: { buffer: uniform } },\n { binding: 1, resource: texture.createView() },\n { binding: 2, resource: sampler },\n ],\n });\n }\n device.queue.writeTexture(\n { texture },\n bytesOf(grid),\n { bytesPerRow: grid.width * 4, rowsPerImage: grid.height },\n { width: grid.width, height: grid.height },\n );\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n device.queue.writeBuffer(\n uniform,\n 0,\n new Float32Array(clipRect(rect, canvas.width, canvas.height)),\n );\n const encoder = device.createCommandEncoder();\n const pass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view: context.getCurrentTexture().createView(),\n clearValue: { r: clear[0], g: clear[1], b: clear[2], a: 1 },\n loadOp: \"clear\",\n storeOp: \"store\",\n },\n ],\n });\n if (grid && bindGroup) {\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bindGroup);\n pass.draw(4);\n }\n pass.end();\n device.queue.submit([encoder.finish()]);\n },\n destroy() {\n destroyed = true;\n texture?.destroy();\n uniform.destroy();\n context.unconfigure();\n device.destroy();\n },\n };\n};\n\n/** Canvas2D backend: the image drawn with nearest-neighbour scaling */\nexport const createCanvasHeatField = (\n canvas: HTMLCanvasElement,\n): HeatFieldRenderer | null => {\n const ctx = canvas.getContext(\"2d\", { alpha: false });\n if (!ctx) return null;\n const image = canvas.ownerDocument.createElement(\"canvas\");\n const imageCtx = image.getContext(\"2d\");\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n return {\n kind: \"canvas2d\",\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.fillStyle = `rgb(${Math.round(clear[0] * 255)}, ${Math.round(clear[1] * 255)}, ${Math.round(clear[2] * 255)})`;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n if (!grid || !imageCtx) return;\n if (grid !== uploaded || grid.version !== uploadedVersion) {\n if (image.width !== grid.width) image.width = grid.width;\n if (image.height !== grid.height) image.height = grid.height;\n const data = imageCtx.createImageData?.(grid.width, grid.height);\n if (!data?.data) return;\n data.data.set(bytesOf(grid));\n imageCtx.putImageData(data, 0, 0);\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n ctx.imageSmoothingEnabled = false;\n ctx.drawImage(\n image,\n rect[0],\n rect[1],\n rect[2] - rect[0],\n rect[3] - rect[1],\n );\n },\n destroy() {\n uploaded = null;\n },\n };\n};\n\n/**\n * Creates the first heat field backend that works, in the chart engine's\n * order and with its preference rules (`auto` follows the global default\n * and skips software GPUs). Every attempt gets a fresh canvas.\n */\nexport const createHeatFieldRenderer = async (\n requested: ChartRendererPreference,\n makeCanvas: () => HTMLCanvasElement,\n onLost: (kind: ChartRendererKind) => void,\n exclude?: ReadonlySet<ChartRendererKind>,\n): Promise<HeatFieldRenderer | null> => {\n const preference = resolveRendererPreference(requested);\n for (const kind of rendererCandidates(preference, exclude)) {\n const requireHardware = preference === \"auto\" || preference !== kind;\n let field: HeatFieldRenderer | null;\n try {\n const canvas = makeCanvas();\n const lost = () => onLost(kind);\n field =\n kind === \"webgpu\"\n ? await createWebGpuHeatField(canvas, lost, requireHardware)\n : kind === \"canvas2d\"\n ? createCanvasHeatField(canvas)\n : createGlHeatField(canvas, kind, lost, requireHardware);\n } catch {\n field = null;\n }\n if (field) return field;\n }\n return null;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"field.js","names":["HEAT_TABLE_SIZE","heatTable","table","last","lut","j","t","curve","percentile","len","values","m","limit","prime","value","n","sorted","k","v","at","q","lo","hi","buildHeatGrid","input","step","tick","x1","x0","y1","y0","g","gs","width","binLo","binHi","ry","base","height","count","cells","reuse","sums","hits","plot","source","sizes","s","r","bins","idx","i","repeat","sources","mid","previous","start","end","stop","hit","paintHeatGrid","grid","cold","scale","GLSL_VERTEX","GLSL_FRAGMENT","clipRect","rect","bytesOf","createGlHeatField","attributes","glContextAttributes","requireHardware","gl","canvas","kind","reject","isSoftwareRenderer","setup","program","compileProgram","corners","texture","objects","uploaded","uploadedVersion","size","destroyed","lost","forget","slot","claimGlSlot","draw","onLost","w","h","clear","textureAt","rectAt","WGSL","STAGE_VERTEX","STAGE_FRAGMENT","createWebGpuHeatField","gpu","adapter","info","device","context","format","layout","module","pipeline","sampler","uniform","bindGroup","encoder","pass","createCanvasHeatField","ctx","image","imageCtx","data","createHeatFieldRenderer","preference","resolveRendererPreference","requested","rendererCandidates","exclude","field","makeCanvas"],"sources":["../../../../../charts/src/engine/orderbook/field.ts"],"sourcesContent":["// Heat field of the order book heatmap. The liquidity of the visible\n// window is rasterized on the CPU into a small image, one texel per column\n// (sampling interval) and price row (tick, or a bucket of rows whose sizes\n// are summed when rows get thinner than the screen allows), and drawn as\n// ONE textured quad\n// with nearest filtering over a clear of the coldest color:\n// - rows and columns abut by construction (every device pixel samples\n// exactly one texel), so there are no anti-aliased seams between cells;\n// - a column fills until the next snapshot (gaps repeat the last book) and\n// the live one fills to the right edge;\n// - empty cells are the cold end of the ramp, never a transparent hole;\n// - the output is opaque (no blending), the same on every backend.\n// The backends mirror the chart engine's (WebGPU -> WebGL2 -> WebGL ->\n// Canvas2D, software GPUs skipped with `auto`), but with their own tiny\n// pipelines: a canvas only ever holds one context type.\n\nimport { resolveRendererPreference } from \"../defaults\";\nimport type { Rgba } from \"../color\";\nimport { rendererCandidates } from \"../renderers/detect\";\nimport {\n compileProgram,\n glContextAttributes,\n isSoftwareRenderer,\n type GlContext,\n} from \"../renderers/gl\";\nimport { claimGlSlot } from \"../renderers/gl-budget\";\nimport type { ChartRendererKind, ChartRendererPreference } from \"../types\";\n\n/** One sampled book: price rows (price / tick) and their resting sizes */\nexport interface HeatSource {\n /** Start time of the column */\n time: number;\n bins: ArrayLike<number>;\n sizes: ArrayLike<number>;\n}\n\n/** The rasterized field: packed RGBA texels, row 0 at the top (highest prices) */\nexport interface HeatGrid {\n width: number;\n height: number;\n pixels: Uint32Array;\n /**\n * Resting size of every texel, same layout as `pixels`: the sizes of the\n * price rows of a texel are summed, its columns max-pooled\n */\n cells: Float32Array;\n /** Price rows (ticks) per texel row; texel rows start at multiples of it */\n rowBins: number;\n /** Times at the left / right edges of the image */\n t0: number;\n t1: number;\n /** Prices at the bottom / top edges of the image */\n p0: number;\n p1: number;\n /** Bumped on every rebuild (uploads are skipped while unchanged) */\n version: number;\n}\n\nexport interface HeatGridInput {\n /** Columns sorted by time (the live book last) */\n sources: readonly HeatSource[];\n /** Sampling interval (ms) */\n step: number;\n /** Price row height */\n tick: number;\n /** Visible time / price ranges */\n x0: number;\n x1: number;\n y0: number;\n y1: number;\n /** End of the data (the live time): texels starting later stay cold */\n end: number;\n /**\n * Largest image (texels). Denser columns are max-pooled (walls stay\n * visible); denser price rows are summed into buckets\n */\n maxWidth: number;\n maxHeight: number;\n /**\n * Smallest number of price rows per texel row (price aggregation, e.g.\n * when a tick is under 2 px); default 1\n */\n rowBins?: number;\n}\n\n/** Entries of a heat table (resolution of the size → color mapping) */\nexport const HEAT_TABLE_SIZE = 1024;\n\n/**\n * Size → color table of a ramp: entry `j` is the color of the relative size\n * `j / HEAT_TABLE_SIZE` through `curve` (0-1 → 0-1). Entry 0 is the cold end.\n */\nexport const heatTable = (\n lut: Uint32Array,\n curve: (r: number) => number,\n): Uint32Array => {\n const table = new Uint32Array(HEAT_TABLE_SIZE + 1);\n const last = lut.length - 1;\n for (let j = 0; j <= HEAT_TABLE_SIZE; j++) {\n const t = Math.min(1, Math.max(0, curve(j / HEAT_TABLE_SIZE)));\n table[j] = lut[Math.round(t * last)] ?? 0;\n }\n return table;\n};\n\n/**\n * `q`-quantile (0-1) of the positive values, NaN without any. Arrays longer\n * than `limit` are sampled (a prime stride, so a grid's rows and columns\n * are both covered).\n */\nexport const percentile = (\n values: ArrayLike<number>,\n q: number,\n limit = 16384,\n): number => {\n const len = values.length;\n const m = Math.min(len, Math.max(1, limit));\n const prime = len % 7919 ? 7919 : 7907;\n const value = (j: number) => values[m === len ? j : (j * prime) % len]!;\n let n = 0;\n for (let j = 0; j < m; j++) if (value(j) > 0) n++;\n if (!n) return NaN;\n const sorted = new Float64Array(n);\n let k = 0;\n for (let j = 0; j < m; j++) {\n const v = value(j);\n if (v > 0) sorted[k++] = v;\n }\n sorted.sort();\n const at = Math.min(n - 1, Math.max(0, q * (n - 1)));\n const lo = Math.floor(at);\n const hi = Math.min(n - 1, lo + 1);\n return sorted[lo]! + (sorted[hi]! - sorted[lo]!) * (at - lo);\n};\n\n/**\n * Rasterizes the visible liquidity into `cells` (the colors are set by\n * `paintHeatGrid`). Pass the previous grid as `reuse` to recycle its\n * buffers. Returns `null` without a valid range.\n */\nexport const buildHeatGrid = (\n input: HeatGridInput,\n reuse?: HeatGrid | null,\n): HeatGrid | null => {\n const { sources, step, tick, x0, x1, y0, y1, end } = input;\n if (\n !(step > 0) ||\n !(tick > 0) ||\n !(x1 > x0) ||\n !(y1 > y0) ||\n !Number.isFinite(x0 + x1 + y0 + y1)\n )\n return null;\n // time texels: `cx` columns each\n const cx = Math.max(\n 1,\n Math.ceil((x1 - x0) / step / Math.max(1, input.maxWidth)),\n );\n const g = step * cx;\n const gs = Math.floor(x0 / g) * g;\n const width = Math.max(1, Math.ceil((x1 - gs) / g));\n // price texels: buckets of `ry` rows (aligned on multiples of `ry`); a\n // row covers [bin - ½, bin + ½) × tick\n const binLo = Math.round(y0 / tick);\n const binHi = Math.round(y1 / tick);\n const ry = Math.max(\n 1,\n Math.round(input.rowBins ?? 1) || 1,\n Math.ceil((binHi - binLo + 1) / Math.max(1, input.maxHeight)),\n );\n const base = Math.floor(binLo / ry) * ry;\n const height = Math.max(1, Math.ceil((binHi + 1 - base) / ry));\n const count = width * height;\n\n const cells =\n reuse && reuse.cells.length === count\n ? reuse.cells.fill(0)\n : new Float32Array(count);\n // a source's rows are summed per bucket first (scratch), then the\n // sources sharing a time texel are max-pooled\n const sums = ry > 1 ? new Float32Array(height) : null;\n const hits: number[] = [];\n const plot = (source: HeatSource, i: number) => {\n const { bins, sizes } = source;\n for (let k = 0; k < sizes.length; k++) {\n const s = sizes[k]!;\n if (!(s > 0)) continue;\n const r = Math.floor((bins[k]! - base) / ry);\n if (r < 0 || r >= height) continue;\n if (sums) {\n if (!sums[r]) hits.push(r);\n sums[r] += s;\n continue;\n }\n const idx = (height - 1 - r) * width + i;\n if (s > cells[idx]!) cells[idx] = s;\n }\n if (!sums) return;\n for (const r of hits) {\n const idx = (height - 1 - r) * width + i;\n if (sums[r]! > cells[idx]!) cells[idx] = sums[r]!;\n sums[r] = 0;\n }\n hits.length = 0;\n };\n const repeat = (i: number) => {\n for (let r = 0, idx = i; r < height; r++, idx += width)\n cells[idx] = cells[idx - 1]!;\n };\n\n // first source inside the image, and the one before (filled forward)\n let lo = 0;\n let hi = sources.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (sources[mid]!.time < gs) lo = mid + 1;\n else hi = mid;\n }\n let s = lo;\n let previous: HeatSource | null = lo > 0 ? sources[lo - 1]! : null;\n for (let i = 0; i < width; i++) {\n const start = gs + i * g;\n if (start >= end) break;\n const stop = start + g;\n let hit = false;\n while (s < sources.length && sources[s]!.time < stop) {\n plot(sources[s]!, i);\n previous = sources[s]!;\n hit = true;\n s++;\n }\n if (hit || !previous) continue;\n if (i === 0) plot(previous, 0);\n else repeat(i);\n }\n\n const pixels =\n reuse && reuse.pixels.length === count\n ? reuse.pixels\n : new Uint32Array(count);\n return {\n width,\n height,\n pixels,\n cells,\n rowBins: ry,\n t0: gs,\n t1: gs + width * g,\n p0: (base - 0.5) * tick,\n p1: (base + height * ry - 0.5) * tick,\n version: (reuse?.version ?? 0) + 1,\n };\n};\n\n/**\n * Colors the cells of a grid: `table[min(last, floor(size × scale))]`\n * (see `heatTable`), empty cells the cold end. Bumps the version.\n */\nexport const paintHeatGrid = (\n grid: HeatGrid,\n table: Uint32Array,\n scale: number,\n): void => {\n const { cells, pixels } = grid;\n const last = table.length - 1;\n const cold = table[0] ?? 0;\n const k = scale > 0 && Number.isFinite(scale) ? scale : 0;\n for (let idx = 0; idx < cells.length; idx++) {\n const v = cells[idx]! * k;\n pixels[idx] = v > 0 ? table[v >= last ? last : v | 0]! : cold;\n }\n grid.version++;\n};\n\n// ------------------------------------------------------------- renderers\n\n/** Draws heat grids on its own canvas (sized and placed by the caller) */\nexport interface HeatFieldRenderer {\n readonly kind: ChartRendererKind;\n readonly canvas: HTMLCanvasElement;\n /** Sets the size of the drawing buffer (device pixels) */\n resize(width: number, height: number): void;\n /**\n * Clears to `clear` (opaque) and draws `grid` stretched over `rect`\n * ([left, top, right, bottom] in device pixels, y down)\n */\n render(\n grid: HeatGrid | null,\n rect: readonly [number, number, number, number],\n clear: Rgba,\n ): void;\n destroy(): void;\n}\n\nconst GLSL_VERTEX = `\nattribute vec2 a_corner;\nuniform vec4 u_rect;\nvarying vec2 v_uv;\nvoid main() {\n v_uv = a_corner;\n gl_Position = vec4(mix(u_rect.x, u_rect.z, a_corner.x), mix(u_rect.y, u_rect.w, a_corner.y), 0.0, 1.0);\n}`;\nconst GLSL_FRAGMENT = `\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\nuniform sampler2D u_texture;\nvarying vec2 v_uv;\nvoid main() {\n gl_FragColor = vec4(texture2D(u_texture, v_uv).rgb, 1.0);\n}`;\n\n/** Clip-space rectangle of a pixel rectangle (y up) */\nconst clipRect = (\n rect: readonly [number, number, number, number],\n width: number,\n height: number,\n): [number, number, number, number] => [\n (rect[0] / width) * 2 - 1,\n 1 - (rect[1] / height) * 2,\n (rect[2] / width) * 2 - 1,\n 1 - (rect[3] / height) * 2,\n];\n\nconst bytesOf = (grid: HeatGrid) =>\n new Uint8Array(\n grid.pixels.buffer,\n grid.pixels.byteOffset,\n grid.width * grid.height * 4,\n );\n\n/** WebGL2 / WebGL backend (GLSL ES 1.00 runs on both) */\nexport const createGlHeatField = (\n canvas: HTMLCanvasElement,\n kind: \"webgl2\" | \"webgl\",\n onLost: () => void,\n requireHardware = false,\n): HeatFieldRenderer | null => {\n const attributes: WebGLContextAttributes = {\n ...glContextAttributes(requireHardware),\n alpha: false,\n premultipliedAlpha: false,\n };\n const gl = canvas.getContext(kind, attributes) as GlContext | null;\n if (!gl) return null;\n // a rejected context is freed now, not at garbage collection\n const reject = () => {\n gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n return null;\n };\n if (requireHardware && isSoftwareRenderer(gl)) return reject();\n\n /** Program, quad and texture: built again when a suspended context returns */\n const setup = () => {\n const program = compileProgram(\n gl,\n { vertex: GLSL_VERTEX, fragment: GLSL_FRAGMENT },\n [\"a_corner\"],\n );\n if (!program) return null;\n const corners = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, corners);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]),\n gl.STATIC_DRAW,\n );\n const texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n return {\n program,\n rectAt: gl.getUniformLocation(program.program, \"u_rect\"),\n textureAt: gl.getUniformLocation(program.program, \"u_texture\"),\n corners,\n texture,\n };\n };\n let objects = setup();\n if (!objects) return reject();\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n let size = [0, 0];\n let destroyed = false;\n let lost = false;\n let last: {\n grid: HeatGrid | null;\n rect: readonly [number, number, number, number];\n clear: Rgba;\n } | null = null;\n\n const forget = () => {\n objects = null;\n uploaded = null;\n uploadedVersion = -1;\n size = [0, 0];\n };\n // past the page-wide context budget the context may be suspended while\n // off-screen: its GPU objects go, and come back (with the last frame)\n // when it is restored\n const slot = claimGlSlot(canvas, gl, {\n suspend: forget,\n restore: () => {\n forget();\n objects = setup();\n if (!objects) {\n lost = true;\n if (!destroyed) onLost();\n } else if (last) draw(last.grid, last.rect, last.clear);\n },\n lost: () => {\n lost = true;\n if (!destroyed) onLost();\n },\n });\n\n const draw = (\n grid: HeatGrid | null,\n rect: readonly [number, number, number, number],\n clear: Rgba,\n ) => {\n if (!objects) return;\n const { program, rectAt, textureAt, corners, texture } = objects;\n const w = canvas.width;\n const h = canvas.height;\n gl.viewport(0, 0, w, h);\n gl.disable(gl.BLEND);\n gl.clearColor(clear[0], clear[1], clear[2], 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n if (!grid) return;\n gl.useProgram(program.program);\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n if (grid !== uploaded || grid.version !== uploadedVersion) {\n gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);\n if (size[0] === grid.width && size[1] === grid.height) {\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n grid.width,\n grid.height,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n bytesOf(grid),\n );\n } else {\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n grid.width,\n grid.height,\n 0,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n bytesOf(grid),\n );\n size = [grid.width, grid.height];\n }\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n gl.uniform1i(textureAt, 0);\n gl.uniform4fv(rectAt, clipRect(rect, w, h));\n gl.bindBuffer(gl.ARRAY_BUFFER, corners);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n };\n\n return {\n kind,\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n if (destroyed) return;\n last = { grid, rect, clear };\n if (lost || !slot.use() || gl.isContextLost()) return;\n draw(grid, rect, clear);\n },\n destroy() {\n destroyed = true;\n last = null;\n slot.release();\n if (objects && !gl.isContextLost()) {\n gl.deleteTexture(objects.texture);\n gl.deleteBuffer(objects.corners);\n gl.deleteProgram(objects.program.program);\n // frees the context now instead of at garbage collection\n gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n }\n objects = null;\n },\n };\n};\n\nconst WGSL = `\nstruct Uniforms { rect: vec4f };\n@group(0) @binding(0) var<uniform> u: Uniforms;\n@group(0) @binding(1) var heat: texture_2d<f32>;\n@group(0) @binding(2) var nearest: sampler;\nstruct Varyings {\n @builtin(position) position: vec4f,\n @location(0) uv: vec2f,\n};\n@vertex fn vs(@builtin(vertex_index) i: u32) -> Varyings {\n let c = vec2f(f32(i & 1u), f32(i >> 1u));\n var out: Varyings;\n out.position = vec4f(mix(u.rect.x, u.rect.z, c.x), mix(u.rect.y, u.rect.w, c.y), 0.0, 1.0);\n out.uv = c;\n return out;\n}\n@fragment fn fs(v: Varyings) -> @location(0) vec4f {\n return vec4f(textureSample(heat, nearest, v.uv).rgb, 1.0);\n}`;\n\ntype GpuNavigator = Navigator & { gpu?: GPU };\n\n// lib.dom has the WebGPU interfaces but not these constant objects\nconst BUFFER_UNIFORM = 0x40;\nconst BUFFER_COPY_DST = 0x08;\nconst TEXTURE_COPY_DST = 0x02;\nconst TEXTURE_BINDING = 0x04;\nconst STAGE_VERTEX = 0x1;\nconst STAGE_FRAGMENT = 0x2;\n\n/** WebGPU backend */\nexport const createWebGpuHeatField = async (\n canvas: HTMLCanvasElement,\n onLost: () => void,\n requireHardware = false,\n): Promise<HeatFieldRenderer | null> => {\n const gpu =\n typeof navigator !== \"undefined\"\n ? (navigator as GpuNavigator).gpu\n : undefined;\n if (!gpu) return null;\n const adapter = await gpu.requestAdapter();\n if (!adapter) return null;\n const info = adapter as GPUAdapter & {\n isFallbackAdapter?: boolean;\n info?: { isFallbackAdapter?: boolean };\n };\n if (\n requireHardware &&\n (info.info?.isFallbackAdapter || info.isFallbackAdapter)\n )\n return null;\n const device = await adapter.requestDevice();\n const context = canvas.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!context) {\n device.destroy();\n return null;\n }\n const format = gpu.getPreferredCanvasFormat();\n context.configure({ device, format, alphaMode: \"opaque\" });\n let destroyed = false;\n void device.lost.then(() => {\n if (!destroyed) onLost();\n });\n\n const layout = device.createBindGroupLayout({\n entries: [\n { binding: 0, visibility: STAGE_VERTEX, buffer: { type: \"uniform\" } },\n { binding: 1, visibility: STAGE_FRAGMENT, texture: {} },\n { binding: 2, visibility: STAGE_FRAGMENT, sampler: {} },\n ],\n });\n const module = device.createShaderModule({ code: WGSL });\n const pipeline = device.createRenderPipeline({\n layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),\n vertex: { module, entryPoint: \"vs\" },\n fragment: { module, entryPoint: \"fs\", targets: [{ format }] },\n primitive: { topology: \"triangle-strip\" },\n });\n const sampler = device.createSampler({\n magFilter: \"nearest\",\n minFilter: \"nearest\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n });\n const uniform = device.createBuffer({\n size: 16,\n usage: BUFFER_UNIFORM | BUFFER_COPY_DST,\n });\n let texture: GPUTexture | null = null;\n let bindGroup: GPUBindGroup | null = null;\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n\n return {\n kind: \"webgpu\",\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n if (destroyed) return;\n if (grid && (grid !== uploaded || grid.version !== uploadedVersion)) {\n if (\n !texture ||\n texture.width !== grid.width ||\n texture.height !== grid.height\n ) {\n texture?.destroy();\n texture = device.createTexture({\n size: { width: grid.width, height: grid.height },\n format: \"rgba8unorm\",\n usage: TEXTURE_COPY_DST | TEXTURE_BINDING,\n });\n bindGroup = device.createBindGroup({\n layout,\n entries: [\n { binding: 0, resource: { buffer: uniform } },\n { binding: 1, resource: texture.createView() },\n { binding: 2, resource: sampler },\n ],\n });\n }\n device.queue.writeTexture(\n { texture },\n bytesOf(grid),\n { bytesPerRow: grid.width * 4, rowsPerImage: grid.height },\n { width: grid.width, height: grid.height },\n );\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n device.queue.writeBuffer(\n uniform,\n 0,\n new Float32Array(clipRect(rect, canvas.width, canvas.height)),\n );\n const encoder = device.createCommandEncoder();\n const pass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view: context.getCurrentTexture().createView(),\n clearValue: { r: clear[0], g: clear[1], b: clear[2], a: 1 },\n loadOp: \"clear\",\n storeOp: \"store\",\n },\n ],\n });\n if (grid && bindGroup) {\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bindGroup);\n pass.draw(4);\n }\n pass.end();\n device.queue.submit([encoder.finish()]);\n },\n destroy() {\n destroyed = true;\n texture?.destroy();\n uniform.destroy();\n context.unconfigure();\n device.destroy();\n },\n };\n};\n\n/** Canvas2D backend: the image drawn with nearest-neighbour scaling */\nexport const createCanvasHeatField = (\n canvas: HTMLCanvasElement,\n): HeatFieldRenderer | null => {\n const ctx = canvas.getContext(\"2d\", { alpha: false });\n if (!ctx) return null;\n const image = canvas.ownerDocument.createElement(\"canvas\");\n const imageCtx = image.getContext(\"2d\");\n let uploaded: HeatGrid | null = null;\n let uploadedVersion = -1;\n return {\n kind: \"canvas2d\",\n canvas,\n resize(width, height) {\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n },\n render(grid, rect, clear) {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.fillStyle = `rgb(${Math.round(clear[0] * 255)}, ${Math.round(clear[1] * 255)}, ${Math.round(clear[2] * 255)})`;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n if (!grid || !imageCtx) return;\n if (grid !== uploaded || grid.version !== uploadedVersion) {\n if (image.width !== grid.width) image.width = grid.width;\n if (image.height !== grid.height) image.height = grid.height;\n const data = imageCtx.createImageData?.(grid.width, grid.height);\n if (!data?.data) return;\n data.data.set(bytesOf(grid));\n imageCtx.putImageData(data, 0, 0);\n uploaded = grid;\n uploadedVersion = grid.version;\n }\n ctx.imageSmoothingEnabled = false;\n ctx.drawImage(\n image,\n rect[0],\n rect[1],\n rect[2] - rect[0],\n rect[3] - rect[1],\n );\n },\n destroy() {\n uploaded = null;\n },\n };\n};\n\n/**\n * Creates the first heat field backend that works, in the chart engine's\n * order and with its preference rules (`auto` follows the global default\n * and skips software GPUs). Every attempt gets a fresh canvas.\n */\nexport const createHeatFieldRenderer = async (\n requested: ChartRendererPreference,\n makeCanvas: () => HTMLCanvasElement,\n onLost: (kind: ChartRendererKind) => void,\n exclude?: ReadonlySet<ChartRendererKind>,\n): Promise<HeatFieldRenderer | null> => {\n const preference = resolveRendererPreference(requested);\n for (const kind of rendererCandidates(preference, exclude)) {\n const requireHardware = preference === \"auto\" || preference !== kind;\n let field: HeatFieldRenderer | null;\n try {\n const canvas = makeCanvas();\n const lost = () => onLost(kind);\n field =\n kind === \"webgpu\"\n ? await createWebGpuHeatField(canvas, lost, requireHardware)\n : kind === \"canvas2d\"\n ? createCanvasHeatField(canvas)\n : createGlHeatField(canvas, kind, lost, requireHardware);\n } catch {\n field = null;\n }\n if (field) return field;\n }\n return null;\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../color.cjs"),t=require("../locale.cjs"),n=require("../scale.cjs"),r=require("../renderers/follow.cjs"),i=require("../time.cjs"),a=require("./book.cjs"),o=require("./format.cjs"),s=require("./host.cjs"),c=require("./field.cjs"),l=require("./layout.cjs");var u=256,d=4096,f=.98,p=1.4,m=[`#0a1830`,`#0f2c57`,`#134a8a`,`#1670b4`,`#1aa0bf`,`#2fc3a0`,`#8ad65a`,`#e8dc3f`,`#ffa733`,`#ff5a2e`],h=[`#eef4fb`,`#cfe1f6`,`#9fc2ee`,`#679ee2`,`#3a73cf`,`#3f4bb0`,`#62309a`,`#9c2783`,`#d12c52`],g=16,_=6,v={en:{time:`Time`,price:`Price`,liquidity:`Liquidity`,buys:`Buys`,sells:`Sells`,bid:`Bid`,ask:`Ask`,bidSide:`Bid side`,askSide:`Ask side`,name:`Liquidity heatmap`},zh:{time:`时间`,price:`价格`,liquidity:`挂单量`,buys:`主动买入`,sells:`主动卖出`,bid:`买一`,ask:`卖一`,bidSide:`买盘`,askSide:`卖盘`,name:`订单簿热力图`},ja:{time:`時刻`,price:`価格`,liquidity:`指値量`,buys:`買い約定`,sells:`売り約定`,bid:`最良買気配`,ask:`最良売気配`,bidSide:`買い板`,askSide:`売り板`,name:`板ヒートマップ`},fr:{time:`Heure`,price:`Prix`,liquidity:`Liquidité`,buys:`Achats`,sells:`Ventes`,bid:`Meilleur achat`,ask:`Meilleure vente`,bidSide:`Côté achat`,askSide:`Côté vente`,name:`Carte de chaleur de la liquidité`}},y=(e,t,n,r)=>{if(!(e>0)||!(t>0))return 0;let i=Math.min(1,e*r/t);switch(n){case`linear`:return i;case`sqrt`:return Math.sqrt(i);default:return Math.log10(1+9*i)}},ee=(ee,b={})=>{let x=b,S=a.createOrderBookStore(),te=s.createEmitter(),C=o.createFormatters(x,2,4),w={up:[0,0,0,1],down:[0,0,0,1]},ne=new Uint32Array(u),T=new Uint32Array(c.HEAT_TABLE_SIZE+1),E=[0,0,0,1],D=!1,O=0,k=[],re=0,A=NaN,j={buyVolume:0,buyNotional:0,sellVolume:0,sellNotional:0},ie=null,M=NaN,ae=0,N=0,P=0,oe=-1/0,F=0,I=0,L=null,R=``,z=``,B=null,V=null,se=0,ce=!1,le=()=>{},ue=new Promise(e=>{le=e}),de=!0,H=NaN,U=[0,1],W=[0,1],fe=!1,G=null,K=NaN,q=NaN,pe=0,J={x:0,y:0,w:0,h:0},Y=null,me=``,X=null,Z=s.createHost(ee,{className:`minerva-orderbook-heatmap`,draw:He,onTheme:()=>{Ce(),Z.invalidate()}}),{root:Q,doc:he}=Z;Q.tabIndex=0,Q.setAttribute(`role`,`figure`),Q.style.touchAction=`none`;let ge=t.localeLabels(v,x.locale,x.labels),_e=()=>ge,ve=()=>{ge=t.localeLabels(v,x.locale,x.labels),Q.setAttribute(`aria-label`,x.ariaLabel??ge.name)},$=()=>Math.max(10,x.interval??100),ye=()=>Math.max($()*4,x.history??3e5),be=()=>Math.max(4,Math.round(x.depth??160)),xe=()=>{if(!Number.isFinite(M))return Date.now();let e=Se()-ae;return M+Math.min(Math.max(0,e),$()*3)},Se=()=>typeof performance<`u`?performance.now():Date.now();function Ce(){let t=Z.theme;w=o.sideColors(t,x);let n=e=>{let n=t.resolve?t.resolve(e,t.primary):t.primary;return[n[0],n[1],n[2],1]},r=[t.background[0],t.background[1],t.background[2],1];D=t.background[3]>0&&e.luminance(r)<.4;let i=(x.colors?.length?x.colors:D?m:h).map(n);E=i[0]??r,ne=e.oklabRamp(i.length>1?i:[E,E],u);let a=x.colorScale??`log`;T=c.heatTable(ne,e=>y(e,1,a,1)**p),z=``}let we=()=>{C=o.createFormatters(x,O>0?Math.max(a.decimalsOf(O),a.inferPriceDecimals(S)):a.inferPriceDecimals(S),a.inferSizeDecimals(S))},Te=()=>{k=[],L=null,R=z=``,B=null,A=NaN,N=P=0,oe=-1/0,F=0,I=0,q=NaN,j.buyVolume=j.buyNotional=j.sellVolume=j.sellNotional=0},Ee=()=>{if(O>0)return;let e=a.inferTickSize(S),t=S.mid();if(x.tickSize&&x.tickSize>0)O=x.tickSize;else if(e>0&&Number.isFinite(t)){let n=t*1e-5/e,r=1;for(let e=1;e<=1e9&&r<n*.75;e*=10)for(let t of[1,2,5])if(r=t*e,r>=n*.75)break;O=a.roundToStep(e*r,e)}else O=Number.isFinite(t)?Math.max(1e-8,t*1e-5):0;O>0&&we()},De=()=>{let e=be(),t=new Float64Array(e*2),n=new Float32Array(e*2),r=0;for(let i of[`bid`,`ask`]){let a=S.count(i),o=0;for(let s=0;s<a;s++){let a=Math.round(S.priceAt(i,s)/O),c=S.sizeAt(i,s);if(r>0&&t[r-1]===a&&o>0){n[r-1]+=c;continue}if(o>=e)break;t[r]=a,n[r]=c,r++,o++}}return{bins:t.slice(0,r),sizes:n.slice(0,r)}},Oe=e=>{if(!(O>0))return;let{bins:t,sizes:n}=De(),r={seq:re++,time:e,bins:t,sizes:n,bestBid:S.bestBid(),bestAsk:S.bestAsk(),buyVolume:j.buyVolume,buyNotional:j.buyNotional,sellVolume:j.sellVolume,sellNotional:j.sellNotional};j.buyVolume=j.buyNotional=j.sellVolume=j.sellNotional=0,k.push(r);let i=e-ye(),a=0;for(;a<k.length&&k[a].time<i;)a++;a&&(k=k.slice(a))},ke=e=>{if(!Number.isFinite(e))return;let t=$();if(!Number.isFinite(A)){A=Math.floor(e/t)*t;return}if(e-A>ye()){Oe(A),A=Math.floor(e/t)*t;return}for(;e>=A+t;)Oe(A),A+=t},Ae=e=>e===void 0||!Number.isFinite(e)?Date.now():((!Number.isFinite(M)||e>=M)&&(M=e,ae=Se()),e),je=e=>{if(Number.isFinite(A)&&e>=A)return null;let t=0,n=k.length;for(;t<n;){let r=t+n>>>1;k[r].time<=e?t=r+1:n=r}return t>0?k[t-1]:null},Me=()=>{if(!Number.isFinite(A)||!(O>0))return null;let e=S.version();return(!B||B.version!==e)&&(B={version:e,...De()}),{time:A,bins:B.bins,sizes:B.sizes}},Ne=(e,t,n,r,i,a)=>{let s=$(),l=Me(),u=Math.min(d,Math.ceil(J.w)),p=Math.min(d,Math.ceil(J.h)),m=k.length?k[k.length-1].seq:-1,h=[e,t,n,r,Math.floor(i/s),k.length,m,B?.version??-1,u,p,O].join(`|`);if(h!==R){let a=l?[...k,l]:k;L=c.buildHeatGrid({sources:a,step:s,tick:O,x0:e,x1:t,y0:n,y1:r,end:i,maxWidth:u,maxHeight:p},L),R=h,z=``}if(!L)return null;let g=x.maxSize;if(g!==void 0&&g>0)N=g;else{let e=Se();if(e-oe>250||!(P>0)){let t=c.percentile(L.cells,f);t>0&&(P=t),oe=e}N>0?P>0&&Math.abs(P/N-1)>.001&&(N+=(P-N)*o.ease(a,700)):N=P}let _=Math.max(.01,x.contrast??1),v=N>0?c.HEAT_TABLE_SIZE*_/N:0;return`${L.version}|${v}`!==z&&(c.paintHeatGrid(L,T,v),z=`${L.version}|${v}`),L},Pe=()=>{let e=$(),t=[],n=0,r=k.length;for(;n<r;){let t=n+r>>>1;k[t].time+e<U[0]?n=t+1:r=t}for(let e=n;e<k.length;e++){let n=k[e];if(n.time>U[1])break;t.push(n)}return t},Fe=(e,t)=>{let n=$(),r=Math.max(1,Math.ceil(_/Math.max(1e-6,t))),i=[],a=NaN,o=0,s=0,c={bv:0,bn:0,sv:0,sn:0},l=()=>{let e=(o+s)/2;c.sv>0&&i.push({time:e,price:c.sn/c.sv,volume:c.sv,buy:!1}),c.bv>0&&i.push({time:e,price:c.bn/c.bv,volume:c.bv,buy:!0}),c.bv=c.bn=c.sv=c.sn=0},u=(e,t,i)=>{let u=Math.floor(e/r);u!==a&&(Number.isFinite(a)&&l(),a=u,o=t),s=t+n,c.bv+=i.buyVolume,c.bn+=i.buyNotional,c.sv+=i.sellVolume,c.sn+=i.sellNotional};for(let t of e)u(t.seq,t.time,t);return Number.isFinite(A)&&A<=U[1]&&u(re,A,j),Number.isFinite(a)&&l(),i},Ie=e=>{e.save(),e.beginPath(),e.rect(J.x,J.y,J.w,J.h),e.clip()},Le=(t,n,r,i,a)=>{if(x.bestLines===!1)return;let o=$(),s=n.map(e=>[e.time,e.time+o,e.bestBid,e.bestAsk]);if(Number.isFinite(A)&&s.push([A,A+o,S.bestBid(),S.bestAsk()]),!s.length)return;for(let e=0;e+1<s.length;e++)s[e][1]=s[e+1][0];let c=a>=2,l=e=>{let t=r(e[0]),n=r(e[1]);return c?[t,n]:[(t+n)/2,(t+n)/2]};Ie(t),t.beginPath();let u=[],d=()=>{if(u.length){u.forEach((e,n)=>{let[r,a]=l(e),o=i(e[3]);n?t.lineTo(r,o):t.moveTo(r,o),t.lineTo(a,o)});for(let e=u.length-1;e>=0;e--){let[n,r]=l(u[e]),a=i(u[e][2]);t.lineTo(r,a),t.lineTo(n,a)}t.closePath(),u=[]}};for(let e of s){let[,,t,n]=e;Number.isFinite(t)&&Number.isFinite(n)&&n>t?u.push(e):d()}d(),t.fillStyle=e.toCss(Z.theme.text,D?.08:.07),t.fill(),t.lineJoin=`round`;for(let[n,r]of[[2,w.up],[3,w.down]]){t.beginPath();let a=!1;for(let e of s){let r=e[n];if(!Number.isFinite(r)){a=!1;continue}let o=i(r),[s,u]=l(e);a?t.lineTo(s,o):t.moveTo(s,o),c&&t.lineTo(u,o),a=!0}t.strokeStyle=e.toCss(E,.55),t.lineWidth=3.5,t.stroke(),t.strokeStyle=e.toCss(r),t.lineWidth=1.5,t.stroke()}t.restore()},Re=(t,n,r,i,a)=>{if(!n.length)return;let s=0;for(let e of n)s=Math.max(s,e.volume);F=F>0?Math.max(s,F*.995):s;let c=x.bubbleVolume??F,l=Math.max(4,x.bubbleSize??28),u=n.map(e=>({...e,d:o.clamp(Math.sqrt(e.volume/c)*l,3,l)})).sort((e,t)=>e.d-t.d);Ie(t),t.lineWidth=1.25,t.textAlign=`center`,t.textBaseline=`middle`,t.font=o.fontOf(Z.theme,x,600,Math.max(8,a-1));for(let n of u){let a=r(n.time),o=i(n.price),s=n.d/2;if(a<J.x-s||a>J.x+J.w+s||o<J.y-s||o>J.y+J.h+s)continue;let c=n.buy?w.up:w.down;if(t.beginPath(),t.arc(a,o,s,0,Math.PI*2),t.fillStyle=e.toCss(c,.62),t.fill(),t.strokeStyle=e.toCss(e.mixOklab(c,[1,1,1,1],.25)),t.stroke(),n.d>=26){let e=C.compact(n.volume);t.measureText(e).width<=n.d-6&&(t.fillStyle=`#fff`,t.fillText(e,a,o+.5))}}t.restore()},ze=(t,n,r,i,a)=>{let s=Z.theme,[c,u]=W,d=Math.max(1,O/(u-c)*J.h),f=0,p=[`bid`,`ask`].map(e=>{let t=S.levels(e,{step:O,limit:be()});for(let e=0;e<t.count;e++){let n=t.price[e];n>=c&&n<=u&&(f=Math.max(f,t.size[e]))}return{side:e,...t}});if((f>I||f<I*.6||!(I>0))&&(I=l.fineCeil(f)),!(I>0))return;let m=n+2,h=Math.max(4,r-6);t.strokeStyle=e.toCss(s.text,.07),t.lineWidth=1,t.setLineDash([2,3]),t.beginPath();for(let e of[.5,1]){let n=Math.round(m+h*e)-.5;t.moveTo(n,J.y),t.lineTo(n,J.y+J.h)}t.stroke(),t.setLineDash([]),t.save(),t.beginPath(),t.rect(n,J.y,r,J.h),t.clip();let g=+(d>=4),_=(e,n)=>{let r=Math.round(i(e+O/2)),a=Math.max(r+1,Math.round(i(e-O/2))-g),o=Math.max(1,Math.min(h,n/I*h));t.rect(m,r,o,a-r)};for(let{side:n,price:r,size:i,count:a}of p){let o=n===`bid`?w.up:w.down;t.beginPath();for(let e=1;e<a;e++){let t=r[e];t>=c-O&&t<=u+O&&_(t,i[e])}t.fillStyle=e.toCss(o,D?.62:.55),t.fill();let s=r[0];a&&s!==void 0&&s>=c&&s<=u&&(t.beginPath(),_(s,i[0]),t.fillStyle=e.toCss(o),t.fill())}t.restore();let v=Math.round(J.y+J.h+4)+.5;t.strokeStyle=e.toCss(s.textMuted,.7),t.beginPath(),t.moveTo(m,v),t.lineTo(m+h,v);for(let e of[0,.5,1]){let n=Math.round(m+h*e)+.5;t.moveTo(n,v),t.lineTo(n,v+3)}t.stroke(),t.font=o.fontOf(s,x,400,Math.max(8,a-1)),t.fillStyle=e.toCss(s.textMuted),t.textBaseline=`top`;let y=C.compact(I),ee=t.measureText(y).width;t.textAlign=`right`,t.fillText(y,m+h+2,v+4),ee+t.measureText(`0`).width+8<h&&(t.textAlign=`left`,t.fillText(`0`,m-1,v+4))},Be=()=>{if(!Y||x.tooltip===!1||!(O>0)||X||!fe)return null;let[e,t]=Y;if(e<J.x||e>J.x+J.w||t<J.y||t>J.y+J.h)return null;let[n,r]=U,[i,o]=W,s=n+(e-J.x)/J.w*(r-n),c=i+(J.y+J.h-t)/J.h*(o-i),l=Math.round(c/O),u=+(l*O).toFixed(Math.min(12,a.decimalsOf(O)+2)),d=je(s);return{hx:e,hy:t,time:s,start:d?d.time:Number.isFinite(A)&&s>=A?A:NaN,column:d,bin:l,rowPrice:u}},Ve=(t,n,r,i,a,s,c,l=`left`)=>{let u=Math.min(t.measureText(n).width+10,a),d=l===`center`?r-u/2:r;t.fillStyle=c?e.toCss(s):e.toCss(E),o.roundRect(t,d,i-g/2,u,g,3),t.fill(),c||(t.strokeStyle=e.toCss(s),t.lineWidth=1,t.stroke()),t.fillStyle=c?e.luminance(s)>.6?`#111`:`#fff`:e.toCss(s),t.textAlign=l,t.textBaseline=`middle`,t.fillText(n,l===`center`?r:d+5,i+.5)};function He(t){let r=Z.ctx;if(!r)return!1;let{width:a,height:s,dpr:c,theme:u}=Z,d=pe?t-pe:0;pe=t;let f=_e(),p=x.fontSize??(a<420?10:11),m=o.fontOf(u,x,400,p),h=o.fontOf(u,x,600,p),_=$(),v=!Number.isFinite(M);v&&S.count(`bid`)+S.count(`ask`)>0&&ke(Date.now());let y=xe();q=Number.isFinite(q)&&y>q-_*4?Math.max(q,y):y;let ee=q;r.setTransform(c,0,0,c,0,0),r.clearRect(0,0,a,s),Ee();let b=S.mid();r.font=h;let te=C.price(Number.isFinite(b)?b*1.0001:0),ne=Math.ceil(r.measureText(te).width)+18;r.font=m;let T=x.profile===!1?0:Math.round(o.clamp(a*.12,56,120)),re=p+12;J={x:0,y:0,w:Math.max(10,a-ne-T),h:Math.max(10,s-re)};let j=J.x+J.w,N=j+T;if(Number.isFinite(H)||(H=Math.max(_*10,x.window??6e4)),de){let e=k.length?k[0].time:A;U=l.fitTimeRange(e,ee,H,Math.min(H,_*60));let t=S.bestBid(),n=S.bestAsk();for(let e of Pe())Number.isFinite(e.bestBid)&&!(e.bestBid>=t)&&(t=e.bestBid),Number.isFinite(e.bestAsk)&&!(e.bestAsk<=n)&&(n=e.bestAsk);Number.isFinite(t)||(t=n),Number.isFinite(n)||(n=t);let r=O>0?O*Math.max(40,J.h/6):0,i=x.priceSpan??(Number.isFinite(K)?K:void 0);if(r>0||i!==void 0){G=l.fitPriceRange(G,t,n,r,i);let[e,a]=G;if(Number.isFinite(e)&&Number.isFinite(a)){if(!fe)W=[e,a],fe=!0;else{let t=o.ease(d,280);W=[W[0]+(e-W[0])*t,W[1]+(a-W[1])*t]}}}}let[P,oe]=U,[F,I]=W,L=e=>J.x+(e-P)/(oe-P)*J.w,R=e=>J.y+J.h-(e-F)/(I-F)*J.h,z=fe&&O>0,B=Pe(),se=_/(oe-P)*J.w,ce=e.toCss(E);if(V){let e=V.canvas;e.style.left=`${J.x}px`,e.style.top=`${J.y}px`,e.style.width=`${J.w}px`,e.style.height=`${J.h}px`;let t=Math.max(1,Math.round(J.w*c)),n=Math.max(1,Math.round(J.h*c));(e.width!==t||e.height!==n)&&V.resize(t,n);let r=z&&Number.isFinite(A)?Ne(P,oe,F,I,ee,d):null,i=t/J.w,a=n/J.h,o=r?[(L(r.t0)-J.x)*i,(R(r.p1)-J.y)*a,(L(r.t1)-J.x)*i,(R(r.p0)-J.y)*a]:[0,0,0,0];V.render(r,o,E)}else r.fillStyle=ce,r.fillRect(J.x,J.y,J.w,J.h);let le=z?n.linearTicks(F,I,Math.max(2,Math.floor(J.h/44))):[],ue=i.timeTicks(P,oe,Math.max(2,Math.floor(J.w/75)),void 0,x.timeZone??`local`);r.strokeStyle=e.toCss(u.text,D?.07:.09),r.lineWidth=1,r.beginPath();for(let e of le){let t=Math.round(R(e))+.5;r.moveTo(J.x,t),r.lineTo(N,t)}for(let e of ue.values){let t=Math.round(L(e))+.5;t<=J.x+1||t>=j-1||(r.moveTo(t,J.y),r.lineTo(t,J.y+J.h))}r.stroke(),z&&(Le(r,B,L,R,se),x.bubbles!==!1&&Re(r,Fe(B,se),L,R,p),T&&ze(r,j,T,R,p)),r.strokeStyle=e.toCss(u.axis),r.lineWidth=1,r.beginPath(),r.moveTo(0,Math.round(J.y+J.h)+.5),r.lineTo(a,Math.round(J.y+J.h)+.5),T&&(r.moveTo(Math.round(j)+.5,J.y),r.lineTo(Math.round(j)+.5,J.y+J.h)),r.moveTo(Math.round(N)+.5,J.y),r.lineTo(Math.round(N)+.5,J.y+J.h),r.stroke();let Y=z?Be():null;r.font=m;let me=Y?o.formatClock(Number.isFinite(Y.start)?Y.start:Y.time,_<1e3,x.timeZone):``,X=Y?r.measureText(me).width/2+8:0;r.fillStyle=e.toCss(u.textMuted),r.textAlign=`center`,r.textBaseline=`top`;for(let e of ue.values){let t=L(e),n=ue.format(e),i=r.measureText(n).width/2;t-i<J.x+2||t+i>j-2||Y&&Math.abs(t-Y.hx)<X+i||r.fillText(n,t,J.y+J.h+6)}let Q=ie,he=[{price:S.bestAsk(),color:w.down,filled:!0},{price:S.bestBid(),color:w.up,filled:!0}];Q&&Q.price!==S.bestBid()&&Q.price!==S.bestAsk()&&he.push({price:Q.price,color:Q.side===`buy`?w.up:w.down,filled:!1});let ge=z?he.filter(e=>Number.isFinite(e.price)&&e.price>=F&&e.price<=I):[],ve=Y?Math.round(R(Y.rowPrice))+.5:NaN,ye=l.layoutAxisLabels(ge.map(e=>({y:R(e.price),h:g})),Y?{y:ve,h:g}:null,le.map(R),p+2,[J.y,J.y+J.h]);r.fillStyle=e.toCss(u.textMuted),r.textAlign=`left`,r.textBaseline=`middle`,le.forEach((e,t)=>{ye.ticks[t]&&r.fillText(C.price(e),N+6,R(e))}),r.font=h,ge.forEach((t,n)=>{let i=ye.pinned[n];if(i==null)return;let o=R(t.price);Math.abs(i-o)>1&&(r.strokeStyle=e.toCss(t.color),r.lineWidth=1,r.beginPath(),r.moveTo(N-4,o),r.lineTo(N+1,i),r.stroke()),Ve(r,C.price(t.price),N+1,i,a-N-2,t.color,t.filled)}),Ue(r,L,R,N,f,Y,ve,me),r.font=m,Z.describe(`${x.ariaLabel??f.name}. ${f.bid} ${C.price(S.bestBid())}, ${f.ask} ${C.price(S.bestAsk())}.`);let be=v||Se()-ae<2e3;return de&&be&&Number.isFinite(A)||fe&&G!==null&&Math.abs(W[0]-G[0])>1e-9}function Ue(t,n,r,i,a,c,l,u){let{theme:d}=Z;if(!c){Z.tooltip.style.display=`none`,me&&(me=``,te.emit(`hover`,null));return}let{hx:f,hy:p,time:m,start:h,column:_,bin:v,rowPrice:y}=c,ee=$(),b=0,ne=NaN,T=NaN,E=0,D=0;if(_){for(let e=0;e<_.bins.length;e++)_.bins[e]===v&&(b+=_.sizes[e]);({bestBid:ne,bestAsk:T,buyVolume:E,sellVolume:D}=_)}else if(Number.isFinite(h)){let e=[`bid`,`ask`].map(e=>S.levels(e,{step:O,limit:be()}));for(let t of e)for(let e=0;e<t.count;e++)Math.round(t.price[e]/O)===v&&(b+=t.size[e]);ne=S.bestBid(),T=S.bestAsk(),E=j.buyVolume,D=j.sellVolume}let k=y<=ne?`bid`:y>=T?`ask`:null;if(t.strokeStyle=e.toCss(d.text,.5),t.lineWidth=1,t.setLineDash([3,3]),t.beginPath(),t.moveTo(Math.round(f)+.5,J.y),t.lineTo(Math.round(f)+.5,J.y+J.h),t.moveTo(J.x,l),t.lineTo(i,l),t.stroke(),t.setLineDash([]),Number.isFinite(h)){let i=n(h),a=n(h+ee),o=r(y+O/2),s=r(y-O/2);t.strokeStyle=e.toCss(d.text,.85),t.strokeRect(i,o,Math.max(2,a-i),Math.max(2,s-o))}t.font=o.fontOf(d,x,600,x.fontSize??(Z.width<420?10:11)),Ve(t,C.price(y),i+1,l,Z.width-i-2,d.text,!0),Ve(t,u,o.clamp(f,J.x+40,J.x+J.w-40),J.y+J.h+g/2+2,J.w,d.text,!0,`center`);let re=k===`bid`?w.up:k===`ask`?w.down:null;s.tooltipHtml(he,Z.tooltip,{text:o.formatClock(Number.isFinite(h)?h:m,!0,x.timeZone),color:void 0,badge:k&&re?{text:k===`bid`?a.bidSide:a.askSide,color:e.toCss(re)}:void 0},[[a.price,C.price(y)],[a.liquidity,C.size(b)],[a.buys,C.size(E)],[a.sells,C.size(D)]]),Z.tooltip.style.display=`block`,Z.placeTooltip(Z.tooltip,f,p,f>J.w*.6?`left`:`right`);let A=`${h}|${v}|${b}|${E}|${D}`;if(A!==me){me=A;let e={time:Number.isFinite(h)?h:m,price:y,size:b,side:k,buyVolume:E,sellVolume:D};te.emit(`hover`,e)}}let We=async(e=new Set)=>{let t=++se,n=await c.createHeatFieldRenderer(x.renderer??`auto`,()=>{let e=he.createElement(`canvas`);return Object.assign(e.style,{position:`absolute`,left:`0`,top:`0`,pointerEvents:`none`}),e.setAttribute(`aria-hidden`,`true`),e},t=>{ce||V?.kind!==t||(V.destroy(),V.canvas.remove(),V=null,We(new Set([...e,t])))},e);if(ce||t!==se){n?.destroy();return}V&&(V.destroy(),V.canvas.remove()),V=n,n?(Q.dataset.renderer=n.kind,Q.insertBefore(n.canvas,Z.canvas),te.emit(`renderer`,n.kind)):delete Q.dataset.renderer,le(n?.kind??null),Z.invalidate()},Ge=r.followDefaultRenderer(()=>x.renderer,()=>void We()),Ke=e=>{de!==e&&(de=e,te.emit(`follow`,e))},qe=e=>{let t=k.length?k[0].time:A;if(!Number.isFinite(t))return e;let n=e[1]-e[0],r=(Number.isFinite(q)?q:xe())+$()+n/2,i=Math.max(t-n/2,Math.min(e[0],r-n));return[i,i+n]},Je=e=>{if(x.interactive===!1)return;let[t,n]=s.localPoint(Q,e);Q.setPointerCapture?.(e.pointerId),X={x:t,y:n,viewX:[...U],viewY:[...W],axis:t>J.x+J.w,span:W[1]-W[0]}},Ye=e=>{let[t,n]=s.localPoint(Q,e);if(Y=[t,n],X){let e=t-X.x,r=n-X.y;if(X.axis){let e=X.span*Math.exp(r*.006),t=(X.viewY[0]+X.viewY[1])/2;K=e,W=[t-e/2,t+e/2],G=[W[0],W[1]]}else if(Math.abs(e)+Math.abs(r)>3){Ke(!1);let t=(X.viewX[1]-X.viewX[0])/J.w*e,n=(X.viewY[1]-X.viewY[0])/J.h*r;U=qe([X.viewX[0]-t,X.viewX[1]-t]),W=[X.viewY[0]+n,X.viewY[1]+n]}}Z.invalidate()},Xe=e=>{Q.releasePointerCapture?.(e.pointerId),X=null,Z.invalidate()},Ze=()=>{X||(Y=null,Z.invalidate())},Qe=(e,t)=>{let[n,r]=U,i=o.clamp((de?H:r-n)*e,$()*10,ye());if(H=i,!de){let e=n+(t-J.x)/J.w*(r-n),a=(e-n)/(r-n);U=qe([e-i*a,e+i*(1-a)])}Z.invalidate()},$e=e=>{let t=o.clamp((W[1]-W[0])*e,O*6||1e-9,1/0),n=(W[0]+W[1])/2;K=t,W=[n-t/2,n+t/2],G=[W[0],W[1]],Z.invalidate()},et=e=>{if(x.interactive===!1||!(e.ctrlKey||e.metaKey))return;e.preventDefault();let[t]=s.localPoint(Q,e),n=Math.exp(e.deltaY*.002);e.shiftKey||t>J.x+J.w?$e(n):Qe(n,t)},tt=()=>{x.interactive!==!1&&it.resetView()},nt=e=>{if(x.interactive!==!1){switch(e.key){case`+`:case`=`:Qe(.8,J.x+J.w);break;case`-`:Qe(1.25,J.x+J.w);break;case`ArrowUp`:case`ArrowDown`:{if(e.shiftKey){$e(e.key===`ArrowUp`?.8:1.25);break}Ke(!1);let t=(W[1]-W[0])*.1*(e.key===`ArrowUp`?1:-1);W=[W[0]+t,W[1]+t],Z.invalidate();break}case`ArrowLeft`:case`ArrowRight`:{Ke(!1);let t=(U[1]-U[0])*.1*(e.key===`ArrowLeft`?-1:1);U=qe([U[0]+t,U[1]+t]),Z.invalidate();break}case`0`:case`Home`:it.resetView();break;default:return}e.preventDefault()}};Q.addEventListener(`pointerdown`,Je),Q.addEventListener(`pointermove`,Ye),Q.addEventListener(`pointerup`,Xe),Q.addEventListener(`pointercancel`,Xe),Q.addEventListener(`pointerleave`,Ze),Q.addEventListener(`wheel`,et,{passive:!1}),Q.addEventListener(`dblclick`,tt),Q.addEventListener(`keydown`,nt);let rt=e=>{let t=Ae(e.time);S.count(`bid`)+S.count(`ask`)>0&&(Ee(),ke(t)),S.applyDelta(e)},it={setBook(e){let t=Ae(e.time);S.count(`bid`)+S.count(`ask`)>0&&ke(t),S.setSnapshot(e),Ee(),we(),Number.isFinite(A)||ke(t),Z.invalidate()},applyDeltas(e){if(Array.isArray(e))for(let t of e)rt(t);else rt(e);!Number.isFinite(A)&&O>0&&ke(xe()),Z.invalidate()},addTrades(e){let t=Array.isArray(e)?e:[e];for(let e of t){if(!(e.size>0)||!Number.isFinite(e.price))continue;Number.isFinite(M)&&(Ae(e.time),ke(e.time));let t=!Number.isFinite(A)||e.time>=A?j:je(e.time);t&&(e.side===`buy`?(t.buyVolume+=e.size,t.buyNotional+=e.size*e.price):(t.sellVolume+=e.size,t.sellNotional+=e.size*e.price)),(!ie||e.time>=ie.time)&&(ie=e)}Z.invalidate()},clear(){S.clear(),Te(),ie=null,M=NaN,O=0,K=NaN,G=null,fe=!1,Z.invalidate()},setOptions(e){let t=x;x=e,ve(),(e.tickSize!==t.tickSize||(e.interval??100)!==(t.interval??100))&&(Te(),O=0,K=NaN,Ee()),e.window!==t.window&&(H=NaN),e.priceSpan!==t.priceSpan&&(K=NaN),(e.renderer??`auto`)!==(t.renderer??`auto`)&&We(),Ce(),we(),Z.invalidate()},resetView(){H=NaN,K=NaN,G=null,Ke(!0),Z.invalidate()},getRenderer:()=>V?.kind??null,ready:ue,getStore:()=>S,on:(e,t)=>te.on(e,t),resize(){Z.invalidate()},destroy(){ce=!0,Ge(),Q.removeEventListener(`pointerdown`,Je),Q.removeEventListener(`pointermove`,Ye),Q.removeEventListener(`pointerup`,Xe),Q.removeEventListener(`pointercancel`,Xe),Q.removeEventListener(`pointerleave`,Ze),Q.removeEventListener(`wheel`,et),Q.removeEventListener(`dblclick`,tt),Q.removeEventListener(`keydown`,nt),V?.destroy(),V=null,te.clear(),Z.destroy(),le(null)}};return ve(),Ce(),We(),it};exports.createOrderBookHeatmap=ee,exports.heatIntensity=y;
1
+ const e=require("../color.cjs"),t=require("../locale.cjs"),n=require("../scale.cjs"),r=require("../renderers/follow.cjs"),i=require("../time.cjs"),a=require("./book.cjs"),o=require("./format.cjs"),s=require("./host.cjs"),c=require("./field.cjs"),l=require("./layout.cjs");var u=256,d=4096,f=.99,p=2,m=[[0,`#0b1322`],[.3,`#0d1a2e`],[.5,`#102a4e`],[.65,`#154a8a`],[.76,`#1b86b8`],[.85,`#3fc3c0`],[.91,`#e8d84a`],[.96,`#ff8c2b`],[1,`#ffe6c2`]],h=[[0,`#fbfcfe`],[.3,`#f3f6fc`],[.5,`#dde7f7`],[.65,`#a8c4ec`],[.76,`#5b8bd6`],[.85,`#2f4fb0`],[.93,`#6a2a9c`],[1,`#c4173f`]],g=16,_=6,v=14,y=3,b=(t,n=u)=>{let r=new Uint32Array(n);if(!t.length)return r;let i=t.map(([,t])=>e.toOklab(t)),a=0;for(let o=0;o<n;o++){let s=o/Math.max(1,n-1);for(;a+1<t.length-1&&s>t[a+1][0];)a++;let[c]=t[a],l=Math.min(t.length-1,a+1),[u]=t[l],d=u>c?Math.min(1,Math.max(0,(s-c)/(u-c))):0,f=i[a],p=i[l];r[o]=e.packColor(e.fromOklab([f[0]+(p[0]-f[0])*d,f[1]+(p[1]-f[1])*d,f[2]+(p[2]-f[2])*d,1]))}return r},x=e=>{if(!(e>0)||e>=p)return 1;let t=p/e;for(let e=1;e<0xe8d4a51000;e*=10)for(let n of[1,2,5])if(n*e>=t)return n*e;return 1},S={en:{time:`Time`,price:`Price`,liquidity:`Liquidity`,buys:`Buys`,sells:`Sells`,bid:`Bid`,ask:`Ask`,bidSide:`Bid side`,askSide:`Ask side`,bubbleHint:`Bubble area = trade size`,name:`Liquidity heatmap`},zh:{time:`时间`,price:`价格`,liquidity:`挂单量`,buys:`主动买入`,sells:`主动卖出`,bid:`买一`,ask:`卖一`,bidSide:`买盘`,askSide:`卖盘`,bubbleHint:`气泡面积 = 成交量`,name:`订单簿热力图`},ja:{time:`時刻`,price:`価格`,liquidity:`指値量`,buys:`買い約定`,sells:`売り約定`,bid:`最良買気配`,ask:`最良売気配`,bidSide:`買い板`,askSide:`売り板`,bubbleHint:`バブル面積 = 出来高`,name:`板ヒートマップ`},fr:{time:`Heure`,price:`Prix`,liquidity:`Liquidité`,buys:`Achats`,sells:`Ventes`,bid:`Meilleur achat`,ask:`Meilleure vente`,bidSide:`Côté achat`,askSide:`Côté vente`,bubbleHint:`Aire de la bulle = volume`,name:`Carte de chaleur de la liquidité`}},C=(e,t,n,r)=>{if(!(e>0)||!(t>0))return 0;let i=Math.min(1,e*r/t);switch(n){case`linear`:return i;case`log`:return Math.log10(1+9*i)**1.2;default:return Math.sqrt(i)}},ee=48,w=(e,t)=>{if(!(t>=e.min)||!(e.max>e.min))return 0;let n=Math.log(t/e.min)/Math.log(e.max/e.min),r=Math.min(47.999999,Math.max(0,n*ee)),i=Math.floor(r),a=r-i,o=e.cdf[i]??0;return o+((e.cdf[i+1]??o)-o)*a},T=(e,t=0)=>{let n=1/0,r=0,i=0;for(let t=0;t<e.length;t++){let a=e[t];a>0&&(i++,a<n&&(n=a),a>r&&(r=a))}if(!i||!(r>n))return null;let a=new Float32Array(49),o=Math.log(r/n);for(let t=0;t<e.length;t++){let r=e[t];if(!(r>0))continue;let i=Math.log(r/n)/o;a[Math.min(ee,Math.floor(i*ee))]+=1}let s=0;for(let e=0;e<=ee;e++)s+=a[e],a[e]=s/i;return{version:t,min:n,max:r,cdf:a}},te=(e,t,n)=>r=>{let i=Math.min(1,Math.max(0,n(r)));if(!e||!(t>0))return i;let a=w(e,r*t);return Math.min(1,.55*i+.45*a)},E=(p,ee={})=>{let w=ee,E=a.createOrderBookStore(),D=s.createEmitter(),O=o.createFormatters(w,2,4),k={up:[0,0,0,1],down:[0,0,0,1]},A=new Uint32Array(u),j=new Uint32Array(c.HEAT_TABLE_SIZE+1),M=e=>Math.sqrt(e),N=null,P=[0,0,0,1],F=!1,I=0,L=[],ne=0,R=NaN,z={buyVolume:0,buyNotional:0,sellVolume:0,sellNotional:0},re=null,ie=NaN,ae=0,B=0,V=0,oe=-1/0,se=0,H=0,U=null,ce=``,W=``,G=null,K=null,le=0,ue=!1,de=()=>{},fe=new Promise(e=>{de=e}),pe=!0,me=NaN,q=[0,1],J=[0,1],he=!1,ge=null,_e=NaN,ve=NaN,ye=0,Y={x:0,y:0,w:0,h:0},be=null,xe=``,X=null,Z=s.createHost(p,{className:`minerva-orderbook-heatmap`,draw:$e,onTheme:()=>{Ae(),Z.invalidate()}}),{root:Q,doc:Se}=Z;Q.tabIndex=0,Q.setAttribute(`role`,`figure`),Q.style.touchAction=`none`;let Ce=t.localeLabels(S,w.locale,w.labels),we=()=>Ce,Te=()=>{Ce=t.localeLabels(S,w.locale,w.labels),Q.setAttribute(`aria-label`,w.ariaLabel??Ce.name)},$=()=>Math.max(10,w.interval??100),Ee=()=>Math.max($()*4,w.history??3e5),De=()=>Math.max(4,Math.round(w.depth??160)),Oe=()=>{if(!Number.isFinite(ie))return Date.now();let e=ke()-ae;return ie+Math.min(Math.max(0,e),$()*3)},ke=()=>typeof performance<`u`?performance.now():Date.now();function Ae(){let t=Z.theme;k=o.sideColors(t,w);let n=e=>{let n=t.resolve?t.resolve(e,t.primary):t.primary;return[n[0],n[1],n[2],1]},r=[t.background[0],t.background[1],t.background[2],1];if(F=t.background[3]>0&&e.luminance(r)<.4,w.colors?.length){let t=w.colors.map(n);P=t[0]??r,A=e.oklabRamp(t.length>1?t:[P,P],u)}else{let t=(F?m:h).map(([t,n])=>[t,e.parseColor(n)??r]);P=t[0][1],A=b(t,u)}let i=w.colorScale??`sqrt`;M=e=>C(e,1,i,1),j=c.heatTable(A,M),W=``}let je=()=>{O=o.createFormatters(w,I>0?Math.max(a.decimalsOf(I),a.inferPriceDecimals(E)):a.inferPriceDecimals(E),a.inferSizeDecimals(E))},Me=e=>{let t=w.sizeUnit?.trim();return t?`${e} ${t}`:e},Ne=()=>{L=[],U=null,ce=W=``,G=null,N=null,R=NaN,B=V=0,oe=-1/0,se=0,H=0,ve=NaN,z.buyVolume=z.buyNotional=z.sellVolume=z.sellNotional=0},Pe=()=>{if(I>0)return;let e=a.inferTickSize(E),t=E.mid();if(w.tickSize&&w.tickSize>0)I=w.tickSize;else if(e>0&&Number.isFinite(t)){let n=t*1e-5/e,r=1;for(let e=1;e<=1e9&&r<n*.75;e*=10)for(let t of[1,2,5])if(r=t*e,r>=n*.75)break;I=a.roundToStep(e*r,e)}else I=Number.isFinite(t)?Math.max(1e-8,t*1e-5):0;I>0&&je()},Fe=()=>{let e=De(),t=new Float64Array(e*2),n=new Float32Array(e*2),r=0;for(let i of[`bid`,`ask`]){let a=E.count(i),o=0;for(let s=0;s<a;s++){let a=Math.round(E.priceAt(i,s)/I),c=E.sizeAt(i,s);if(r>0&&t[r-1]===a&&o>0){n[r-1]+=c;continue}if(o>=e)break;t[r]=a,n[r]=c,r++,o++}}return{bins:t.slice(0,r),sizes:n.slice(0,r)}},Ie=e=>{if(!(I>0))return;let{bins:t,sizes:n}=Fe(),r={seq:ne++,time:e,bins:t,sizes:n,bestBid:E.bestBid(),bestAsk:E.bestAsk(),buyVolume:z.buyVolume,buyNotional:z.buyNotional,sellVolume:z.sellVolume,sellNotional:z.sellNotional};z.buyVolume=z.buyNotional=z.sellVolume=z.sellNotional=0,L.push(r);let i=e-Ee(),a=0;for(;a<L.length&&L[a].time<i;)a++;a&&(L=L.slice(a))},Le=e=>{if(!Number.isFinite(e))return;let t=$();if(!Number.isFinite(R)){R=Math.floor(e/t)*t;return}if(e-R>Ee()){Ie(R),R=Math.floor(e/t)*t;return}for(;e>=R+t;)Ie(R),R+=t},Re=e=>e===void 0||!Number.isFinite(e)?Date.now():((!Number.isFinite(ie)||e>=ie)&&(ie=e,ae=ke()),e),ze=e=>{if(Number.isFinite(R)&&e>=R)return null;let t=0,n=L.length;for(;t<n;){let r=t+n>>>1;L[r].time<=e?t=r+1:n=r}return t>0?L[t-1]:null},Be=()=>{if(!Number.isFinite(R)||!(I>0))return null;let e=E.version();return(!G||G.version!==e)&&(G={version:e,...Fe()}),{time:R,bins:G.bins,sizes:G.sizes}},Ve=(e,t,n,r,i,a)=>{let s=$(),l=Be(),u=Math.min(d,Math.ceil(Y.w)),p=Math.min(d,Math.ceil(Y.h)),m=x(I/(r-n)*Y.h),h=L.length?L[L.length-1].seq:-1,g=[e,t,n,r,Math.floor(i/s),L.length,h,G?.version??-1,u,p,m,I].join(`|`);if(g!==ce){let a=l?[...L,l]:L;U=c.buildHeatGrid({sources:a,step:s,tick:I,x0:e,x1:t,y0:n,y1:r,end:i,maxWidth:u,maxHeight:p,rowBins:m},U),ce=g,W=``}if(!U)return null;let _=w.maxSize;if(_!==void 0&&_>0)B=_;else{let e=ke();if(e-oe>250||!(V>0)){let t=c.percentile(U.cells,f);t>0&&(V=t),oe=e,N=T(U.cells,U.version)}B>0?V>0&&Math.abs(V/B-1)>.001&&(B+=(V-B)*o.ease(a,700)):B=V}let v=Math.max(.01,w.contrast??1),y=B>0?c.HEAT_TABLE_SIZE*v/B:0,b=`${U.version}|${y}|${N?.version??-1}`;return b!==W&&(j=c.heatTable(A,te(N,B/v,M)),c.paintHeatGrid(U,j,y),W=b),U},He=()=>{let e=$(),t=[],n=0,r=L.length;for(;n<r;){let t=n+r>>>1;L[t].time+e<q[0]?n=t+1:r=t}for(let e=n;e<L.length;e++){let n=L[e];if(n.time>q[1])break;t.push(n)}return t},Ue=(e,t)=>{let n=$(),r=Math.max(1,Math.ceil(_/Math.max(1e-6,t))),i=[],a=NaN,o=0,s=0,c={bv:0,bn:0,sv:0,sn:0},l=()=>{let e=(o+s)/2;c.sv>0&&i.push({time:e,price:c.sn/c.sv,volume:c.sv,buy:!1}),c.bv>0&&i.push({time:e,price:c.bn/c.bv,volume:c.bv,buy:!0}),c.bv=c.bn=c.sv=c.sn=0},u=(e,t,i)=>{let u=Math.floor(e/r);u!==a&&(Number.isFinite(a)&&l(),a=u,o=t),s=t+n,c.bv+=i.buyVolume,c.bn+=i.buyNotional,c.sv+=i.sellVolume,c.sn+=i.sellNotional};for(let t of e)u(t.seq,t.time,t);return Number.isFinite(R)&&R<=q[1]&&u(ne,R,z),Number.isFinite(a)&&l(),i},We=e=>{e.save(),e.beginPath(),e.rect(Y.x,Y.y,Y.w,Y.h),e.clip()},Ge=(t,n,r,i,a)=>{if(w.bestLines===!1)return;let o=$(),s=n.map(e=>[e.time,e.time+o,e.bestBid,e.bestAsk]);if(Number.isFinite(R)&&s.push([R,R+o,E.bestBid(),E.bestAsk()]),!s.length)return;for(let e=0;e+1<s.length;e++)s[e][1]=s[e+1][0];let c=a>=2,l=e=>{let t=r(e[0]),n=r(e[1]);return c?[t,n]:[(t+n)/2,(t+n)/2]};We(t),t.beginPath();let u=[],d=()=>{if(u.length){u.forEach((e,n)=>{let[r,a]=l(e),o=i(e[3]);n?t.lineTo(r,o):t.moveTo(r,o),t.lineTo(a,o)});for(let e=u.length-1;e>=0;e--){let[n,r]=l(u[e]),a=i(u[e][2]);t.lineTo(r,a),t.lineTo(n,a)}t.closePath(),u=[]}};for(let e of s){let[,,t,n]=e;Number.isFinite(t)&&Number.isFinite(n)&&n>t?u.push(e):d()}d(),t.fillStyle=e.toCss(Z.theme.text,F?.08:.07),t.fill(),t.lineJoin=`round`;for(let[n,r]of[[2,k.up],[3,k.down]]){t.beginPath();let a=!1;for(let e of s){let r=e[n];if(!Number.isFinite(r)){a=!1;continue}let o=i(r),[s,u]=l(e);a?t.lineTo(s,o):t.moveTo(s,o),c&&t.lineTo(u,o),a=!0}t.strokeStyle=e.toCss(P,.55),t.lineWidth=3.5,t.stroke(),t.strokeStyle=e.toCss(r),t.lineWidth=1.5,t.stroke()}t.restore()},Ke=(t,n,r,i,a)=>{if(!n.length)return;let s=0;for(let e of n){let t=r(e.time);t>=Y.x&&t<=Y.x+Y.w&&(s=Math.max(s,e.volume))}s>0&&(se=se>0?Math.max(s,se*.995):s);let c=w.bubbleVolume??se;if(!(c>0))return;let l=Math.max(y,w.bubbleSize??v),u=Math.min(y,l),d=n.map(e=>({...e,d:o.clamp(Math.sqrt(e.volume/c)*l,u,l)})).sort((e,t)=>e.d-t.d);We(t),t.lineWidth=1,t.textAlign=`center`,t.textBaseline=`middle`,t.font=o.fontOf(Z.theme,w,600,Math.max(8,a-1));let f=F?[1,1,1,1]:[0,0,0,1];for(let n of d){let a=r(n.time),o=i(n.price),s=n.d/2;if(a<Y.x-s||a>Y.x+Y.w+s||o<Y.y-s||o>Y.y+Y.h+s)continue;let c=n.buy?k.up:k.down;if(t.beginPath(),t.arc(a,o,Math.max(1,s-.5),0,Math.PI*2),t.fillStyle=e.toCss(c,.35),t.fill(),t.strokeStyle=e.toCss(e.mixOklab(c,f,.2),.9),t.stroke(),n.d>=26){let r=O.compact(n.volume);t.measureText(r).width<=n.d-6&&(t.fillStyle=e.toCss(F?[1,1,1,1]:[.08,.08,.1,1]),t.fillText(r,a,o+.5))}}t.restore()},qe=(e,t)=>{let n=[],r=[],i=E.count(e),a=0,o=NaN;for(let s=0;s<i;s++){let i=Math.round(E.priceAt(e,s)/I);if(i!==o){if(++a>De())break;o=i}let c=Math.floor(i/t),l=E.sizeAt(e,s);n.length&&n[n.length-1]===c?r[r.length-1]+=l:(n.push(c),r.push(l))}return{side:e,buckets:n,sizes:r}},Je=(t,n,r,i,a,s)=>{let c=Z.theme,[u,d]=J,f=Math.max(1,I*s/(d-u)*Y.h),p=e=>(e*s-.5)*I,m=e=>(e*s+s-.5)*I,h=0,g=[`bid`,`ask`].map(e=>{let t=qe(e,s);return t.buckets.forEach((e,n)=>{m(e)>=u&&p(e)<=d&&(h=Math.max(h,t.sizes[n]))}),t});if((h>H||h<H*.6||!(H>0))&&(H=l.fineCeil(h)),!(H>0))return;let _=n+2,v=Math.max(4,r-6);t.strokeStyle=e.toCss(c.text,.07),t.lineWidth=1,t.setLineDash([2,3]),t.beginPath();for(let e of[.5,1]){let n=Math.round(_+v*e)-.5;t.moveTo(n,Y.y),t.lineTo(n,Y.y+Y.h)}t.stroke(),t.setLineDash([]),t.save(),t.beginPath(),t.rect(n,Y.y,r,Y.h),t.clip();let y=+(f>=4),b=(e,n)=>{let r=Math.round(i(m(e))),a=Math.max(r+1,Math.round(i(p(e)))-y),o=Math.max(1,Math.min(v,n/H*v));t.rect(_,r,o,a-r)};for(let{side:n,buckets:r,sizes:i}of g){let a=n===`bid`?k.up:k.down;t.beginPath();for(let e=1;e<r.length;e++){let t=r[e];m(t)>=u&&p(t)<=d&&b(t,i[e])}t.fillStyle=e.toCss(a,F?.62:.55),t.fill();let o=r[0];o!==void 0&&m(o)>=u&&p(o)<=d&&(t.beginPath(),b(o,i[0]),t.fillStyle=e.toCss(a),t.fill())}t.restore();let x=Math.round(Y.y+Y.h+4)+.5;t.strokeStyle=e.toCss(c.textMuted,.7),t.beginPath(),t.moveTo(_,x),t.lineTo(_+v,x);for(let e of[0,.5,1]){let n=Math.round(_+v*e)+.5;t.moveTo(n,x),t.lineTo(n,x+3)}t.stroke(),t.font=o.fontOf(c,w,400,Math.max(8,a-1)),t.fillStyle=e.toCss(c.textMuted),t.textBaseline=`top`;let S=O.compact(H),C=t.measureText(S).width;t.textAlign=`right`,t.fillText(S,_+v+2,x+4),C+t.measureText(`0`).width+8<v&&(t.textAlign=`left`,t.fillText(`0`,_-1,x+4))},Ye=e=>{if(!be||w.tooltip===!1||!(I>0)||X||!he)return null;let[t,n]=be;if(t<Y.x||t>Y.x+Y.w||n<Y.y||n>Y.y+Y.h)return null;let[r,i]=q,[o,s]=J,c=r+(t-Y.x)/Y.w*(i-r),l=o+(Y.y+Y.h-n)/Y.h*(s-o),u=Math.floor(Math.round(l/I)/e),d=Math.min(12,a.decimalsOf(I)+2),f=+(u*e*I).toFixed(d),p=+((u*e+e-1)*I).toFixed(d),m=+((f+p)/2).toFixed(d),h=ze(c);return{hx:t,hy:n,time:c,start:h?h.time:Number.isFinite(R)&&c>=R?R:NaN,column:h,bucket:u,ry:e,low:f,high:p,rowPrice:m}},Xe=(t,n,r,i,a,s,c,l=`left`)=>{let u=Math.min(t.measureText(n).width+10,a),d=l===`center`?r-u/2:r;t.fillStyle=c?e.toCss(s):e.toCss(P),o.roundRect(t,d,i-g/2,u,g,3),t.fill(),c||(t.strokeStyle=e.toCss(s),t.lineWidth=1,t.stroke()),t.fillStyle=c?e.luminance(s)>.6?`#111`:`#fff`:e.toCss(s),t.textAlign=l,t.textBaseline=`middle`,t.fillText(n,l===`center`?r:d+5,i+.5)},Ze=e=>`rgb(${e&255}, ${e>>>8&255}, ${e>>>16&255})`,Qe=(t,n)=>{if(Y.w<200||Y.h<96)return;let r=Z.theme,i=we(),a=w.sizeUnit?.trim(),s=a?`${i.liquidity} · ${a}`:i.liquidity,c=o.fontOf(r,w,600,n-1),l=o.fontOf(r,w,400,n-1),u=n-2,d=B>0?O.size(B):`–`;t.font=c;let f=t.measureText(s).width;t.font=o.fontOf(r,w,400,u);let p=t.measureText(`0`).width,m=t.measureText(d).width;t.font=l;let h=t.measureText(i.bubbleHint).width,g=u+10,_=Math.max(76,f,h+g)+14,v=n-1,y=14+v+3+7+2+u+6+v,b=Y.x+8,x=Y.y+8;if(b+_>Y.x+Y.w-8)return;t.fillStyle=e.toCss(r.background,F?.82:.88),t.strokeStyle=e.toCss(r.axis,.6),t.lineWidth=1,o.roundRect(t,b+.5,x+.5,_,y,6),t.fill(),t.stroke();let S=b+7;t.textAlign=`left`,t.textBaseline=`middle`,t.font=c,t.fillStyle=e.toCss(r.textMuted),t.fillText(s,S,x+7+v/2);let C=x+7+v+3,ee=t.createLinearGradient(S,C,S+76,C);for(let e=0;e<=8;e++){let t=e/8,n=A[Math.round(t*(A.length-1))]??0;ee.addColorStop(t,Ze(n))}t.fillStyle=ee,o.roundRect(t,S,C,76,7,2),t.fill(),t.font=o.fontOf(r,w,400,u),t.fillStyle=e.toCss(r.textMuted);let T=C+7+2+u/2;t.fillText(`0`,S,T),t.textAlign=`right`,t.fillText(d,S+Math.max(76,m+p),T),t.textAlign=`left`;let te=T+u/2+6+v/2,E=u/2;for(let[n,r]of[k.up,k.down].entries())t.fillStyle=e.toCss(r,.9),t.beginPath(),t.arc(S+E+n*(u+4),te,E,0,Math.PI*2),t.fill();t.font=l,t.fillStyle=e.toCss(r.textMuted),t.fillText(i.bubbleHint,S+g,te)};function $e(t){let r=Z.ctx;if(!r)return!1;let{width:a,height:s,dpr:c,theme:u}=Z,d=ye?t-ye:0;ye=t;let f=we(),p=w.fontSize??(a<420?10:11),m=o.fontOf(u,w,400,p),h=o.fontOf(u,w,600,p),_=$(),v=!Number.isFinite(ie);v&&E.count(`bid`)+E.count(`ask`)>0&&Le(Date.now());let y=Oe();ve=Number.isFinite(ve)&&y>ve-_*4?Math.max(ve,y):y;let b=ve;r.setTransform(c,0,0,c,0,0),r.clearRect(0,0,a,s),Pe();let S=E.mid();r.font=h;let C=O.price(Number.isFinite(S)?S*1.0001:0),ee=Math.ceil(r.measureText(C).width)+18;r.font=m;let T=w.profile===!1?0:Math.round(o.clamp(a*.12,56,120)),te=p+12;Y={x:0,y:0,w:Math.max(10,a-ee-T),h:Math.max(10,s-te)};let D=Y.x+Y.w,A=D+T;if(Number.isFinite(me)||(me=Math.max(_*10,w.window??6e4)),pe){let e=L.length?L[0].time:R;q=l.fitTimeRange(e,b,me,Math.min(me,_*60));let t=E.bestBid(),n=E.bestAsk();for(let e of He())Number.isFinite(e.bestBid)&&!(e.bestBid>=t)&&(t=e.bestBid),Number.isFinite(e.bestAsk)&&!(e.bestAsk<=n)&&(n=e.bestAsk);Number.isFinite(t)||(t=n),Number.isFinite(n)||(n=t);let r=I>0?I*Math.max(40,Y.h/6):0,i=w.priceSpan??(Number.isFinite(_e)?_e:void 0);if(r>0||i!==void 0){ge=l.fitPriceRange(ge,t,n,r,i);let[e,a]=ge;if(Number.isFinite(e)&&Number.isFinite(a)){if(!he)J=[e,a],he=!0;else{let t=o.ease(d,280);J=[J[0]+(e-J[0])*t,J[1]+(a-J[1])*t]}}}}let[j,M]=q,[N,F]=J,ne=e=>Y.x+(e-j)/(M-j)*Y.w,z=e=>Y.y+Y.h-(e-N)/(F-N)*Y.h,B=he&&I>0,V=He(),oe=_/(M-j)*Y.w,se=B?x(I/(F-N)*Y.h):1,H=e.toCss(P);if(K){let e=K.canvas;e.style.left=`${Y.x}px`,e.style.top=`${Y.y}px`,e.style.width=`${Y.w}px`,e.style.height=`${Y.h}px`;let t=Math.max(1,Math.round(Y.w*c)),n=Math.max(1,Math.round(Y.h*c));(e.width!==t||e.height!==n)&&K.resize(t,n);let r=B&&Number.isFinite(R)?Ve(j,M,N,F,b,d):null;r&&(se=r.rowBins);let i=t/Y.w,a=n/Y.h,o=r?[(ne(r.t0)-Y.x)*i,(z(r.p1)-Y.y)*a,(ne(r.t1)-Y.x)*i,(z(r.p0)-Y.y)*a]:[0,0,0,0];K.render(r,o,P)}else r.fillStyle=H,r.fillRect(Y.x,Y.y,Y.w,Y.h);let U=B?n.linearTicks(N,F,Math.max(2,Math.floor(Y.h/44))):[],ce=i.timeTicks(j,M,Math.max(2,Math.floor(Y.w/75)),void 0,w.timeZone??`local`);r.strokeStyle=e.toCss(u.axis),r.lineWidth=1,r.beginPath();for(let e of U){let t=Math.round(z(e))+.5;r.moveTo(A,t),r.lineTo(A+4,t)}for(let e of ce.values){let t=Math.round(ne(e))+.5;t<=Y.x+1||t>=D-1||(r.moveTo(t,Y.y+Y.h),r.lineTo(t,Y.y+Y.h+4))}r.stroke(),B&&(w.bubbles!==!1&&Ke(r,Ue(V,oe),ne,z,p),Ge(r,V,ne,z,oe),T&&Je(r,D,T,z,p,se)),r.strokeStyle=e.toCss(u.axis),r.lineWidth=1,r.beginPath(),r.moveTo(0,Math.round(Y.y+Y.h)+.5),r.lineTo(a,Math.round(Y.y+Y.h)+.5),T&&(r.moveTo(Math.round(D)+.5,Y.y),r.lineTo(Math.round(D)+.5,Y.y+Y.h)),r.moveTo(Math.round(A)+.5,Y.y),r.lineTo(Math.round(A)+.5,Y.y+Y.h),r.stroke(),w.legend!==!1&&Qe(r,p);let W=B?Ye(se):null;r.font=m;let G=W?o.formatClock(Number.isFinite(W.start)?W.start:W.time,_<1e3,w.timeZone):``,le=W?r.measureText(G).width/2+8:0;r.fillStyle=e.toCss(u.textMuted),r.textAlign=`center`,r.textBaseline=`top`;for(let e of ce.values){let t=ne(e),n=ce.format(e),i=r.measureText(n).width/2;t-i<Y.x+2||t+i>D-2||W&&Math.abs(t-W.hx)<le+i||r.fillText(n,t,Y.y+Y.h+6)}let ue=re,de=[{price:E.bestAsk(),color:k.down,filled:!0},{price:E.bestBid(),color:k.up,filled:!0}];ue&&ue.price!==E.bestBid()&&ue.price!==E.bestAsk()&&de.push({price:ue.price,color:ue.side===`buy`?k.up:k.down,filled:!1});let fe=B?de.filter(e=>Number.isFinite(e.price)&&e.price>=N&&e.price<=F):[],be=W?Math.round(z(W.rowPrice))+.5:NaN,xe=l.layoutAxisLabels(fe.map(e=>({y:z(e.price),h:g})),W?{y:be,h:g}:null,U.map(z),p+2,[Y.y,Y.y+Y.h]);r.fillStyle=e.toCss(u.textMuted),r.textAlign=`left`,r.textBaseline=`middle`,U.forEach((e,t)=>{xe.ticks[t]&&r.fillText(O.price(e),A+6,z(e))}),r.font=h,fe.forEach((t,n)=>{let i=xe.pinned[n];if(i==null)return;let o=z(t.price);Math.abs(i-o)>1&&(r.strokeStyle=e.toCss(t.color),r.lineWidth=1,r.beginPath(),r.moveTo(A-4,o),r.lineTo(A+1,i),r.stroke()),Xe(r,O.price(t.price),A+1,i,a-A-2,t.color,t.filled)}),et(r,ne,z,A,f,W,be,G),r.font=m,Z.describe(`${w.ariaLabel??f.name}. ${f.bid} ${O.price(E.bestBid())}, ${f.ask} ${O.price(E.bestAsk())}.`);let X=v||ke()-ae<2e3;return pe&&X&&Number.isFinite(R)||he&&ge!==null&&Math.abs(J[0]-ge[0])>1e-9}function et(t,n,r,i,a,c,l,u){let{theme:d}=Z;if(!c){Z.tooltip.style.display=`none`,xe&&(xe=``,D.emit(`hover`,null));return}let{hx:f,hy:p,time:m,start:h,column:_,bucket:v,ry:y,low:b,high:x,rowPrice:S}=c,C=e=>Math.floor(e/y)===v,ee=$(),T=0,te=NaN,A=NaN,j=0,M=0;if(_){for(let e=0;e<_.bins.length;e++)C(_.bins[e])&&(T+=_.sizes[e]);({bestBid:te,bestAsk:A,buyVolume:j,sellVolume:M}=_)}else if(Number.isFinite(h)){let e=Be();if(e)for(let t=0;t<e.bins.length;t++)C(e.bins[t])&&(T+=e.sizes[t]);te=E.bestBid(),A=E.bestAsk(),j=z.buyVolume,M=z.sellVolume}let N=x<=te?`bid`:b>=A?`ask`:null;if(t.strokeStyle=e.toCss(d.text,.5),t.lineWidth=1,t.setLineDash([3,3]),t.beginPath(),t.moveTo(Math.round(f)+.5,Y.y),t.lineTo(Math.round(f)+.5,Y.y+Y.h),t.moveTo(Y.x,l),t.lineTo(i,l),t.stroke(),t.setLineDash([]),Number.isFinite(h)){let i=n(h),a=n(h+ee),o=r((v*y+y-.5)*I),s=r((v*y-.5)*I);t.strokeStyle=e.toCss(d.text,.85),t.strokeRect(i,o,Math.max(2,a-i),Math.max(2,s-o))}t.font=o.fontOf(d,w,600,w.fontSize??(Z.width<420?10:11)),Xe(t,O.price(S),i+1,l,Z.width-i-2,d.text,!0),Xe(t,u,o.clamp(f,Y.x+40,Y.x+Y.w-40),Y.y+Y.h+g/2+2,Y.w,d.text,!0,`center`);let P=N===`bid`?k.up:N===`ask`?k.down:null;s.tooltipHtml(Se,Z.tooltip,{text:o.formatClock(Number.isFinite(h)?h:m,!0,w.timeZone),color:void 0,badge:N&&P?{text:N===`bid`?a.bidSide:a.askSide,color:e.toCss(P)}:void 0},[[a.price,y>1?`${O.price(b)} – ${O.price(x)}`:O.price(S)],[a.liquidity,Me(O.size(T))],[a.buys,Me(O.size(j))],[a.sells,Me(O.size(M))]]),Z.tooltip.style.display=`block`,Z.placeTooltip(Z.tooltip,f,p,f>Y.w*.6?`left`:`right`);let F=`${h}|${v}|${y}|${T}|${j}|${M}`;if(F!==xe){xe=F;let e={time:Number.isFinite(h)?h:m,price:b,priceHigh:x,size:T,side:N,buyVolume:j,sellVolume:M};D.emit(`hover`,e)}}let tt=async(e=new Set)=>{let t=++le,n=await c.createHeatFieldRenderer(w.renderer??`auto`,()=>{let e=Se.createElement(`canvas`);return Object.assign(e.style,{position:`absolute`,left:`0`,top:`0`,pointerEvents:`none`}),e.setAttribute(`aria-hidden`,`true`),e},t=>{ue||K?.kind!==t||(K.destroy(),K.canvas.remove(),K=null,tt(new Set([...e,t])))},e);if(ue||t!==le){n?.destroy();return}K&&(K.destroy(),K.canvas.remove()),K=n,n?(Q.dataset.renderer=n.kind,Q.insertBefore(n.canvas,Z.canvas),D.emit(`renderer`,n.kind)):delete Q.dataset.renderer,de(n?.kind??null),Z.invalidate()},nt=r.followDefaultRenderer(()=>w.renderer,()=>void tt()),rt=e=>{pe!==e&&(pe=e,D.emit(`follow`,e))},it=e=>{let t=L.length?L[0].time:R;if(!Number.isFinite(t))return e;let n=e[1]-e[0],r=(Number.isFinite(ve)?ve:Oe())+$()+n/2,i=Math.max(t-n/2,Math.min(e[0],r-n));return[i,i+n]},at=e=>{if(w.interactive===!1)return;let[t,n]=s.localPoint(Q,e);Q.setPointerCapture?.(e.pointerId),X={x:t,y:n,viewX:[...q],viewY:[...J],axis:t>Y.x+Y.w,span:J[1]-J[0]}},ot=e=>{let[t,n]=s.localPoint(Q,e);if(be=[t,n],X){let e=t-X.x,r=n-X.y;if(X.axis){let e=X.span*Math.exp(r*.006),t=(X.viewY[0]+X.viewY[1])/2;_e=e,J=[t-e/2,t+e/2],ge=[J[0],J[1]]}else if(Math.abs(e)+Math.abs(r)>3){rt(!1);let t=(X.viewX[1]-X.viewX[0])/Y.w*e,n=(X.viewY[1]-X.viewY[0])/Y.h*r;q=it([X.viewX[0]-t,X.viewX[1]-t]),J=[X.viewY[0]+n,X.viewY[1]+n]}}Z.invalidate()},st=e=>{Q.releasePointerCapture?.(e.pointerId),X=null,Z.invalidate()},ct=()=>{X||(be=null,Z.invalidate())},lt=(e,t)=>{let[n,r]=q,i=o.clamp((pe?me:r-n)*e,$()*10,Ee());if(me=i,!pe){let e=n+(t-Y.x)/Y.w*(r-n),a=(e-n)/(r-n);q=it([e-i*a,e+i*(1-a)])}Z.invalidate()},ut=e=>{let t=o.clamp((J[1]-J[0])*e,I*6||1e-9,1/0),n=(J[0]+J[1])/2;_e=t,J=[n-t/2,n+t/2],ge=[J[0],J[1]],Z.invalidate()},dt=e=>{if(w.interactive===!1||!(e.ctrlKey||e.metaKey))return;e.preventDefault();let[t]=s.localPoint(Q,e),n=Math.exp(e.deltaY*.002);e.shiftKey||t>Y.x+Y.w?ut(n):lt(n,t)},ft=()=>{w.interactive!==!1&&ht.resetView()},pt=e=>{if(w.interactive!==!1){switch(e.key){case`+`:case`=`:lt(.8,Y.x+Y.w);break;case`-`:lt(1.25,Y.x+Y.w);break;case`ArrowUp`:case`ArrowDown`:{if(e.shiftKey){ut(e.key===`ArrowUp`?.8:1.25);break}rt(!1);let t=(J[1]-J[0])*.1*(e.key===`ArrowUp`?1:-1);J=[J[0]+t,J[1]+t],Z.invalidate();break}case`ArrowLeft`:case`ArrowRight`:{rt(!1);let t=(q[1]-q[0])*.1*(e.key===`ArrowLeft`?-1:1);q=it([q[0]+t,q[1]+t]),Z.invalidate();break}case`0`:case`Home`:ht.resetView();break;default:return}e.preventDefault()}};Q.addEventListener(`pointerdown`,at),Q.addEventListener(`pointermove`,ot),Q.addEventListener(`pointerup`,st),Q.addEventListener(`pointercancel`,st),Q.addEventListener(`pointerleave`,ct),Q.addEventListener(`wheel`,dt,{passive:!1}),Q.addEventListener(`dblclick`,ft),Q.addEventListener(`keydown`,pt);let mt=e=>{let t=Re(e.time);E.count(`bid`)+E.count(`ask`)>0&&(Pe(),Le(t)),E.applyDelta(e)},ht={setBook(e){let t=Re(e.time);E.count(`bid`)+E.count(`ask`)>0&&Le(t),E.setSnapshot(e),Pe(),je(),Number.isFinite(R)||Le(t),Z.invalidate()},applyDeltas(e){if(Array.isArray(e))for(let t of e)mt(t);else mt(e);!Number.isFinite(R)&&I>0&&Le(Oe()),Z.invalidate()},addTrades(e){let t=Array.isArray(e)?e:[e];for(let e of t){if(!(e.size>0)||!Number.isFinite(e.price))continue;Number.isFinite(ie)&&(Re(e.time),Le(e.time));let t=!Number.isFinite(R)||e.time>=R?z:ze(e.time);t&&(e.side===`buy`?(t.buyVolume+=e.size,t.buyNotional+=e.size*e.price):(t.sellVolume+=e.size,t.sellNotional+=e.size*e.price)),(!re||e.time>=re.time)&&(re=e)}Z.invalidate()},clear(){E.clear(),Ne(),re=null,ie=NaN,I=0,_e=NaN,ge=null,he=!1,Z.invalidate()},setOptions(e){let t=w;w=e,Te(),(e.tickSize!==t.tickSize||(e.interval??100)!==(t.interval??100))&&(Ne(),I=0,_e=NaN,Pe()),e.window!==t.window&&(me=NaN),e.priceSpan!==t.priceSpan&&(_e=NaN),(e.renderer??`auto`)!==(t.renderer??`auto`)&&tt(),Ae(),je(),Z.invalidate()},resetView(){me=NaN,_e=NaN,ge=null,rt(!0),Z.invalidate()},getRenderer:()=>K?.kind??null,ready:fe,getStore:()=>E,on:(e,t)=>D.on(e,t),resize(){Z.invalidate()},destroy(){ue=!0,nt(),Q.removeEventListener(`pointerdown`,at),Q.removeEventListener(`pointermove`,ot),Q.removeEventListener(`pointerup`,st),Q.removeEventListener(`pointercancel`,st),Q.removeEventListener(`pointerleave`,ct),Q.removeEventListener(`wheel`,dt),Q.removeEventListener(`dblclick`,ft),Q.removeEventListener(`keydown`,pt),K?.destroy(),K=null,D.clear(),Z.destroy(),de(null)}};return Te(),Ae(),tt(),ht};exports.createOrderBookHeatmap=E,exports.heatCurve=te,exports.heatIntensity=C,exports.positionedRamp=b,exports.rowBucket=x,exports.sizeCdf=T;
2
2
  //# sourceMappingURL=heatmap.cjs.map