@wick-charts/vue 0.5.1 → 0.6.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 (80) hide show
  1. package/README.md +18 -3
  2. package/dist/BarSeries.vue.js +26 -20
  3. package/dist/CandlestickSeries.vue.js +30 -24
  4. package/dist/ChartContainer.vue.js +88 -65
  5. package/dist/HeatmapSeries.vue.js +40 -0
  6. package/dist/HeatmapSeries.vue2.js +4 -0
  7. package/dist/LineSeries.vue.js +26 -20
  8. package/dist/PieSeries.vue.js +24 -18
  9. package/dist/core/dist/animation/animator.js +21 -21
  10. package/dist/core/dist/animation/config.js +114 -87
  11. package/dist/core/dist/animation/easing.js +3 -1
  12. package/dist/core/dist/animation/intro-wave.js +68 -0
  13. package/dist/core/dist/axis/dom-labels.js +13 -14
  14. package/dist/core/dist/chart/badge-animator.js +56 -0
  15. package/dist/core/dist/chart/edge-indicators.js +28 -13
  16. package/dist/core/dist/chart/last-value.js +18 -17
  17. package/dist/core/dist/chart/y-target.js +13 -12
  18. package/dist/core/dist/chart.js +679 -452
  19. package/dist/core/dist/components/annotation-chip.js +28 -0
  20. package/dist/core/dist/components/edge-indicator.js +58 -26
  21. package/dist/core/dist/components/loading-indicator.js +46 -0
  22. package/dist/core/dist/components/marker.js +49 -31
  23. package/dist/core/dist/components/reference-line.js +27 -36
  24. package/dist/core/dist/components/time-region.js +30 -28
  25. package/dist/core/dist/data/store.js +38 -19
  26. package/dist/core/dist/data/sync.js +60 -38
  27. package/dist/core/dist/heatmap-tooltip.js +16 -0
  28. package/dist/core/dist/interactions/handler.js +67 -43
  29. package/dist/core/dist/perf/perf-hud.js +5 -5
  30. package/dist/core/dist/scales/x-scale.js +85 -37
  31. package/dist/core/dist/scales/y-scale.js +38 -27
  32. package/dist/core/dist/series/bar-intro.js +18 -0
  33. package/dist/core/dist/series/bar.js +337 -205
  34. package/dist/core/dist/series/base-multi-layer.js +224 -96
  35. package/dist/core/dist/series/candlestick-intro.js +57 -0
  36. package/dist/core/dist/series/candlestick.js +454 -276
  37. package/dist/core/dist/series/heatmap.js +387 -0
  38. package/dist/core/dist/series/line-intro.js +85 -0
  39. package/dist/core/dist/series/line.js +590 -282
  40. package/dist/core/dist/series/painters/builtins.js +2 -2
  41. package/dist/core/dist/series/pie.js +396 -259
  42. package/dist/core/dist/series/register-builtins.js +8 -7
  43. package/dist/core/dist/series/types.js +6 -0
  44. package/dist/core/dist/series/wave-intro.js +26 -0
  45. package/dist/core/dist/theme/create.js +69 -63
  46. package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
  47. package/dist/core/dist/theme/themes/sand-dune.js +2 -2
  48. package/dist/core/dist/utils/color.js +109 -34
  49. package/dist/core/dist/utils/deep-equal.js +18 -0
  50. package/dist/core/dist/utils/time.js +25 -19
  51. package/dist/index.d.ts +1405 -123
  52. package/dist/index.js +177 -130
  53. package/dist/ui/Crosshair.vue.js +20 -21
  54. package/dist/ui/HeatmapTooltip.vue.js +96 -0
  55. package/dist/ui/HeatmapTooltip.vue2.js +4 -0
  56. package/dist/ui/InfoBar.vue.js +46 -47
  57. package/dist/ui/Legend.vue.js +80 -79
  58. package/dist/ui/PieLegend.vue.js +5 -5
  59. package/dist/ui/PieTooltip.vue.js +77 -67
  60. package/dist/ui/Tooltip.vue.js +60 -60
  61. package/dist/ui/YAxis.vue.js +2 -2
  62. package/dist/ui/YLabel.vue.js +94 -61
  63. package/package.json +2 -2
  64. package/src/BarSeries.vue +23 -7
  65. package/src/CandlestickSeries.vue +23 -7
  66. package/src/ChartContainer.vue +134 -12
  67. package/src/HeatmapSeries.vue +69 -0
  68. package/src/LineSeries.vue +23 -7
  69. package/src/PieSeries.vue +22 -6
  70. package/src/index.ts +84 -3
  71. package/src/ui/Crosshair.vue +1 -2
  72. package/src/ui/HeatmapTooltip.vue +144 -0
  73. package/src/ui/InfoBar.vue +1 -2
  74. package/src/ui/Legend.vue +13 -0
  75. package/src/ui/Marker.vue +1 -1
  76. package/src/ui/PieTooltip.vue +10 -0
  77. package/src/ui/ReferenceLine.vue +2 -2
  78. package/src/ui/TimeRegion.vue +2 -2
  79. package/src/ui/Tooltip.vue +2 -2
  80. package/src/ui/YLabel.vue +123 -8
