@wick-charts/vue 0.8.0 → 0.8.2

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 (48) hide show
  1. package/README.md +2 -0
  2. package/dist/BandSeries.vue.js +43 -32
  3. package/dist/BarSeries.vue.js +44 -33
  4. package/dist/CandlestickSeries.vue.js +24 -23
  5. package/dist/ChartContainer.vue.js +1 -1
  6. package/dist/HeatmapSeries.vue.js +21 -20
  7. package/dist/LineSeries.vue.js +43 -32
  8. package/dist/PieSeries.vue.js +25 -24
  9. package/dist/composables.js +63 -36
  10. package/dist/core/dist/axis/dom-labels.js +64 -53
  11. package/dist/core/dist/chart/badge-animator.js +38 -28
  12. package/dist/core/dist/chart/options.js +1 -1
  13. package/dist/core/dist/chart/y-target.js +38 -32
  14. package/dist/core/dist/chart.js +852 -709
  15. package/dist/core/dist/data/decimation.js +52 -51
  16. package/dist/core/dist/data/store.js +38 -20
  17. package/dist/core/dist/data/sync.js +97 -59
  18. package/dist/core/dist/navigator/controller.js +11 -11
  19. package/dist/core/dist/perf/perf-hud.js +3 -3
  20. package/dist/core/dist/scales/tick-tracker.js +2 -1
  21. package/dist/core/dist/scales/time-ticks.js +99 -0
  22. package/dist/core/dist/scales/x-scale.js +33 -27
  23. package/dist/core/dist/series/band.js +83 -83
  24. package/dist/core/dist/series/bar.js +240 -211
  25. package/dist/core/dist/series/base-multi-layer.js +288 -240
  26. package/dist/core/dist/series/candlestick.js +168 -168
  27. package/dist/core/dist/series/line.js +545 -455
  28. package/dist/core/dist/snapshots.js +109 -86
  29. package/dist/core/dist/utils/point.js +4 -0
  30. package/dist/core/dist/utils/time.js +42 -26
  31. package/dist/index.d.ts +67 -28
  32. package/dist/ui/InfoBar.vue.js +69 -69
  33. package/dist/ui/NumberFlow.vue.js +36 -27
  34. package/dist/ui/Tooltip.vue.js +128 -131
  35. package/dist/ui/YLabel.vue.js +47 -47
  36. package/package.json +2 -2
  37. package/src/BandSeries.vue +20 -5
  38. package/src/BarSeries.vue +20 -5
  39. package/src/CandlestickSeries.vue +5 -4
  40. package/src/ChartContainer.vue +15 -9
  41. package/src/HeatmapSeries.vue +5 -4
  42. package/src/LineSeries.vue +20 -5
  43. package/src/PieSeries.vue +6 -5
  44. package/src/composables.ts +64 -1
  45. package/src/ui/InfoBar.vue +11 -3
  46. package/src/ui/NumberFlow.vue +17 -3
  47. package/src/ui/Tooltip.vue +23 -12
  48. package/src/ui/YLabel.vue +28 -27
