@wick-charts/vue 0.5.1 → 0.6.1
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.
- package/README.md +45 -6
- package/dist/BarSeries.vue.js +26 -20
- package/dist/CandlestickSeries.vue.js +30 -24
- package/dist/ChartContainer.vue.js +125 -72
- package/dist/HeatmapSeries.vue.js +40 -0
- package/dist/HeatmapSeries.vue2.js +4 -0
- package/dist/LineSeries.vue.js +26 -20
- package/dist/PieSeries.vue.js +24 -18
- package/dist/core/dist/animation/animator.js +21 -21
- package/dist/core/dist/animation/config.js +114 -87
- package/dist/core/dist/animation/easing.js +3 -1
- package/dist/core/dist/animation/intro-wave.js +68 -0
- package/dist/core/dist/axis/dom-labels.js +13 -14
- package/dist/core/dist/chart/badge-animator.js +56 -0
- package/dist/core/dist/chart/edge-indicators.js +28 -13
- package/dist/core/dist/chart/last-value.js +18 -17
- package/dist/core/dist/chart/options.js +27 -16
- package/dist/core/dist/chart/y-target.js +13 -12
- package/dist/core/dist/chart.js +868 -441
- package/dist/core/dist/components/annotation-chip.js +28 -0
- package/dist/core/dist/components/crosshair.js +8 -6
- package/dist/core/dist/components/edge-indicator.js +58 -26
- package/dist/core/dist/components/loading-indicator.js +46 -0
- package/dist/core/dist/components/marker.js +49 -31
- package/dist/core/dist/components/reference-line.js +27 -36
- package/dist/core/dist/components/time-region.js +30 -28
- package/dist/core/dist/data/store.js +38 -19
- package/dist/core/dist/data/sync.js +60 -38
- package/dist/core/dist/heatmap-tooltip.js +16 -0
- package/dist/core/dist/interactions/handler.js +86 -46
- package/dist/core/dist/perf/perf-hud.js +5 -5
- package/dist/core/dist/scales/x-scale.js +85 -37
- package/dist/core/dist/scales/y-scale.js +38 -27
- package/dist/core/dist/series/bar-intro.js +18 -0
- package/dist/core/dist/series/bar.js +337 -205
- package/dist/core/dist/series/base-multi-layer.js +224 -96
- package/dist/core/dist/series/candlestick-intro.js +57 -0
- package/dist/core/dist/series/candlestick.js +454 -276
- package/dist/core/dist/series/heatmap.js +387 -0
- package/dist/core/dist/series/line-intro.js +85 -0
- package/dist/core/dist/series/line.js +590 -282
- package/dist/core/dist/series/painters/builtins.js +2 -2
- package/dist/core/dist/series/pie.js +396 -259
- package/dist/core/dist/series/register-builtins.js +8 -7
- package/dist/core/dist/series/types.js +6 -0
- package/dist/core/dist/series/wave-intro.js +26 -0
- package/dist/core/dist/theme/create.js +69 -63
- package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
- package/dist/core/dist/theme/themes/sand-dune.js +2 -2
- package/dist/core/dist/utils/color.js +109 -34
- package/dist/core/dist/utils/deep-equal.js +18 -0
- package/dist/core/dist/utils/time.js +25 -19
- package/dist/index.d.ts +1494 -122
- package/dist/index.js +177 -130
- package/dist/ui/Crosshair.vue.js +20 -21
- package/dist/ui/HeatmapTooltip.vue.js +96 -0
- package/dist/ui/HeatmapTooltip.vue2.js +4 -0
- package/dist/ui/InfoBar.vue.js +46 -47
- package/dist/ui/Legend.vue.js +80 -79
- package/dist/ui/PieLegend.vue.js +5 -5
- package/dist/ui/PieTooltip.vue.js +77 -67
- package/dist/ui/Tooltip.vue.js +60 -60
- package/dist/ui/YAxis.vue.js +2 -2
- package/dist/ui/YLabel.vue.js +94 -61
- package/package.json +2 -2
- package/src/BarSeries.vue +23 -7
- package/src/CandlestickSeries.vue +23 -7
- package/src/ChartContainer.vue +250 -13
- package/src/HeatmapSeries.vue +69 -0
- package/src/LineSeries.vue +23 -7
- package/src/PieSeries.vue +22 -6
- package/src/index.ts +84 -3
- package/src/ui/Crosshair.vue +1 -2
- package/src/ui/HeatmapTooltip.vue +144 -0
- package/src/ui/InfoBar.vue +1 -2
- package/src/ui/Legend.vue +13 -0
- package/src/ui/Marker.vue +1 -1
- package/src/ui/PieTooltip.vue +10 -0
- package/src/ui/ReferenceLine.vue +2 -2
- package/src/ui/TimeRegion.vue +2 -2
- package/src/ui/Tooltip.vue +2 -2
- package/src/ui/YLabel.vue +123 -8
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Animator as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { Animator as y } from "../animation/animator.js";
|
|
2
|
+
import { IntroWave as c } from "../animation/intro-wave.js";
|
|
3
|
+
import { ScalarSpring as V } from "../animation/scalar-spring.js";
|
|
4
|
+
import { TimeSeriesStore as L } from "../data/store.js";
|
|
5
|
+
import { resolveColor as A } from "../utils/color.js";
|
|
6
|
+
import { normalizeTimePointArray as m, normalizeTime as g } from "../utils/time.js";
|
|
7
|
+
import { sumStack as p, renderedStackPercentTop as v, renderedStackTop as d } from "./stack-math.js";
|
|
8
|
+
const b = (f, t, e) => f + (t - f) * e;
|
|
9
|
+
class R {
|
|
9
10
|
stores;
|
|
10
11
|
// --- Animation state (per layer) ----------------------------------------
|
|
11
12
|
/**
|
|
@@ -35,10 +36,25 @@ class D {
|
|
|
35
36
|
* loops multiply the layer's alpha into `globalAlpha` per draw.
|
|
36
37
|
*/
|
|
37
38
|
#s;
|
|
39
|
+
/**
|
|
40
|
+
* Initial-load reveal clock — armed once when the dataset transitions
|
|
41
|
+
* empty → non-empty in {@link setData}, shared across every layer so a
|
|
42
|
+
* multi-layer seed rides one wave. Subclasses read it through
|
|
43
|
+
* {@link introProgressAt} (per-element wave) or directly (line's sweep).
|
|
44
|
+
*/
|
|
45
|
+
introWave = new c();
|
|
46
|
+
/** History-prepend reveal clock — armed by {@link prependPoints} so newly
|
|
47
|
+
* loaded older points wave in from the data boundary instead of popping.
|
|
48
|
+
* Shared across layers: a multi-layer prepend rides one wave. */
|
|
49
|
+
historyWave = new c();
|
|
50
|
+
/** Prepended time span: `from` = deepest new point, `to` = the boundary
|
|
51
|
+
* (the pre-prepend first point). Stagger position is `0` at the boundary
|
|
52
|
+
* and `1` at the deepest point. */
|
|
53
|
+
historyRange = null;
|
|
38
54
|
constructor(t) {
|
|
39
|
-
this.stores = Array.from({ length: t }, () => new
|
|
55
|
+
this.stores = Array.from({ length: t }, () => new L()), this.entries = Array.from({ length: t }, () => /* @__PURE__ */ new Map()), this.displayedLastValues = new Array(t).fill(null), this.#t = new Array(t).fill(null), this.#e = new Array(t).fill(null), this.#s = Array.from(
|
|
40
56
|
{ length: t },
|
|
41
|
-
() => new
|
|
57
|
+
() => new y({ initial: 1, duration: 0, lerp: b })
|
|
42
58
|
);
|
|
43
59
|
}
|
|
44
60
|
// --- Color accessors ------------------------------------------------------
|
|
@@ -47,63 +63,88 @@ class D {
|
|
|
47
63
|
* layer on the theme base in `options.colors`). Kept separate from the base so
|
|
48
64
|
* a theme swap, which rewrites `options.colors`, leaves these untouched.
|
|
49
65
|
*/
|
|
50
|
-
#
|
|
66
|
+
#i = [];
|
|
51
67
|
setColorOverrides(t) {
|
|
52
|
-
this.#
|
|
68
|
+
this.#i = t;
|
|
53
69
|
}
|
|
54
70
|
/** The active resolver for a layer — the `data` override if set, else the theme base (cycled). */
|
|
55
|
-
#
|
|
56
|
-
const e = this.#
|
|
71
|
+
#r(t) {
|
|
72
|
+
const e = this.#i[t];
|
|
57
73
|
if (e !== void 0) return e;
|
|
58
74
|
const s = this.options.colors;
|
|
59
75
|
return s[t % s.length];
|
|
60
76
|
}
|
|
61
77
|
/** The first layer's color resolver (string or value-fn). */
|
|
62
78
|
getColor() {
|
|
63
|
-
return this.#
|
|
79
|
+
return this.#r(0);
|
|
64
80
|
}
|
|
65
81
|
getColors() {
|
|
66
82
|
return this.options.colors;
|
|
67
83
|
}
|
|
68
84
|
/** Resolve one layer's color for a given datum value. */
|
|
69
85
|
resolveLayerColor(t, e) {
|
|
70
|
-
return
|
|
86
|
+
return A(this.#r(t), e);
|
|
71
87
|
}
|
|
72
88
|
// --- Data ingest ----------------------------------------------------------
|
|
73
89
|
setData(t, e = 0) {
|
|
74
90
|
const s = this.stores[e];
|
|
75
91
|
if (!s) return;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
let i = !1;
|
|
93
|
+
for (const n of this.stores)
|
|
94
|
+
n.length > 0 && (i = !0);
|
|
95
|
+
const r = m(t ?? []);
|
|
96
|
+
s.setData(r), !i && r.length > 0 && this.introWave.arm(this.options.introMs);
|
|
97
|
+
const l = s.last();
|
|
98
|
+
this.displayedLastValues[e] = l ? l.value : null, this.#t[e] = null, this.#e[e] = null, this.entries[e].clear(), this.historyWave.finish(), this.historyRange = null;
|
|
80
99
|
}
|
|
81
100
|
appendPoint(t, e = 0) {
|
|
82
101
|
const s = this.stores[e];
|
|
83
102
|
if (!s) return;
|
|
84
|
-
const i = t, r =
|
|
103
|
+
const i = t, r = g(i.time), l = s.last(), n = s.length;
|
|
85
104
|
s.append({ ...i, time: r });
|
|
86
105
|
const o = this.#t[e];
|
|
87
|
-
o !== null &&
|
|
106
|
+
o !== null && l !== void 0 && s.length > n && (this.#e[e] = { time: l.time, anim: o }), this.displayedLastValues[e] = i.value, this.#t[e] = null;
|
|
88
107
|
const a = this.options.entryMs;
|
|
89
108
|
this.isEntryEnabled() && a > 0 && this.entries[e].set(r, { startTime: performance.now() });
|
|
90
109
|
}
|
|
110
|
+
prependPoints(t, e = 0) {
|
|
111
|
+
const s = this.stores[e];
|
|
112
|
+
if (!s || t.length === 0) return;
|
|
113
|
+
const i = m(t), r = s.first()?.time;
|
|
114
|
+
s.prepend(i), this.#n(i[0]?.time, r);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Arm (or extend) the history-reveal wave for freshly prepended points.
|
|
118
|
+
* While a reveal is already in flight — including a same-frame prepend to
|
|
119
|
+
* another layer — only the range grows; restarting the clock would snap
|
|
120
|
+
* half-revealed points back to invisible.
|
|
121
|
+
*/
|
|
122
|
+
#n(t, e) {
|
|
123
|
+
const s = this.options.historyRevealMs;
|
|
124
|
+
if (!(this.options.historyReveal === "none" || s <= 0) && !(t === void 0 || e === void 0)) {
|
|
125
|
+
if (this.historyWave.active && this.historyRange !== null) {
|
|
126
|
+
this.historyRange = { from: Math.min(this.historyRange.from, t), to: this.historyRange.to };
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.historyRange = { from: t, to: e }, this.historyWave.arm(s);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
91
132
|
updateLastPoint(t, e = 0) {
|
|
92
133
|
const s = this.stores[e];
|
|
93
134
|
if (!s) return;
|
|
94
135
|
const i = t;
|
|
95
|
-
s.updateLast({ ...i, time:
|
|
96
|
-
const r = i.value,
|
|
97
|
-
if (
|
|
136
|
+
s.updateLast({ ...i, time: g(i.time) });
|
|
137
|
+
const r = i.value, l = this.options.smoothMs;
|
|
138
|
+
if (l <= 0) {
|
|
98
139
|
this.displayedLastValues[e] = r, this.#t[e] = null;
|
|
99
140
|
return;
|
|
100
141
|
}
|
|
101
|
-
let
|
|
102
|
-
if (
|
|
142
|
+
let n = this.#t[e];
|
|
143
|
+
if (n === null) {
|
|
103
144
|
const o = this.displayedLastValues[e] ?? r;
|
|
104
|
-
|
|
145
|
+
n = new V(o), this.#t[e] = n;
|
|
105
146
|
}
|
|
106
|
-
|
|
147
|
+
n.retarget(r, { settleMs: l });
|
|
107
148
|
}
|
|
108
149
|
keepLast(t, e = 0) {
|
|
109
150
|
const s = this.stores[e];
|
|
@@ -146,15 +187,42 @@ class D {
|
|
|
146
187
|
/**
|
|
147
188
|
* Per-point entrance progress in `[0, 1]`. Reads the local entry registry,
|
|
148
189
|
* returning `1` for a settled or absent entry (which matches the visual
|
|
149
|
-
* default: nothing to fade in).
|
|
190
|
+
* default: nothing to fade in). Takes no render context — progress is a
|
|
191
|
+
* pure function of wall time — so tooltip/last-value queries (which have
|
|
192
|
+
* no context to hand) can read it too.
|
|
150
193
|
*/
|
|
151
|
-
entranceProgress(t, e
|
|
152
|
-
const
|
|
153
|
-
if (
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
156
|
-
const
|
|
157
|
-
return
|
|
194
|
+
entranceProgress(t, e) {
|
|
195
|
+
const s = this.entries[t]?.get(e);
|
|
196
|
+
if (s === void 0) return 1;
|
|
197
|
+
const i = this.options.entryMs;
|
|
198
|
+
if (i <= 0) return 1;
|
|
199
|
+
const r = performance.now() - s.startTime;
|
|
200
|
+
return r <= 0 ? 0 : r >= i ? 1 : r / i;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Initial-load reveal progress for a datum, keyed by its normalized
|
|
204
|
+
* position across the *visible* time window — the wave sweeps whatever
|
|
205
|
+
* the user actually sees, regardless of how much history sits off-screen.
|
|
206
|
+
* `1` when no intro is in flight. Subclasses that animate per element
|
|
207
|
+
* (bar) fold this into their {@link entranceProgress} override; the line
|
|
208
|
+
* renders its own continuous sweep instead.
|
|
209
|
+
*/
|
|
210
|
+
introProgressAt(t, e) {
|
|
211
|
+
if (!this.introWave.active) return 1;
|
|
212
|
+
const s = t.timeScale.getRange(), i = s.to - s.from, r = i > 0 ? (e - s.from) / i : 0;
|
|
213
|
+
return this.introWave.progressAt(r);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* History-prepend reveal progress for a datum. Stagger position is
|
|
217
|
+
* anchored at the data boundary — `0` there, `1` at the deepest prepended
|
|
218
|
+
* point — so the wave travels into history. `1` for points outside the
|
|
219
|
+
* prepended span or when no reveal is in flight.
|
|
220
|
+
*/
|
|
221
|
+
historyProgressAt(t) {
|
|
222
|
+
const e = this.historyRange;
|
|
223
|
+
if (!this.historyWave.active || e === null || t >= e.to) return 1;
|
|
224
|
+
const s = e.to - e.from, i = s > 0 ? (e.to - t) / s : 0;
|
|
225
|
+
return this.historyWave.progressAt(i);
|
|
158
226
|
}
|
|
159
227
|
/**
|
|
160
228
|
* Trailing data points whose entrance is still unsettled, oldest first.
|
|
@@ -167,16 +235,16 @@ class D {
|
|
|
167
235
|
* on every append. Renderers lerp each chain link from the previous
|
|
168
236
|
* link's *rendered* position instead, so geometry stays continuous.
|
|
169
237
|
*/
|
|
170
|
-
unsettledTail(t
|
|
171
|
-
const
|
|
172
|
-
if (!
|
|
173
|
-
const
|
|
174
|
-
for (let
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
177
|
-
|
|
238
|
+
unsettledTail(t) {
|
|
239
|
+
const e = this.stores[t]?.getAll();
|
|
240
|
+
if (!e || e.length < 2) return [];
|
|
241
|
+
const s = [];
|
|
242
|
+
for (let i = e.length - 1; i >= 1; i--) {
|
|
243
|
+
const r = this.entranceProgress(t, e[i].time);
|
|
244
|
+
if (r >= 1) break;
|
|
245
|
+
s.unshift({ time: e[i].time, progress: r });
|
|
178
246
|
}
|
|
179
|
-
return
|
|
247
|
+
return s;
|
|
180
248
|
}
|
|
181
249
|
/**
|
|
182
250
|
* Substitute the renderer-smoothed last value for `rawValue` when the
|
|
@@ -186,11 +254,31 @@ class D {
|
|
|
186
254
|
* happened yet.
|
|
187
255
|
*/
|
|
188
256
|
effectiveValue(t, e, s, i) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
257
|
+
return this.liveValue(e, s, i);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The ctx-independent core of {@link effectiveValue} — used directly by the
|
|
261
|
+
* tooltip/last-value query methods below, which have no render context to
|
|
262
|
+
* hand a subclass's ctx-dependent override (e.g. Line's intro value
|
|
263
|
+
* transform). Those queries only need the live smoothing/chase this base
|
|
264
|
+
* method already provides, never the intro's positional transform.
|
|
265
|
+
*/
|
|
266
|
+
liveValue(t, e, s) {
|
|
267
|
+
const i = this.stores[t]?.last()?.time;
|
|
268
|
+
if (i !== void 0 && e === i)
|
|
269
|
+
return this.displayedLastValues[t] ?? s;
|
|
270
|
+
const r = this.#e[t];
|
|
271
|
+
return r !== null && r.time === e ? r.anim.current : s;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Value a last-value/tooltip query should report for `time` — defaults to
|
|
275
|
+
* {@link liveValue}. Distinct from `liveValue` so a subclass can layer its
|
|
276
|
+
* *entrance* animation's value-space equivalent on top (see Line's
|
|
277
|
+
* override) without that lerp feeding back into `effectiveValue`, which
|
|
278
|
+
* the renderer's own per-point draws use as an unlerp'd target.
|
|
279
|
+
*/
|
|
280
|
+
snapshotValue(t, e, s) {
|
|
281
|
+
return this.liveValue(t, e, s);
|
|
194
282
|
}
|
|
195
283
|
// --- Animation lifecycle --------------------------------------------------
|
|
196
284
|
/**
|
|
@@ -200,12 +288,13 @@ class D {
|
|
|
200
288
|
* `performance.now`) can drive progression deterministically.
|
|
201
289
|
*/
|
|
202
290
|
tickAnimations(t) {
|
|
291
|
+
this.introWave.tick(t), this.historyWave.tick(t);
|
|
203
292
|
for (const e of this.#s) e.tick(t);
|
|
204
293
|
for (let e = 0; e < this.stores.length; e++) {
|
|
205
294
|
const s = this.#t[e];
|
|
206
295
|
if (s !== null) {
|
|
207
|
-
const
|
|
208
|
-
this.displayedLastValues[e] = s.current,
|
|
296
|
+
const n = s.tick(t);
|
|
297
|
+
this.displayedLastValues[e] = s.current, n || (this.#t[e] = null);
|
|
209
298
|
}
|
|
210
299
|
const i = this.#e[e];
|
|
211
300
|
i !== null && !i.anim.tick(t) && (this.#e[e] = null);
|
|
@@ -214,13 +303,15 @@ class D {
|
|
|
214
303
|
this.entries[e].clear();
|
|
215
304
|
continue;
|
|
216
305
|
}
|
|
217
|
-
const
|
|
218
|
-
for (const [
|
|
219
|
-
t - o.startTime >= r &&
|
|
306
|
+
const l = this.entries[e];
|
|
307
|
+
for (const [n, o] of l)
|
|
308
|
+
t - o.startTime >= r && l.delete(n);
|
|
220
309
|
}
|
|
221
310
|
}
|
|
222
|
-
/** True while any layer has an active chase, unsettled entry,
|
|
311
|
+
/** True while any layer has an active chase, unsettled entry, alpha fade,
|
|
312
|
+
* or the initial-load reveal is still sweeping. */
|
|
223
313
|
get needsAnimation() {
|
|
314
|
+
if (this.introWave.active || this.historyWave.active) return !0;
|
|
224
315
|
for (const t of this.#s)
|
|
225
316
|
if (t.animating) return !0;
|
|
226
317
|
for (const t of this.#t)
|
|
@@ -231,12 +322,18 @@ class D {
|
|
|
231
322
|
if (t.size > 0) return !0;
|
|
232
323
|
return !1;
|
|
233
324
|
}
|
|
325
|
+
/** Reveal-front position of the initial-load intro; `1` once settled. */
|
|
326
|
+
getIntroFront() {
|
|
327
|
+
return this.introWave.sweep();
|
|
328
|
+
}
|
|
234
329
|
/**
|
|
235
|
-
* Abort in-flight per-point entrance animations on every layer
|
|
236
|
-
* chase (`displayedLastValues`) is
|
|
237
|
-
* is subtle and shouldn't jump when
|
|
330
|
+
* Abort in-flight per-point entrance animations on every layer, including
|
|
331
|
+
* the initial-load reveal. Live-value chase (`displayedLastValues`) is
|
|
332
|
+
* intentionally left alone — its motion is subtle and shouldn't jump when
|
|
333
|
+
* the viewport moves.
|
|
238
334
|
*/
|
|
239
335
|
cancelEntranceAnimations() {
|
|
336
|
+
this.introWave.finish();
|
|
240
337
|
for (const t of this.entries) t.clear();
|
|
241
338
|
}
|
|
242
339
|
/**
|
|
@@ -296,18 +393,21 @@ class D {
|
|
|
296
393
|
if (!this.stores[i].isVisible()) continue;
|
|
297
394
|
const r = this.stores[i].getVisibleData(t - e, t + e);
|
|
298
395
|
if (r.length === 0) continue;
|
|
299
|
-
let
|
|
396
|
+
let l = r[0], n = Math.abs(r[0].time - t);
|
|
300
397
|
for (let o = 1; o < r.length; o++) {
|
|
301
398
|
const a = Math.abs(r[o].time - t);
|
|
302
|
-
a <=
|
|
399
|
+
a <= n && (n = a, l = r[o]);
|
|
303
400
|
}
|
|
304
401
|
s.push({
|
|
305
402
|
layerIndex: i,
|
|
306
|
-
time:
|
|
307
|
-
|
|
403
|
+
time: l.time,
|
|
404
|
+
// Routes through the same live/pinned-chase smoothing the renderer
|
|
405
|
+
// paints, so hovering the live edge mid-animation doesn't jump ahead
|
|
406
|
+
// to the raw target before the on-screen marker gets there.
|
|
407
|
+
value: this.snapshotValue(i, l.time, l.value),
|
|
308
408
|
// Resolve the layer's color at the hovered datum's value so a value-fn
|
|
309
409
|
// colors the tooltip dot to match the bar / segment under the cursor.
|
|
310
|
-
color: this.resolveLayerColor(i,
|
|
410
|
+
color: this.resolveLayerColor(i, l.value)
|
|
311
411
|
});
|
|
312
412
|
}
|
|
313
413
|
return s.length > 0 ? s : null;
|
|
@@ -315,32 +415,60 @@ class D {
|
|
|
315
415
|
getStackedLastValue() {
|
|
316
416
|
if (this.stores.length <= 1) {
|
|
317
417
|
const r = this.stores[0]?.last();
|
|
318
|
-
return r ? { value: r.value, isLive: !0 } : null;
|
|
319
|
-
}
|
|
320
|
-
let t = -1 / 0;
|
|
321
|
-
for (const r of this.stores) {
|
|
322
|
-
if (!r.isVisible()) continue;
|
|
323
|
-
const n = r.last();
|
|
324
|
-
n && n.time > t && (t = n.time);
|
|
418
|
+
return r ? { value: this.snapshotValue(0, r.time, r.value), isLive: !0 } : null;
|
|
325
419
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (e === "off") {
|
|
420
|
+
const t = this.options.stacking;
|
|
421
|
+
if (t === "off") {
|
|
329
422
|
for (let r = this.stores.length - 1; r >= 0; r--) {
|
|
330
423
|
if (!this.stores[r].isVisible()) continue;
|
|
331
|
-
const
|
|
332
|
-
if (
|
|
424
|
+
const l = this.stores[r].last();
|
|
425
|
+
if (l) return { value: this.snapshotValue(r, l.time, l.value), isLive: !0 };
|
|
333
426
|
}
|
|
334
427
|
return null;
|
|
335
428
|
}
|
|
429
|
+
let e = !1;
|
|
336
430
|
const s = [];
|
|
337
|
-
for (
|
|
338
|
-
if (!r.isVisible()) continue;
|
|
339
|
-
const
|
|
340
|
-
|
|
431
|
+
for (let r = 0; r < this.stores.length; r++) {
|
|
432
|
+
if (!this.stores[r].isVisible()) continue;
|
|
433
|
+
const l = this.stores[r].last();
|
|
434
|
+
if (!l) {
|
|
435
|
+
s.push(0);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
e = !0, s.push(this.snapshotValue(r, l.time, l.value));
|
|
439
|
+
}
|
|
440
|
+
if (!e) return null;
|
|
441
|
+
const i = p(s);
|
|
442
|
+
return { value: t === "percent" ? v(i) : d(i), isLive: !0 };
|
|
443
|
+
}
|
|
444
|
+
getStackedValueAtTime(t, e) {
|
|
445
|
+
if (this.stores.length <= 1) {
|
|
446
|
+
const n = this.stores[0]?.findNearest(t, e);
|
|
447
|
+
return n ? this.snapshotValue(0, n.time, n.value) : null;
|
|
448
|
+
}
|
|
449
|
+
const s = this.options.stacking;
|
|
450
|
+
if (s === "off") {
|
|
451
|
+
for (let n = this.stores.length - 1; n >= 0; n--) {
|
|
452
|
+
if (!this.stores[n].isVisible()) continue;
|
|
453
|
+
const o = this.stores[n].findNearest(t, e);
|
|
454
|
+
if (o) return this.snapshotValue(n, o.time, o.value);
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
let i = !1;
|
|
459
|
+
const r = [];
|
|
460
|
+
for (let n = 0; n < this.stores.length; n++) {
|
|
461
|
+
if (!this.stores[n].isVisible()) continue;
|
|
462
|
+
const o = this.stores[n].findNearest(t, e);
|
|
463
|
+
if (!o) {
|
|
464
|
+
r.push(0);
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
i = !0, r.push(this.snapshotValue(n, o.time, o.value));
|
|
341
468
|
}
|
|
342
|
-
|
|
343
|
-
|
|
469
|
+
if (!i) return null;
|
|
470
|
+
const l = p(r);
|
|
471
|
+
return s === "percent" ? v(l) : d(l);
|
|
344
472
|
}
|
|
345
473
|
getLayerLastSnapshots() {
|
|
346
474
|
if (this.stores.length <= 1) return null;
|
|
@@ -351,7 +479,7 @@ class D {
|
|
|
351
479
|
s && t.push({
|
|
352
480
|
layerIndex: e,
|
|
353
481
|
time: s.time,
|
|
354
|
-
value: s.value,
|
|
482
|
+
value: this.snapshotValue(e, s.time, s.value),
|
|
355
483
|
color: this.resolveLayerColor(e, s.value)
|
|
356
484
|
});
|
|
357
485
|
}
|
|
@@ -412,27 +540,27 @@ class D {
|
|
|
412
540
|
const i = this.stores.map((o) => o.isVisible() ? o.getVisibleData(t, e) : []);
|
|
413
541
|
if (s === "off") {
|
|
414
542
|
let o = 1 / 0, a = -1 / 0;
|
|
415
|
-
for (const
|
|
416
|
-
for (const
|
|
417
|
-
Number.isFinite(
|
|
543
|
+
for (const h of i)
|
|
544
|
+
for (const u of h)
|
|
545
|
+
Number.isFinite(u.value) && (u.value < o && (o = u.value), u.value > a && (a = u.value));
|
|
418
546
|
return o < 1 / 0 ? { min: o, max: a } : null;
|
|
419
547
|
}
|
|
420
548
|
const r = /* @__PURE__ */ new Map();
|
|
421
549
|
for (let o = 0; o < i.length; o++)
|
|
422
550
|
for (const a of i[o]) {
|
|
423
|
-
let
|
|
424
|
-
|
|
551
|
+
let h = r.get(a.time);
|
|
552
|
+
h || (h = new Array(i.length).fill(0), r.set(a.time, h)), h[o] = Number.isFinite(a.value) ? a.value : 0;
|
|
425
553
|
}
|
|
426
|
-
let
|
|
554
|
+
let l = 0, n = 0;
|
|
427
555
|
for (const o of r.values()) {
|
|
428
|
-
let a = 0,
|
|
429
|
-
for (const
|
|
430
|
-
|
|
431
|
-
a >
|
|
556
|
+
let a = 0, h = 0;
|
|
557
|
+
for (const u of o)
|
|
558
|
+
u > 0 ? a += u : h += u;
|
|
559
|
+
a > n && (n = a), h < l && (l = h);
|
|
432
560
|
}
|
|
433
|
-
return
|
|
561
|
+
return n > l ? { min: l, max: n } : null;
|
|
434
562
|
}
|
|
435
563
|
}
|
|
436
564
|
export {
|
|
437
|
-
|
|
565
|
+
R as BaseMultiLayerSeries
|
|
438
566
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { lerp as p } from "../utils/math.js";
|
|
2
|
+
import { fadeIntro as g } from "./wave-intro.js";
|
|
3
|
+
function h(e) {
|
|
4
|
+
return e <= 0 ? 0 : e >= 1 ? 1 : e;
|
|
5
|
+
}
|
|
6
|
+
function w() {
|
|
7
|
+
return () => ({
|
|
8
|
+
element: (e) => ({ unfold: e.progress, alpha: e.progress })
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
const b = 0.55, m = 0.45, d = 0.35, k = 1.5;
|
|
12
|
+
function Y(e = {}) {
|
|
13
|
+
const l = e.fallback ?? g();
|
|
14
|
+
return (r) => {
|
|
15
|
+
const s = r.placeholders;
|
|
16
|
+
if (s === void 0 || s.length === 0) return l(r);
|
|
17
|
+
const f = l(r);
|
|
18
|
+
return {
|
|
19
|
+
...f,
|
|
20
|
+
element: (t) => {
|
|
21
|
+
const u = t.element === "wick" ? t.x : t.x + t.barWidth / 2;
|
|
22
|
+
let o = null, a = 1 / 0;
|
|
23
|
+
for (const c of s) {
|
|
24
|
+
const i = Math.abs(c.x - u);
|
|
25
|
+
i < a && (a = i, o = c);
|
|
26
|
+
}
|
|
27
|
+
if (o === null || a > o.width * k)
|
|
28
|
+
return f.element?.(t) ?? {};
|
|
29
|
+
const n = t.progress;
|
|
30
|
+
return t.element === "volume" ? { alpha: n } : {
|
|
31
|
+
topY: p(o.y - o.halfHeight, t.topY, n),
|
|
32
|
+
bottomY: p(o.y + o.halfHeight, t.bottomY, n),
|
|
33
|
+
offsetX: (o.x - u) * (1 - n),
|
|
34
|
+
alpha: d + (1 - d) * n,
|
|
35
|
+
tint: 1 - n
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function y() {
|
|
42
|
+
return () => ({
|
|
43
|
+
element: (e) => {
|
|
44
|
+
if (e.element === "wick") {
|
|
45
|
+
const r = h(e.progress / b);
|
|
46
|
+
return { unfold: r, alpha: r > 0 ? 1 : 0 };
|
|
47
|
+
}
|
|
48
|
+
const l = h((e.progress - m) / (1 - m));
|
|
49
|
+
return { unfold: l, alpha: l };
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
w as candleUnfoldIntro,
|
|
55
|
+
Y as skeletonMorphIntro,
|
|
56
|
+
y as wickBodyIntro
|
|
57
|
+
};
|