@wick-charts/vue 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +5 -3
  2. package/dist/BarSeries.vue.js +44 -0
  3. package/dist/BarSeries.vue2.js +4 -0
  4. package/dist/CandlestickSeries.vue.js +45 -0
  5. package/dist/CandlestickSeries.vue2.js +4 -0
  6. package/dist/ChartContainer.vue.js +168 -0
  7. package/dist/ChartContainer.vue2.js +4 -0
  8. package/dist/LineSeries.vue.js +44 -0
  9. package/dist/LineSeries.vue2.js +4 -0
  10. package/dist/PieSeries.vue.js +34 -0
  11. package/dist/PieSeries.vue2.js +4 -0
  12. package/dist/composables.js +44 -0
  13. package/dist/context.js +25 -0
  14. package/dist/core/dist/animation/animator.js +72 -0
  15. package/dist/core/dist/animation/config.js +145 -0
  16. package/dist/core/dist/animation/easing.js +4 -0
  17. package/dist/core/dist/animation/scalar-spring.js +57 -0
  18. package/dist/core/dist/animation/spring.js +11 -0
  19. package/dist/core/dist/animation/time.js +19 -0
  20. package/dist/core/dist/animation/viewport-engine.js +174 -0
  21. package/dist/core/dist/animation/visible-range-spring.js +64 -0
  22. package/dist/core/dist/animation/y-range-hermite.js +72 -0
  23. package/dist/core/dist/animation/y-range-snap.js +31 -0
  24. package/dist/core/dist/animation/y-range-spring.js +59 -0
  25. package/dist/core/dist/axis/dom-labels.js +60 -0
  26. package/dist/core/dist/canvas-manager.js +109 -0
  27. package/dist/core/dist/chart/edge-indicators.js +26 -0
  28. package/dist/core/dist/chart/fit-to-data.js +9 -0
  29. package/dist/core/dist/chart/last-value.js +31 -0
  30. package/dist/core/dist/chart/options.js +35 -0
  31. package/dist/core/dist/chart/pan-zoom-math.js +66 -0
  32. package/dist/core/dist/chart/streaming-cadence.js +70 -0
  33. package/dist/core/dist/chart/streaming-target.js +22 -0
  34. package/dist/core/dist/chart/viewport-padding.js +6 -0
  35. package/dist/core/dist/chart/y-target.js +24 -0
  36. package/dist/core/dist/chart.js +1495 -0
  37. package/dist/core/dist/components/crosshair.js +9 -0
  38. package/dist/core/dist/components/edge-indicator.js +36 -0
  39. package/dist/core/dist/components/grid.js +22 -0
  40. package/dist/core/dist/components/marker.js +41 -0
  41. package/dist/core/dist/components/reference-line.js +48 -0
  42. package/dist/core/dist/components/time-region.js +35 -0
  43. package/dist/core/dist/data/decimation.js +54 -0
  44. package/dist/core/dist/data/store.js +76 -0
  45. package/dist/core/dist/data/sync.js +47 -0
  46. package/dist/core/dist/events.js +19 -0
  47. package/dist/core/dist/interactions/handler.js +84 -0
  48. package/dist/core/dist/interactions/pan.js +26 -0
  49. package/dist/core/dist/interactions/zoom.js +21 -0
  50. package/dist/core/dist/navigator/controller.js +374 -0
  51. package/dist/core/dist/navigator/decimate.js +44 -0
  52. package/dist/core/dist/navigator/interactions.js +28 -0
  53. package/dist/core/dist/navigator/render.js +68 -0
  54. package/dist/core/dist/perf/counting-context.js +19 -0
  55. package/dist/core/dist/perf/perf-hud.js +453 -0
  56. package/dist/core/dist/perf/perf-monitor.js +132 -0
  57. package/dist/core/dist/render-scheduler.js +31 -0
  58. package/dist/core/dist/scales/tick-tracker.js +110 -0
  59. package/dist/core/dist/scales/x-scale.js +145 -0
  60. package/dist/core/dist/scales/y-scale.js +156 -0
  61. package/dist/core/dist/series/bar.js +341 -0
  62. package/dist/core/dist/series/base-multi-layer.js +438 -0
  63. package/dist/core/dist/series/candlestick.js +481 -0
  64. package/dist/core/dist/series/definition.js +11 -0
  65. package/dist/core/dist/series/line.js +446 -0
  66. package/dist/core/dist/series/painters/builtins.js +36 -0
  67. package/dist/core/dist/series/painters/canvas-path.js +79 -0
  68. package/dist/core/dist/series/painters/resolve.js +32 -0
  69. package/dist/core/dist/series/pie.js +545 -0
  70. package/dist/core/dist/series/register-builtins.js +11 -0
  71. package/dist/core/dist/series/stack-math.js +17 -0
  72. package/dist/core/dist/snapshots.js +107 -0
  73. package/dist/core/dist/theme/create.js +176 -0
  74. package/dist/core/dist/theme/resolve.js +14 -0
  75. package/dist/core/dist/theme/themes/andromeda.js +33 -0
  76. package/dist/core/dist/theme/themes/ayu-mirage.js +33 -0
  77. package/dist/core/dist/theme/themes/catppuccin.js +33 -0
  78. package/dist/core/dist/theme/themes/dracula.js +35 -0
  79. package/dist/core/dist/theme/themes/github-light.js +34 -0
  80. package/dist/core/dist/theme/themes/gruvbox.js +33 -0
  81. package/dist/core/dist/theme/themes/handwritten.js +101 -0
  82. package/dist/core/dist/theme/themes/high-contrast.js +33 -0
  83. package/dist/core/dist/theme/themes/lavender-mist.js +33 -0
  84. package/dist/core/dist/theme/themes/light-pink.js +34 -0
  85. package/dist/core/dist/theme/themes/material-palenight.js +33 -0
  86. package/dist/core/dist/theme/themes/minimal-light.js +34 -0
  87. package/dist/core/dist/theme/themes/mint-breeze.js +33 -0
  88. package/dist/core/dist/theme/themes/monokai-pro.js +33 -0
  89. package/dist/core/dist/theme/themes/night-owl.js +35 -0
  90. package/dist/core/dist/theme/themes/one-dark-pro.js +33 -0
  91. package/dist/core/dist/theme/themes/panda.js +33 -0
  92. package/dist/core/dist/theme/themes/peach-cream.js +33 -0
  93. package/dist/core/dist/theme/themes/quiet-light.js +37 -0
  94. package/dist/core/dist/theme/themes/rose-pine-dawn.js +33 -0
  95. package/dist/core/dist/theme/themes/sand-dune.js +33 -0
  96. package/dist/core/dist/theme/themes/solarized-light.js +34 -0
  97. package/dist/core/dist/tooltip-position.js +10 -0
  98. package/dist/core/dist/utils/color.js +37 -0
  99. package/dist/core/dist/utils/format.js +29 -0
  100. package/dist/core/dist/utils/math.js +26 -0
  101. package/dist/core/dist/utils/poisoned-data-reporter.js +15 -0
  102. package/dist/core/dist/utils/time.js +41 -0
  103. package/dist/index.d.ts +827 -63
  104. package/dist/index.js +142 -8025
  105. package/dist/ui/Crosshair.vue.js +53 -0
  106. package/dist/ui/Crosshair.vue2.js +4 -0
  107. package/dist/ui/InfoBar.vue.js +143 -0
  108. package/dist/ui/InfoBar.vue2.js +4 -0
  109. package/dist/ui/Legend.vue.js +212 -0
  110. package/dist/ui/Legend.vue2.js +4 -0
  111. package/dist/ui/Marker.vue.js +47 -0
  112. package/dist/ui/Marker.vue2.js +4 -0
  113. package/dist/ui/Navigator.vue.js +58 -0
  114. package/dist/ui/Navigator.vue2.js +4 -0
  115. package/dist/ui/NumberFlow.vue.js +69 -0
  116. package/dist/ui/NumberFlow.vue2.js +4 -0
  117. package/dist/ui/PieLegend.vue.js +132 -0
  118. package/dist/ui/PieLegend.vue2.js +4 -0
  119. package/dist/ui/PieTooltip.vue.js +135 -0
  120. package/dist/ui/PieTooltip.vue2.js +4 -0
  121. package/dist/ui/ReferenceLine.vue.js +44 -0
  122. package/dist/ui/ReferenceLine.vue2.js +4 -0
  123. package/dist/ui/TimeAxis.vue.js +43 -0
  124. package/dist/ui/TimeAxis.vue2.js +4 -0
  125. package/dist/ui/TimeRegion.vue.js +41 -0
  126. package/dist/ui/TimeRegion.vue2.js +4 -0
  127. package/dist/ui/Title.vue.js +54 -0
  128. package/dist/ui/Title.vue2.js +4 -0
  129. package/dist/ui/Tooltip.vue.js +195 -0
  130. package/dist/ui/Tooltip.vue2.js +4 -0
  131. package/dist/ui/YAxis.vue.js +42 -0
  132. package/dist/ui/YAxis.vue2.js +4 -0
  133. package/dist/ui/YLabel.vue.js +105 -0
  134. package/dist/ui/YLabel.vue2.js +4 -0
  135. package/package.json +2 -2
  136. package/src/BarSeries.vue +12 -13
  137. package/src/CandlestickSeries.vue +17 -6
  138. package/src/LineSeries.vue +12 -13
  139. package/src/PieSeries.vue +2 -1
  140. package/src/index.ts +23 -0
  141. package/src/ui/Legend.vue +1 -2
  142. package/src/ui/Marker.vue +62 -0
  143. package/src/ui/ReferenceLine.vue +58 -0
  144. package/src/ui/TimeRegion.vue +54 -0
