@wick-charts/vue 0.6.4 → 0.8.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 (55) hide show
  1. package/README.md +21 -7
  2. package/dist/BandSeries.vue.js +20 -18
  3. package/dist/BarSeries.vue.js +15 -13
  4. package/dist/CandlestickSeries.vue.js +31 -29
  5. package/dist/ChartContainer.vue.js +77 -70
  6. package/dist/LineSeries.vue.js +19 -17
  7. package/dist/composables.js +46 -36
  8. package/dist/core/dist/animation/viewport-engine.js +155 -96
  9. package/dist/core/dist/axis/dom-labels.js +56 -51
  10. package/dist/core/dist/chart/scale-guards.js +23 -5
  11. package/dist/core/dist/chart/x-guards.js +37 -0
  12. package/dist/core/dist/chart.js +1286 -843
  13. package/dist/core/dist/data/sync.js +37 -31
  14. package/dist/core/dist/navigator/controller.js +37 -37
  15. package/dist/core/dist/perf/perf-hud.js +3 -3
  16. package/dist/core/dist/scales/tick-tracker.js +2 -2
  17. package/dist/core/dist/scales/x-scale.js +167 -53
  18. package/dist/core/dist/scales/y-scale.js +36 -34
  19. package/dist/core/dist/series/band.js +266 -213
  20. package/dist/core/dist/series/bar.js +297 -291
  21. package/dist/core/dist/series/base-multi-layer.js +283 -237
  22. package/dist/core/dist/series/candlestick.js +1 -0
  23. package/dist/core/dist/series/line.js +21 -20
  24. package/dist/core/dist/snapshots.js +55 -43
  25. package/dist/index.d.ts +323 -58
  26. package/dist/index.js +9 -9
  27. package/dist/ui/Crosshair.vue.js +51 -27
  28. package/dist/ui/InfoBar.vue.js +37 -37
  29. package/dist/ui/Marker.vue.js +14 -11
  30. package/dist/ui/Navigator.vue.js +23 -23
  31. package/dist/ui/ReferenceLine.vue.js +19 -16
  32. package/dist/ui/Tooltip.vue.js +91 -86
  33. package/dist/ui/XAxis.vue.js +48 -0
  34. package/dist/ui/XAxis.vue2.js +4 -0
  35. package/dist/ui/YAxis.vue.js +44 -28
  36. package/dist/ui/YLabel.vue.js +78 -74
  37. package/package.json +9 -3
  38. package/src/BandSeries.vue +11 -6
  39. package/src/BarSeries.vue +13 -6
  40. package/src/CandlestickSeries.vue +9 -5
  41. package/src/ChartContainer.vue +20 -0
  42. package/src/LineSeries.vue +13 -6
  43. package/src/composables.ts +23 -4
  44. package/src/index.ts +8 -1
  45. package/src/ui/Crosshair.vue +41 -1
  46. package/src/ui/InfoBar.vue +2 -1
  47. package/src/ui/Marker.vue +5 -1
  48. package/src/ui/Navigator.vue +2 -1
  49. package/src/ui/ReferenceLine.vue +5 -1
  50. package/src/ui/Tooltip.vue +7 -4
  51. package/src/ui/{TimeAxis.vue → XAxis.vue} +18 -5
  52. package/src/ui/YAxis.vue +66 -12
  53. package/src/ui/YLabel.vue +35 -5
  54. package/dist/ui/TimeAxis.vue.js +0 -44
  55. package/dist/ui/TimeAxis.vue2.js +0 -4
@@ -1,12 +1,12 @@
1
1
  import { Animator as I } from "../animation/animator.js";
2
- import { DEFAULT_HISTORY_REVEAL as F, DEFAULT_BAND_INTRO as z, DEFAULT_BAND_SMOOTH as _, DEFAULT_BAND_ENTRY as O } from "../animation/config.js";
3
- import { easeOutCubic as $ } from "../animation/easing.js";
4
- import { IntroWave as D } from "../animation/intro-wave.js";
5
- import { ScalarSpring as N } from "../animation/scalar-spring.js";
6
- import { decimateBandData as Y } from "../data/decimation.js";
2
+ import { DEFAULT_HISTORY_REVEAL as z, DEFAULT_BAND_INTRO as F, DEFAULT_BAND_SMOOTH as O, DEFAULT_BAND_ENTRY as _ } from "../animation/config.js";
3
+ import { easeOutCubic as Y } from "../animation/easing.js";
4
+ import { IntroWave as N } from "../animation/intro-wave.js";
5
+ import { ScalarSpring as S } from "../animation/scalar-spring.js";
6
+ import { decimateBandData as $ } from "../data/decimation.js";
7
7
  import { TimeSeriesStore as H } from "../data/store.js";
8
- import { resolveColor as U, hexToRgba as A } from "../utils/color.js";
9
- import { lerp as P } from "../utils/math.js";
8
+ import { resolveColor as U, hexToRgba as T } from "../utils/color.js";
9
+ import { lerp as L } from "../utils/math.js";
10
10
  import { normalizeTime as W } from "../utils/time.js";
11
11
  import { unfoldIntro as J, scaleMean as j, backfillSweepIntro as G } from "./line-intro.js";
12
12
  import { buildCurveSegments as B, replaySegmentsForward as R, replaySegmentsReversed as Q } from "./painters/canvas-path.js";
@@ -16,62 +16,62 @@ const Z = {
16
16
  stroke: { visible: !0, width: 1, color: void 0 },
17
17
  curve: "straight",
18
18
  entryAnimation: "grow",
19
- entryMs: O,
20
- smoothMs: _,
21
- introMs: z,
22
- historyRevealMs: F,
19
+ entryMs: _,
20
+ smoothMs: O,
21
+ introMs: F,
22
+ historyRevealMs: z,
23
23
  introAnimation: void 0,
24
24
  historyReveal: void 0
25
25
  }, q = 0.4, K = 0.04, E = 0.6, tt = G();