@@ -1,60 +1,81 @@
1
- import { DEFAULT_LINE_PULSE as et, DEFAULT_LINE_SMOOTH as it, DEFAULT_LINE_ENTRY as ot } from "../animation/config.js";
2
- import { easeOutCubic as J } from "../animation/easing.js";
3
- import { decimateLineData as K } from "../data/decimation.js";
4
- import { hexToRgba as D } from "../utils/color.js";
5
- import { lerp as U } from "../utils/math.js";
6
- import { BaseMultiLayerSeries as nt } from "./base-multi-layer.js";
7
- import { buildCurveSegments as Q } from "./painters/canvas-path.js";
8
- import { resolveLinePainter as lt } from "./painters/resolve.js";
9
- const rt = {
1
+ import { DEFAULT_HISTORY_REVEAL as tt, DEFAULT_LINE_INTRO as et, DEFAULT_LINE_PULSE as it, DEFAULT_LINE_SMOOTH as ot, DEFAULT_LINE_ENTRY as st } from "../animation/config.js";
2
+ import { easeOutCubic as _ } from "../animation/easing.js";
3
+ import { decimateLineData as j } from "../data/decimation.js";
4
+ import { hexToRgba as C } from "../utils/color.js";
5
+ import { lerp as Y } from "../utils/math.js";
6
+ import { BaseMultiLayerSeries as rt } from "./base-multi-layer.js";
7
+ import { unfoldIntro as lt, backfillSweepIntro as at } from "./line-intro.js";
8
+ import { buildCurveSegments as q } from "./painters/canvas-path.js";
9
+ import { resolveLinePainter as ht } from "./painters/resolve.js";
10
+ const ct = {
10
11
  colors: ["#2962FF"],
11
12
  strokeWidth: 1,
12
13
  area: { visible: !0 },
13
14
  pulse: !0,
14
15
  stacking: "off",
15
16
  curve: "straight",
16
- entryMs: ot,
17
- smoothMs: it,
18
- pulseMs: et
17
+ entryMs: st,
18
+ smoothMs: ot,
19
+ pulseMs: it,
20
+ introMs: et,
21
+ historyRevealMs: tt
19
22
  };
20
- function Z(v) {
23
+ function Q(v) {
21
24
  const t = v.areaFill, e = t !== void 0 && v.area === void 0 ? { visible: !!t } : v.area;
22
25
  return {
23
26
  ...v,
24
27
  area: e,
25
- entryMs: v.entryMs === !1 ? 0 : v.entryMs ?? ot,
26
- smoothMs: v.smoothMs === !1 ? 0 : v.smoothMs ?? it,
27
- pulseMs: v.pulseMs === !1 ? 0 : v.pulseMs ?? et
28
+ entryMs: v.entryMs === !1 ? 0 : v.entryMs ?? st,
29
+ smoothMs: v.smoothMs === !1 ? 0 : v.smoothMs ?? ot,
30
+ pulseMs: v.pulseMs === !1 ? 0 : v.pulseMs ?? it,
31
+ introMs: v.introMs === !1 ? 0 : v.introMs ?? et,
32
+ historyRevealMs: v.historyRevealMs === !1 ? 0 : v.historyRevealMs ?? tt
28
33
  };
29
34
  }
30
- function $(v) {
35
+ function Z(v) {
31
36
  return v.map(([t, e]) => ({ x: t, y: e }));
32
37
  }
33
- function tt(v, t) {
38
+ const $ = 0.15, ut = at();
39
+ function U(v, t, e) {
40
+ if (v.length === 0) return null;
41
+ if (t <= v[0].time) return Number.isFinite(v[0].value) ? e(v[0]) : null;
42
+ const i = v[v.length - 1];
43
+ if (t >= i.time) return Number.isFinite(i.value) ? e(i) : null;
44
+ let s = 0, o = v.length - 1;
45
+ for (; o - s > 1; ) {
46
+ const a = s + o >> 1;
47
+ v[a].time <= t ? s = a : o = a;
48
+ }
49
+ const n = v[s], r = v[o];
50
+ if (!Number.isFinite(n.value) || !Number.isFinite(r.value)) return null;
51
+ const l = r.time - n.time;
52
+ return l <= 0 ? e(n) : Y(e(n), e(r), (t - n.time) / l);
53
+ }
54
+ function K(v, t) {
34
55
  for (const e of t)
35
56
  e.kind === "line" ? v.lineTo(e.x, e.y) : v.bezierCurveTo(e.cp1x, e.cp1y, e.cp2x, e.cp2y, e.x, e.y);
36
57
  }
37
- function at(v, t, e) {
38
- for (let s = e.length - 1; s >= 0; s--) {
39
- const r = e[s], n = s > 0 ? e[s - 1] : t[0];
40
- r.kind === "line" ? v.lineTo(n.x, n.y) : v.bezierCurveTo(r.cp2x, r.cp2y, r.cp1x, r.cp1y, n.x, n.y);
58
+ function ft(v, t, e) {
59
+ for (let i = e.length - 1; i >= 0; i--) {
60
+ const s = e[i], o = i > 0 ? e[i - 1] : t[0];
61
+ s.kind === "line" ? v.lineTo(o.x, o.y) : v.bezierCurveTo(s.cp2x, s.cp2y, s.cp1x, s.cp1y, o.x, o.y);
41
62
  }
42
63
  }
43
- class ht extends nt {
64
+ class mt extends rt {
44
65
  kind = "line";
45
66
  areaGradientCache = /* @__PURE__ */ new Map();
46
67
  constructor(t, e) {
47
- super(t), this.options = Z({ ...rt, ...e });
68
+ super(t), this.options = Q({ ...ct, ...e });
48
69
  }
49
70
  updateOptions(t) {
50
- this.options = Z({ ...this.options, ...t });
71
+ this.options = Q({ ...this.options, ...t });
51
72
  }
52
73
  getStacking() {
53
74
  return this.options.stacking;
54
75
  }
55
76
  applyTheme(t, e) {
56
- const s = this.stores.length === 1 ? [t.line.color] : t.seriesColors.slice(0, this.stores.length);
57
- this.updateOptions({ colors: s }), this.options.strokeWidth === e.line.width && this.updateOptions({ strokeWidth: t.line.width });
77
+ const i = this.stores.length === 1 ? [t.line.color] : t.seriesColors.slice(0, this.stores.length);
78
+ this.updateOptions({ colors: i }), this.options.strokeWidth === e.line.width && this.updateOptions({ strokeWidth: t.line.width });
58
79
  }
59
80
  isEntryEnabled() {
60
81
  return (this.options.entryAnimation ?? "grow") !== "none";
@@ -66,15 +87,254 @@ class ht extends nt {
66
87
  return this.hasPulse;
67
88
  }
68
89
  hasOverlayContentInRange(t, e) {
69
- for (let s = 0; s < this.stores.length; s++) {
70
- if (this.getLayerAlpha(s) <= 0) continue;
71
- const r = this.stores[s].last();
72
- if (r && r.time >= t) return !0;
90
+ for (let i = 0; i < this.stores.length; i++) {
91
+ if (this.getLayerAlpha(i) <= 0) continue;
92
+ const s = this.stores[i].last();
93
+ if (s && s.time >= t) return !0;
73
94
  }
74
95
  return !1;
75
96
  }
76
97
  render(t) {
77
- this.tickAnimations(performance.now()), this.options.stacking === "off" ? this.renderOff(t) : this.renderStacked(t, this.options.stacking === "percent");
98
+ this.tickAnimations(performance.now());
99
+ const { context: e } = t.scope;
100
+ this.historyDirectives = null;
101
+ const i = this.historyRange;
102
+ if (this.historyWave.active && i !== null) {
103
+ const r = this.options.historyReveal ?? ut;
104
+ r !== "none" && (this.historyDirectives = r(this.buildHistoryFrame(t, i)));
105
+ }
106
+ const s = this.historyDirectives, o = s?.ghostAlpha ?? 0;
107
+ o > 0 && (e.save(), e.globalAlpha *= o, this.introGhostPass = !0, this.renderBody(t), this.introGhostPass = !1, e.restore());
108
+ const n = this.applyHistoryClip(t, s, i);
109
+ this.introWave.active ? this.renderWithIntro(t) : (this.introDirectives = null, this.renderBody(t)), n && e.restore(), s?.heads !== void 0 && s.heads.length > 0 && this.drawIntroHeads(t, s.heads, this.historyWave.linear());
110
+ }
111
+ /**
112
+ * Initial-load intro pass: the resolved LineIntroFn describes this frame
113
+ * declaratively (clip window / ghost pass / heads / value transform); the
114
+ * renderer executes the directives around the untouched body pass.
115
+ */
116
+ renderWithIntro(t) {
117
+ const e = this.resolveIntro()(this.buildIntroFrame(t));
118
+ this.introDirectives = e;
119
+ const { context: i } = t.scope, { width: s, height: o } = t.scope.bitmapSize, n = e.ghostAlpha ?? 0;
120
+ n > 0 && (i.save(), i.globalAlpha *= n, this.introGhostPass = !0, this.renderBody(t), this.introGhostPass = !1, i.restore());
121
+ const r = e.clip, l = r !== void 0 && (r.fromX !== void 0 || r.toX !== void 0);
122
+ if (l) {
123
+ const a = r.fromX ?? 0, p = r.toX ?? s;
124
+ i.save(), i.beginPath(), i.rect(a, 0, Math.max(0, p - a), o), i.clip();
125
+ }
126
+ this.renderBody(t), l && i.restore(), e.heads !== void 0 && e.heads.length > 0 && this.drawIntroHeads(t, e.heads, this.introWave.linear());
127
+ }
128
+ /**
129
+ * Apply the history reveal's clip directive, mapped from reveal space
130
+ * (`x = 0` at the data boundary, increasing into the prepended history)
131
+ * to bitmap space. Everything at or after the boundary always draws; a
132
+ * small pad keeps the stroke cap at the reveal front from being shaved.
133
+ */
134
+ applyHistoryClip(t, e, i) {
135
+ const s = e?.clip;
136
+ if (s === void 0 || i === null || s.fromX === void 0 && s.toX === void 0) return !1;
137
+ const { context: o } = t.scope, { width: n, height: r } = t.scope.bitmapSize, l = t.timeScale.timeToBitmapX(i.to), a = Math.abs(l - t.timeScale.timeToBitmapX(i.from)), p = Math.max(2, (this.options.strokeWidth ?? 1) * t.scope.horizontalPixelRatio), f = s.fromX ?? 0, y = s.toX ?? a;
138
+ return o.save(), o.beginPath(), o.rect(l - y - p, 0, Math.max(0, y - f + p), r), o.rect(l, 0, Math.max(0, n - l), r), o.clip(), !0;
139
+ }
140
+ renderBody(t) {
141
+ this.options.stacking === "off" ? this.renderOff(t) : this.renderStacked(t, this.options.stacking === "percent");
142
+ }
143
+ /** True while a ghost pre-pass is drawing — skips the area fill so the
144
+ * translucent pass shows only the stroke skeleton. */
145
+ introGhostPass = !1;
146
+ /**
147
+ * Directives produced for the current intro frame. Kept between passes so
148
+ * the overlay (pulse dot) applies the same value transform the main pass
149
+ * drew with; `null` once the wave settles.
150
+ */
151
+ introDirectives = null;
152
+ /** Per-frame history-reveal directives; `null` when no reveal is in flight. */
153
+ historyDirectives = null;
154
+ /** Default intro, built lazily — one instance per renderer. */
155
+ defaultIntro = null;
156
+ resolveIntro() {
157
+ const t = this.options.introAnimation;
158
+ return t !== void 0 ? t : (this.defaultIntro === null && (this.defaultIntro = lt()), this.defaultIntro);
159
+ }
160
+ /**
161
+ * Frame context handed to the intro fn — progress plus memoized data
162
+ * accessors, so a directive-producing fn stays pure and cheap.
163
+ */
164
+ buildIntroFrame(t) {
165
+ return this.buildFrame(t, {
166
+ progress: this.introWave.linear(),
167
+ range: t.timeScale.getRange(),
168
+ // Plot-area extent, not the canvas bitmap — the canvas also carries the
169
+ // axis strips, so `bitmapSize` would make `width / 2` land right of the
170
+ // data center and any width-based x→time mapping sample the wrong time.
171
+ width: t.timeScale.getMediaWidth() * t.scope.horizontalPixelRatio
172
+ });
173
+ }
174
+ /**
175
+ * Localized frame for the history reveal fn: `range` is the prepended
176
+ * span (boundary at `range.to`), `width` its bitmap width, and the data
177
+ * accessors are scoped to that span — `layerMean` anchors an unfold to
178
+ * the new history, not the whole window.
179
+ */
180
+ buildHistoryFrame(t, e) {
181
+ return this.buildFrame(t, {
182
+ progress: this.historyWave.linear(),
183
+ range: e,
184
+ width: Math.abs(t.timeScale.timeToBitmapX(e.to) - t.timeScale.timeToBitmapX(e.from))
185
+ });
186
+ }
187
+ buildFrame(t, e) {
188
+ const { timeScale: i, yScale: s, scope: o } = t, { progress: n, range: r, width: l } = e, a = new Array(this.stores.length), p = new Array(this.stores.length);
189
+ let f;
190
+ const y = (h) => {
191
+ let m = a[h];
192
+ return m === void 0 && (m = this.stores[h]?.getVisibleData(r.from, r.to) ?? [], a[h] = m), m;
193
+ };
194
+ return {
195
+ progress: n,
196
+ range: r,
197
+ width: l,
198
+ height: s.getMediaHeight() * o.verticalPixelRatio,
199
+ stacking: this.options.stacking,
200
+ timeToX: (h) => i.timeToBitmapX(h),
201
+ xToTime: (h) => i.xToTime(h / o.horizontalPixelRatio),
202
+ valueToY: (h) => s.valueToBitmapY(h),
203
+ layerCount: this.stores.length,
204
+ layerData: y,
205
+ layerMean: (h) => {
206
+ let m = p[h];
207
+ if (m === void 0) {
208
+ let u = 0, A = 0;
209
+ for (const R of y(h))
210
+ Number.isFinite(R.value) && (u += R.value, A++);
211
+ m = A > 0 ? u / A : null, p[h] = m;
212
+ }
213
+ return m;
214
+ },
215
+ primaryPath: () => {
216
+ if (f === void 0) {
217
+ f = null;
218
+ for (let h = 0; h < this.stores.length; h++) {
219
+ if (this.getLayerAlpha(h) <= 0 || !this.stores[h].isVisible()) continue;
220
+ const m = y(h).filter((u) => Number.isFinite(u.value));
221
+ if (!(m.length < 2)) {
222
+ f = m.map((u) => ({
223
+ x: i.timeToBitmapX(u.time),
224
+ y: s.valueToBitmapY(u.value),
225
+ time: u.time
226
+ }));
227
+ break;
228
+ }
229
+ }
230
+ }
231
+ return f;
232
+ }
233
+ };
234
+ }
235
+ /**
236
+ * A custom/built-in intro's value transform rides this hook: every
237
+ * rendered value (stroke, area, stacked cumulative, trailing endpoint,
238
+ * overlay pulse) already flows through `effectiveValue`, so one override
239
+ * animates the whole geometry.
240
+ */
241
+ effectiveValue(t, e, i, s) {
242
+ const o = super.effectiveValue(t, e, i, s), n = this.historyWave.active ? this.historyDirectives?.value : void 0, r = this.historyRange;
243
+ if (n !== void 0 && r !== null && i < r.to) {
244
+ const y = r.to - r.from, h = y > 0 ? Math.min(1, Math.max(0, (r.to - i) / y)) : 0;
245
+ return n({ layerIndex: e, time: i, value: o, position: h });
246
+ }
247
+ const l = this.introWave.active ? this.introDirectives?.value : void 0;
248
+ if (l === void 0) return o;
249
+ const a = t.timeScale.getRange(), p = a.to - a.from, f = p > 0 ? Math.min(1, Math.max(0, (i - a.from) / p)) : 0;
250
+ return l({ layerIndex: e, time: i, value: o, position: f });
251
+ }
252
+ /**
253
+ * Extends the base last-value query with the 'grow' entrance's value-space
254
+ * equivalent of {@link chainedTailPositions}'s eased position lerp — the Y
255
+ * scale is affine, so lerping the *value* by the same eased progress and
256
+ * mapping it through `yScale` afterward lands on the identical pixel the
257
+ * renderer paints. Without this, a tooltip/YLabel query would report a
258
+ * freshly-appended point's raw value the instant it lands, `entryMs`
259
+ * before the marker visually arrives there.
260
+ */
261
+ snapshotValue(t, e, i) {
262
+ const s = super.snapshotValue(t, e, i);
263
+ return (this.options.entryAnimation ?? "grow") !== "grow" ? s : this.chainedTailValues(t)?.get(e) ?? s;
264
+ }
265
+ /** Value-space counterpart of {@link chainedTailPositions} — see {@link snapshotValue}. */
266
+ chainedTailValues(t) {
267
+ const e = this.unsettledTail(t);
268
+ if (e.length === 0) return null;
269
+ const i = this.stores[t].getAll(), s = i.length - 1 - e.length;
270
+ if (s < 0) return null;
271
+ const o = i[s];
272
+ if (!Number.isFinite(o.value)) return null;
273
+ let n = this.liveValue(t, o.time, o.value);
274
+ const r = /* @__PURE__ */ new Map();
275
+ for (let l = 0; l < e.length; l++) {
276
+ const a = i[s + 1 + l];
277
+ if (!Number.isFinite(a.value)) return null;
278
+ const p = _(e[l].progress), f = this.liveValue(t, a.time, a.value), y = Y(n, f, p);
279
+ r.set(a.time, y), n = y;
280
+ }
281
+ return r;
282
+ }
283
+ /**
284
+ * Glowing pulse dots riding the intro's head anchors — the line reads as
285
+ * being plotted live, and hands off to the regular pulse dot the frame
286
+ * the reveal lands. Off-mode only: recomputing the stacked cumulative at
287
+ * an arbitrary head time isn't worth it for a one-second decoration.
288
+ */
289
+ drawIntroHeads(t, e, i) {
290
+ if (this.options.stacking !== "off") return;
291
+ const s = Math.min(1, i / $), o = Math.min(1, (1 - i) / $), n = Math.max(0, Math.min(s, o));
292
+ if (n <= 0) return;
293
+ const { scope: r } = t;
294
+ for (const l of e)
295
+ for (let a = 0; a < this.stores.length; a++) {
296
+ const p = this.getLayerAlpha(a);
297
+ if (p <= 0 || !this.stores[a].isVisible()) continue;
298
+ const f = this.introHeadAnchor(t, a, l);
299
+ f !== null && this.drawPulse({
300
+ ctx: r.context,
301
+ x: f.x,
302
+ y: f.y,
303
+ color: this.resolveLayerColor(a, f.value),
304
+ pixelRatio: r.horizontalPixelRatio,
305
+ phase: i * 2,
306
+ alpha: n * p
307
+ });
308
+ }
309
+ }
310
+ /**
311
+ * Where a head dot sits for one layer: pinned to the polyline as it is
312
+ * actually drawn this frame. Interior anchors interpolate through
313
+ * {@link effectiveValue}, so live smoothing and the intro's own value
314
+ * transform are honored while data streams during the reveal. Past the
315
+ * last point the head parks on the trailing endpoint — the exact spot the
316
+ * settled pulse dot takes over — and before the first point it parks on
317
+ * the line's start. Without the clamps the head slides into the
318
+ * right-padding region beyond the line's end (the sweep front travels the
319
+ * visible range, not the data span) and jumps back on settle.
320
+ */
321
+ introHeadAnchor(t, e, i) {
322
+ const { timeScale: s, yScale: o } = t, n = s.getRange(), r = this.stores[e].getVisibleData(n.from, n.to);
323
+ if (r.length === 0) return null;
324
+ const l = this.stores[e].last();
325
+ if (l !== void 0 && i.time >= l.time) {
326
+ if (!Number.isFinite(l.value)) return null;
327
+ const f = this.trailingEndpoint(t, e);
328
+ return f === null ? null : { x: f.x, y: f.y, value: l.value };
329
+ }
330
+ const a = r[0];
331
+ if (i.time <= a.time) {
332
+ if (!Number.isFinite(a.value)) return null;
333
+ const f = this.effectiveValue(t, e, a.time, a.value);
334
+ return { x: s.timeToBitmapX(a.time), y: o.valueToBitmapY(f), value: a.value };
335
+ }
336
+ const p = U(r, i.time, (f) => this.effectiveValue(t, e, f.time, f.value));
337
+ return p === null ? null : { x: i.x, y: o.valueToBitmapY(p), value: p };
78
338
  }
79
339
  /**
80
340
  * Rendered positions of the layer's still-unsettled trailing points, keyed
@@ -88,20 +348,70 @@ class ht extends nt {
88
348
  * unsettled or any value in the chain (anchor included) is non-finite —
89
349
  * callers fall back to raw geometry, mirroring the old NaN guard.
90
350
  */
351
+ /**
352
+ * Stacked cumulative value for `layerIndex` at `queryT`, alpha-weighted
353
+ * and reduced through {@link effectiveValue} — the single source of truth
354
+ * shared by {@link renderStacked}'s geometry and the overlay's crosshair /
355
+ * pulse dots, so they can never disagree. Any OTHER layer without a
356
+ * sample exactly at `queryT` holds its nearest earlier value forward
357
+ * instead of contributing 0: ragged streams tick independently, so a
358
+ * lagging sibling shouldn't zero out the moment another layer ticks past
359
+ * it (see `renderStacked`'s `valueMaps` comment for the full rationale).
360
+ */
361
+ stackedValueAt(t, e, i) {
362
+ const s = this.options.stacking === "percent", o = (l) => {
363
+ const a = this.getLayerAlpha(l);
364
+ if (a <= 0) return 0;
365
+ const p = this.stores[l].getAll();
366
+ if (p.length === 0 || i < p[0].time) return 0;
367
+ const f = U(p, i, (y) => this.effectiveValue(t, l, y.time, y.value));
368
+ return f === null ? 0 : f * a;
369
+ };
370
+ let n = 0;
371
+ if (s)
372
+ for (let l = 0; l < this.stores.length; l++) n += o(l);
373
+ let r = 0;
374
+ for (let l = 0; l <= e; l++) {
375
+ const a = o(l);
376
+ r += s && n > 0 ? a / n * 100 : a;
377
+ }
378
+ return r;
379
+ }
380
+ /**
381
+ * Bitmap position for layer `li`'s stacked boundary at time `t`, chain-
382
+ * lerped through that layer's own still-unsettled trailing entries when
383
+ * `t` is its current live tip — a single dot has no shared edge to tear,
384
+ * so (unlike `renderStacked`'s polygon boundaries) gating off the layer's
385
+ * own entrance state is enough. Falls back to the raw settled position
386
+ * for historical points or when the 'grow' entrance is disabled.
387
+ */
388
+ stackedPositionAt(t, e, i) {
389
+ const { timeScale: s, yScale: o } = t, n = s.timeToBitmapX(i), r = o.valueToBitmapY(this.stackedValueAt(t, e, i)), l = this.stores[e].last()?.time;
390
+ if ((this.options.entryAnimation ?? "grow") !== "grow" || i !== l) return { x: n, y: r };
391
+ const a = this.unsettledTail(e), p = this.stores[e].getAll(), f = p.length - 1 - a.length;
392
+ if (a.length === 0 || f < 0) return { x: n, y: r };
393
+ const y = p[f];
394
+ let h = s.timeToBitmapX(y.time), m = o.valueToBitmapY(this.stackedValueAt(t, e, y.time));
395
+ for (let u = 0; u < a.length; u++) {
396
+ const A = p[f + 1 + u], R = _(a[u].progress), M = s.timeToBitmapX(A.time), I = o.valueToBitmapY(this.stackedValueAt(t, e, A.time));
397
+ h = Y(h, M, R), m = Y(m, I, R);
398
+ }
399
+ return { x: h, y: m };
400
+ }
91
401
  chainedTailPositions(t, e) {
92
- const s = this.unsettledTail(t, e);
93
- if (s.length === 0) return null;
94
- const r = this.stores[e].getAll(), n = r.length - 1 - s.length;
95
- if (n < 0) return null;
96
- const { timeScale: l, yScale: d } = t, L = r[n];
97
- if (!Number.isFinite(L.value)) return null;
98
- let k = l.timeToBitmapX(L.time), B = d.valueToBitmapY(this.effectiveValue(t, e, L.time, L.value));
402
+ const i = this.unsettledTail(e);
403
+ if (i.length === 0) return null;
404
+ const s = this.stores[e].getAll(), o = s.length - 1 - i.length;
405
+ if (o < 0) return null;
406
+ const { timeScale: n, yScale: r } = t, l = s[o];
407
+ if (!Number.isFinite(l.value)) return null;
408
+ let a = n.timeToBitmapX(l.time), p = r.valueToBitmapY(this.effectiveValue(t, e, l.time, l.value));
99
409
  const f = /* @__PURE__ */ new Map();
100
- for (let m = 0; m < s.length; m++) {
101
- const h = r[n + 1 + m];
410
+ for (let y = 0; y < i.length; y++) {
411
+ const h = s[o + 1 + y];
102
412
  if (!Number.isFinite(h.value)) return null;
103
- const P = J(s[m].progress), o = l.timeToBitmapX(h.time), C = d.valueToBitmapY(this.effectiveValue(t, e, h.time, h.value)), y = U(k, o, P), g = U(B, C, P);
104
- f.set(h.time, { x: y, y: g }), k = y, B = g;
413
+ const m = _(i[y].progress), u = n.timeToBitmapX(h.time), A = r.valueToBitmapY(this.effectiveValue(t, e, h.time, h.value)), R = Y(a, u, m), M = Y(p, A, m);
414
+ f.set(h.time, { x: R, y: M }), a = R, p = M;
105
415
  }
106
416
  return f;
107
417
  }
@@ -116,10 +426,10 @@ class ht extends nt {
116
426
  * of teleporting to the raw last.time while the line still unfurls.
117
427
  */
118
428
  trailingEndpoint(t, e) {
119
- const s = this.stores[e].last();
120
- if (!s) return null;
121
- const { timeScale: r, yScale: n } = t, l = r.timeToBitmapX(s.time), d = n.valueToBitmapY(this.effectiveValue(t, e, s.time, s.value));
122
- return (this.options.entryAnimation ?? "grow") !== "grow" ? { x: l, y: d } : this.chainedTailPositions(t, e)?.get(s.time) ?? { x: l, y: d };
429
+ const i = this.stores[e].last();
430
+ if (!i) return null;
431
+ const { timeScale: s, yScale: o } = t, n = s.timeToBitmapX(i.time), r = o.valueToBitmapY(this.effectiveValue(t, e, i.time, i.value));
432
+ return (this.options.entryAnimation ?? "grow") !== "grow" ? { x: n, y: r } : this.chainedTailPositions(t, e)?.get(i.time) ?? { x: n, y: r };
123
433
  }
124
434
  /**
125
435
  * Vertical stroke + area gradients for `options.threshold`, pinned to the
@@ -131,191 +441,232 @@ class ht extends nt {
131
441
  * the row would miss almost every frame anyway.
132
442
  */
133
443
  buildThresholdPaint(t, e) {
134
- const s = this.options.threshold;
135
- if (!s) return null;
136
- const { scope: r, yScale: n } = t, { context: l } = r, d = r.bitmapSize.height, L = s.above, k = s.below ?? e, B = Math.min(1, Math.max(0, n.valueToBitmapY(s.value) / d)), f = Math.min(6 * r.verticalPixelRatio, d * 0.02) / d, m = Math.max(0, B - f), h = Math.min(1, B + f), P = l.createLinearGradient(0, 0, 0, d);
137
- P.addColorStop(0, L), P.addColorStop(m, L), P.addColorStop(h, k), P.addColorStop(1, k);
138
- const o = l.createLinearGradient(0, 0, 0, d);
139
- return o.addColorStop(0, D(L, 0.26)), o.addColorStop(m, D(L, 0.14)), o.addColorStop(h, D(k, 0.1)), o.addColorStop(1, D(k, 0.01)), { stroke: P, area: o };
444
+ const i = this.options.threshold;
445
+ if (!i) return null;
446
+ const { scope: s, yScale: o } = t, { context: n } = s, r = s.bitmapSize.height, l = i.above, a = i.below ?? e, p = Math.min(1, Math.max(0, o.valueToBitmapY(i.value) / r)), f = Math.min(6 * s.verticalPixelRatio, r * 0.02) / r, y = Math.max(0, p - f), h = Math.min(1, p + f), m = n.createLinearGradient(0, 0, 0, r);
447
+ m.addColorStop(0, l), m.addColorStop(y, l), m.addColorStop(h, a), m.addColorStop(1, a);
448
+ const u = n.createLinearGradient(0, 0, 0, r);
449
+ return u.addColorStop(0, C(l, 0.26)), u.addColorStop(y, C(l, 0.14)), u.addColorStop(h, C(a, 0.1)), u.addColorStop(1, C(a, 0.01)), { stroke: m, area: u };
450
+ }
451
+ /**
452
+ * Dot markers at each data point (`options.points`). Callers pass the same
453
+ * animated vertices the stroke was built from, so the dots glide with the
454
+ * entrance unfurl and live-value smoothing instead of snapping to raw
455
+ * geometry. Skipped for the frame when the average horizontal spacing falls
456
+ * under ~1.5 dot diameters — dots that dense melt into a fat line and hide
457
+ * the stroke.
458
+ */
459
+ drawPointMarkers(t) {
460
+ const e = this.options.points;
461
+ if (!e?.visible) return;
462
+ const { context: i, points: s, pixelRatio: o, color: n } = t;
463
+ if (s.length === 0) return;
464
+ const r = Math.max(1, (e.radius ?? 3) * o);
465
+ if (!(s.length > 1 && (s[s.length - 1].x - s[0].x) / (s.length - 1) < r * 3)) {
466
+ i.beginPath();
467
+ for (const l of s)
468
+ i.moveTo(l.x + r, l.y), i.arc(l.x, l.y, r, 0, Math.PI * 2);
469
+ i.fillStyle = e.color ?? n, i.fill();
470
+ }
140
471
  }
141
472
  /** Each layer drawn independently */
142
473
  renderOff(t) {
143
- const { scope: e, timeScale: s, yScale: r } = t, { context: n } = e, l = s.getRange(), { verticalPixelRatio: d } = e, L = this.options.strokeWidth > 0, k = Math.max(1, Math.round(this.options.strokeWidth * d)), B = this.options.entryAnimation ?? "grow", f = lt(this.options.linePainter ?? this.options.curve ?? "straight"), m = {
144
- ctx: n,
474
+ const { scope: e, timeScale: i, yScale: s } = t, { context: o } = e, n = i.getRange(), { verticalPixelRatio: r } = e, l = this.options.strokeWidth > 0, a = Math.max(1, Math.round(this.options.strokeWidth * r)), p = this.options.entryAnimation ?? "grow", f = ht(this.options.linePainter ?? this.options.curve ?? "straight"), y = {
475
+ ctx: o,
145
476
  theme: t.theme,
146
477
  horizontalPixelRatio: e.horizontalPixelRatio,
147
- verticalPixelRatio: d
478
+ verticalPixelRatio: r
148
479
  };
149
480
  for (let h = 0; h < this.stores.length; h++) {
150
- const P = this.getLayerAlpha(h);
151
- if (P <= 0) continue;
152
- let o = this.stores[h].getVisibleData(l.from, l.to);
153
- const C = e.mediaSize.width;
154
- if (o.length > C * 2 && (o = K(o, Math.round(C * 1.5))), o.length < 2) continue;
155
- const y = this.stores[h].last()?.value ?? o[o.length - 1].value, g = this.resolveLayerColor(h, y), I = this.buildThresholdPaint(t, g), E = o[o.length - 1], b = this.stores[h].last(), W = b !== void 0 && E.time === b.time, Y = W ? this.entranceProgress(t, h, E.time) : 1, N = W && B === "fade" && Y < 1, T = (W ? this.trailingEndpoint(t, h) : null) ?? {
156
- x: s.timeToBitmapX(E.time),
157
- y: r.valueToBitmapY(this.effectiveValue(t, h, E.time, E.value))
158
- }, z = T.x, i = T.y, c = W && B === "grow" ? this.chainedTailPositions(t, h) : null, a = P < 1;
159
- (a || N) && (n.save(), a && (n.globalAlpha *= P), N && (n.globalAlpha *= Y));
160
- const S = o.length - 1, p = [];
161
- let x = null;
162
- for (let u = 0; u < S; u++) {
163
- const w = o[u].value;
164
- if (!Number.isFinite(w)) {
165
- x = null;
481
+ const m = this.getLayerAlpha(h);
482
+ if (m <= 0) continue;
483
+ let u = this.stores[h].getVisibleData(n.from, n.to);
484
+ const A = e.mediaSize.width;
485
+ if (u.length > A * 2 && (u = j(u, Math.round(A * 1.5))), u.length < 2) continue;
486
+ const R = this.stores[h].last()?.value ?? u[u.length - 1].value, M = this.resolveLayerColor(h, R), I = this.buildThresholdPaint(t, M), F = u[u.length - 1], z = this.stores[h].last(), D = z !== void 0 && F.time === z.time, N = D ? this.entranceProgress(h, F.time) : 1, W = D && p === "fade" && N < 1, E = (D ? this.trailingEndpoint(t, h) : null) ?? {
487
+ x: i.timeToBitmapX(F.time),
488
+ y: s.valueToBitmapY(this.effectiveValue(t, h, F.time, F.value))
489
+ }, G = E.x, c = E.y, x = D && p === "grow" ? this.chainedTailPositions(t, h) : null, b = m < 1;
490
+ (b || W) && (o.save(), b && (o.globalAlpha *= m), W && (o.globalAlpha *= N));
491
+ const S = u.length - 1, d = [];
492
+ let T = null;
493
+ for (let P = 0; P < S; P++) {
494
+ const B = u[P].value;
495
+ if (!Number.isFinite(B)) {
496
+ T = null;
166
497
  continue;
167
498
  }
168
- x || (x = [], p.push(x));
169
- const A = c?.get(o[u].time);
170
- if (A)
171
- x.push({ x: A.x, y: A.y });
499
+ T || (T = [], d.push(T));
500
+ const g = x?.get(u[P].time);
501
+ if (g)
502
+ T.push({ x: g.x, y: g.y });
172
503
  else {
173
- const O = r.valueToBitmapY(this.effectiveValue(t, h, o[u].time, w));
174
- x.push({ x: s.timeToBitmapX(o[u].time), y: O });
504
+ const L = s.valueToBitmapY(this.effectiveValue(t, h, u[P].time, B));
505
+ T.push({ x: i.timeToBitmapX(u[P].time), y: L });
175
506
  }
176
507
  }
177
- const F = o[S]?.value, _ = Number.isFinite(z) && Number.isFinite(i) && Number.isFinite(F), H = B === "grow" && Y < 1;
178
- let X = null;
179
- if (_ && (x ? (x.push({ x: z, y: i }), X = x) : p.push([{ x: z, y: i }])), L && p.some((u) => u.length >= 2)) {
180
- n.beginPath();
181
- for (const u of p)
182
- u.length < 2 || f(m, { points: u, color: g, lineWidth: k, closing: !1, grew: H && u === X });
183
- n.strokeStyle = I ? I.stroke : g, n.lineWidth = k, n.lineJoin = "round", n.lineCap = "round", n.stroke();
508
+ const k = u[S]?.value, V = Number.isFinite(G) && Number.isFinite(c) && Number.isFinite(k), X = p === "grow" && N < 1;
509
+ let H = null;
510
+ if (V && (T ? (T.push({ x: G, y: c }), H = T) : d.push([{ x: G, y: c }])), l && d.some((P) => P.length >= 2)) {
511
+ o.beginPath();
512
+ for (const P of d)
513
+ P.length < 2 || f(y, { points: P, color: M, lineWidth: a, closing: !1, grew: X && P === H });
514
+ o.strokeStyle = I ? I.stroke : M, o.lineWidth = a, o.lineJoin = "round", o.lineCap = "round", o.stroke();
184
515
  }
185
- if (L) {
186
- const u = Math.max(1, k / 2);
187
- let w = !1;
188
- for (const A of p)
189
- A.length === 1 && (w || (n.beginPath(), w = !0), n.moveTo(A[0].x + u, A[0].y), n.arc(A[0].x, A[0].y, u, 0, Math.PI * 2));
190
- w && (n.fillStyle = g, n.fill());
516
+ if (l) {
517
+ const P = Math.max(1, a / 2);
518
+ let B = !1;
519
+ for (const g of d)
520
+ g.length === 1 && (B || (o.beginPath(), B = !0), o.moveTo(g[0].x + P, g[0].y), o.arc(g[0].x, g[0].y, P, 0, Math.PI * 2));
521
+ B && (o.fillStyle = M, o.fill());
191
522
  }
192
- if (this.options.area.visible) {
193
- const u = e.bitmapSize.height;
194
- let w;
523
+ if (this.options.area.visible && !this.introGhostPass) {
524
+ const P = e.bitmapSize.height;
525
+ let B;
195
526
  if (I)
196
- w = I.area;
527
+ B = I.area;
197
528
  else {
198
- const A = String(h), O = this.areaGradientCache.get(A);
199
- O && O.bottomY === u && O.color === g ? w = O.gradient : (w = n.createLinearGradient(0, 0, 0, u), w.addColorStop(0, D(g, 0.12)), w.addColorStop(1, D(g, 0.01)), this.areaGradientCache.set(A, { gradient: w, bottomY: u, color: g }));
529
+ const g = String(h), L = this.areaGradientCache.get(g);
530
+ L && L.bottomY === P && L.color === M ? B = L.gradient : (B = o.createLinearGradient(0, 0, 0, P), B.addColorStop(0, C(M, 0.12)), B.addColorStop(1, C(M, 0.01)), this.areaGradientCache.set(g, { gradient: B, bottomY: P, color: M }));
200
531
  }
201
- n.fillStyle = w;
202
- for (const A of p)
203
- A.length < 2 || (n.beginPath(), f(m, { points: A, color: g, lineWidth: k, closing: !0, grew: H && A === X }), n.lineTo(A[A.length - 1].x, u), n.lineTo(A[0].x, u), n.closePath(), n.fill());
532
+ o.fillStyle = B;
533
+ for (const g of d)
534
+ g.length < 2 || (o.beginPath(), f(y, { points: g, color: M, lineWidth: a, closing: !0, grew: X && g === H }), o.lineTo(g[g.length - 1].x, P), o.lineTo(g[0].x, P), o.closePath(), o.fill());
535
+ }
536
+ if (this.options.points?.visible) {
537
+ const P = [];
538
+ for (const B of d)
539
+ for (const g of B) P.push(g);
540
+ this.drawPointMarkers({ context: o, points: P, pixelRatio: e.horizontalPixelRatio, color: M });
204
541
  }
205
- (N || a) && n.restore();
542
+ (W || b) && o.restore();
206
543
  }
207
544
  }
208
545
  /** Stacked area rendering */
209
546
  renderStacked(t, e) {
210
- const { scope: s, timeScale: r, yScale: n } = t, { context: l } = s, d = r.getRange(), { verticalPixelRatio: L } = s, k = this.options.strokeWidth > 0, B = Math.max(1, Math.round(this.options.strokeWidth * L)), f = this.options.curve ?? "straight", m = s.mediaSize.width, h = this.stores.map((i, c) => {
211
- if (this.getLayerAlpha(c) <= 0) return [];
212
- let a = i.getVisibleData(d.from, d.to);
213
- return a.length > m * 2 && (a = K(a, Math.round(m * 1.5))), a;
214
- }), P = /* @__PURE__ */ new Set();
215
- for (const i of h)
216
- for (const c of i) P.add(c.time);
217
- const o = Array.from(P).sort((i, c) => i - c);
218
- if (o.length < 2) return;
219
- const C = h.map((i, c) => {
220
- const a = /* @__PURE__ */ new Map(), S = this.getLayerAlpha(c);
221
- for (const p of i) a.set(p.time, this.effectiveValue(t, c, p.time, p.value) * S);
222
- return a;
223
- }), y = Array.from({ length: this.stores.length }, () => new Array(o.length).fill(0));
224
- for (let i = 0; i < o.length; i++) {
225
- const c = o[i];
226
- let a = 0;
547
+ const { scope: i, timeScale: s, yScale: o } = t, { context: n } = i, r = s.getRange(), { verticalPixelRatio: l } = i, a = this.options.strokeWidth > 0, p = Math.max(1, Math.round(this.options.strokeWidth * l)), f = this.options.curve ?? "straight", y = i.mediaSize.width, h = this.stores.map((c, x) => {
548
+ if (this.getLayerAlpha(x) <= 0) return [];
549
+ let b = c.getVisibleData(r.from, r.to);
550
+ return b.length > y * 2 && (b = j(b, Math.round(y * 1.5))), b;
551
+ }), m = /* @__PURE__ */ new Set();
552
+ for (const c of h)
553
+ for (const x of c) m.add(x.time);
554
+ const u = Array.from(m).sort((c, x) => c - x);
555
+ if (u.length < 2) return;
556
+ const A = h.map((c, x) => {
557
+ const b = /* @__PURE__ */ new Map();
558
+ if (c.length === 0) return b;
559
+ const S = this.getLayerAlpha(x), d = c[0].time;
560
+ for (const T of u) {
561
+ if (T < d) continue;
562
+ const k = U(c, T, (V) => this.effectiveValue(t, x, V.time, V.value));
563
+ k !== null && b.set(T, k * S);
564
+ }
565
+ return b;
566
+ }), R = Array.from({ length: this.stores.length }, () => new Array(u.length).fill(0));
567
+ for (let c = 0; c < u.length; c++) {
568
+ const x = u[c];
569
+ let b = 0;
227
570
  if (e)
228
- for (let p = 0; p < this.stores.length; p++) {
229
- const x = C[p].get(c);
230
- Number.isFinite(x) && (a += x);
571
+ for (let d = 0; d < this.stores.length; d++) {
572
+ const T = A[d].get(x);
573
+ Number.isFinite(T) && (b += T);
231
574
  }
232
575
  let S = 0;
233
- for (let p = 0; p < this.stores.length; p++) {
234
- const x = C[p].get(c), F = Number.isFinite(x) ? x : 0;
235
- S += e && a > 0 ? F / a * 100 : F, y[p][i] = S;
576
+ for (let d = 0; d < this.stores.length; d++) {
577
+ const T = A[d].get(x), k = Number.isFinite(T) ? T : 0;
578
+ S += e && b > 0 ? k / b * 100 : k, R[d][c] = S;
236
579
  }
237
580
  }
238
- const g = this.options.entryAnimation ?? "grow", I = /* @__PURE__ */ new Map();
239
- for (let i = 0; i < o.length; i++) I.set(o[i], i);
240
- const E = Array.from({ length: this.stores.length }, () => []), b = new Array(this.stores.length).fill(1);
241
- for (let i = 0; i < this.stores.length; i++) {
242
- if (this.getLayerAlpha(i) <= 0) continue;
243
- const c = this.unsettledTail(t, i), a = c.length;
244
- if (a === 0) continue;
581
+ const M = this.options.entryAnimation ?? "grow", I = /* @__PURE__ */ new Map();
582
+ for (let c = 0; c < u.length; c++) I.set(u[c], c);
583
+ const F = new Array(this.stores.length).fill(1);
584
+ for (let c = 0; c < this.stores.length; c++) {
585
+ if (this.getLayerAlpha(c) <= 0) continue;
586
+ const x = this.unsettledTail(c), b = x.length;
587
+ if (b === 0) continue;
245
588
  let S = !0;
246
- for (let F = 0; F < a; F++)
247
- if (I.get(c[F].time) !== o.length - a + F) {
589
+ for (let d = 0; d < b; d++)
590
+ if (I.get(x[d].time) !== u.length - b + d) {
248
591
  S = !1;
249
592
  break;
250
593
  }
251
- if (!S) continue;
252
- const p = this.stores[i].getAll(), x = p.length - 1 - a;
253
- x < 0 || I.get(p[x].time) === o.length - a - 1 && (E[i] = c.map((F) => J(F.progress)), b[i] = c[a - 1].progress);
594
+ S && (F[c] = x[b - 1].progress);
254
595
  }
255
- const W = (i, c) => {
256
- const a = c.length;
257
- if (!(a === 0 || i.length < a + 1))
258
- for (let S = 0; S < a; S++) {
259
- const p = i.length - a + S, x = i[p - 1], F = i[p];
260
- i[p] = [U(x[0], F[0], c[S]), U(x[1], F[1], c[S])];
596
+ const z = [];
597
+ if (M === "grow")
598
+ for (let c = u.length - 1; c >= 0; c--) {
599
+ const x = u[c];
600
+ let b = 1, S = !1;
601
+ for (let d = 0; d < this.stores.length; d++) {
602
+ if (this.getLayerAlpha(d) <= 0 || this.entries[d]?.get(x) === void 0) continue;
603
+ const T = this.entranceProgress(d, x);
604
+ T >= 1 || (S = !0, T < b && (b = T));
261
605
  }
262
- }, Y = s.bitmapSize.height;
263
- let N = -1, T = -1;
264
- for (let i = 0; i < this.stores.length; i++)
265
- if (!(this.getLayerAlpha(i) <= 0))
266
- if (N < 0)
267
- N = i;
268
- else {
269
- T = i;
270
- break;
606
+ if (!S) break;
607
+ z.unshift(_(b));
608
+ }
609
+ const D = (c, x) => {
610
+ const b = x.length;
611
+ if (!(b === 0 || c.length < b + 1))
612
+ for (let S = 0; S < b; S++) {
613
+ const d = c.length - b + S, T = c[d - 1], k = c[d];
614
+ c[d] = [Y(T[0], k[0], x[S]), Y(T[1], k[1], x[S])];
271
615
  }
272
- const z = N >= 0 ? this.getLayerAlpha(N) : 1;
273
- for (let i = this.stores.length - 1; i >= 0; i--) {
274
- const c = this.getLayerAlpha(i);
275
- if (c <= 0) continue;
276
- const a = this.stores[i].last()?.value ?? 0, S = this.resolveLayerColor(i, a), p = E[i];
277
- let x = -1;
278
- for (let R = i - 1; R >= 0; R--)
279
- if (this.getLayerAlpha(R) > 0) {
280
- x = R;
616
+ }, N = i.bitmapSize.height;
617
+ let W = -1, E = -1;
618
+ for (let c = 0; c < this.stores.length; c++)
619
+ if (!(this.getLayerAlpha(c) <= 0))
620
+ if (W < 0)
621
+ W = c;
622
+ else {
623
+ E = c;
281
624
  break;
282
625
  }
283
- const F = x >= 0 ? E[x] : [], _ = i === N, H = T >= 0 && i === T && z < 1, X = [];
284
- for (let R = 0; R < o.length; R++) {
285
- const V = i > 0 ? n.valueToBitmapY(y[i - 1][R]) : Y;
286
- let G = V;
287
- _ ? G = Y : H && (G = V + (Y - V) * (1 - z)), X.push([r.timeToBitmapX(o[R]), G]);
626
+ const G = W >= 0 ? this.getLayerAlpha(W) : 1;
627
+ for (let c = this.stores.length - 1; c >= 0; c--) {
628
+ const x = this.getLayerAlpha(c);
629
+ if (x <= 0) continue;
630
+ const b = this.stores[c].last()?.value ?? 0, S = this.resolveLayerColor(c, b), d = c === W, T = E >= 0 && c === E && G < 1, k = [];
631
+ for (let g = 0; g < u.length; g++) {
632
+ const L = c > 0 ? o.valueToBitmapY(R[c - 1][g]) : N;
633
+ let O = L;
634
+ d ? O = N : T && (O = L + (N - L) * (1 - G)), k.push([s.timeToBitmapX(u[g]), O]);
288
635
  }
289
- g === "grow" && W(X, F);
290
- const u = [];
291
- for (let R = 0; R < o.length; R++) {
292
- let V = n.valueToBitmapY(y[i][R]);
293
- _ && c < 1 && (V = Y + (V - Y) * c), u.push([r.timeToBitmapX(o[R]), V]);
636
+ M === "grow" && !d && D(k, z);
637
+ const V = [];
638
+ for (let g = 0; g < u.length; g++) {
639
+ let L = o.valueToBitmapY(R[c][g]);
640
+ d && x < 1 && (L = N + (L - N) * x), V.push([s.timeToBitmapX(u[g]), L]);
294
641
  }
295
- g === "grow" && W(u, p);
296
- const w = $(u), A = Q(w, f, g === "grow" && p.length > 0), O = g === "fade" && b[i] < 1;
297
- if (O && (l.save(), l.globalAlpha = b[i]), this.options.area.visible) {
298
- let R = u[0][1], V = X[0][1];
299
- for (let M = 1; M < u.length; M++)
300
- u[M][1] < R && (R = u[M][1]);
301
- for (let M = 1; M < X.length; M++)
302
- X[M][1] > V && (V = X[M][1]);
303
- let G = D(S, 0.25);
304
- if (V > R + 0.5) {
305
- const M = l.createLinearGradient(0, R, 0, V);
306
- M.addColorStop(0, D(S, 0.25)), M.addColorStop(1, D(S, 0.05)), G = M;
642
+ M === "grow" && D(V, z);
643
+ const X = Z(V), H = q(X, f, M === "grow" && z.length > 0), P = M === "fade" && F[c] < 1;
644
+ if (P && (n.save(), n.globalAlpha *= F[c]), this.options.area.visible && !this.introGhostPass) {
645
+ let g = V[0][1], L = k[0][1];
646
+ for (let w = 1; w < V.length; w++)
647
+ V[w][1] < g && (g = V[w][1]);
648
+ for (let w = 1; w < k.length; w++)
649
+ k[w][1] > L && (L = k[w][1]);
650
+ let O = C(S, 0.25);
651
+ if (L > g + 0.5) {
652
+ const w = n.createLinearGradient(0, g, 0, L);
653
+ w.addColorStop(0, C(S, 0.25)), w.addColorStop(1, C(S, 0.05)), O = w;
307
654
  }
308
- if (l.beginPath(), l.moveTo(w[0].x, w[0].y), tt(l, A), _)
309
- for (let M = X.length - 1; M >= 0; M--)
310
- l.lineTo(X[M][0], X[M][1]);
655
+ if (n.beginPath(), n.moveTo(X[0].x, X[0].y), K(n, H), d)
656
+ for (let w = k.length - 1; w >= 0; w--)
657
+ n.lineTo(k[w][0], k[w][1]);
311
658
  else {
312
- const M = $(X), st = Q(M, f, g === "grow" && F.length > 0), q = M[M.length - 1];
313
- l.lineTo(q.x, q.y), at(l, M, st);
659
+ const w = Z(k), nt = q(w, f, M === "grow" && z.length > 0), J = w[w.length - 1];
660
+ n.lineTo(J.x, J.y), ft(n, w, nt);
314
661
  }
315
- l.closePath(), l.fillStyle = G, l.fill();
662
+ n.closePath(), n.fillStyle = O, n.fill();
663
+ }
664
+ const B = a && x < 1;
665
+ if (B && (n.save(), n.globalAlpha *= x), a && (n.beginPath(), n.moveTo(X[0].x, X[0].y), K(n, H), n.strokeStyle = S, n.lineWidth = p, n.lineJoin = "round", n.lineCap = "round", n.stroke()), B && n.restore(), this.options.points?.visible) {
666
+ const g = x < 1;
667
+ g && (n.save(), n.globalAlpha *= x), this.drawPointMarkers({ context: n, points: X, pixelRatio: i.horizontalPixelRatio, color: S }), g && n.restore();
316
668
  }
317
- const j = k && c < 1;
318
- j && (l.save(), l.globalAlpha *= c), k && (l.beginPath(), l.moveTo(w[0].x, w[0].y), tt(l, A), l.strokeStyle = S, l.lineWidth = B, l.lineJoin = "round", l.lineCap = "round", l.stroke()), j && l.restore(), O && l.restore();
669
+ P && n.restore();
319
670
  }
320
671
  }
321
672
  /**
@@ -324,97 +675,54 @@ class ht extends nt {
324
675
  */
325
676
  drawOverlay(t) {
326
677
  this.tickAnimations(performance.now());
327
- const { scope: e, timeScale: s, yScale: r, crosshair: n, dataInterval: l } = t, d = e, L = this.options.pulseMs, k = L > 0 ? performance.now() / (L * 2 * Math.PI) % 1 : 0;
328
- if (n) {
329
- const B = this.options.stacking, f = 4 * d.horizontalPixelRatio, m = [], h = [];
330
- for (let o = 0; o < this.stores.length; o++) {
331
- const C = this.stores[o].findNearest(n.time, l);
332
- C ? (m.push(C.value), h.push(C.time)) : (m.push(0), h.push(null));
333
- }
334
- const P = [];
335
- if (B === "off")
336
- for (const o of m) P.push(o);
337
- else {
338
- let o = 0;
339
- if (B === "percent")
340
- for (let y = 0; y < m.length; y++)
341
- o += m[y] * this.getLayerAlpha(y);
342
- let C = 0;
343
- for (let y = 0; y < m.length; y++) {
344
- const g = m[y] * this.getLayerAlpha(y);
345
- C += B === "percent" && o > 0 ? g / o * 100 : g, P.push(C);
346
- }
347
- }
348
- for (let o = 0; o < this.stores.length; o++) {
349
- const C = h[o];
350
- if (C === null) continue;
351
- const y = this.getLayerAlpha(o);
352
- if (y <= 0) continue;
353
- const g = this.resolveLayerColor(o, m[o]), I = s.timeToBitmapX(C), E = r.valueToBitmapY(P[o]), b = y < 1;
354
- b && (e.context.save(), e.context.globalAlpha *= y), e.context.save(), e.context.globalAlpha *= 0.25, e.context.beginPath(), e.context.arc(I, E, f + 3 * d.horizontalPixelRatio, 0, Math.PI * 2), e.context.fillStyle = g, e.context.fill(), e.context.restore(), e.context.beginPath(), e.context.arc(I, E, f, 0, Math.PI * 2), e.context.fillStyle = g, e.context.fill(), b && e.context.restore();
678
+ const { scope: e, timeScale: i, yScale: s, crosshair: o, dataInterval: n } = t, r = e, l = this.options.pulseMs, a = l > 0 ? performance.now() / (l * 2 * Math.PI) % 1 : 0;
679
+ if (o) {
680
+ const y = this.options.stacking, h = 4 * r.horizontalPixelRatio;
681
+ for (let m = 0; m < this.stores.length; m++) {
682
+ const u = this.getLayerAlpha(m);
683
+ if (u <= 0) continue;
684
+ const A = this.stores[m].findNearest(o.time, n);
685
+ if (!A) continue;
686
+ const R = this.resolveLayerColor(m, A.value), { x: M, y: I } = y === "off" ? {
687
+ x: i.timeToBitmapX(A.time),
688
+ y: s.valueToBitmapY(this.effectiveValue(t, m, A.time, A.value))
689
+ } : this.stackedPositionAt(t, m, A.time), F = u < 1;
690
+ F && (e.context.save(), e.context.globalAlpha *= u), e.context.save(), e.context.globalAlpha *= 0.25, e.context.beginPath(), e.context.arc(M, I, h + 3 * r.horizontalPixelRatio, 0, Math.PI * 2), e.context.fillStyle = R, e.context.fill(), e.context.restore(), e.context.beginPath(), e.context.arc(M, I, h, 0, Math.PI * 2), e.context.fillStyle = R, e.context.fill(), F && e.context.restore();
355
691
  }
356
692
  }
357
- if (this.hasPulse && L > 0) {
358
- const B = this.options.stacking;
359
- for (let f = 0; f < this.stores.length; f++) {
360
- const m = this.getLayerAlpha(f);
693
+ const p = this.introWave.active && this.introDirectives?.clip !== void 0;
694
+ let f = 1;
695
+ if (p && (f = Math.max(0, (this.introWave.linear() - (1 - $)) / $)), this.hasPulse && l > 0 && f > 0) {
696
+ const y = this.options.stacking;
697
+ for (let h = 0; h < this.stores.length; h++) {
698
+ const m = this.getLayerAlpha(h);
361
699
  if (m <= 0) continue;
362
- const h = this.stores[f].last()?.value ?? 0, P = this.resolveLayerColor(f, h);
363
- if (B === "off") {
364
- const b = this.trailingEndpoint(t, f);
365
- if (!b) continue;
700
+ const u = this.stores[h].last()?.value ?? 0, A = this.resolveLayerColor(h, u);
701
+ if (y === "off") {
702
+ const F = this.trailingEndpoint(t, h);
703
+ if (!F) continue;
366
704
  this.drawPulse({
367
705
  ctx: e.context,
368
- x: b.x,
369
- y: b.y,
370
- color: P,
371
- pixelRatio: d.horizontalPixelRatio,
372
- phase: k,
373
- alpha: m
706
+ x: F.x,
707
+ y: F.y,
708
+ color: A,
709
+ pixelRatio: r.horizontalPixelRatio,
710
+ phase: a,
711
+ alpha: m * f
374
712
  });
375
713
  continue;
376
714
  }
377
- const o = this.stores[f].last();
378
- if (!o) continue;
379
- const C = o.time, y = B === "percent", g = (b) => {
380
- const W = (T) => {
381
- const z = this.getLayerAlpha(T);
382
- if (z <= 0) return 0;
383
- const i = T === f && b === C ? o : this.stores[T].findNearest(b, 0);
384
- return !i || i.time !== b ? 0 : this.effectiveValue(t, T, b, i.value) * z;
385
- };
386
- let Y = 0;
387
- if (y)
388
- for (let T = 0; T < this.stores.length; T++)
389
- Y += W(T);
390
- let N = 0;
391
- for (let T = 0; T <= f; T++) {
392
- const z = W(T);
393
- N += y && Y > 0 ? z / Y * 100 : z;
394
- }
395
- return N;
396
- };
397
- let I = s.timeToBitmapX(C), E = r.valueToBitmapY(g(C));
398
- if ((this.options.entryAnimation ?? "grow") === "grow") {
399
- const b = this.unsettledTail(t, f), W = this.stores[f].getAll(), Y = W.length - 1 - b.length;
400
- if (b.length > 0 && Y >= 0) {
401
- const N = W[Y];
402
- let T = s.timeToBitmapX(N.time), z = r.valueToBitmapY(g(N.time));
403
- for (let i = 0; i < b.length; i++) {
404
- const c = W[Y + 1 + i], a = J(b[i].progress), S = s.timeToBitmapX(c.time), p = r.valueToBitmapY(g(c.time));
405
- T = U(T, S, a), z = U(z, p, a);
406
- }
407
- I = T, E = z;
408
- }
409
- }
715
+ const R = this.stores[h].last();
716
+ if (!R) continue;
717
+ const { x: M, y: I } = this.stackedPositionAt(t, h, R.time);
410
718
  this.drawPulse({
411
719
  ctx: e.context,
412
- x: I,
413
- y: E,
414
- color: P,
415
- pixelRatio: d.horizontalPixelRatio,
416
- phase: k,
417
- alpha: m
720
+ x: M,
721
+ y: I,
722
+ color: A,
723
+ pixelRatio: r.horizontalPixelRatio,
724
+ phase: a,
725
+ alpha: m * f
418
726
  });
419
727
  }
420
728
  }
@@ -422,25 +730,25 @@ class ht extends nt {
422
730
  drawPulse({
423
731
  ctx: t,
424
732
  x: e,
425
- y: s,
426
- color: r,
427
- pixelRatio: n,
428
- phase: l,
429
- alpha: d = 1
733
+ y: i,
734
+ color: s,
735
+ pixelRatio: o,
736
+ phase: n,
737
+ alpha: r = 1
430
738
  }) {
431
- const L = 3 * n, k = 0.4 + 0.6 * Math.abs(Math.sin(l * 2 * Math.PI)), B = L + 4 * n * k, f = d < 1;
432
- f && (t.save(), t.globalAlpha *= d), t.beginPath(), t.arc(e, s, B, 0, Math.PI * 2), t.fillStyle = D(r, k * 0.3), t.fill(), t.beginPath(), t.arc(e, s, L, 0, Math.PI * 2), t.fillStyle = r, t.fill(), f && t.restore();
739
+ const l = 3 * o, a = 0.4 + 0.6 * Math.abs(Math.sin(n * 2 * Math.PI)), p = l + 4 * o * a, f = r < 1;
740
+ f && (t.save(), t.globalAlpha *= r), t.beginPath(), t.arc(e, i, p, 0, Math.PI * 2), t.fillStyle = C(s, a * 0.3), t.fill(), t.beginPath(), t.arc(e, i, l, 0, Math.PI * 2), t.fillStyle = s, t.fill(), f && t.restore();
433
741
  }
434
742
  }
435
- const xt = {
743
+ const Pt = {
436
744
  type: "line",
437
- create: ({ theme: v, layerCount: t }, e) => new ht(t, {
745
+ create: ({ theme: v, layerCount: t }, e) => new mt(t, {
438
746
  colors: t === 1 ? [v.line.color] : v.seriesColors.slice(0, t),
439
747
  strokeWidth: v.line.width,
440
748
  ...e
441
749
  })
442
750
  };
443
751
  export {
444
- ht as LineRenderer,
445
- xt as LineSeriesDef
752
+ mt as LineRenderer,
753
+ Pt as LineSeriesDef
446
754
  };