@@ -0,0 +1,481 @@
1
+ import { Animator as G } from "../animation/animator.js";
2
+ import { DEFAULT_CANDLESTICK_SMOOTH as U, DEFAULT_CANDLESTICK_ENTRY as X } from "../animation/config.js";
3
+ import { easeOutCubic as j } from "../animation/easing.js";
4
+ import { ScalarSpring as P } from "../animation/scalar-spring.js";
5
+ import { decimateOHLCData as q } from "../data/decimation.js";
6
+ import { TimeSeriesStore as J } from "../data/store.js";
7
+ import { resolveCandlestickBodyColor as E } from "../theme/resolve.js";
8
+ import { hexToRgba as $ } from "../utils/color.js";
9
+ import { clamp as Q, lerp as V } from "../utils/math.js";
10
+ import { isPoisonedNumber as N, reportPoisonedData as Z } from "../utils/poisoned-data-reporter.js";
11
+ import { normalizeOHLCArray as tt, normalizeTime as F } from "../utils/time.js";
12
+ import { fillRoundedRect as H } from "./painters/canvas-path.js";
13
+ import { resolveCandlePainter as et } from "./painters/resolve.js";
14
+ const it = 0.15, ot = 5e-3;
15
+ class st {
16
+ #t;
17
+ #e;
18
+ #o;
19
+ #n;
20
+ #i;
21
+ #s;
22
+ // Sticky once any seen candle carries volume — mirrors the old lerp, which
23
+ // only emitted `volume` when a side had it, so a volume-less candle stays
24
+ // volume-less and the histogram keeps skipping it.
25
+ #r;
26
+ constructor(t) {
27
+ this.#t = new P(t.open), this.#e = new P(t.high), this.#o = new P(t.low), this.#n = new P(t.close), this.#i = new P(t.volume ?? 0), this.#s = t.time, this.#r = t.volume !== void 0;
28
+ }
29
+ retarget(t, e = {}) {
30
+ this.#s = t.time, t.volume !== void 0 && (this.#r = !0), this.#t.retarget(t.open, e), this.#e.retarget(t.high, e), this.#o.retarget(t.low, e), this.#n.retarget(t.close, e), this.#i.retarget(t.volume ?? 0, e);
31
+ }
32
+ tick(t) {
33
+ const e = this.#t.tick(t), s = this.#e.tick(t), i = this.#o.tick(t), r = this.#n.tick(t), o = this.#i.tick(t);
34
+ return e || s || i || r || o;
35
+ }
36
+ get current() {
37
+ const t = {
38
+ time: this.#s,
39
+ open: this.#t.current,
40
+ high: this.#e.current,
41
+ low: this.#o.current,
42
+ close: this.#n.current
43
+ };
44
+ return this.#r && (t.volume = this.#i.current), t;
45
+ }
46
+ }
47
+ const O = 2, nt = { tl: !0, tr: !0, br: !0, bl: !0 }, _ = { tl: !0, tr: !0, br: !1, bl: !1 }, rt = {
48
+ up: { body: "#26a69a", wick: "#26a69a" },
49
+ down: { body: "#ef5350", wick: "#ef5350" },
50
+ bodyWidthRatio: 0.6,
51
+ cornerRadius: O,
52
+ entryMs: X,
53
+ smoothMs: U
54
+ };
55
+ function I(a) {
56
+ return {
57
+ ...a,
58
+ entryMs: a.entryMs === !1 ? 0 : a.entryMs ?? X,
59
+ smoothMs: a.smoothMs === !1 ? 0 : a.smoothMs ?? U
60
+ };
61
+ }
62
+ class at {
63
+ kind = "candlestick";
64
+ store;
65
+ options;
66
+ // --- Animation state ----------------------------------------------------
67
+ /** Smoothed OHLC for the live last candle. Reset on `appendPoint` (new
68
+ * candle → identity snap) and chased on `updateLastPoint`. */
69
+ displayedLast = null;
70
+ /** Per-candle entrance registry. Single-layer, so no per-layer split. */
71
+ entries = /* @__PURE__ */ new Map();
72
+ #t = null;
73
+ /** EMA-smoothed volume scale (tallest visible bar). `null` re-seeds (snaps)
74
+ * on the next frame — set on construction and bulk data replacement. */
75
+ #e = null;
76
+ /** False while {@link #displayedMaxVol} is still chasing the raw window max —
77
+ * feeds {@link needsAnimation} so frames keep flowing until it converges. */
78
+ #o = !0;
79
+ /** Whether the previous frame was rendering decimated (bucketed) candles.
80
+ * Crossing this boundary changes `volume` semantics (per-candle ↔ summed
81
+ * bucket), so the volume scale snaps rather than easing — otherwise the EMA
82
+ * clamps every bar to full band height for ~30 frames. */
83
+ #n = !1;
84
+ /** Series-level alpha for visibility cross-fade. Chart calls {@link setAlpha} on hide. */
85
+ #i = new G({
86
+ initial: 1,
87
+ duration: 0,
88
+ lerp: (t, e, s) => t + (e - t) * s
89
+ });
90
+ /** Body gradients keyed by `top|bottom|height` — built once at y=0..h and
91
+ * positioned per candle via `ctx.translate`, instead of a fresh
92
+ * `createLinearGradient` for every body on every frame. */
93
+ #s = /* @__PURE__ */ new Map();
94
+ constructor(t, e) {
95
+ this.store = t, this.options = I({ ...rt, ...e }), this.displayedLast = t.last() ?? null;
96
+ }
97
+ isEntryEnabled() {
98
+ return (this.options.entryAnimation ?? "unfold") !== "none";
99
+ }
100
+ updateOptions(t) {
101
+ this.options = I({ ...this.options, ...t });
102
+ }
103
+ getColor() {
104
+ return E(this.options.up.body);
105
+ }
106
+ // --- SeriesRenderer interface implementation ------------------------------
107
+ setData(t) {
108
+ this.store.setData(tt(t ?? []));
109
+ const e = this.store.last();
110
+ this.displayedLast = e ?? null, this.#t = null, this.entries.clear(), this.#e = null;
111
+ }
112
+ appendPoint(t) {
113
+ const e = t, s = F(e.time), i = { ...e, time: s };
114
+ this.store.append(i), this.displayedLast = i, this.#t = null;
115
+ const r = this.options.entryMs;
116
+ this.isEntryEnabled() && r > 0 && this.entries.set(s, { startTime: performance.now() });
117
+ }
118
+ updateLastPoint(t) {
119
+ const e = t, s = F(e.time), i = { ...e, time: s };
120
+ this.store.updateLast(i);
121
+ const r = this.options.smoothMs;
122
+ if (r <= 0) {
123
+ this.displayedLast = i, this.#t = null;
124
+ return;
125
+ }
126
+ let o = this.#t;
127
+ if (o === null) {
128
+ const l = this.displayedLast ?? i;
129
+ o = new st(l), this.#t = o;
130
+ }
131
+ o.retarget(i, { settleMs: r });
132
+ }
133
+ keepLast(t) {
134
+ if (t < 0) return;
135
+ const e = this.store.length - t;
136
+ e <= 0 || this.store.trimStart(e);
137
+ }
138
+ getLayerCount() {
139
+ return 1;
140
+ }
141
+ setLayerVisible(t, e) {
142
+ }
143
+ isLayerVisible(t) {
144
+ return !0;
145
+ }
146
+ getLayerColors() {
147
+ return [E(this.options.up.body)];
148
+ }
149
+ applyTheme(t, e) {
150
+ this.updateOptions({
151
+ up: { ...t.candlestick.up },
152
+ down: { ...t.candlestick.down }
153
+ });
154
+ }
155
+ onDataChanged(t) {
156
+ return this.store.on("update", t), () => this.store.off("update", t);
157
+ }
158
+ dispose() {
159
+ this.store.removeAllListeners();
160
+ }
161
+ // --- Animation lifecycle ------------------------------------------------
162
+ /**
163
+ * Advance the live-OHLC chase + alpha fade against `now` and prune
164
+ * fully-settled entrance entries. Called from `render()` once per frame.
165
+ */
166
+ tickAnimations(t) {
167
+ this.#i.tick(t);
168
+ const e = this.#t;
169
+ if (e !== null) {
170
+ const i = e.tick(t);
171
+ this.displayedLast = e.current, i || (this.#t = null);
172
+ }
173
+ const s = this.options.entryMs;
174
+ if (s <= 0) {
175
+ this.entries.clear();
176
+ return;
177
+ }
178
+ for (const [i, r] of this.entries)
179
+ t - r.startTime >= s && this.entries.delete(i);
180
+ }
181
+ /** True while OHLC chase, any per-candle entrance, alpha fade, or the volume
182
+ * scale is unsettled. */
183
+ get needsAnimation() {
184
+ return this.#i.animating || this.#t !== null || this.entries.size > 0 || !this.#o;
185
+ }
186
+ /** Abort in-flight per-candle entrance animations. Live-OHLC chase is left intact. */
187
+ cancelEntranceAnimations() {
188
+ this.entries.clear();
189
+ }
190
+ setAlpha(t, e) {
191
+ this.#i.setTarget(t, { duration: e });
192
+ }
193
+ getAlpha() {
194
+ return this.#i.current;
195
+ }
196
+ getLastValue() {
197
+ const t = this.store.last();
198
+ return t ? t.close : null;
199
+ }
200
+ getDataAtTime(t, e) {
201
+ return this.store.findNearest(t, e);
202
+ }
203
+ // --- TimeSeriesRenderer data queries --------------------------------------
204
+ getTimeBounds() {
205
+ const t = this.store.first(), e = this.store.last();
206
+ return !t || !e ? null : { first: t.time, last: e.time };
207
+ }
208
+ getLastDataPoint() {
209
+ return this.store.last() ?? null;
210
+ }
211
+ getSecondLastDataPoint() {
212
+ const t = this.store.getAll();
213
+ return t.length >= 2 ? t[t.length - 2] : null;
214
+ }
215
+ sampleTimes(t) {
216
+ return this.store.getAll().slice(0, t).map((e) => e.time);
217
+ }
218
+ getVisibleDataPoints(t, e) {
219
+ return this.store.getVisibleData(t, e);
220
+ }
221
+ getValueRange(t, e) {
222
+ const s = this.store.getVisibleData(t, e);
223
+ let i = 1 / 0, r = -1 / 0;
224
+ for (const o of s)
225
+ Number.isFinite(o.low) && o.low < i && (i = o.low), Number.isFinite(o.high) && o.high > r && (r = o.high);
226
+ return i === 1 / 0 || r === -1 / 0 ? null : { min: i, max: r };
227
+ }
228
+ render(t) {
229
+ this.tickAnimations(performance.now());
230
+ const { scope: e, timeScale: s, yScale: i, dataInterval: r } = t, { context: o, horizontalPixelRatio: l } = e, M = s.getRange();
231
+ let h = this.store.getVisibleData(M.from, M.to);
232
+ const d = e.mediaSize.width, k = h.length > d * 2;
233
+ if (k && (h = q(h, Math.round(d * 1.5))), h.length === 0) return;
234
+ const y = this.displayedLast;
235
+ if (!k && y !== null) {
236
+ const p = h.length - 1;
237
+ h[p].time === y.time && (h = [...h.slice(0, p), y]);
238
+ }
239
+ let c = null;
240
+ if (this.entries.size > 0) {
241
+ const p = this.options.entryMs, u = performance.now();
242
+ for (const B of h) {
243
+ const D = this.entries.get(B.time);
244
+ if (D === void 0) continue;
245
+ const W = u - D.startTime, C = p <= 0 ? 1 : Math.min(1, Math.max(0, W / p));
246
+ if (C >= 1) continue;
247
+ const K = j(C);
248
+ c === null && (c = /* @__PURE__ */ new Map()), c.set(B.time, K);
249
+ }
250
+ }
251
+ const L = s.barWidthBitmap(r), m = Math.round(30 * l), b = h.length <= 2 ? Math.min(m, L) : L, w = Math.max(1, Math.round(l));
252
+ let n = Math.max(1, Math.round(b * this.options.bodyWidthRatio) - 2);
253
+ (n & 1) !== (w & 1) && (n = n > 1 ? n - 1 : 2);
254
+ const T = Math.floor(n / 2), Y = k !== this.#n;
255
+ this.#n = k;
256
+ const x = Math.round(i.getMediaHeight() * e.verticalPixelRatio);
257
+ this.drawVolume({
258
+ ctx: o,
259
+ data: h,
260
+ timeScale: s,
261
+ chartHeight: x,
262
+ barWidth: b,
263
+ wickWidth: w,
264
+ entranceByTime: c,
265
+ snapVolScale: Y,
266
+ radius: (this.options.cornerRadius ?? O) * l
267
+ });
268
+ const f = [], v = [], g = [];
269
+ let A = null;
270
+ for (let p = 0; p < h.length; p++) {
271
+ const u = h[p];
272
+ if (N(u.open) || N(u.close) || N(u.high) || N(u.low)) {
273
+ g.push(p), A === null && (A = u);
274
+ continue;
275
+ }
276
+ u.close >= u.open ? f.push(u) : v.push(u);
277
+ }
278
+ A !== null && Z(this, "candlestick", g, `time ${A.time}`);
279
+ const S = {
280
+ painter: et(this.options.candlePainter),
281
+ env: {
282
+ ctx: o,
283
+ theme: t.theme,
284
+ horizontalPixelRatio: l,
285
+ verticalPixelRatio: e.verticalPixelRatio
286
+ },
287
+ radius: (this.options.cornerRadius ?? O) * l
288
+ }, R = {
289
+ ctx: o,
290
+ timeScale: s,
291
+ yScale: i,
292
+ halfBody: T,
293
+ bodyWidth: n,
294
+ wickWidth: w,
295
+ entranceByTime: c,
296
+ candlePass: S
297
+ };
298
+ this.drawCandles({
299
+ ...R,
300
+ candles: f,
301
+ body: this.options.up.body,
302
+ wickColor: this.options.up.wick
303
+ }), this.drawCandles({
304
+ ...R,
305
+ candles: v,
306
+ body: this.options.down.body,
307
+ wickColor: this.options.down.wick
308
+ });
309
+ }
310
+ drawVolume({
311
+ ctx: t,
312
+ data: e,
313
+ timeScale: s,
314
+ chartHeight: i,
315
+ barWidth: r,
316
+ wickWidth: o,
317
+ entranceByTime: l,
318
+ snapVolScale: M,
319
+ radius: h
320
+ }) {
321
+ let d = 0;
322
+ for (const n of e)
323
+ Number.isFinite(n.volume) && n.volume > d && (d = n.volume);
324
+ if (d === 0) {
325
+ this.#e = null, this.#o = !0;
326
+ return;
327
+ }
328
+ this.#e === null || M ? this.#e = d : this.#e += (d - this.#e) * it, this.#o = Math.abs(d - this.#e) <= d * ot;
329
+ const k = this.#e, y = i * 0.2;
330
+ let c = Math.max(1, r - 2);
331
+ (c & 1) !== (o & 1) && (c = c > 1 ? c - 1 : 2);
332
+ const L = Math.floor(c / 2), m = $(E(this.options.up.body), 0.2), b = $(E(this.options.down.body), 0.2), w = this.options.entryAnimation ?? "unfold";
333
+ for (const n of e) {
334
+ if (!Number.isFinite(n.volume) || n.volume <= 0) continue;
335
+ const T = n.volume, Y = s.timeToBitmapX(n.time), x = Math.min(y, Math.max(1, T / k * y)), f = n.close >= n.open;
336
+ t.fillStyle = f ? m : b;
337
+ const v = l?.get(n.time) ?? 1;
338
+ if (v >= 1 || w === "none") {
339
+ H(t, {
340
+ x: Y - L,
341
+ y: i - x,
342
+ width: c,
343
+ height: x,
344
+ radius: h,
345
+ corners: _
346
+ });
347
+ continue;
348
+ }
349
+ const g = z(v, w, {
350
+ x: Y - L,
351
+ barWidth: c,
352
+ anchorY: i,
353
+ topY: i - x,
354
+ bottomY: i
355
+ });
356
+ t.save(), t.globalAlpha = g.alpha, H(t, {
357
+ x: g.x,
358
+ y: g.topY,
359
+ width: c,
360
+ height: Math.max(1, g.bottomY - g.topY),
361
+ radius: h,
362
+ corners: _
363
+ }), t.restore();
364
+ }
365
+ }
366
+ drawCandles({
367
+ ctx: t,
368
+ candles: e,
369
+ timeScale: s,
370
+ yScale: i,
371
+ halfBody: r,
372
+ bodyWidth: o,
373
+ wickWidth: l,
374
+ body: M,
375
+ wickColor: h,
376
+ entranceByTime: d,
377
+ candlePass: k
378
+ }) {
379
+ if (e.length === 0) return;
380
+ const y = this.options.entryAnimation ?? "unfold", c = o + 2;
381
+ t.fillStyle = h;
382
+ for (const m of e) {
383
+ const b = d?.get(m.time) ?? 1, w = s.timeToBitmapX(m.time), n = i.valueToBitmapY(m.open), T = i.valueToBitmapY(m.high), Y = i.valueToBitmapY(m.low), x = w - Math.floor(l / 2);
384
+ if (b >= 1 || y === "none") {
385
+ t.fillRect(x, T, l, Y - T);
386
+ continue;
387
+ }
388
+ const f = z(b, y, {
389
+ x,
390
+ barWidth: c,
391
+ anchorY: n,
392
+ topY: T,
393
+ bottomY: Y
394
+ });
395
+ t.save(), t.globalAlpha = f.alpha, t.fillRect(f.x, f.topY, l, Math.max(1, f.bottomY - f.topY)), t.restore();
396
+ }
397
+ const L = Array.isArray(M);
398
+ for (const m of e) {
399
+ const b = d?.get(m.time) ?? 1, w = s.timeToBitmapX(m.time), n = i.valueToBitmapY(m.open), T = i.valueToBitmapY(m.close), Y = Math.min(n, T), x = Math.max(n, T), f = Math.max(1, x - Y), v = b < 1 && y !== "none";
400
+ let g = w - r, A = Y, S = f, R = 1;
401
+ if (v) {
402
+ const C = z(b, y, {
403
+ x: w - r,
404
+ barWidth: c,
405
+ anchorY: n,
406
+ topY: Y,
407
+ bottomY: x
408
+ });
409
+ g = C.x, A = C.topY, S = Math.max(1, C.bottomY - C.topY), R = C.alpha;
410
+ }
411
+ v && t.save();
412
+ const p = Array.isArray(M) ? M[0] : M, u = L && S > 2, B = u ? this.#r(t, M, S) : p;
413
+ t.fillStyle = B, v && (t.globalAlpha = R), u && t.translate(0, A);
414
+ const D = u ? 0 : A, W = Q(k.radius, 0, Math.min(o, S) / 2);
415
+ W < 1 && !this.options.candlePainter ? t.fillRect(g, D, o, S) : k.painter(k.env, {
416
+ geom: { x: g, y: D, width: o, height: S },
417
+ fillStyle: B,
418
+ color: p,
419
+ corners: nt,
420
+ radius: W,
421
+ progress: b,
422
+ isBullish: m.close >= m.open
423
+ }), u && t.translate(0, -A), v && t.restore();
424
+ }
425
+ }
426
+ /**
427
+ * Cached 2-stop body gradient anchored at y = 0..height. Heights quantize
428
+ * to whole device px (sub-pixel ramp drift is invisible) so same-height
429
+ * bodies share one `CanvasGradient` instead of allocating per candle per
430
+ * frame. The map is hard-bounded — entrance animations sweep heights
431
+ * continuously, and a full clear is cheaper than an eviction policy.
432
+ */
433
+ #r(t, e, s) {
434
+ const i = Math.max(3, Math.round(s)), r = `${e[0]}|${e[1]}|${i}`, o = this.#s.get(r);
435
+ if (o !== void 0) return o;
436
+ this.#s.size >= 512 && this.#s.clear();
437
+ const l = t.createLinearGradient(0, 0, 0, i);
438
+ return l.addColorStop(0, e[0]), l.addColorStop(1, e[1]), this.#s.set(r, l), l;
439
+ }
440
+ }
441
+ function z(a, t, e) {
442
+ switch (t) {
443
+ case "none":
444
+ return { x: e.x, topY: e.topY, bottomY: e.bottomY, alpha: 1 };
445
+ case "fade":
446
+ return { x: e.x, topY: e.topY, bottomY: e.bottomY, alpha: a };
447
+ case "unfold":
448
+ return {
449
+ x: e.x,
450
+ topY: V(e.anchorY, e.topY, a),
451
+ bottomY: V(e.anchorY, e.bottomY, a),
452
+ alpha: 1
453
+ };
454
+ case "slide":
455
+ return {
456
+ x: e.x + (1 - a) * e.barWidth,
457
+ topY: e.topY,
458
+ bottomY: e.bottomY,
459
+ alpha: a
460
+ };
461
+ case "fade-unfold":
462
+ return {
463
+ x: e.x,
464
+ topY: V(e.anchorY, e.topY, a),
465
+ bottomY: V(e.anchorY, e.bottomY, a),
466
+ alpha: a
467
+ };
468
+ }
469
+ }
470
+ const xt = {
471
+ type: "candlestick",
472
+ create: ({ theme: a }, t) => new at(new J(), {
473
+ up: { ...a.candlestick.up },
474
+ down: { ...a.candlestick.down },
475
+ ...t
476
+ })
477
+ };
478
+ export {
479
+ at as CandlestickRenderer,
480
+ xt as CandlestickSeriesDef
481
+ };
@@ -0,0 +1,11 @@
1
+ const i = /* @__PURE__ */ new Map();
2
+ function n(e) {
3
+ i.set(e.type, e);
4
+ }
5
+ function t(e) {
6
+ return i.get(e);
7
+ }
8
+ export {
9
+ n as registerSeriesDefinition,
10
+ t as resolveSeriesDefinition
11
+ };