26
- function S(l, t) {
27
- return l === !1 ? 0 : l ?? t;
26
+ function k(a, t) {
27
+ return a === !1 ? 0 : a ?? t;
28
28
  }
29
- function V(l, t) {
29
+ function V(a, t) {
30
30
  const i = t.stroke;
31
31
  return {
32
- colors: t.colors ?? l.colors,
33
- fill: "fill" in t ? t.fill : l.fill,
32
+ colors: t.colors ?? a.colors,
33
+ fill: "fill" in t ? t.fill : a.fill,
34
34
  stroke: {
35
- visible: i?.visible ?? l.stroke.visible,
36
- width: i?.width ?? l.stroke.width,
37
- color: i !== void 0 && "color" in i ? i.color : l.stroke.color
35
+ visible: i?.visible ?? a.stroke.visible,
36
+ width: i?.width ?? a.stroke.width,
37
+ color: i !== void 0 && "color" in i ? i.color : a.stroke.color
38
38
  },
39
- curve: t.curve ?? l.curve,
40
- entryAnimation: t.entryAnimation ?? l.entryAnimation,
41
- entryMs: S(t.entryMs, l.entryMs),
42
- smoothMs: S(t.smoothMs, l.smoothMs),
43
- introMs: S(t.introMs, l.introMs),
44
- historyRevealMs: S(t.historyRevealMs, l.historyRevealMs),
45
- introAnimation: "introAnimation" in t ? t.introAnimation : l.introAnimation,
46
- historyReveal: "historyReveal" in t ? t.historyReveal : l.historyReveal
39
+ curve: t.curve ?? a.curve,
40
+ entryAnimation: t.entryAnimation ?? a.entryAnimation,
41
+ entryMs: k(t.entryMs, a.entryMs),
42
+ smoothMs: k(t.smoothMs, a.smoothMs),
43
+ introMs: k(t.introMs, a.introMs),
44
+ historyRevealMs: k(t.historyRevealMs, a.historyRevealMs),
45
+ introAnimation: "introAnimation" in t ? t.introAnimation : a.introAnimation,
46
+ historyReveal: "historyReveal" in t ? t.historyReveal : a.historyReveal
47
47
  };
48
48
  }
49
- const et = (l, t, i) => l + (t - l) * i;
50
- function L(l) {
51
- return l <= 0 ? 0 : l >= 1 ? 1 : l;
49
+ const et = (a, t, i) => a + (t - a) * i;
50
+ function P(a) {
51
+ return a <= 0 ? 0 : a >= 1 ? 1 : a;
52
52
  }
53
- function T(l) {
54
- const t = W(l.time), { low: i, high: e } = l;
55
- return !Number.isFinite(i) || !Number.isFinite(e) ? { ...l, time: t, low: Number.NaN, high: Number.NaN } : { ...l, time: t, low: Math.min(i, e), high: Math.max(i, e) };
53
+ function A(a) {
54
+ const t = W(a.time), { low: i, high: e } = a;
55
+ return !Number.isFinite(i) || !Number.isFinite(e) ? { ...a, time: t, low: Number.NaN, high: Number.NaN } : { ...a, time: t, low: Math.min(i, e), high: Math.max(i, e) };
56
56
  }
57
- function b(l) {
58
- return !Number.isFinite(l.low);
57
+ function b(a) {
58
+ return !Number.isFinite(a.low);
59
59
  }
60
- function x(l) {
61
- return { low: l.low, high: l.high };
60
+ function x(a) {
61
+ return { low: a.low, high: a.high };
62
62
  }
63
- function it(l) {
64
- const { upperSegs: t, lowerSegs: i } = l;
63
+ function it(a) {
64
+ const { upperSegs: t, lowerSegs: i } = a;
65
65
  for (let e = 0; e < t.length; e++) {
66
66
  const o = t[e], s = i[e];
67
67
  if (o.kind !== "bezier" || s.kind !== "bezier") continue;
68
- const n = C(o.cp1y, s.cp1y), a = C(o.cp2y, s.cp2y);
69
- t[e] = { ...o, cp1y: n.top, cp2y: a.top }, i[e] = { ...s, cp1y: n.bottom, cp2y: a.bottom };
68
+ const n = C(o.cp1y, s.cp1y), l = C(o.cp2y, s.cp2y);
69
+ t[e] = { ...o, cp1y: n.top, cp2y: l.top }, i[e] = { ...s, cp1y: n.bottom, cp2y: l.bottom };
70
70
  }
71
71
  }
72
- function C(l, t) {
73
- if (l <= t) return { top: l, bottom: t };
74
- const i = (l + t) / 2;
72
+ function C(a, t) {
73
+ if (a <= t) return { top: a, bottom: t };
74
+ const i = (a + t) / 2;
75
75
  return { top: i, bottom: i };
76
76
  }
77
77
  class ot {
@@ -88,17 +88,19 @@ class ot {
88
88
  * new point lands.
89
89
  */
90
90
  pinned = null;
91
+ /** Per-point eases started by `morphData`, keyed by point time; pruned on settle. */
92
+ morphs = /* @__PURE__ */ new Map();
91
93
  }
92
94
  class st {
93
95
  kind = "band";
94
96
  #e;
95
97
  #t;
96
98
  /** Per-layer colors carried in `data` (sparse); kept apart so a theme swap leaves them alone. */
97
- #p = [];
99
+ #f = [];
98
100
  /** Initial-load reveal, armed once on the empty → non-empty seed and shared by every layer. */
99
- #i = new D();
101
+ #i = new N();
100
102
  /** History-prepend reveal, armed by {@link prependPoints}. */
101
- #o = new D();
103
+ #o = new N();
102
104
  /** Prepended span: `from` = deepest new point, `to` = the pre-prepend first point. */
103
105
  #s = null;
104
106
  #a = null;
@@ -119,23 +121,61 @@ class st {
119
121
  setData(t, i = 0) {
120
122
  const e = this.#t[i];
121
123
  if (!e) return;
122
- const o = this.#t.some((a) => a.store.length > 0), s = (t ?? []).map(T);
124
+ const o = this.#t.some((l) => l.store.length > 0), s = (t ?? []).map(A);
123
125
  e.store.setData(s), !o && s.length > 0 && this.#i.arm(this.#e.introMs);
124
126
  const n = e.store.last();
125
- e.displayedLast = n ? x(n) : null, e.chase = null, e.pinned = null, e.entries.clear(), this.#o.finish(), this.#s = null;
127
+ e.displayedLast = n ? x(n) : null, e.chase = null, e.pinned = null, e.morphs.clear(), e.entries.clear(), this.#o.finish(), this.#s = null;
128
+ }
129
+ /**
130
+ * Replace a layer like {@link setData}, but ease each sample that keeps its
131
+ * `time` from the edges on screen to its new ones over `smoothMs`; a sample
132
+ * with a new `time` plays its entrance.
133
+ */
134
+ morphData(t, i = 0) {
135
+ const e = this.#t[i];
136
+ if (!e) return;
137
+ if (!this.#t.some((h) => h.store.length > 0)) {
138
+ this.setData(t, i);
139
+ return;
140
+ }
141
+ const o = /* @__PURE__ */ new Map();
142
+ for (const h of e.store.getAll())
143
+ o.set(h.time, this.#u(e, h));
144
+ const s = (t ?? []).map(A);
145
+ e.store.setData(s);
146
+ const n = this.#e.smoothMs, l = this.#e.entryAnimation !== "none" && this.#e.entryMs > 0, r = /* @__PURE__ */ new Map();
147
+ for (const h of s) {
148
+ const u = o.get(h.time);
149
+ if (u === void 0) {
150
+ l && e.entries.set(h.time, performance.now());
151
+ continue;
152
+ }
153
+ if (u.low === h.low && u.high === h.high || n <= 0 || b(h) || !Number.isFinite(u.low)) continue;
154
+ const g = e.morphs.get(h.time) ?? {
155
+ low: new S(u.low),
156
+ high: new S(u.high)
157
+ };
158
+ g.low.target !== h.low && g.low.retarget(h.low, { settleMs: n }), g.high.target !== h.high && g.high.retarget(h.high, { settleMs: n }), r.set(h.time, g);
159
+ }
160
+ const c = new Set(s.map((h) => h.time));
161
+ for (const h of e.entries.keys())
162
+ c.has(h) || e.entries.delete(h);
163
+ e.morphs = r;
164
+ const p = e.store.last();
165
+ e.displayedLast = p ? x(p) : null, e.chase = null, e.pinned = null;
126
166
  }
127
167
  appendPoint(t, i = 0) {
128
168
  const e = this.#t[i];
129
169
  if (!e) return;
130
- const o = T(t), s = e.store.last(), n = e.store.length;
170
+ const o = A(t), s = e.store.last(), n = e.store.length;
131
171
  e.store.append(o);
132
- const a = e.store.length > n;
133
- e.chase !== null && s !== void 0 && a && (e.pinned = { time: s.time, chase: e.chase }), e.displayedLast = x(o), e.chase = null, this.#e.entryAnimation !== "none" && this.#e.entryMs > 0 && e.entries.set(o.time, performance.now());
172
+ const l = e.store.length > n;
173
+ e.chase !== null && s !== void 0 && l && (e.pinned = { time: s.time, chase: e.chase }), e.displayedLast = x(o), e.chase = null, this.#e.entryAnimation !== "none" && this.#e.entryMs > 0 && e.entries.set(o.time, performance.now());
134
174
  }
135
175
  prependPoints(t, i = 0) {
136
176
  const e = this.#t[i];
137
177
  if (!e || t.length === 0) return;
138
- const o = t.map(T), s = e.store.first()?.time;
178
+ const o = t.map(A), s = e.store.first()?.time;
139
179
  e.store.prepend(o), this.#A(o[0]?.time, s);
140
180
  }
141
181
  /** While a reveal is in flight only the range grows — a restart would hide half-revealed points again. */
@@ -152,18 +192,20 @@ class st {
152
192
  updateLastPoint(t, i = 0) {
153
193
  const e = this.#t[i];
154
194
  if (!e) return;
155
- const o = T(t);
195
+ const o = A(t), s = e.store.last()?.time;
156
196
  e.store.updateLast(o);
157
- const s = this.#e.smoothMs;
158
- if (s <= 0 || b(o)) {
197
+ const n = s === void 0 ? void 0 : e.morphs.get(s);
198
+ s !== void 0 && n !== void 0 && (e.morphs.delete(s), e.displayedLast = { low: n.low.current, high: n.high.current }, e.chase = n);
199
+ const l = this.#e.smoothMs;
200
+ if (l <= 0 || b(o)) {
159
201
  e.displayedLast = x(o), e.chase = null;
160
202
  return;
161
203
  }
162
204
  if (e.chase === null) {
163
- const n = e.displayedLast, a = n !== null && Number.isFinite(n.low) ? n : x(o);
164
- e.chase = { low: new N(a.low), high: new N(a.high) };
205
+ const r = e.displayedLast, c = r !== null && Number.isFinite(r.low) ? r : x(o);
206
+ e.chase = { low: new S(c.low), high: new S(c.high) };
165
207
  }
166
- e.chase.low.retarget(o.low, { settleMs: s }), e.chase.high.retarget(o.high, { settleMs: s });
208
+ e.chase.low.retarget(o.low, { settleMs: l }), e.chase.high.retarget(o.high, { settleMs: l });
167
209
  }
168
210
  keepLast(t, i = 0) {
169
211
  const e = this.#t[i];
@@ -182,19 +224,19 @@ class st {
182
224
  return this.#t[t]?.store.isVisible() ?? !0;
183
225
  }
184
226
  setColorOverrides(t) {
185
- this.#p = t;
227
+ this.#f = t;
186
228
  }
187
229
  /** Representative color per layer — a value-fn resolves at the layer's last midpoint. */
188
230
  getLayerColors() {
189
231
  return this.#t.map((t, i) => this.#r(i));
190
232
  }
191
233
  #r(t) {
192
- const i = this.#p[t], e = this.#e.colors, o = i ?? e[t % e.length], s = this.#t[t]?.store.last(), n = s !== void 0 && !b(s) ? (s.low + s.high) / 2 : 0;
234
+ const i = this.#f[t], e = this.#e.colors, o = i ?? e[t % e.length], s = this.#t[t]?.store.last(), n = s !== void 0 && !b(s) ? (s.low + s.high) / 2 : 0;
193
235
  return U(o, n);
194
236
  }
195
237
  // --- Animation ------------------------------------------------------------
196
238
  /** Advance owned animators. Called by both passes; every clock samples `now`, so a second tick is a no-op. */
197
- #f(t) {
239
+ #g(t) {
198
240
  this.#i.tick(t), this.#o.tick(t);
199
241
  for (const i of this.#t)
200
242
  i.alpha.tick(t), this.#S(i, t), this.#T(i, t);
@@ -210,6 +252,10 @@ class st {
210
252
  const s = o.chase.low.tick(i), n = o.chase.high.tick(i);
211
253
  !s && !n && (t.pinned = null);
212
254
  }
255
+ for (const [s, n] of t.morphs) {
256
+ const l = n.low.tick(i), r = n.high.tick(i);
257
+ !l && !r && t.morphs.delete(s);
258
+ }
213
259
  }
214
260
  #T(t, i) {
215
261
  const e = this.#e.entryMs;
@@ -220,15 +266,15 @@ class st {
220
266
  for (const [o, s] of t.entries)
221
267
  i - s >= e && t.entries.delete(o);
222
268
  }
223
- #g(t, i) {
269
+ #d(t, i) {
224
270
  const e = t.entries.get(i), o = this.#e.entryMs;
225
- return e === void 0 || o <= 0 ? 1 : L((performance.now() - e) / o);
271
+ return e === void 0 || o <= 0 ? 1 : P((performance.now() - e) / o);
226
272
  }
227
273
  /** Trailing points whose entrance is unsettled, oldest first; stops at the first settled one. */
228
- #P(t) {
274
+ #k(t) {
229
275
  const i = t.store.getAll(), e = [];
230
276
  for (let o = i.length - 1; o >= 1; o--) {
231
- const s = this.#g(t, i[o].time);
277
+ const s = this.#d(t, i[o].time);
232
278
  if (s >= 1) break;
233
279
  e.unshift({ time: i[o].time, progress: s });
234
280
  }
@@ -236,8 +282,10 @@ class st {
236
282
  }
237
283
  get needsAnimation() {
238
284
  if (this.#i.active || this.#o.active) return !0;
239
- for (const t of this.#t)
240
- if (t.alpha.animating || t.chase !== null || t.pinned !== null || t.entries.size > 0) return !0;
285
+ for (const t of this.#t) {
286
+ const i = t.chase !== null || t.pinned !== null || t.morphs.size > 0;
287
+ if (t.alpha.animating || i || t.entries.size > 0) return !0;
288
+ }
241
289
  return !1;
242
290
  }
243
291
  getIntroFront() {
@@ -263,24 +311,26 @@ class st {
263
311
  return this.#t[t]?.alpha.current ?? 1;
264
312
  }
265
313
  // --- Geometry -------------------------------------------------------------
266
- /** Stored edges with the live chase applied: the last point, or the pinned chase on the point an append displaced. */
267
- #d(t, i) {
268
- const e = t.store.last();
269
- if (e !== void 0 && i.time === e.time) return t.displayedLast ?? x(i);
270
- const o = t.pinned;
271
- return o !== null && o.time === i.time ? { low: o.chase.low.current, high: o.chase.high.current } : x(i);
314
+ /** Stored edges with the live chase applied: a morph ease, the last point, or the pinned chase on the point an append displaced. */
315
+ #u(t, i) {
316
+ const e = t.morphs.get(i.time);
317
+ if (e !== void 0) return { low: e.low.current, high: e.high.current };
318
+ const o = t.store.last();
319
+ if (o !== void 0 && i.time === o.time) return t.displayedLast ?? x(i);
320
+ const s = t.pinned;
321
+ return s !== null && s.time === i.time ? { low: s.chase.low.current, high: s.chase.high.current } : x(i);
272
322
  }
273
323
  /** The active intro / history value transform for one sample, or `null` when none applies. */
274
- #R(t, i, e) {
324
+ #L(t, i, e) {
275
325
  const o = this.#o.active ? this.#n?.value : void 0, s = this.#s;
276
326
  if (o !== void 0 && s !== null && e < s.to) {
277
- const m = s.to - s.from, f = m > 0 ? L((s.to - e) / m) : 0;
278
- return (u) => o({ layerIndex: i, time: e, value: u, position: f });
327
+ const p = s.to - s.from, h = p > 0 ? P((s.to - e) / p) : 0;
328
+ return (u) => o({ layerIndex: i, time: e, value: u, position: h });
279
329
  }
280
330
  const n = this.#i.active ? this.#a?.value : void 0;
281
331
  if (n === void 0) return null;
282
- const a = t.timeScale.getRange(), r = a.to - a.from, c = r > 0 ? L((e - a.from) / r) : 0;
283
- return (m) => n({ layerIndex: i, time: e, value: m, position: c });
332
+ const l = t.timeScale.getRange(), r = l.to - l.from, c = r > 0 ? P((e - l.from) / r) : 0;
333
+ return (p) => n({ layerIndex: i, time: e, value: p, position: c });
284
334
  }
285
335
  /**
286
336
  * Where a sample draws this frame, or `null` for a gap (non-finite, or an
@@ -290,10 +340,10 @@ class st {
290
340
  #l(t, i, e) {
291
341
  const { timeScale: o, yScale: s } = t;
292
342
  if (b(e) || !s.isPlottable(e.low) || !s.isPlottable(e.high)) return null;
293
- const n = this.#t[i], a = this.#d(n, e), r = this.#R(t, i, e.time), c = r === null ? a.low : r(a.low), m = r === null ? a.high : r(a.high);
294
- if (!s.isPlottable(c) || !s.isPlottable(m)) return null;
295
- const f = s.valueToBitmapYExact(c), u = s.valueToBitmapYExact(m);
296
- return { x: o.timeToBitmapXExact(e.time), top: Math.min(f, u), bottom: Math.max(f, u) };
343
+ const n = this.#t[i], l = this.#u(n, e), r = this.#L(t, i, e.time), c = r === null ? l.low : r(l.low), p = r === null ? l.high : r(l.high);
344
+ if (!s.isPlottable(c) || !s.isPlottable(p)) return null;
345
+ const h = s.valueToBitmapYExact(c), u = s.valueToBitmapYExact(p);
346
+ return { x: o.timeToBitmapXExact(e.time), top: Math.min(h, u), bottom: Math.max(h, u) };
297
347
  }
298
348
  /**
299
349
  * Rendered vertices of the layer's still-entering tail, keyed by time. Each
@@ -302,29 +352,29 @@ class st {
302
352
  */
303
353
  #v(t, i) {
304
354
  if (this.#e.entryAnimation !== "grow") return null;
305
- const e = this.#t[i], o = this.#P(e);
355
+ const e = this.#t[i], o = this.#k(e);
306
356
  if (o.length === 0) return null;
307
357
  const s = e.store.getAll(), n = s.length - 1 - o.length;
308
358
  if (n < 0) return null;
309
- const a = this.#l(t, i, s[n]);
310
- if (a === null) return null;
359
+ const l = this.#l(t, i, s[n]);
360
+ if (l === null) return null;
311
361
  const r = /* @__PURE__ */ new Map();
312
- let c = a;
313
- for (let m = 0; m < o.length; m++) {
314
- const f = s[n + 1 + m], u = this.#l(t, i, f);
362
+ let c = l;
363
+ for (let p = 0; p < o.length; p++) {
364
+ const h = s[n + 1 + p], u = this.#l(t, i, h);
315
365
  if (u === null) return null;
316
- const v = $(o[m].progress), y = {
317
- x: P(c.x, u.x, v),
318
- top: P(c.top, u.top, v),
319
- bottom: P(c.bottom, u.bottom, v)
366
+ const g = Y(o[p].progress), w = {
367
+ x: L(c.x, u.x, g),
368
+ top: L(c.top, u.top, g),
369
+ bottom: L(c.bottom, u.bottom, g)
320
370
  };
321
- r.set(f.time, y), c = y;
371
+ r.set(h.time, w), c = w;
322
372
  }
323
373
  return r;
324
374
  }
325
375
  // --- Rendering ------------------------------------------------------------
326
376
  render(t) {
327
- this.#f(performance.now());
377
+ this.#g(performance.now());
328
378
  const { context: i } = t.scope;
329
379
  this.#n = null;
330
380
  const e = this.#s;
@@ -333,137 +383,137 @@ class st {
333
383
  n !== "none" && (this.#n = n(this.#C(t, e)));
334
384
  }
335
385
  const o = this.#n;
336
- this.#y(t, o?.ghostAlpha ?? 0);
386
+ this.#w(t, o?.ghostAlpha ?? 0);
337
387
  const s = this.#D(t, o, e);
338
- this.#i.active ? this.#L(t) : (this.#a = null, this.#u(t)), s && i.restore();
388
+ this.#i.active ? this.#R(t) : (this.#a = null, this.#m(t)), s && i.restore();
339
389
  }
340
- #L(t) {
341
- const i = (this.#e.introAnimation ?? this.#k())(this.#V(t));
342
- this.#a = i, this.#y(t, i.ghostAlpha ?? 0);
343
- const { context: e } = t.scope, { width: o, height: s } = t.scope.bitmapSize, n = i.clip, a = n !== void 0 && (n.fromX !== void 0 || n.toX !== void 0);
344
- if (a) {
390
+ #R(t) {
391
+ const i = (this.#e.introAnimation ?? this.#P())(this.#V(t));
392
+ this.#a = i, this.#w(t, i.ghostAlpha ?? 0);
393
+ const { context: e } = t.scope, { width: o, height: s } = t.scope.bitmapSize, n = i.clip, l = n !== void 0 && (n.fromX !== void 0 || n.toX !== void 0);
394
+ if (l) {
345
395
  const r = n.fromX ?? 0, c = n.toX ?? o;
346
396
  e.save(), e.beginPath(), e.rect(r, 0, Math.max(0, c - r), s), e.clip();
347
397
  }
348
- this.#u(t), a && e.restore();
398
+ this.#m(t), l && e.restore();
349
399
  }
350
- #k() {
400
+ #P() {
351
401
  return this.#h === null && (this.#h = J()), this.#h;
352
402
  }
353
403
  /** Edges-only skeleton under the main pass, so a clip reveal never reads as an empty chart. */
354
- #y(t, i) {
404
+ #w(t, i) {
355
405
  if (i <= 0) return;
356
406
  const { context: e } = t.scope;
357
- e.save(), e.globalAlpha *= i, this.#c = !0, this.#u(t), this.#c = !1, e.restore();
407
+ e.save(), e.globalAlpha *= i, this.#c = !0, this.#m(t), this.#c = !1, e.restore();
358
408
  }
359
409
  /** History clip, mapped from reveal space (`x = 0` at the data boundary) to bitmap space. */
360
410
  #D(t, i, e) {
361
411
  const o = i?.clip;
362
412
  if (o === void 0 || e === null || o.fromX === void 0 && o.toX === void 0) return !1;
363
- const { context: s } = t.scope, { width: n, height: a } = t.scope.bitmapSize, r = t.timeScale.timeToBitmapXExact(e.to), c = Math.abs(r - t.timeScale.timeToBitmapXExact(e.from)), m = Math.max(2, this.#e.stroke.width * t.scope.horizontalPixelRatio), f = o.fromX ?? 0, u = o.toX ?? c;
364
- return s.save(), s.beginPath(), s.rect(r - u - m, 0, Math.max(0, u - f + m), a), s.rect(r, 0, Math.max(0, n - r), a), s.clip(), !0;
413
+ const { context: s } = t.scope, { width: n, height: l } = t.scope.bitmapSize, r = t.timeScale.timeToBitmapXExact(e.to), c = Math.abs(r - t.timeScale.timeToBitmapXExact(e.from)), p = Math.max(2, this.#e.stroke.width * t.scope.horizontalPixelRatio), h = o.fromX ?? 0, u = o.toX ?? c;
414
+ return s.save(), s.beginPath(), s.rect(r - u - p, 0, Math.max(0, u - h + p), l), s.rect(r, 0, Math.max(0, n - r), l), s.clip(), !0;
365
415
  }
366
- #u(t) {
416
+ #m(t) {
367
417
  for (let i = 0; i < this.#t.length; i++)
368
418
  this.#N(t, i);
369
419
  }
370
420
  #N(t, i) {
371
421
  const e = this.#t[i], o = e.alpha.current;
372
422
  if (o <= 0) return;
373
- const { scope: s, timeScale: n } = t, a = n.getRange();
374
- let r = e.store.getVisibleData(a.from, a.to);
375
- if (r.length > s.mediaSize.width * 2 && (r = Y(r, Math.round(s.mediaSize.width * 1.5))), r.length === 0) return;
376
- const c = r[r.length - 1], m = this.#w(e, r), f = m ? this.#v(t, i) : null, u = this.#B(t, { layerIndex: i, data: r, grown: f });
423
+ const { scope: s, timeScale: n } = t, l = n.getRange();
424
+ let r = e.store.getVisibleData(l.from, l.to);
425
+ if (r.length > s.mediaSize.width * 2 && (r = $(r, Math.round(s.mediaSize.width * 1.5))), r.length === 0) return;
426
+ const c = r[r.length - 1], p = this.#y(e, r), h = p ? this.#v(t, i) : null, u = this.#B(t, { layerIndex: i, data: r, grown: h });
377
427
  if (u.length === 0) return;
378
- const v = m ? this.#g(e, c.time) : 1, y = m && !b(c) && this.#e.entryAnimation === "fade" && v < 1 ? nt(u) : null, { context: h } = s;
379
- h.save(), o < 1 && (h.globalAlpha *= o);
380
- const p = this.#r(i), d = { ctx: t, runs: u, color: p, growing: f !== null };
381
- if (y === null)
382
- this.#m(d);
428
+ const g = p ? this.#d(e, c.time) : 1, w = p && !b(c) && this.#e.entryAnimation === "fade" && g < 1 ? nt(u) : null, { context: m } = s;
429
+ m.save(), o < 1 && (m.globalAlpha *= o);
430
+ const f = this.#r(i), v = { ctx: t, runs: u, color: f, growing: h !== null };
431
+ if (w === null)
432
+ this.#p(v);
383
433
  else {
384
- const { width: g, height: w } = s.bitmapSize;
385
- h.save(), h.beginPath(), h.rect(0, 0, y, w), h.clip(), this.#m(d), h.restore(), h.save(), h.beginPath(), h.rect(y, 0, Math.max(0, g - y), w), h.clip(), h.globalAlpha *= v, this.#m(d), h.restore();
434
+ const { width: d, height: y } = s.bitmapSize;
435
+ m.save(), m.beginPath(), m.rect(0, 0, w, y), m.clip(), this.#p(v), m.restore(), m.save(), m.beginPath(), m.rect(w, 0, Math.max(0, d - w), y), m.clip(), m.globalAlpha *= g, this.#p(v), m.restore();
386
436
  }
387
- h.restore();
437
+ m.restore();
388
438
  }
389
439
  /** Split the visible slice into runs of drawable vertices; a gap ends a run. */
390
440
  /**
391
441
  * Whether a visible slice ends at the live point. Panned into history, the
392
442
  * slice's last point is an interior sample, and the live-tail entrance must not apply.
393
443
  */
394
- #w(t, i) {
444
+ #y(t, i) {
395
445
  const e = t.store.last(), o = i[i.length - 1];
396
446
  return e !== void 0 && o !== void 0 && o.time === e.time;
397
447
  }
398
448
  #B(t, i) {
399
449
  const { layerIndex: e, data: o, grown: s } = i, n = [];
400
- let a = null;
450
+ let l = null;
401
451
  for (const r of o) {
402
452
  const c = s?.get(r.time) ?? this.#l(t, e, r);
403
453
  if (c === null) {
404
- a = null;
454
+ l = null;
405
455
  continue;
406
456
  }
407
- a === null && (a = [], n.push(a)), a.push(c);
457
+ l === null && (l = [], n.push(l)), l.push(c);
408
458
  }
409
459
  return n;
410
460
  }
411
- #m(t) {
412
- const { ctx: i, runs: e, color: o, growing: s } = t, { context: n, verticalPixelRatio: a } = i.scope, r = this.#e.curve, c = [], m = [];
413
- for (let h = 0; h < e.length; h++) {
414
- const p = e[h];
415
- if (p.length < 2) {
416
- m.push(p[0]);
461
+ #p(t) {
462
+ const { ctx: i, runs: e, color: o, growing: s } = t, { context: n, verticalPixelRatio: l } = i.scope, r = this.#e.curve, c = [], p = [];
463
+ for (let m = 0; m < e.length; m++) {
464
+ const f = e[m];
465
+ if (f.length < 2) {
466
+ p.push(f[0]);
417
467
  continue;
418
468
  }
419
- const d = s && h === e.length - 1, g = p.map((M) => ({ x: M.x, y: M.top })), w = p.map((M) => ({ x: M.x, y: M.bottom })), k = {
420
- upper: g,
421
- lower: w,
422
- upperSegs: B(g, r, d),
423
- lowerSegs: B(w, r, d)
469
+ const v = s && m === e.length - 1, d = f.map((M) => ({ x: M.x, y: M.top })), y = f.map((M) => ({ x: M.x, y: M.bottom })), D = {
470
+ upper: d,
471
+ lower: y,
472
+ upperSegs: B(d, r, v),
473
+ lowerSegs: B(y, r, v)
424
474
  };
425
- it(k), c.push(k);
475
+ it(D), c.push(D);
426
476
  }
427
477
  if (!this.#c && c.length > 0) {
428
478
  n.fillStyle = this.#E({ context: n, paths: c, color: o });
429
- for (const h of c) {
430
- n.beginPath(), n.moveTo(h.upper[0].x, h.upper[0].y), R(n, h.upperSegs);
431
- const p = h.lower[h.lower.length - 1];
432
- n.lineTo(p.x, p.y), Q(n, h.lower, h.lowerSegs), n.closePath(), n.fill();
479
+ for (const m of c) {
480
+ n.beginPath(), n.moveTo(m.upper[0].x, m.upper[0].y), R(n, m.upperSegs);
481
+ const f = m.lower[m.lower.length - 1];
482
+ n.lineTo(f.x, f.y), Q(n, m.lower, m.lowerSegs), n.closePath(), n.fill();
433
483
  }
434
484
  }
435
- const f = this.#e.stroke, u = f.color ?? A(o, E), v = Math.max(1, Math.round(f.width * a)), y = f.visible && f.width > 0;
436
- if (y && c.length > 0) {
485
+ const h = this.#e.stroke, u = h.color ?? T(o, E), g = Math.max(1, Math.round(h.width * l)), w = h.visible && h.width > 0;
486
+ if (w && c.length > 0) {
437
487
  n.beginPath();
438
- for (const h of c)
439
- n.moveTo(h.upper[0].x, h.upper[0].y), R(n, h.upperSegs), n.moveTo(h.lower[0].x, h.lower[0].y), R(n, h.lowerSegs);
440
- n.strokeStyle = u, n.lineWidth = v, n.lineJoin = "round", n.lineCap = "round", n.stroke();
488
+ for (const m of c)
489
+ n.moveTo(m.upper[0].x, m.upper[0].y), R(n, m.upperSegs), n.moveTo(m.lower[0].x, m.lower[0].y), R(n, m.lowerSegs);
490
+ n.strokeStyle = u, n.lineWidth = g, n.lineJoin = "round", n.lineCap = "round", n.stroke();
441
491
  }
442
- if (m.length > 0) {
492
+ if (p.length > 0) {
443
493
  n.beginPath();
444
- for (const h of m)
445
- n.moveTo(h.x, h.top), n.lineTo(h.x, h.bottom);
446
- n.strokeStyle = y ? u : A(o, E), n.lineWidth = v, n.lineCap = "round", n.stroke();
494
+ for (const m of p)
495
+ n.moveTo(m.x, m.top), n.lineTo(m.x, m.bottom);
496
+ n.strokeStyle = w ? u : T(o, E), n.lineWidth = g, n.lineCap = "round", n.stroke();
447
497
  }
448
498
  }
449
499
  /** A gradient fill spans the layer's drawn extent this frame; a degenerate extent paints solid. */
450
500
  #E(t) {
451
501
  const { context: i, paths: e, color: o } = t, s = this.#e.fill;
452
502
  if (typeof s == "string") return s;
453
- const [n, a] = s ?? [
454
- A(o, q),
455
- A(o, K)
503
+ const [n, l] = s ?? [
504
+ T(o, q),
505
+ T(o, K)
456
506
  ];
457
507
  let r = 1 / 0, c = -1 / 0;
458
- for (const f of e) {
459
- for (const u of f.upper)
508
+ for (const h of e) {
509
+ for (const u of h.upper)
460
510
  u.y < r && (r = u.y);
461
- for (const u of f.lower)
511
+ for (const u of h.lower)
462
512
  u.y > c && (c = u.y);
463
513
  }
464
514
  if (!(c > r + 0.5)) return n;
465
- const m = i.createLinearGradient(0, r, 0, c);
466
- return m.addColorStop(0, n), m.addColorStop(1, a), m;
515
+ const p = i.createLinearGradient(0, r, 0, c);
516
+ return p.addColorStop(0, n), p.addColorStop(1, l), p;
467
517
  }
468
518
  // --- Intro frames ---------------------------------------------------------
469
519
  #V(t) {
@@ -488,32 +538,32 @@ class st {
488
538
  * `layerMean` is the center the default unfold opens the band out of.
489
539
  */
490
540
  #b(t, i) {
491
- const { timeScale: e, yScale: o, scope: s } = t, { progress: n, range: a, width: r } = i, c = this.#t.length, m = new Array(c), f = new Array(c);
541
+ const { timeScale: e, yScale: o, scope: s } = t, { progress: n, range: l, width: r } = i, c = this.#t.length, p = new Array(c), h = new Array(c);
492
542
  let u;
493
- const v = (p) => {
494
- const d = m[p];
495
- if (d !== void 0) return d;
496
- const g = (this.#t[p]?.store.getVisibleData(a.from, a.to) ?? []).map((w) => ({
497
- time: w.time,
498
- value: b(w) ? Number.NaN : o.lerpValue(w.low, w.high, 0.5)
543
+ const g = (f) => {
544
+ const v = p[f];
545
+ if (v !== void 0) return v;
546
+ const d = (this.#t[f]?.store.getVisibleData(l.from, l.to) ?? []).map((y) => ({
547
+ time: y.time,
548
+ value: b(y) ? Number.NaN : o.lerpValue(y.low, y.high, 0.5)
499
549
  }));
500
- return m[p] = g, g;
501
- }, y = (p) => {
502
- const d = f[p];
503
- if (d !== void 0) return d;
504
- const g = j(v(p), o);
505
- return f[p] = g, g;
506
- }, h = () => {
550
+ return p[f] = d, d;
551
+ }, w = (f) => {
552
+ const v = h[f];
553
+ if (v !== void 0) return v;
554
+ const d = j(g(f), o);
555
+ return h[f] = d, d;
556
+ }, m = () => {
507
557
  if (u !== void 0) return u;
508
558
  u = null;
509
- for (let p = 0; p < c; p++) {
510
- if (this.getLayerAlpha(p) <= 0 || !this.isLayerVisible(p)) continue;
511
- const d = v(p).filter((g) => o.isPlottable(g.value));
512
- if (!(d.length < 2)) {
513
- u = d.map((g) => ({
514
- x: e.timeToBitmapXExact(g.time),
515
- y: o.valueToBitmapYExact(g.value),
516
- time: g.time
559
+ for (let f = 0; f < c; f++) {
560
+ if (this.getLayerAlpha(f) <= 0 || !this.isLayerVisible(f)) continue;
561
+ const v = g(f).filter((d) => o.isPlottable(d.value));
562
+ if (!(v.length < 2)) {
563
+ u = v.map((d) => ({
564
+ x: e.timeToBitmapXExact(d.time),
565
+ y: o.valueToBitmapYExact(d.value),
566
+ time: d.time
517
567
  }));
518
568
  break;
519
569
  }
@@ -522,51 +572,51 @@ class st {
522
572
  };
523
573
  return {
524
574
  progress: n,
525
- range: a,
575
+ range: l,
526
576
  width: r,
527
577
  height: o.getMediaHeight() * s.verticalPixelRatio,
528
578
  stacking: "off",
529
- timeToX: (p) => e.timeToBitmapXExact(p),
530
- xToTime: (p) => e.xToTime(p / s.horizontalPixelRatio),
531
- valueToY: (p) => o.valueToBitmapYExact(p),
532
- lerpValue: (p, d, g) => o.lerpValue(p, d, g),
579
+ timeToX: (f) => e.timeToBitmapXExact(f),
580
+ xToTime: (f) => e.xToTime(f / s.horizontalPixelRatio),
581
+ valueToY: (f) => o.valueToBitmapYExact(f),
582
+ lerpValue: (f, v, d) => o.lerpValue(f, v, d),
533
583
  layerCount: c,
534
- layerData: v,
535
- layerMean: y,
536
- primaryPath: h
584
+ layerData: g,
585
+ layerMean: w,
586
+ primaryPath: m
537
587
  };
538
588
  }
539
589
  // --- Overlay --------------------------------------------------------------
540
590
  /** Crosshair dots on both edges of every visible band at the hovered sample. */
541
591
  drawOverlay(t) {
542
- this.#f(performance.now());
592
+ this.#g(performance.now());
543
593
  const { crosshair: i, scope: e } = t;
544
594
  if (i === null) return;
545
- const { context: o, horizontalPixelRatio: s } = e, n = 3 * s, a = n + 3 * s;
595
+ const { context: o, horizontalPixelRatio: s } = e, n = 3 * s, l = n + 3 * s;
546
596
  for (let r = 0; r < this.#t.length; r++) {
547
- const c = this.#t[r], m = c.alpha.current;
548
- if (m <= 0) continue;
549
- const f = c.store.findNearest(i.time, t.dataInterval);
550
- if (f === null) continue;
551
- const u = this.#X(t, r, f);
597
+ const c = this.#t[r], p = c.alpha.current;
598
+ if (p <= 0) continue;
599
+ const h = c.store.findNearest(i.time, t.dataInterval);
600
+ if (h === null) continue;
601
+ const u = this.#X(t, r, h);
552
602
  if (u === null) continue;
553
- const v = this.#r(r);
554
- o.save(), o.globalAlpha *= m, o.fillStyle = v;
555
- for (const y of [u.top, u.bottom])
556
- o.save(), o.globalAlpha *= 0.25, o.beginPath(), o.arc(u.x, y, a, 0, Math.PI * 2), o.fill(), o.restore(), o.beginPath(), o.arc(u.x, y, n, 0, Math.PI * 2), o.fill();
603
+ const g = this.#r(r);
604
+ o.save(), o.globalAlpha *= p, o.fillStyle = g;
605
+ for (const w of [u.top, u.bottom])
606
+ o.save(), o.globalAlpha *= 0.25, o.beginPath(), o.arc(u.x, w, l, 0, Math.PI * 2), o.fill(), o.restore(), o.beginPath(), o.arc(u.x, w, n, 0, Math.PI * 2), o.fill();
557
607
  o.restore();
558
608
  }
559
609
  }
560
610
  /** The hovered sample where the fill draws it: an entering tail point sits on its grown head. */
561
611
  #X(t, i, e) {
562
612
  const o = this.#t[i], s = t.timeScale.getRange(), n = o.store.getVisibleData(s.from, s.to);
563
- return (this.#w(o, n) ? this.#v(t, i) : null)?.get(e.time) ?? this.#l(t, i, e);
613
+ return (this.#y(o, n) ? this.#v(t, i) : null)?.get(e.time) ?? this.#l(t, i, e);
564
614
  }
565
615
  // --- Data queries ---------------------------------------------------------
566
616
  /** A sample as a query reports it: the drawn (live-chased) edges, `null` for a gap. */
567
617
  #x(t, i) {
568
618
  if (b(i)) return null;
569
- const e = this.#d(t, i);
619
+ const e = this.#u(t, i);
570
620
  return { ...i, low: Math.min(e.low, e.high), high: Math.max(e.low, e.high) };
571
621
  }
572
622
  getDataAtTime(t, i) {
@@ -585,14 +635,16 @@ class st {
585
635
  const o = this.#t[e];
586
636
  if (!o.store.isVisible()) continue;
587
637
  const s = t(o), n = s === null ? null : this.#x(o, s);
588
- n !== null && i.push({
638
+ if (n === null) continue;
639
+ const l = {
589
640
  layerIndex: e,
590
641
  time: n.time,
591
642
  value: (n.low + n.high) / 2,
592
643
  color: this.#r(e),
593
644
  low: n.low,
594
645
  high: n.high
595
- });
646
+ };
647
+ n.x !== void 0 && (l.x = n.x), i.push(l);
596
648
  }
597
649
  return i.length > 0 ? i : null;
598
650
  }
@@ -633,9 +685,9 @@ class st {
633
685
  getValueRange(t, i, e) {
634
686
  const o = e?.plottable;
635
687
  let s = 1 / 0, n = -1 / 0;
636
- for (const a of this.#t)
637
- if (a.store.isVisible())
638
- for (const r of a.store.getVisibleData(t, i))
688
+ for (const l of this.#t)
689
+ if (l.store.isVisible())
690
+ for (const r of l.store.getVisibleData(t, i))
639
691
  b(r) || o && (!o(r.low) || !o(r.high)) || (r.low < s && (s = r.low), r.high > n && (n = r.high));
640
692
  return s < 1 / 0 ? { min: s, max: n } : null;
641
693
  }
@@ -653,18 +705,19 @@ class st {
653
705
  t.store.removeAllListeners();
654
706
  }
655
707
  }
656
- function X(l, t) {
657
- return t === 1 ? [l.bands.upper] : l.seriesColors.slice(0, t);
708
+ function X(a, t) {
709
+ return t === 1 ? [a.bands.upper] : a.seriesColors.slice(0, t);
658
710
  }
659
- function nt(l) {
660
- const t = l[l.length - 1];
711
+ function nt(a) {
712
+ const t = a[a.length - 1];
661
713
  return t.length < 2 ? null : Math.round(t[t.length - 2].x);
662
714
  }
663
- const yt = {
715
+ const wt = {
664
716
  type: "band",
665
- create: ({ theme: l, layerCount: t }, i) => new st(t, { colors: X(l, t), ...i })
717
+ xTypes: ["time", "numeric", "category"],
718
+ create: ({ theme: a, layerCount: t }, i) => new st(t, { colors: X(a, t), ...i })
666
719
  };
667
720
  export {
668
721
  st as BandRenderer,
669
- yt as BandSeriesDef
722
+ wt as BandSeriesDef
670
723
  };