@@ -1,73 +1,74 @@
1
- function D(t, h) {
2
- return t.length <= h ? t : v(
1
+ function k(t, n) {
2
+ return t.length <= n ? t : D(
3
3
  t,
4
- h,
5
- (l) => l.time,
6
- (l) => l.value
4
+ n,
5
+ (h) => h.time,
6
+ (h) => h.value
7
7
  );
8
8
  }
9
- function k(t, h) {
10
- if (t.length <= h) return t;
11
- const l = Math.ceil(t.length / h), u = [];
12
- for (let o = 0; o < t.length; o += l) {
13
- const n = Math.min(o + l, t.length);
9
+ function x(t, n) {
10
+ if (t.length <= n) return t;
11
+ const h = Math.ceil(t.length / n), a = [];
12
+ for (let l = 0; l < t.length; l += h) {
13
+ const o = Math.min(l + h, t.length);
14
14
  let s = -1 / 0, i = 1 / 0, c = 0;
15
- for (let r = o; r < n; r++)
16
- t[r].high > s && (s = t[r].high), t[r].low < i && (i = t[r].low), c += t[r].volume ?? 0;
17
- u.push({
18
- time: t[o].time,
19
- open: t[o].open,
15
+ for (let e = l; e < o; e++)
16
+ t[e].high > s && (s = t[e].high), t[e].low < i && (i = t[e].low), c += t[e].volume ?? 0;
17
+ a.push({
18
+ time: t[l].time,
19
+ open: t[l].open,
20
20
  high: s,
21
21
  low: i,
22
- close: t[n - 1].close,
22
+ close: t[o - 1].close,
23
23
  volume: c
24
24
  });
25
25
  }
26
- return u;
26
+ return a;
27
27
  }
28
- function x(t, h) {
29
- if (t.length <= h || h < 3) return t;
30
- const l = t.length - 1, u = Math.ceil((t.length - 2) / (h - 2)), o = [t[0]];
31
- for (let n = 1; n < l; n += u) {
32
- const s = Math.min(n + u, l);
33
- let i = 1 / 0, c = -1 / 0, r = !1;
34
- for (let f = n; f < s; f++) {
35
- const a = t[f];
36
- if (!Number.isFinite(a.low) || !Number.isFinite(a.high)) {
37
- r = !0;
28
+ function L(t, n) {
29
+ if (t.length <= n || n < 3) return t;
30
+ const h = t.length - 1, a = Math.ceil((t.length - 2) / (n - 2)), l = [t[0]];
31
+ for (let o = 1; o < h; o += a) {
32
+ const s = Math.min(o + a, h);
33
+ let i = 1 / 0, c = -1 / 0, e = !1;
34
+ for (let m = o; m < s; m++) {
35
+ const r = t[m];
36
+ if (!Number.isFinite(r.low) || !Number.isFinite(r.high)) {
37
+ e = !0;
38
38
  break;
39
39
  }
40
- a.low < i && (i = a.low), a.high > c && (c = a.high);
40
+ r.low < i && (i = r.low), r.high > c && (c = r.high);
41
41
  }
42
- o.push(r ? { time: t[n].time, low: Number.NaN, high: Number.NaN } : { time: t[n].time, low: i, high: c });
42
+ l.push(e ? { time: t[o].time, low: Number.NaN, high: Number.NaN } : { time: t[o].time, low: i, high: c });
43
43
  }
44
- return o.push(t[l]), o;
44
+ return l.push(t[h]), l;
45
45
  }
46
- function v(t, h, l, u) {
47
- if (h >= t.length || h < 3) return t;
48
- const o = [t[0]], n = (t.length - 2) / (h - 2);
46
+ function D(t, n, h, a) {
47
+ if (n >= t.length || n < 3) return t;
48
+ const l = [t[0]], o = (t.length - 2) / (n - 2);
49
49
  let s = 0;
50
- for (let i = 0; i < h - 2; i++) {
51
- const c = Math.floor((i + 1) * n) + 1, r = Math.min(Math.floor((i + 2) * n) + 1, t.length - 1);
52
- let f = 0, a = 0;
53
- const M = r, p = Math.min(Math.floor((i + 3) * n) + 1, t.length), g = p - M;
54
- if (g > 0) {
55
- for (let e = M; e < p; e++)
56
- f += l(t[e]), a += u(t[e]);
57
- f /= g, a /= g;
50
+ for (let i = 0; i < n - 2; i++) {
51
+ const c = Math.floor((i + 1) * o) + 1, e = Math.min(Math.floor((i + 2) * o) + 1, t.length - 1), m = h(t[s]), r = a(t[s]), p = Number.isFinite(r);
52
+ let g = 0, N = 0, b = 0;
53
+ const d = e, v = Math.min(Math.floor((i + 3) * o) + 1, t.length);
54
+ for (let u = d; u < v; u++) {
55
+ const f = a(t[u]);
56
+ Number.isFinite(f) && (g += h(t[u]), N += f, b++);
58
57
  }
59
- let w = -1, m = c;
60
- const N = l(t[s]), b = u(t[s]);
61
- for (let e = c; e < r; e++) {
62
- const d = Math.abs((N - f) * (u(t[e]) - b) - (N - l(t[e])) * (a - b));
63
- d > w && (w = d, m = e);
58
+ b > 0 ? (g /= b, N /= b) : (g = m, N = p ? r : 0);
59
+ let w = -1, M = c;
60
+ for (let u = c; u < e; u++) {
61
+ const f = a(t[u]);
62
+ if (!Number.isFinite(f)) continue;
63
+ const F = p ? Math.abs((m - g) * (f - r) - (m - h(t[u])) * (N - r)) : 0;
64
+ F > w && (w = F, M = u);
64
65
  }
65
- o.push(t[m]), s = m;
66
+ l.push(t[M]), s = M;
66
67
  }
67
- return o.push(t[t.length - 1]), o;
68
+ return l.push(t[t.length - 1]), l;
68
69
  }
69
70
  export {
70
- x as decimateBandData,
71
- D as decimateLineData,
72
- k as decimateOHLCData
71
+ L as decimateBandData,
72
+ k as decimateLineData,
73
+ x as decimateOHLCData
73
74
  };
@@ -1,10 +1,16 @@
1
- import { EventEmitter as d } from "../events.js";
1
+ import { EventEmitter as l } from "../events.js";
2
2
  import { binarySearch as n } from "../utils/math.js";
3
- class u extends d {
3
+ class u extends l {
4
4
  data = [];
5
5
  _visible = !0;
6
6
  cachedRange = null;
7
7
  cachedResult = [];
8
+ // Points `trimStart` dropped, oldest first. A view whose left edge is older
9
+ // than the kept head still draws them, so a rolling window slides out of view.
10
+ exited = [];
11
+ // Leftmost `from` read since the last trim: older exited points are out of every view since then.
12
+ lowestReadFrom = Number.POSITIVE_INFINITY;
13
+ appendedSinceTrim = 0;
8
14
  // Dev-only, warn-once-per-instance: these two conditions are almost always
9
15
  // a persistent bug in the caller's feed (not a one-off), so a per-call
10
16
  // warning would just spam the console on every tick.
@@ -25,7 +31,7 @@ class u extends d {
25
31
  }
26
32
  !a && process.env.NODE_ENV !== "production" && !this.warnedUnsorted && (this.warnedUnsorted = !0, console.warn(
27
33
  "[wick-charts] data is not sorted by time — re-sorting on every setData() call is wasted work. Sort your feed by `time` ascending before passing it in."
28
- )), this.data = a ? t.slice() : [...t].sort((e, i) => e.time - i.time), this.cachedRange = null, this.emit("update");
34
+ )), this.data = a ? t.slice() : [...t].sort((e, s) => e.time - s.time), this.exited = [], this.appendedSinceTrim = 0, this.cachedRange = null, this.emit("update");
29
35
  }
30
36
  append(t) {
31
37
  if (this.data.length > 0 && t.time <= this.data[this.data.length - 1].time) {
@@ -34,7 +40,7 @@ class u extends d {
34
40
  )), this.updateLast(t);
35
41
  return;
36
42
  }
37
- this.data.push(t), this.cachedRange = null, this.emit("update");
43
+ this.data.push(t), this.appendedSinceTrim++, this.cachedRange = null, this.emit("update");
38
44
  }
39
45
  updateLast(t) {
40
46
  this.data.length !== 0 && (this.data[this.data.length - 1] = t, this.cachedRange = null, this.emit("update"));
@@ -47,16 +53,22 @@ class u extends d {
47
53
  * is already validated and no re-sort is needed here. No-op on empty input.
48
54
  */
49
55
  prepend(t) {
50
- t.length !== 0 && (this.data = t.concat(this.data), this.cachedRange = null, this.emit("update"));
56
+ t.length !== 0 && (this.data = t.concat(this.data), this.exited = [], this.cachedRange = null, this.emit("update"));
51
57
  }
52
58
  trimStart(t) {
53
- if (!(t <= 0 || this.data.length === 0)) {
54
- if (t >= this.data.length) {
55
- this.data = [], this.cachedRange = null, this.emit("update");
56
- return;
57
- }
58
- this.data = this.data.slice(t), this.cachedRange = null, this.emit("update");
59
- }
59
+ if (t <= 0 || this.data.length === 0) return;
60
+ const a = this.data.slice(0, t), e = a.slice(Math.max(0, a.length - this.appendedSinceTrim)), s = e.length === a.length ? this.exited.concat(e) : e;
61
+ this.data = this.data.slice(t), this.exited = this.reachedByView(s), this.appendedSinceTrim = 0, this.lowestReadFrom = Number.POSITIVE_INFINITY, this.cachedRange = null, this.emit("update");
62
+ }
63
+ /**
64
+ * The exited points the leftmost view read since the last trim needs to reach its left edge.
65
+ * None without a read, so a chart that does not paint (a hidden tab) does not pile them up.
66
+ */
67
+ reachedByView(t) {
68
+ const a = this.lowestReadFrom, e = this.data[0];
69
+ if (e === void 0 || e.time <= a) return [];
70
+ const s = Math.max(0, n(t, a, (h) => h.time) - 1);
71
+ return t.slice(s);
60
72
  }
61
73
  getAll() {
62
74
  return this.data;
@@ -64,8 +76,14 @@ class u extends d {
64
76
  getVisibleData(t, a) {
65
77
  if (this.data.length === 0) return [];
66
78
  if (this.cachedRange && this.cachedRange.from === t && this.cachedRange.to === a) return this.cachedResult;
67
- const e = Math.max(0, n(this.data, t, (s) => s.time) - 1), i = Math.min(this.data.length, n(this.data, a, (s) => s.time) + 1);
68
- return this.cachedResult = this.data.slice(e, i), this.cachedRange = { from: t, to: a }, this.cachedResult;
79
+ this.lowestReadFrom = Math.min(this.lowestReadFrom, t);
80
+ const e = Math.max(0, n(this.data, t, (i) => i.time) - 1), s = Math.min(this.data.length, n(this.data, a, (i) => i.time) + 1);
81
+ let h = this.data.slice(e, s);
82
+ if (e === 0 && this.data[0].time > t && this.exited.length > 0) {
83
+ const i = Math.max(0, n(this.exited, t, (r) => r.time) - 1), d = Math.min(this.exited.length, n(this.exited, a, (r) => r.time) + 1);
84
+ h = this.exited.slice(i, d).concat(h);
85
+ }
86
+ return this.cachedResult = h, this.cachedRange = { from: t, to: a }, h;
69
87
  }
70
88
  first() {
71
89
  return this.data[0];
@@ -81,13 +99,13 @@ class u extends d {
81
99
  }
82
100
  findNearest(t, a) {
83
101
  if (this.data.length === 0) return null;
84
- const e = n(this.data, t, (h) => h.time);
85
- let i = null, s = a;
86
- for (let h = Math.max(0, e - 1); h <= Math.min(this.data.length - 1, e + 1); h++) {
87
- const r = Math.abs(this.data[h].time - t);
88
- r <= s && (s = r, i = this.data[h]);
102
+ const e = n(this.data, t, (i) => i.time);
103
+ let s = null, h = a;
104
+ for (let i = Math.max(0, e - 1); i <= Math.min(this.data.length - 1, e + 1); i++) {
105
+ const d = Math.abs(this.data[i].time - t);
106
+ d <= h && (h = d, s = this.data[i]);
89
107
  }
90
- return i;
108
+ return s;
91
109
  }
92
110
  }
93
111
  export {
@@ -1,75 +1,113 @@
1
- import { normalizeTime as y } from "../utils/time.js";
2
- function i(t) {
3
- return "x" in t ? t.x : y(t.time);
1
+ import { normalizeTime as A } from "../utils/time.js";
2
+ function i(a) {
3
+ return "x" in a ? a.x : A(a.time);
4
4
  }
5
- const m = { len: 0, firstTime: null, lastTime: null, data: null }, p = 20;
6
- function g(t, a) {
7
- if (i(t) !== i(a)) return !1;
8
- const r = Object.keys(t), e = Object.keys(a);
9
- return r.length !== e.length ? !1 : r.every((n) => n === "time" || t[n] === a[n]);
5
+ const S = { len: 0, firstTime: null, lastTime: null, data: null, last: null }, b = 20;
6
+ function o(a, t) {
7
+ if (i(a) !== i(t)) return !1;
8
+ const l = Object.keys(a), e = Object.keys(t);
9
+ return l.length !== e.length ? !1 : l.every((r) => r === "time" || a[r] === t[r]);
10
10
  }
11
- function c(t, a) {
12
- if (!t || t.length !== a.length || t === a) return !1;
13
- for (let r = 0; r < a.length - 1; r++)
14
- if (t[r] !== a[r] && !g(t[r], a[r]))
11
+ function p(a, t) {
12
+ if (!a || a.length !== t.length || a === t) return !1;
13
+ for (let l = 0; l < t.length - 1; l++)
14
+ if (a[l] !== t[l] && !o(a[l], t[l]))
15
15
  return !1;
16
16
  return !0;
17
17
  }
18
- function T(t, a, r) {
19
- if (!t || t.length === 0 || r <= 0 || t.length !== a.length - r) return !1;
20
- for (let e = 1; e < r; e++)
21
- if (i(a[e - 1]) >= i(a[e])) return !1;
22
- if (i(a[r - 1]) >= i(t[0])) return !1;
23
- for (let e = 0; e < t.length; e++)
24
- if (!g(t[e], a[r + e])) return !1;
18
+ function E(a, t, l) {
19
+ if (!a || a.length === 0 || l <= 0 || a.length !== t.length - l) return !1;
20
+ for (let e = 1; e < l; e++)
21
+ if (i(t[e - 1]) >= i(t[e])) return !1;
22
+ if (i(t[l - 1]) >= i(a[0])) return !1;
23
+ for (let e = 0; e < a.length; e++)
24
+ if (!o(a[e], t[l + e])) return !1;
25
25
  return !0;
26
26
  }
27
- function A(t) {
28
- return typeof t == "object" && t !== null && !Array.isArray(t) && Array.isArray(t.data);
27
+ function m(a, t, l) {
28
+ const e = a.data;
29
+ if (!e) return "unchanged";
30
+ if (e === t) return T(a, t) ? "lastEdited" : "unchanged";
31
+ const r = e.length - l;
32
+ if (r <= 0 || r > t.length) return null;
33
+ for (let u = 0; u < r - 1; u++) {
34
+ const f = e[l + u];
35
+ if (f !== t[u] && !o(f, t[u]))
36
+ return null;
37
+ }
38
+ for (let u = r; u < t.length; u++)
39
+ if (i(t[u - 1]) >= i(t[u])) return null;
40
+ const n = e[e.length - 1], s = t[r - 1];
41
+ return n === s || o(n, s) ? "unchanged" : i(n) !== i(s) ? null : "lastEdited";
29
42
  }
30
- function b(t) {
31
- if (!Array.isArray(t)) return [t];
32
- if (t.length === 0) return [{ data: [] }];
33
- const a = t[0];
34
- return Array.isArray(a) || A(a) ? t.map((r) => Array.isArray(r) ? { data: r } : r) : [{ data: t }];
43
+ function T(a, t) {
44
+ const l = a.last ?? null, e = t[a.len - 1];
45
+ return l === null || e === void 0 ? !1 : i(l) === i(e) && !o(l, e);
35
46
  }
36
- function L(t) {
37
- const { chart: a, id: r } = t, e = b(t.data), n = e.length > 1 ? e.map((l, f) => l.label ?? `Series ${f + 1}`) : [e[0].label];
38
- a.setSeriesLabels(r, n), a.setLayerColors(
39
- r,
40
- e.map((l) => l.color)
47
+ function h(a) {
48
+ const t = a[a.length - 1];
49
+ return { len: a.length, firstTime: i(a[0]), lastTime: i(t), data: a, last: { ...t } };
50
+ }
51
+ function L(a) {
52
+ return typeof a == "object" && a !== null && !Array.isArray(a) && Array.isArray(a.data);
53
+ }
54
+ function v(a) {
55
+ if (!Array.isArray(a)) return [a];
56
+ if (a.length === 0) return [{ data: [] }];
57
+ const t = a[0];
58
+ return Array.isArray(t) || L(t) ? a.map((l) => Array.isArray(l) ? { data: l } : l) : [{ data: a }];
59
+ }
60
+ function j(a) {
61
+ const { chart: t, id: l } = a, e = v(a.data), r = e.length > 1 ? e.map((s, u) => s.label ?? `Series ${u + 1}`) : [e[0].label];
62
+ t.setSeriesLabels(l, r), t.setLayerColors(
63
+ l,
64
+ e.map((s) => s.color)
41
65
  );
42
- const s = [];
43
- return a.batch(() => {
44
- for (let l = 0; l < e.length; l++)
45
- s[l] = S({
46
- chart: a,
47
- id: r,
48
- data: e[l].data,
49
- prev: t.prev[l] ?? m,
50
- layerIndex: l
66
+ const n = [];
67
+ return t.batch(() => {
68
+ for (let s = 0; s < e.length; s++)
69
+ n[s] = x({
70
+ chart: t,
71
+ id: l,
72
+ data: e[s].data,
73
+ prev: a.prev[s] ?? S,
74
+ layerIndex: s
51
75
  });
52
- }), s;
76
+ }), n;
53
77
  }
54
- function S(t) {
55
- const { chart: a, id: r, data: e, prev: n, layerIndex: s } = t;
78
+ function x(a) {
79
+ const { chart: t, id: l, data: e, prev: r, layerIndex: n } = a;
56
80
  if (e.length === 0)
57
- return a.setSeriesData(r, [], s), { len: 0, firstTime: null, lastTime: null, data: [] };
58
- if (n.data === e && n.len === e.length) return n;
59
- const l = i(e[0]), f = i(e[e.length - 1]);
60
- if (typeof l == "string")
61
- return e.length === n.len && c(n.data, e) ? a.updateData(r, e[e.length - 1], s) : a.setSeriesData(r, e, s), { len: e.length, firstTime: l, lastTime: f, data: e };
62
- const h = n.firstTime !== null && n.firstTime !== l, u = e.length - n.len, d = n.lastTime !== null && n.lastTime !== f;
63
- return h && u === 0 && d ? a.batch(() => {
64
- a.appendData(r, e[e.length - 1], s), a.keepLast(r, e.length, s);
65
- }) : T(n.data, e, u) ? a.prependData(r, e.slice(0, u), s) : n.len === 0 || e.length < n.len || u > p || h ? a.setSeriesData(r, e, s) : e.length === n.len ? c(n.data, e) ? a.updateData(r, e[e.length - 1], s) : a.setSeriesData(r, e, s) : a.batch(() => {
66
- for (let o = n.len; o < e.length; o++)
67
- a.appendData(r, e[o], s);
68
- }), { len: e.length, firstTime: l, lastTime: f, data: e };
81
+ return t.setSeriesData(l, [], n), { len: 0, firstTime: null, lastTime: null, data: [], last: null };
82
+ if (r.data === e && r.len === e.length)
83
+ return T(r, e) ? (t.updateData(l, e[e.length - 1], n), h(e)) : r;
84
+ const s = i(e[0]), u = i(e[e.length - 1]);
85
+ if (typeof s == "string")
86
+ return e.length === r.len && p(r.data, e) ? t.updateData(l, e[e.length - 1], n) : t.setSeriesData(l, e, n), h(e);
87
+ const f = r.firstTime !== null && r.firstTime !== s, c = e.length - r.len, D = r.lastTime !== null && r.lastTime !== u, g = f && c === 0 && D ? m(r, e, 1) : null;
88
+ if (g !== null)
89
+ t.batch(() => {
90
+ g === "lastEdited" && t.updateData(l, e[e.length - 2], n), t.appendData(l, e[e.length - 1], n), t.keepLast(l, e.length, n);
91
+ });
92
+ else if (E(r.data, e, c))
93
+ t.prependData(l, e.slice(0, c), n);
94
+ else if (r.len === 0 || e.length < r.len || c > b || f)
95
+ t.setSeriesData(l, e, n);
96
+ else if (e.length === r.len)
97
+ p(r.data, e) ? t.updateData(l, e[e.length - 1], n) : t.setSeriesData(l, e, n);
98
+ else {
99
+ const y = m(r, e, 0);
100
+ y === null ? t.setSeriesData(l, e, n) : t.batch(() => {
101
+ y === "lastEdited" && t.updateData(l, e[r.len - 1], n);
102
+ for (let d = r.len; d < e.length; d++)
103
+ t.appendData(l, e[d], n);
104
+ });
105
+ }
106
+ return h(e);
69
107
  }
70
108
  export {
71
- m as EMPTY_SYNC_STATE,
72
- L as syncLayers,
73
- S as syncSeriesLayer,
74
- b as toLayers
109
+ S as EMPTY_SYNC_STATE,
110
+ j as syncLayers,
111
+ x as syncSeriesLayer,
112
+ v as toLayers
75
113
  };
@@ -3,7 +3,7 @@ import { XScale as T } from "../scales/x-scale.js";
3
3
  import { YScale as k } from "../scales/y-scale.js";
4
4
  import { decimateCandles as C, decimateLinear as R } from "./decimate.js";
5
5
  import { hitTest as b, computeSnapCenter as E, computePan as I, computeResize as $ } from "./interactions.js";
6
- import { computeWindowGeometry as M, renderBackground as L, renderMiniCandlestick as N, renderMiniBar as V, renderMiniLine as P } from "./render.js";
6
+ import { computeWindowGeometry as M, renderBackground as L, renderMiniCandlestick as P, renderMiniBar as V, renderMiniLine as N } from "./render.js";
7
7
  import { Animator as S } from "../animation/animator.js";
8
8
  import { easeOutCubic as z } from "../animation/easing.js";
9
9
  class G {
@@ -61,16 +61,16 @@ class G {
61
61
  #$;
62
62
  #M;
63
63
  #L;
64
- #N;
64
+ #P;
65
65
  #y;
66
66
  #V;
67
67
  constructor(t) {
68
68
  this.#s = t.container, this.#e = t.chart, this.#x = t.data, this.#v = t.options ?? {}, window.getComputedStyle(this.#s).position === "static" && (this.#s.style.position = "relative"), this.#t = document.createElement("canvas"), this.#t.style.position = "absolute", this.#t.style.left = "0", this.#t.style.top = "0", this.#t.style.height = "100%", this.#t.style.touchAction = "none", this.#s.appendChild(this.#t);
69
69
  const e = this.#t.getContext("2d", { alpha: !0 });
70
70
  if (!e) throw new Error("NavigatorController: failed to acquire 2D context");
71
- this.#z = e, this.#n = document.createElement("div"), this.#n.dataset.chartNavigatorOverlay = "", this.#n.style.cssText = "position:absolute;left:0;top:0;height:100%;pointer-events:none;", this.#u = document.createElement("div"), this.#u.style.cssText = "position:absolute;left:0;top:0;bottom:0;", this.#r = document.createElement("div"), this.#r.style.cssText = "position:absolute;top:0;bottom:0;", this.#l = document.createElement("div"), this.#l.style.cssText = "position:absolute;top:0;bottom:0;box-sizing:border-box;", this.#a = y(), this.#c = y(), this.#n.append(this.#u, this.#r, this.#l, this.#a, this.#c), this.#s.appendChild(this.#n), this.#I = () => this.#B(), this.#$ = () => this.#f(), this.#M = () => this.#B(), this.#e.on("viewportChange", this.#I), this.#e.on("overlayChange", this.#$), this.#e.on("tickFrame", this.#M), this.#L = (s) => this.#U(s), this.#N = (s) => this.#J(s), this.#y = (s) => this.#K(s), this.#V = () => {
71
+ this.#z = e, this.#n = document.createElement("div"), this.#n.dataset.chartNavigatorOverlay = "", this.#n.style.cssText = "position:absolute;left:0;top:0;height:100%;pointer-events:none;", this.#u = document.createElement("div"), this.#u.style.cssText = "position:absolute;left:0;top:0;bottom:0;", this.#r = document.createElement("div"), this.#r.style.cssText = "position:absolute;top:0;bottom:0;", this.#l = document.createElement("div"), this.#l.style.cssText = "position:absolute;top:0;bottom:0;box-sizing:border-box;", this.#a = y(), this.#c = y(), this.#n.append(this.#u, this.#r, this.#l, this.#a, this.#c), this.#s.appendChild(this.#n), this.#I = () => this.#B(), this.#$ = () => this.#f(), this.#M = () => this.#B(), this.#e.on("viewportChange", this.#I), this.#e.on("overlayChange", this.#$), this.#e.on("tickFrame", this.#M), this.#L = (s) => this.#U(s), this.#P = (s) => this.#J(s), this.#y = (s) => this.#K(s), this.#V = () => {
72
72
  this.#g === null && (this.#t.style.cursor = "default");
73
- }, this.#t.addEventListener("pointerdown", this.#L), this.#t.addEventListener("pointermove", this.#N), this.#t.addEventListener("pointerup", this.#y), this.#t.addEventListener("pointercancel", this.#y), this.#t.addEventListener("pointerleave", this.#V), this.#E = new ResizeObserver((s) => this.#j(s[0])), this.#E.observe(this.#s), this.#D();
73
+ }, this.#t.addEventListener("pointerdown", this.#L), this.#t.addEventListener("pointermove", this.#P), this.#t.addEventListener("pointerup", this.#y), this.#t.addEventListener("pointercancel", this.#y), this.#t.addEventListener("pointerleave", this.#V), this.#E = new ResizeObserver((s) => this.#j(s[0])), this.#E.observe(this.#s), this.#D();
74
74
  const i = this.#s.getBoundingClientRect();
75
75
  i.width > 0 && i.height > 0 && this.#W(i.width, i.height), this.#f();
76
76
  }
@@ -100,7 +100,7 @@ class G {
100
100
  t !== void 0 && (this.#s.style.height = `${t}px`);
101
101
  }
102
102
  destroy() {
103
- this.#e.off("viewportChange", this.#I), this.#e.off("overlayChange", this.#$), this.#e.off("tickFrame", this.#M), this.#t.removeEventListener("pointerdown", this.#L), this.#t.removeEventListener("pointermove", this.#N), this.#t.removeEventListener("pointerup", this.#y), this.#t.removeEventListener("pointercancel", this.#y), this.#t.removeEventListener("pointerleave", this.#V), this.#E.disconnect(), this.#p !== null && (cancelAnimationFrame(this.#p), this.#p = null), this.#t.remove(), this.#n.remove();
103
+ this.#e.off("viewportChange", this.#I), this.#e.off("overlayChange", this.#$), this.#e.off("tickFrame", this.#M), this.#t.removeEventListener("pointerdown", this.#L), this.#t.removeEventListener("pointermove", this.#P), this.#t.removeEventListener("pointerup", this.#y), this.#t.removeEventListener("pointercancel", this.#y), this.#t.removeEventListener("pointerleave", this.#V), this.#E.disconnect(), this.#p !== null && (cancelAnimationFrame(this.#p), this.#p = null), this.#t.remove(), this.#n.remove();
104
104
  }
105
105
  /** CSS pixel height of the strip — theme default unless overridden. */
106
106
  get height() {
@@ -158,7 +158,7 @@ class G {
158
158
  /** Keep scales synced with current data bounds + size. Safe to call ahead of
159
159
  * the first RAF-driven render — pointer handlers rely on this so hit-tests
160
160
  * compute against primed scales even on the opening gesture. */
161
- #P() {
161
+ #N() {
162
162
  const t = this.#b(), e = this.#Z();
163
163
  return this.#d.update(t, this.#i, this.#h), this.#A.update(e, this.#m, this.#h), { xRange: t, yRange: e };
164
164
  }
@@ -172,7 +172,7 @@ class G {
172
172
  return this.#g !== null ? this.#e.getVisibleRange() : this.#e.getAnimationState().xRange;
173
173
  }
174
174
  #S() {
175
- return this.#P(), M(this.#d, this.#Y(), this.#b());
175
+ return this.#N(), M(this.#d, this.#Y(), this.#b());
176
176
  }
177
177
  #H() {
178
178
  const t = this.#b(), e = t.to - t.from;
@@ -237,7 +237,7 @@ class G {
237
237
  // --- render ------------------------------------------------------------
238
238
  #_() {
239
239
  if (this.#i <= 0 || this.#m <= 0) return;
240
- const t = this.#e.getTheme().navigator, { xRange: e } = this.#P();
240
+ const t = this.#e.getTheme().navigator, { xRange: e } = this.#N();
241
241
  this.#X();
242
242
  const i = this.#z, s = this.#t.width, n = this.#t.height;
243
243
  i.save(), i.clearRect(0, 0, s, n), i.scale(this.#h, this.#h);
@@ -254,12 +254,12 @@ class G {
254
254
  this.#o !== null && (this.#o.tick(performance.now()), l = this.#o.current, this.#o.animating ? this.#f() : this.#o = null);
255
255
  const r = Math.max(1, Math.round(this.#i)), a = this.#x;
256
256
  if (a.type === "candlestick")
257
- N(h, this.#q(a.points, r, C), l);
257
+ P(h, this.#q(a.points, r, C), l);
258
258
  else {
259
259
  const c = f(a), g = c.length === 1, u = this.#R >= 0 ? this.#R : c.length - 1;
260
260
  for (let d = 0; d < c.length; d++) {
261
261
  const p = this.#q(c[d], r, R), m = d === u ? l : 1;
262
- a.type === "bar" ? V(h, p, m) : P(h, p, g, m);
262
+ a.type === "bar" ? V(h, p, m) : N(h, p, g, m);
263
263
  }
264
264
  }
265
265
  i.restore(), this.#G(t, e);
@@ -277,7 +277,7 @@ class G {
277
277
  this.#_();
278
278
  return;
279
279
  }
280
- const i = this.#e.getTheme().navigator, { xRange: s } = this.#P();
280
+ const i = this.#e.getTheme().navigator, { xRange: s } = this.#N();
281
281
  this.#G(i, s);
282
282
  }
283
283
  /** Decimate `points` into `buckets`, reusing the cached result while the
@@ -20,7 +20,7 @@ function I(i) {
20
20
  function O(i) {
21
21
  return -I(i) / 12;
22
22
  }
23
- const B = "#9aa6b6", c = "#5d6877", C = "#e8eef7", x = "#cdd6e2", y = "#3fd68f", V = "#f5c451", $ = "#f4756a", Y = "#5d6877", X = {
23
+ const V = "#9aa6b6", c = "#5d6877", C = "#e8eef7", x = "#cdd6e2", y = "#3fd68f", B = "#f5c451", $ = "#f4756a", Y = "#5d6877", X = {
24
24
  position: "absolute",
25
25
  top: "8px",
26
26
  right: "8px",
@@ -34,7 +34,7 @@ const B = "#9aa6b6", c = "#5d6877", C = "#e8eef7", x = "#cdd6e2", y = "#3fd68f",
34
34
  border: "1px solid rgba(255, 255, 255, 0.09)",
35
35
  borderRadius: "10px",
36
36
  boxShadow: "0 10px 28px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.05)",
37
- color: B,
37
+ color: V,
38
38
  font: "10px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace",
39
39
  fontVariantNumeric: "tabular-nums",
40
40
  letterSpacing: "0.02em",
@@ -50,7 +50,7 @@ function G(i) {
50
50
  }`, i.head.appendChild(e);
51
51
  }
52
52
  function v(i) {
53
- return i <= H ? y : i <= F ? V : $;
53
+ return i <= H ? y : i <= F ? B : $;
54
54
  }
55
55
  function A(i) {
56
56
  return i >= 1e6 ? `${(i / 1e6).toFixed(1)}M` : i >= 1e4 ? `${(i / 1e3).toFixed(1)}k` : Math.round(i).toLocaleString("en-US");
@@ -74,8 +74,9 @@ class m {
74
74
  const t = [];
75
75
  let e = !1;
76
76
  for (const [o, r] of this.#t) {
77
+ r.animating && (e = !0);
77
78
  const i = r.current;
78
- i <= 0 || (t.push({ value: o, opacity: i }), r.animating && (e = !0));
79
+ i <= 0 || t.push({ value: o, opacity: i });
79
80
  }
80
81
  return { entries: t, isAnimating: e };
81
82
  }
@@ -0,0 +1,99 @@
1
+ const d = (e) => -new Date(e).getTimezoneOffset() * 6e4, M = () => 0, l = /* @__PURE__ */ new Map();
2
+ function F(e) {
3
+ const t = U(e.timeZone);
4
+ return e.interval < 864e5 ? T(e, t) : v(e, t);
5
+ }
6
+ function T(e, t) {
7
+ const { from: n, to: o, interval: i, max: r } = e, a = [];
8
+ if (!(Number.isFinite(n) && Number.isFinite(o) && n <= o)) return a;
9
+ let u = t(n), f = n, c = y({ start: n, offset: u, interval: i });
10
+ for (; a.length < r; ) {
11
+ const h = Math.min(c, o);
12
+ if (t(h) !== u) {
13
+ const m = g({ from: f, to: h, offsetAt: t });
14
+ u = t(m), f = m, c = y({ start: m, offset: u, interval: i });
15
+ continue;
16
+ }
17
+ if (c > o) break;
18
+ a.push(c), f = c, c += i;
19
+ }
20
+ return a;
21
+ }
22
+ function y(e) {
23
+ const { start: t, offset: n, interval: o } = e;
24
+ return Math.ceil((t + n) / o) * o - n;
25
+ }
26
+ function g(e) {
27
+ const { offsetAt: t } = e, n = t(e.from);
28
+ let o = e.from, i = e.to;
29
+ for (; i - o > 1; ) {
30
+ const r = Math.floor((o + i) / 2);
31
+ t(r) === n ? o = r : i = r;
32
+ }
33
+ return i;
34
+ }
35
+ function v(e, t) {
36
+ const { from: n, to: o, interval: i, max: r } = e, a = p(i, new Date(n + t(n))), u = [];
37
+ for (let f = 0; u.length < r; f++) {
38
+ const c = C(a(f), t);
39
+ if (!(c <= o)) break;
40
+ c >= n && u.push(c);
41
+ }
42
+ return u;
43
+ }
44
+ function p(e, t) {
45
+ const n = t.getUTCFullYear(), o = t.getUTCMonth(), i = t.getUTCDate();
46
+ if (e >= 31536e6) {
47
+ const r = Math.round(e / 31536e6), a = Math.floor(n / r) * r;
48
+ return (u) => s({ year: a + u * r, month: 0, day: 1 });
49
+ }
50
+ if (e >= 2592e6) {
51
+ const r = e >= 7776e6 ? 3 : 1, a = Math.floor(o / r) * r;
52
+ return (u) => s({ year: n, month: a + u * r, day: 1 });
53
+ }
54
+ if (e >= 6048e5) {
55
+ const r = (t.getUTCDay() + 6) % 7;
56
+ return (a) => s({ year: n, month: o, day: i - r + a * 7 });
57
+ }
58
+ return (r) => s({ year: n, month: o, day: i + r });
59
+ }
60
+ function s(e) {
61
+ const t = /* @__PURE__ */ new Date(0);
62
+ return t.setUTCFullYear(e.year, e.month, e.day), t.getTime();
63
+ }
64
+ function C(e, t) {
65
+ const n = e - t(e - 864e5), o = e - t(e + 864e5), i = n + t(n) === e, r = o + t(o) === e;
66
+ return i && r ? Math.min(n, o) : r ? o : n;
67
+ }
68
+ function U(e) {
69
+ if (e === void 0) return d;
70
+ if (e === "UTC") return M;
71
+ let t = l.get(e);
72
+ return t === void 0 && (t = D(e), l.set(e, t)), t;
73
+ }
74
+ function D(e) {
75
+ const t = new Intl.DateTimeFormat("en-US", {
76
+ timeZone: e,
77
+ hourCycle: "h23",
78
+ year: "numeric",
79
+ month: "numeric",
80
+ day: "numeric",
81
+ hour: "numeric",
82
+ minute: "numeric",
83
+ second: "numeric"
84
+ }), n = /* @__PURE__ */ new Map();
85
+ return (o) => {
86
+ const i = Math.floor(o / 9e5);
87
+ let r = n.get(i);
88
+ return r === void 0 && (n.size >= 4096 && n.clear(), r = w(t, i * 9e5), n.set(i, r)), r;
89
+ };
90
+ }
91
+ function w(e, t) {
92
+ const n = { year: 0, month: 1, day: 1, hour: 0, minute: 0, second: 0 };
93
+ for (const o of e.formatToParts(t))
94
+ o.type in n && (n[o.type] = Number(o.value));
95
+ return s({ year: n.year, month: n.month - 1, day: n.day }) + ((n.hour * 60 + n.minute) * 60 + n.second) * 1e3 - t;
96
+ }
97
+ export {
98
+ F as timeTicks
99
+ };