@wick-charts/vue 0.6.1 → 0.6.3
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/dist/ChartContainer.vue.js +43 -37
- package/dist/LineSeries.vue.js +2 -2
- package/dist/composables.js +39 -26
- package/dist/core/dist/animation/config.js +66 -64
- package/dist/core/dist/animation/intro-wave.js +19 -21
- package/dist/core/dist/animation/reduced-motion.js +6 -0
- package/dist/core/dist/axis/dom-labels.js +58 -45
- package/dist/core/dist/chart/badge-animator.js +15 -19
- package/dist/core/dist/chart/options.js +5 -5
- package/dist/core/dist/chart/scale-guards.js +26 -0
- package/dist/core/dist/chart/y-target.js +46 -19
- package/dist/core/dist/chart.js +752 -570
- package/dist/core/dist/components/crosshair.js +8 -8
- package/dist/core/dist/components/grid.js +28 -15
- package/dist/core/dist/components/marker.js +28 -28
- package/dist/core/dist/components/reference-line.js +16 -16
- package/dist/core/dist/interactions/handler.js +3 -2
- package/dist/core/dist/interactions/zoom.js +6 -5
- package/dist/core/dist/navigator/controller.js +43 -40
- package/dist/core/dist/perf/perf-hud.js +3 -3
- package/dist/core/dist/scales/log-scale.js +76 -0
- package/dist/core/dist/scales/tick-tracker.js +2 -2
- package/dist/core/dist/scales/x-scale.js +47 -32
- package/dist/core/dist/scales/y-scale.js +155 -38
- package/dist/core/dist/series/bar-intro.js +11 -11
- package/dist/core/dist/series/bar.js +299 -249
- package/dist/core/dist/series/base-multi-layer.js +100 -76
- package/dist/core/dist/series/candlestick.js +252 -249
- package/dist/core/dist/series/heatmap.js +16 -16
- package/dist/core/dist/series/line-intro.js +18 -18
- package/dist/core/dist/series/line.js +522 -424
- package/dist/core/dist/series/scale-stack.js +25 -0
- package/dist/core/dist/tooltip-position.js +5 -5
- package/dist/core/dist/utils/pixel-grid.js +10 -0
- package/dist/index.d.ts +279 -32
- package/dist/index.js +59 -57
- package/dist/ui/Crosshair.vue.js +14 -14
- package/dist/ui/HeatmapTooltip.vue.js +6 -6
- package/dist/ui/PieTooltip.vue.js +4 -4
- package/dist/ui/TimeAxis.vue.js +23 -22
- package/dist/ui/Tooltip.vue.js +71 -69
- package/dist/ui/YAxis.vue.js +25 -24
- package/dist/ui/YLabel.vue.js +50 -49
- package/package.json +2 -2
- package/src/ChartContainer.vue +20 -8
- package/src/composables.ts +35 -1
- package/src/index.ts +5 -0
- package/src/ui/Crosshair.vue +2 -2
- package/src/ui/TimeAxis.vue +7 -4
- package/src/ui/Tooltip.vue +4 -1
- package/src/ui/YAxis.vue +5 -3
- package/src/ui/YLabel.vue +3 -3
|
@@ -1,74 +1,94 @@
|
|
|
1
|
-
import { DEFAULT_HISTORY_REVEAL as
|
|
2
|
-
import { easeOutCubic as
|
|
3
|
-
import { decimateLineData as
|
|
4
|
-
import { hexToRgba as
|
|
5
|
-
import { lerp as
|
|
6
|
-
import { BaseMultiLayerSeries as
|
|
7
|
-
import { unfoldIntro as
|
|
8
|
-
import { buildCurveSegments as
|
|
9
|
-
import { resolveLinePainter as
|
|
10
|
-
|
|
1
|
+
import { DEFAULT_HISTORY_REVEAL as nt, DEFAULT_LINE_INTRO as lt, DEFAULT_LINE_PULSE as at, DEFAULT_LINE_SMOOTH as rt, DEFAULT_LINE_ENTRY as ht } from "../animation/config.js";
|
|
2
|
+
import { easeOutCubic as U } from "../animation/easing.js";
|
|
3
|
+
import { decimateLineData as q } from "../data/decimation.js";
|
|
4
|
+
import { hexToRgba as X } from "../utils/color.js";
|
|
5
|
+
import { lerp as N } from "../utils/math.js";
|
|
6
|
+
import { BaseMultiLayerSeries as ut } from "./base-multi-layer.js";
|
|
7
|
+
import { unfoldIntro as ft, backfillSweepIntro as pt } from "./line-intro.js";
|
|
8
|
+
import { buildCurveSegments as tt } from "./painters/canvas-path.js";
|
|
9
|
+
import { resolveLinePainter as mt } from "./painters/resolve.js";
|
|
10
|
+
import { ScaleStack as et } from "./scale-stack.js";
|
|
11
|
+
const gt = {
|
|
11
12
|
colors: ["#2962FF"],
|
|
12
13
|
strokeWidth: 1,
|
|
13
14
|
area: { visible: !0 },
|
|
14
15
|
pulse: !0,
|
|
15
16
|
stacking: "off",
|
|
16
17
|
curve: "straight",
|
|
17
|
-
entryMs:
|
|
18
|
-
smoothMs:
|
|
19
|
-
pulseMs:
|
|
20
|
-
introMs:
|
|
21
|
-
historyRevealMs:
|
|
18
|
+
entryMs: ht,
|
|
19
|
+
smoothMs: rt,
|
|
20
|
+
pulseMs: at,
|
|
21
|
+
introMs: lt,
|
|
22
|
+
historyRevealMs: nt
|
|
22
23
|
};
|
|
23
|
-
function
|
|
24
|
-
const t =
|
|
24
|
+
function it(x) {
|
|
25
|
+
const t = x.areaFill, e = t !== void 0 && x.area === void 0 ? { visible: !!t } : x.area;
|
|
25
26
|
return {
|
|
26
|
-
...
|
|
27
|
+
...x,
|
|
27
28
|
area: e,
|
|
28
|
-
entryMs:
|
|
29
|
-
smoothMs:
|
|
30
|
-
pulseMs:
|
|
31
|
-
introMs:
|
|
32
|
-
historyRevealMs:
|
|
29
|
+
entryMs: x.entryMs === !1 ? 0 : x.entryMs ?? ht,
|
|
30
|
+
smoothMs: x.smoothMs === !1 ? 0 : x.smoothMs ?? rt,
|
|
31
|
+
pulseMs: x.pulseMs === !1 ? 0 : x.pulseMs ?? at,
|
|
32
|
+
introMs: x.introMs === !1 ? 0 : x.introMs ?? lt,
|
|
33
|
+
historyRevealMs: x.historyRevealMs === !1 ? 0 : x.historyRevealMs ?? nt
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
-
return
|
|
36
|
+
function ot(x) {
|
|
37
|
+
return x.map(([t, e]) => ({ x: t, y: e }));
|
|
37
38
|
}
|
|
38
|
-
const
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
const J = 0.15, dt = pt();
|
|
40
|
+
function j(x, t, e) {
|
|
41
|
+
const { resolve: i, lerp: o = N } = e;
|
|
42
|
+
if (x.length === 0) return null;
|
|
43
|
+
if (t <= x[0].time) return Number.isFinite(x[0].value) ? i(x[0]) : null;
|
|
44
|
+
const s = x[x.length - 1];
|
|
45
|
+
if (t >= s.time) return Number.isFinite(s.value) ? i(s) : null;
|
|
46
|
+
let l = 0, a = x.length - 1;
|
|
47
|
+
for (; a - l > 1; ) {
|
|
48
|
+
const p = l + a >> 1;
|
|
49
|
+
x[p].time <= t ? l = p : a = p;
|
|
50
|
+
}
|
|
51
|
+
const f = x[l], r = x[a];
|
|
52
|
+
if (!Number.isFinite(f.value) || !Number.isFinite(r.value)) return null;
|
|
53
|
+
const m = r.time - f.time;
|
|
54
|
+
return m <= 0 ? i(f) : o(i(f), i(r), (t - f.time) / m);
|
|
53
55
|
}
|
|
54
|
-
function
|
|
56
|
+
function xt(x, t) {
|
|
57
|
+
const e = t.getTransform();
|
|
58
|
+
let i = 0, o = 0;
|
|
59
|
+
for (const l of x)
|
|
60
|
+
t.isPlottable(l.value) && (i += e === null ? l.value : e.forward(l.value), o++);
|
|
61
|
+
if (o === 0) return null;
|
|
62
|
+
const s = i / o;
|
|
63
|
+
return e === null ? s : e.inverse(s);
|
|
64
|
+
}
|
|
65
|
+
function vt(x, t) {
|
|
66
|
+
let e = 0, i = x.length - 1;
|
|
67
|
+
for (; e <= i; ) {
|
|
68
|
+
const o = e + i >> 1;
|
|
69
|
+
if (x[o] === t) return o;
|
|
70
|
+
x[o] < t ? e = o + 1 : i = o - 1;
|
|
71
|
+
}
|
|
72
|
+
return -1;
|
|
73
|
+
}
|
|
74
|
+
function st(x, t) {
|
|
55
75
|
for (const e of t)
|
|
56
|
-
e.kind === "line" ?
|
|
76
|
+
e.kind === "line" ? x.lineTo(e.x, e.y) : x.bezierCurveTo(e.cp1x, e.cp1y, e.cp2x, e.cp2y, e.x, e.y);
|
|
57
77
|
}
|
|
58
|
-
function
|
|
78
|
+
function yt(x, t, e) {
|
|
59
79
|
for (let i = e.length - 1; i >= 0; i--) {
|
|
60
|
-
const
|
|
61
|
-
|
|
80
|
+
const o = e[i], s = i > 0 ? e[i - 1] : t[0];
|
|
81
|
+
o.kind === "line" ? x.lineTo(s.x, s.y) : x.bezierCurveTo(o.cp2x, o.cp2y, o.cp1x, o.cp1y, s.x, s.y);
|
|
62
82
|
}
|
|
63
83
|
}
|
|
64
|
-
class
|
|
84
|
+
class bt extends ut {
|
|
65
85
|
kind = "line";
|
|
66
86
|
areaGradientCache = /* @__PURE__ */ new Map();
|
|
67
87
|
constructor(t, e) {
|
|
68
|
-
super(t), this.options =
|
|
88
|
+
super(t), this.options = it({ ...gt, ...e });
|
|
69
89
|
}
|
|
70
90
|
updateOptions(t) {
|
|
71
|
-
this.options =
|
|
91
|
+
this.options = it({ ...this.options, ...t });
|
|
72
92
|
}
|
|
73
93
|
getStacking() {
|
|
74
94
|
return this.options.stacking;
|
|
@@ -89,24 +109,24 @@ class mt extends rt {
|
|
|
89
109
|
hasOverlayContentInRange(t, e) {
|
|
90
110
|
for (let i = 0; i < this.stores.length; i++) {
|
|
91
111
|
if (this.getLayerAlpha(i) <= 0) continue;
|
|
92
|
-
const
|
|
93
|
-
if (
|
|
112
|
+
const o = this.stores[i].last();
|
|
113
|
+
if (o && o.time >= t) return !0;
|
|
94
114
|
}
|
|
95
115
|
return !1;
|
|
96
116
|
}
|
|
97
117
|
render(t) {
|
|
98
|
-
this.tickAnimations(performance.now());
|
|
118
|
+
this.tickAnimations(performance.now()), this.lastYScale = t.yScale;
|
|
99
119
|
const { context: e } = t.scope;
|
|
100
120
|
this.historyDirectives = null;
|
|
101
121
|
const i = this.historyRange;
|
|
102
122
|
if (this.historyWave.active && i !== null) {
|
|
103
|
-
const
|
|
104
|
-
|
|
123
|
+
const a = this.options.historyReveal ?? dt;
|
|
124
|
+
a !== "none" && (this.historyDirectives = a(this.buildHistoryFrame(t, i)));
|
|
105
125
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
this.introWave.active ? this.renderWithIntro(t) : (this.introDirectives = null, this.renderBody(t)),
|
|
126
|
+
const o = this.historyDirectives, s = o?.ghostAlpha ?? 0;
|
|
127
|
+
s > 0 && (e.save(), e.globalAlpha *= s, this.introGhostPass = !0, this.renderBody(t), this.introGhostPass = !1, e.restore());
|
|
128
|
+
const l = this.applyHistoryClip(t, o, i);
|
|
129
|
+
this.introWave.active ? this.renderWithIntro(t) : (this.introDirectives = null, this.renderBody(t)), l && e.restore(), o?.heads !== void 0 && o.heads.length > 0 && this.drawIntroHeads(t, o.heads, this.historyWave.linear());
|
|
110
130
|
}
|
|
111
131
|
/**
|
|
112
132
|
* Initial-load intro pass: the resolved LineIntroFn describes this frame
|
|
@@ -116,14 +136,14 @@ class mt extends rt {
|
|
|
116
136
|
renderWithIntro(t) {
|
|
117
137
|
const e = this.resolveIntro()(this.buildIntroFrame(t));
|
|
118
138
|
this.introDirectives = e;
|
|
119
|
-
const { context: i } = t.scope, { width:
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
const
|
|
124
|
-
i.save(), i.beginPath(), i.rect(
|
|
139
|
+
const { context: i } = t.scope, { width: o, height: s } = t.scope.bitmapSize, l = e.ghostAlpha ?? 0;
|
|
140
|
+
l > 0 && (i.save(), i.globalAlpha *= l, this.introGhostPass = !0, this.renderBody(t), this.introGhostPass = !1, i.restore());
|
|
141
|
+
const a = e.clip, f = a !== void 0 && (a.fromX !== void 0 || a.toX !== void 0);
|
|
142
|
+
if (f) {
|
|
143
|
+
const r = a.fromX ?? 0, m = a.toX ?? o;
|
|
144
|
+
i.save(), i.beginPath(), i.rect(r, 0, Math.max(0, m - r), s), i.clip();
|
|
125
145
|
}
|
|
126
|
-
this.renderBody(t),
|
|
146
|
+
this.renderBody(t), f && i.restore(), e.heads !== void 0 && e.heads.length > 0 && this.drawIntroHeads(t, e.heads, this.introWave.linear());
|
|
127
147
|
}
|
|
128
148
|
/**
|
|
129
149
|
* Apply the history reveal's clip directive, mapped from reveal space
|
|
@@ -132,14 +152,22 @@ class mt extends rt {
|
|
|
132
152
|
* small pad keeps the stroke cap at the reveal front from being shaved.
|
|
133
153
|
*/
|
|
134
154
|
applyHistoryClip(t, e, i) {
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
const { context:
|
|
138
|
-
return
|
|
155
|
+
const o = e?.clip;
|
|
156
|
+
if (o === void 0 || i === null || o.fromX === void 0 && o.toX === void 0) return !1;
|
|
157
|
+
const { context: s } = t.scope, { width: l, height: a } = t.scope.bitmapSize, f = t.timeScale.timeToBitmapXExact(i.to), r = Math.abs(f - t.timeScale.timeToBitmapXExact(i.from)), m = Math.max(2, (this.options.strokeWidth ?? 1) * t.scope.horizontalPixelRatio), p = o.fromX ?? 0, v = o.toX ?? r;
|
|
158
|
+
return s.save(), s.beginPath(), s.rect(f - v - m, 0, Math.max(0, v - p + m), a), s.rect(f, 0, Math.max(0, l - f), a), s.clip(), !0;
|
|
139
159
|
}
|
|
140
160
|
renderBody(t) {
|
|
141
|
-
this.options.stacking === "off" ? this.renderOff(t) : this.renderStacked(t, this.options.stacking === "percent");
|
|
161
|
+
this.options.stacking === "off" ? (this.stackedEdges = null, this.renderOff(t)) : this.renderStacked(t, this.options.stacking === "percent");
|
|
142
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* What the stacked pass drew this frame, in data space — shared columns,
|
|
165
|
+
* their eased cumulative per layer, and the per-column grow chain. Lets the
|
|
166
|
+
* overlay's dots reproduce the painted geometry against its own scales
|
|
167
|
+
* instead of re-deriving the entrance from a different chain.
|
|
168
|
+
* `null` when the stacked path didn't run.
|
|
169
|
+
*/
|
|
170
|
+
stackedEdges = null;
|
|
143
171
|
/** True while a ghost pre-pass is drawing — skips the area fill so the
|
|
144
172
|
* translucent pass shows only the stroke skeleton. */
|
|
145
173
|
introGhostPass = !1;
|
|
@@ -151,11 +179,13 @@ class mt extends rt {
|
|
|
151
179
|
introDirectives = null;
|
|
152
180
|
/** Per-frame history-reveal directives; `null` when no reveal is in flight. */
|
|
153
181
|
historyDirectives = null;
|
|
182
|
+
/** Y scale of the last render — value queries run without a render context. */
|
|
183
|
+
lastYScale = null;
|
|
154
184
|
/** Default intro, built lazily — one instance per renderer. */
|
|
155
185
|
defaultIntro = null;
|
|
156
186
|
resolveIntro() {
|
|
157
187
|
const t = this.options.introAnimation;
|
|
158
|
-
return t !== void 0 ? t : (this.defaultIntro === null && (this.defaultIntro =
|
|
188
|
+
return t !== void 0 ? t : (this.defaultIntro === null && (this.defaultIntro = ft()), this.defaultIntro);
|
|
159
189
|
}
|
|
160
190
|
/**
|
|
161
191
|
* Frame context handed to the intro fn — progress plus memoized data
|
|
@@ -181,54 +211,51 @@ class mt extends rt {
|
|
|
181
211
|
return this.buildFrame(t, {
|
|
182
212
|
progress: this.historyWave.linear(),
|
|
183
213
|
range: e,
|
|
184
|
-
width: Math.abs(
|
|
214
|
+
width: Math.abs(
|
|
215
|
+
t.timeScale.timeToBitmapXExact(e.to) - t.timeScale.timeToBitmapXExact(e.from)
|
|
216
|
+
)
|
|
185
217
|
});
|
|
186
218
|
}
|
|
187
219
|
buildFrame(t, e) {
|
|
188
|
-
const { timeScale: i, yScale:
|
|
189
|
-
let
|
|
190
|
-
const
|
|
191
|
-
let
|
|
192
|
-
return
|
|
220
|
+
const { timeScale: i, yScale: o, scope: s } = t, { progress: l, range: a, width: f } = e, r = new Array(this.stores.length), m = new Array(this.stores.length);
|
|
221
|
+
let p;
|
|
222
|
+
const v = (n) => {
|
|
223
|
+
let u = r[n];
|
|
224
|
+
return u === void 0 && (u = this.stores[n]?.getVisibleData(a.from, a.to) ?? [], r[n] = u), u;
|
|
193
225
|
};
|
|
194
226
|
return {
|
|
195
|
-
progress:
|
|
196
|
-
range:
|
|
197
|
-
width:
|
|
198
|
-
height:
|
|
227
|
+
progress: l,
|
|
228
|
+
range: a,
|
|
229
|
+
width: f,
|
|
230
|
+
height: o.getMediaHeight() * s.verticalPixelRatio,
|
|
199
231
|
stacking: this.options.stacking,
|
|
200
|
-
timeToX: (
|
|
201
|
-
xToTime: (
|
|
202
|
-
valueToY: (
|
|
232
|
+
timeToX: (n) => i.timeToBitmapXExact(n),
|
|
233
|
+
xToTime: (n) => i.xToTime(n / s.horizontalPixelRatio),
|
|
234
|
+
valueToY: (n) => o.valueToBitmapYExact(n),
|
|
235
|
+
lerpValue: (n, u, c) => o.lerpValue(n, u, c),
|
|
203
236
|
layerCount: this.stores.length,
|
|
204
|
-
layerData:
|
|
205
|
-
layerMean: (
|
|
206
|
-
let
|
|
207
|
-
|
|
208
|
-
let u = 0, A = 0;
|
|
209
|
-
for (const R of y(h))
|
|
210
|
-
Number.isFinite(R.value) && (u += R.value, A++);
|
|
211
|
-
m = A > 0 ? u / A : null, p[h] = m;
|
|
212
|
-
}
|
|
213
|
-
return m;
|
|
237
|
+
layerData: v,
|
|
238
|
+
layerMean: (n) => {
|
|
239
|
+
let u = m[n];
|
|
240
|
+
return u === void 0 && (u = xt(v(n), o), m[n] = u), u;
|
|
214
241
|
},
|
|
215
242
|
primaryPath: () => {
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
for (let
|
|
219
|
-
if (this.getLayerAlpha(
|
|
220
|
-
const
|
|
221
|
-
if (!(
|
|
222
|
-
|
|
223
|
-
x: i.
|
|
224
|
-
y:
|
|
225
|
-
time:
|
|
243
|
+
if (p === void 0) {
|
|
244
|
+
p = null;
|
|
245
|
+
for (let n = 0; n < this.stores.length; n++) {
|
|
246
|
+
if (this.getLayerAlpha(n) <= 0 || !this.stores[n].isVisible()) continue;
|
|
247
|
+
const u = v(n).filter((c) => o.isPlottable(c.value));
|
|
248
|
+
if (!(u.length < 2)) {
|
|
249
|
+
p = u.map((c) => ({
|
|
250
|
+
x: i.timeToBitmapXExact(c.time),
|
|
251
|
+
y: o.valueToBitmapYExact(c.value),
|
|
252
|
+
time: c.time
|
|
226
253
|
}));
|
|
227
254
|
break;
|
|
228
255
|
}
|
|
229
256
|
}
|
|
230
257
|
}
|
|
231
|
-
return
|
|
258
|
+
return p;
|
|
232
259
|
}
|
|
233
260
|
};
|
|
234
261
|
}
|
|
@@ -238,47 +265,55 @@ class mt extends rt {
|
|
|
238
265
|
* overlay pulse) already flows through `effectiveValue`, so one override
|
|
239
266
|
* animates the whole geometry.
|
|
240
267
|
*/
|
|
241
|
-
effectiveValue(t, e, i,
|
|
242
|
-
const
|
|
243
|
-
if (
|
|
244
|
-
const
|
|
245
|
-
return
|
|
268
|
+
effectiveValue(t, e, i, o) {
|
|
269
|
+
const s = super.effectiveValue(t, e, i, o), l = this.historyWave.active ? this.historyDirectives?.value : void 0, a = this.historyRange;
|
|
270
|
+
if (l !== void 0 && a !== null && i < a.to) {
|
|
271
|
+
const v = a.to - a.from, n = v > 0 ? Math.min(1, Math.max(0, (a.to - i) / v)) : 0;
|
|
272
|
+
return l({ layerIndex: e, time: i, value: s, position: n });
|
|
246
273
|
}
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
const
|
|
250
|
-
return
|
|
274
|
+
const f = this.introWave.active ? this.introDirectives?.value : void 0;
|
|
275
|
+
if (f === void 0) return s;
|
|
276
|
+
const r = t.timeScale.getRange(), m = r.to - r.from, p = m > 0 ? Math.min(1, Math.max(0, (i - r.from) / m)) : 0;
|
|
277
|
+
return f({ layerIndex: e, time: i, value: s, position: p });
|
|
251
278
|
}
|
|
252
279
|
/**
|
|
253
280
|
* Extends the base last-value query with the 'grow' entrance's value-space
|
|
254
|
-
* equivalent of {@link chainedTailPositions}'s eased position lerp — the
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* before the marker visually arrives there.
|
|
281
|
+
* equivalent of {@link chainedTailPositions}'s eased position lerp — the
|
|
282
|
+
* value lerps along the Y axis by the same eased progress, so mapping it
|
|
283
|
+
* through `yScale` lands on the identical pixel the renderer paints. Without
|
|
284
|
+
* this, a tooltip/YLabel query would report a freshly-appended point's raw
|
|
285
|
+
* value the instant it lands, `entryMs` before the marker visually arrives there.
|
|
260
286
|
*/
|
|
261
287
|
snapshotValue(t, e, i) {
|
|
262
|
-
const
|
|
263
|
-
return (this.options.entryAnimation ?? "grow") !== "grow" ?
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
const o = super.snapshotValue(t, e, i);
|
|
289
|
+
return (this.options.entryAnimation ?? "grow") !== "grow" ? o : this.chainedTailValues(t)?.get(e) ?? o;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Value-space counterpart of {@link chainedTailPositions} — see {@link snapshotValue}.
|
|
293
|
+
* `resolve` lets the stacked renderer feed its ctx-aware `effectiveValue`
|
|
294
|
+
* in; query paths, which have no render context, keep the `liveValue` default.
|
|
295
|
+
*/
|
|
296
|
+
chainedTailValues(t, e = (i, o) => this.liveValue(t, i, o)) {
|
|
297
|
+
const i = this.unsettledTail(t);
|
|
298
|
+
if (i.length === 0) return null;
|
|
299
|
+
const o = this.stores[t].getAll(), s = o.length - 1 - i.length;
|
|
270
300
|
if (s < 0) return null;
|
|
271
|
-
const
|
|
272
|
-
if (!Number.isFinite(
|
|
273
|
-
let
|
|
274
|
-
const
|
|
275
|
-
for (let
|
|
276
|
-
const
|
|
277
|
-
if (!Number.isFinite(
|
|
278
|
-
const p =
|
|
279
|
-
|
|
301
|
+
const l = o[s];
|
|
302
|
+
if (!Number.isFinite(l.value)) return null;
|
|
303
|
+
let a = e(l.time, l.value);
|
|
304
|
+
const f = /* @__PURE__ */ new Map();
|
|
305
|
+
for (let r = 0; r < i.length; r++) {
|
|
306
|
+
const m = o[s + 1 + r];
|
|
307
|
+
if (!Number.isFinite(m.value)) return null;
|
|
308
|
+
const p = U(i[r].progress), v = e(m.time, m.value), n = this.axisLerp(a, v, p);
|
|
309
|
+
f.set(m.time, n), a = n;
|
|
280
310
|
}
|
|
281
|
-
return
|
|
311
|
+
return f;
|
|
312
|
+
}
|
|
313
|
+
/** `lerp` along the last rendered Y axis — plain before the first render. */
|
|
314
|
+
axisLerp(t, e, i) {
|
|
315
|
+
const o = this.lastYScale;
|
|
316
|
+
return o === null ? N(t, e, i) : o.lerpValue(t, e, i);
|
|
282
317
|
}
|
|
283
318
|
/**
|
|
284
319
|
* Glowing pulse dots riding the intro's head anchors — the line reads as
|
|
@@ -288,22 +323,22 @@ class mt extends rt {
|
|
|
288
323
|
*/
|
|
289
324
|
drawIntroHeads(t, e, i) {
|
|
290
325
|
if (this.options.stacking !== "off") return;
|
|
291
|
-
const
|
|
292
|
-
if (
|
|
293
|
-
const { scope:
|
|
294
|
-
for (const
|
|
295
|
-
for (let
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
ctx:
|
|
301
|
-
x:
|
|
302
|
-
y:
|
|
303
|
-
color: this.resolveLayerColor(
|
|
304
|
-
pixelRatio:
|
|
326
|
+
const o = Math.min(1, i / J), s = Math.min(1, (1 - i) / J), l = Math.max(0, Math.min(o, s));
|
|
327
|
+
if (l <= 0) return;
|
|
328
|
+
const { scope: a } = t;
|
|
329
|
+
for (const f of e)
|
|
330
|
+
for (let r = 0; r < this.stores.length; r++) {
|
|
331
|
+
const m = this.getLayerAlpha(r);
|
|
332
|
+
if (m <= 0 || !this.stores[r].isVisible()) continue;
|
|
333
|
+
const p = this.introHeadAnchor(t, r, f);
|
|
334
|
+
p !== null && this.drawPulse({
|
|
335
|
+
ctx: a.context,
|
|
336
|
+
x: p.x,
|
|
337
|
+
y: p.y,
|
|
338
|
+
color: this.resolveLayerColor(r, p.value),
|
|
339
|
+
pixelRatio: a.horizontalPixelRatio,
|
|
305
340
|
phase: i * 2,
|
|
306
|
-
alpha:
|
|
341
|
+
alpha: l * m
|
|
307
342
|
});
|
|
308
343
|
}
|
|
309
344
|
}
|
|
@@ -319,22 +354,30 @@ class mt extends rt {
|
|
|
319
354
|
* visible range, not the data span) and jumps back on settle.
|
|
320
355
|
*/
|
|
321
356
|
introHeadAnchor(t, e, i) {
|
|
322
|
-
const { timeScale:
|
|
323
|
-
if (
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
if (!
|
|
327
|
-
const
|
|
328
|
-
return
|
|
357
|
+
const { timeScale: o, yScale: s } = t, l = o.getRange(), a = this.stores[e].getVisibleData(l.from, l.to);
|
|
358
|
+
if (a.length === 0) return null;
|
|
359
|
+
const f = this.stores[e].last();
|
|
360
|
+
if (f !== void 0 && i.time >= f.time) {
|
|
361
|
+
if (!s.isPlottable(f.value)) return null;
|
|
362
|
+
const p = this.trailingEndpoint(t, e);
|
|
363
|
+
return p === null ? null : { x: p.x, y: p.y, value: f.value };
|
|
329
364
|
}
|
|
330
|
-
const
|
|
331
|
-
if (i.time <=
|
|
332
|
-
if (!
|
|
333
|
-
const
|
|
334
|
-
return {
|
|
365
|
+
const r = a[0];
|
|
366
|
+
if (i.time <= r.time) {
|
|
367
|
+
if (!s.isPlottable(r.value)) return null;
|
|
368
|
+
const p = this.effectiveValue(t, e, r.time, r.value);
|
|
369
|
+
return {
|
|
370
|
+
x: o.timeToBitmapXExact(r.time),
|
|
371
|
+
y: s.valueToBitmapYExact(p),
|
|
372
|
+
value: r.value
|
|
373
|
+
};
|
|
335
374
|
}
|
|
336
|
-
const
|
|
337
|
-
|
|
375
|
+
const m = j(a, i.time, {
|
|
376
|
+
resolve: (p) => this.effectiveValue(t, e, p.time, p.value),
|
|
377
|
+
// Along the axis, so the dot stays on the straight segment the stroke draws.
|
|
378
|
+
lerp: (p, v, n) => !s.isPlottable(p) || !s.isPlottable(v) ? Number.NaN : s.lerpValue(p, v, n)
|
|
379
|
+
});
|
|
380
|
+
return m === null || !s.isPlottable(m) ? null : { x: i.x, y: s.valueToBitmapYExact(m), value: m };
|
|
338
381
|
}
|
|
339
382
|
/**
|
|
340
383
|
* Rendered positions of the layer's still-unsettled trailing points, keyed
|
|
@@ -359,61 +402,95 @@ class mt extends rt {
|
|
|
359
402
|
* it (see `renderStacked`'s `valueMaps` comment for the full rationale).
|
|
360
403
|
*/
|
|
361
404
|
stackedValueAt(t, e, i) {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
405
|
+
const o = this.options.stacking === "percent", s = (this.options.entryAnimation ?? "grow") === "grow", l = new Array(this.stores.length), a = (n) => {
|
|
406
|
+
if (!s) return null;
|
|
407
|
+
const u = l[n];
|
|
408
|
+
if (u !== void 0) return u;
|
|
409
|
+
const c = this.chainedTailValues(n, (y, k) => this.effectiveValue(t, n, y, k));
|
|
410
|
+
return l[n] = c, c;
|
|
411
|
+
}, f = (n) => {
|
|
412
|
+
const u = this.stores[n].getAll();
|
|
413
|
+
if (u.length === 0 || i < u[0].time) return null;
|
|
414
|
+
const c = a(n);
|
|
415
|
+
return j(u, i, {
|
|
416
|
+
resolve: (y) => c?.get(y.time) ?? this.effectiveValue(t, n, y.time, y.value)
|
|
417
|
+
});
|
|
418
|
+
}, { yScale: r } = t;
|
|
419
|
+
if (r.getTransform() !== null && !o) {
|
|
420
|
+
const n = new et(r);
|
|
421
|
+
for (let u = 0; u <= e; u++) {
|
|
422
|
+
const c = this.getLayerAlpha(u), y = c > 0 ? f(u) : null;
|
|
423
|
+
y !== null && r.isPlottable(y) && n.push(y, c);
|
|
424
|
+
}
|
|
425
|
+
return n.edge;
|
|
426
|
+
}
|
|
427
|
+
const m = (n) => {
|
|
428
|
+
const u = this.getLayerAlpha(n);
|
|
429
|
+
if (u <= 0) return 0;
|
|
430
|
+
const c = f(n);
|
|
431
|
+
return c === null ? 0 : c * u;
|
|
369
432
|
};
|
|
370
|
-
let
|
|
371
|
-
if (
|
|
372
|
-
for (let
|
|
373
|
-
let
|
|
374
|
-
for (let
|
|
375
|
-
const
|
|
376
|
-
|
|
433
|
+
let p = 0;
|
|
434
|
+
if (o)
|
|
435
|
+
for (let n = 0; n < this.stores.length; n++) p += m(n);
|
|
436
|
+
let v = 0;
|
|
437
|
+
for (let n = 0; n <= e; n++) {
|
|
438
|
+
const u = m(n);
|
|
439
|
+
v += o && p > 0 ? u / p * 100 : u;
|
|
377
440
|
}
|
|
378
|
-
return
|
|
441
|
+
return v;
|
|
379
442
|
}
|
|
380
443
|
/**
|
|
381
|
-
* Bitmap position for layer `li`'s stacked boundary at time `t
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
444
|
+
* Bitmap position for layer `li`'s stacked boundary at time `t`.
|
|
445
|
+
*
|
|
446
|
+
* Reads back the vertex {@link renderStacked} actually painted this frame
|
|
447
|
+
* whenever `t` is one of its columns. The stacked entrance is driven by a
|
|
448
|
+
* *shared* per-column chain (columns are common to every layer), which this
|
|
449
|
+
* layer's own entrance state cannot reconstruct — deriving it here is what
|
|
450
|
+
* left the pulse dots hanging a column ahead of the stroke on a ragged
|
|
451
|
+
* feed. Falls back to the raw settled position off-column (decimated
|
|
452
|
+
* history, or before the first stacked frame).
|
|
387
453
|
*/
|
|
388
454
|
stackedPositionAt(t, e, i) {
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
391
|
-
const a = this.unsettledTail(e),
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
let
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
455
|
+
const o = this.paintedStackVertex(t, e, i);
|
|
456
|
+
if (o !== null) return o;
|
|
457
|
+
const { timeScale: s, yScale: l } = t, a = l.valueToBitmapYExact(this.stackedValueAt(t, e, i)), f = s.timeToBitmapXExact(i), r = this.unsettledTail(e), m = this.stores[e].getAll(), p = m.length - 1 - r.length;
|
|
458
|
+
if ((this.options.entryAnimation ?? "grow") !== "grow" || i !== m[m.length - 1]?.time || r.length === 0 || p < 0) return { x: f, y: a };
|
|
459
|
+
let v = s.timeToBitmapXExact(m[p].time);
|
|
460
|
+
for (let n = 0; n < r.length; n++)
|
|
461
|
+
v = N(v, s.timeToBitmapXExact(m[p + 1 + n].time), U(r[n].progress));
|
|
462
|
+
return { x: v, y: a };
|
|
463
|
+
}
|
|
464
|
+
/** Upper-edge vertex of layer `li` at column `t`, replayed from the last
|
|
465
|
+
* stacked frame's data-space record against `ctx`'s scales. */
|
|
466
|
+
paintedStackVertex(t, e, i) {
|
|
467
|
+
const o = this.stackedEdges, s = o?.cumulative[e];
|
|
468
|
+
if (o === null || s === void 0) return null;
|
|
469
|
+
const { times: l, growChain: a, collapse: f } = o, r = vt(l, i);
|
|
470
|
+
if (r < 0) return null;
|
|
471
|
+
const { timeScale: m, yScale: p } = t, v = t.scope.bitmapSize.height, n = f[e] ?? 1, u = p.valueToBitmapYExact(s[r]), c = n >= 1 ? u : v + (u - v) * n, y = l.length - a.length;
|
|
472
|
+
if (r < y) return { x: m.timeToBitmapXExact(i), y: c };
|
|
473
|
+
let k = m.timeToBitmapXExact(l[y - 1]);
|
|
474
|
+
for (let w = 0; w <= r - y; w++)
|
|
475
|
+
k = N(k, m.timeToBitmapXExact(l[y + w]), a[w]);
|
|
476
|
+
return { x: k, y: c };
|
|
400
477
|
}
|
|
401
478
|
chainedTailPositions(t, e) {
|
|
402
479
|
const i = this.unsettledTail(e);
|
|
403
480
|
if (i.length === 0) return null;
|
|
404
|
-
const
|
|
405
|
-
if (
|
|
406
|
-
const { timeScale:
|
|
407
|
-
if (!
|
|
408
|
-
let
|
|
409
|
-
const
|
|
410
|
-
for (let
|
|
411
|
-
const
|
|
412
|
-
if (!
|
|
413
|
-
const
|
|
414
|
-
|
|
481
|
+
const o = this.stores[e].getAll(), s = o.length - 1 - i.length;
|
|
482
|
+
if (s < 0) return null;
|
|
483
|
+
const { timeScale: l, yScale: a } = t, f = o[s];
|
|
484
|
+
if (!a.isPlottable(f.value)) return null;
|
|
485
|
+
let r = l.timeToBitmapXExact(f.time), m = a.valueToBitmapYExact(this.effectiveValue(t, e, f.time, f.value));
|
|
486
|
+
const p = /* @__PURE__ */ new Map();
|
|
487
|
+
for (let v = 0; v < i.length; v++) {
|
|
488
|
+
const n = o[s + 1 + v];
|
|
489
|
+
if (!a.isPlottable(n.value)) return null;
|
|
490
|
+
const u = U(i[v].progress), c = l.timeToBitmapXExact(n.time), y = a.valueToBitmapYExact(this.effectiveValue(t, e, n.time, n.value)), k = N(r, c, u), w = N(m, y, u);
|
|
491
|
+
p.set(n.time, { x: k, y: w }), r = k, m = w;
|
|
415
492
|
}
|
|
416
|
-
return
|
|
493
|
+
return p;
|
|
417
494
|
}
|
|
418
495
|
/**
|
|
419
496
|
* Bitmap coordinates for the trailing endpoint of a layer — i.e. where the
|
|
@@ -428,8 +505,8 @@ class mt extends rt {
|
|
|
428
505
|
trailingEndpoint(t, e) {
|
|
429
506
|
const i = this.stores[e].last();
|
|
430
507
|
if (!i) return null;
|
|
431
|
-
const { timeScale:
|
|
432
|
-
return (this.options.entryAnimation ?? "grow") !== "grow" ? { x:
|
|
508
|
+
const { timeScale: o, yScale: s } = t, l = o.timeToBitmapXExact(i.time), a = s.valueToBitmapYExact(this.effectiveValue(t, e, i.time, i.value));
|
|
509
|
+
return (this.options.entryAnimation ?? "grow") !== "grow" ? { x: l, y: a } : this.chainedTailPositions(t, e)?.get(i.time) ?? { x: l, y: a };
|
|
433
510
|
}
|
|
434
511
|
/**
|
|
435
512
|
* Vertical stroke + area gradients for `options.threshold`, pinned to the
|
|
@@ -443,10 +520,10 @@ class mt extends rt {
|
|
|
443
520
|
buildThresholdPaint(t, e) {
|
|
444
521
|
const i = this.options.threshold;
|
|
445
522
|
if (!i) return null;
|
|
446
|
-
const { scope:
|
|
447
|
-
|
|
448
|
-
const
|
|
449
|
-
return
|
|
523
|
+
const { scope: o, yScale: s } = t, { context: l } = o, a = o.bitmapSize.height, f = i.above, r = i.below ?? e, m = Math.min(1, Math.max(0, s.valueToBitmapYExact(i.value) / a)), p = Math.min(6 * o.verticalPixelRatio, a * 0.02) / a, v = Math.max(0, m - p), n = Math.min(1, m + p), u = l.createLinearGradient(0, 0, 0, a);
|
|
524
|
+
u.addColorStop(0, f), u.addColorStop(v, f), u.addColorStop(n, r), u.addColorStop(1, r);
|
|
525
|
+
const c = l.createLinearGradient(0, 0, 0, a);
|
|
526
|
+
return c.addColorStop(0, X(f, 0.26)), c.addColorStop(v, X(f, 0.14)), c.addColorStop(n, X(r, 0.1)), c.addColorStop(1, X(r, 0.01)), { stroke: u, area: c };
|
|
450
527
|
}
|
|
451
528
|
/**
|
|
452
529
|
* Dot markers at each data point (`options.points`). Callers pass the same
|
|
@@ -459,215 +536,235 @@ class mt extends rt {
|
|
|
459
536
|
drawPointMarkers(t) {
|
|
460
537
|
const e = this.options.points;
|
|
461
538
|
if (!e?.visible) return;
|
|
462
|
-
const { context: i, points:
|
|
463
|
-
if (
|
|
464
|
-
const
|
|
465
|
-
if (!(
|
|
539
|
+
const { context: i, points: o, pixelRatio: s, color: l } = t;
|
|
540
|
+
if (o.length === 0) return;
|
|
541
|
+
const a = Math.max(1, (e.radius ?? 3) * s);
|
|
542
|
+
if (!(o.length > 1 && (o[o.length - 1].x - o[0].x) / (o.length - 1) < a * 3)) {
|
|
466
543
|
i.beginPath();
|
|
467
|
-
for (const
|
|
468
|
-
i.moveTo(
|
|
469
|
-
i.fillStyle = e.color ??
|
|
544
|
+
for (const f of o)
|
|
545
|
+
i.moveTo(f.x + a, f.y), i.arc(f.x, f.y, a, 0, Math.PI * 2);
|
|
546
|
+
i.fillStyle = e.color ?? l, i.fill();
|
|
470
547
|
}
|
|
471
548
|
}
|
|
472
549
|
/** Each layer drawn independently */
|
|
473
550
|
renderOff(t) {
|
|
474
|
-
const { scope: e, timeScale: i, yScale:
|
|
475
|
-
ctx:
|
|
551
|
+
const { scope: e, timeScale: i, yScale: o } = t, { context: s } = e, l = i.getRange(), { verticalPixelRatio: a } = e, f = this.options.strokeWidth > 0, r = Math.max(1, Math.round(this.options.strokeWidth * a)), m = this.options.entryAnimation ?? "grow", p = mt(this.options.linePainter ?? this.options.curve ?? "straight"), v = {
|
|
552
|
+
ctx: s,
|
|
476
553
|
theme: t.theme,
|
|
477
554
|
horizontalPixelRatio: e.horizontalPixelRatio,
|
|
478
|
-
verticalPixelRatio:
|
|
555
|
+
verticalPixelRatio: a
|
|
479
556
|
};
|
|
480
|
-
for (let
|
|
481
|
-
const
|
|
482
|
-
if (
|
|
483
|
-
let
|
|
484
|
-
const
|
|
485
|
-
if (
|
|
486
|
-
const
|
|
487
|
-
x: i.
|
|
488
|
-
y:
|
|
489
|
-
},
|
|
490
|
-
(
|
|
491
|
-
const
|
|
492
|
-
let
|
|
493
|
-
for (let
|
|
494
|
-
const
|
|
495
|
-
if (!
|
|
496
|
-
|
|
557
|
+
for (let n = 0; n < this.stores.length; n++) {
|
|
558
|
+
const u = this.getLayerAlpha(n);
|
|
559
|
+
if (u <= 0) continue;
|
|
560
|
+
let c = this.stores[n].getVisibleData(l.from, l.to);
|
|
561
|
+
const y = e.mediaSize.width;
|
|
562
|
+
if (c.length > y * 2 && (c = q(c, Math.round(y * 1.5))), c.length < 2) continue;
|
|
563
|
+
const k = this.stores[n].last()?.value ?? c[c.length - 1].value, w = this.resolveLayerColor(n, k), B = this.buildThresholdPaint(t, w), L = c[c.length - 1], z = this.stores[n].last(), D = z !== void 0 && L.time === z.time, F = D ? this.entranceProgress(n, L.time) : 1, C = D && m === "fade" && F < 1, O = (D ? this.trailingEndpoint(t, n) : null) ?? {
|
|
564
|
+
x: i.timeToBitmapXExact(L.time),
|
|
565
|
+
y: o.valueToBitmapYExact(this.effectiveValue(t, n, L.time, L.value))
|
|
566
|
+
}, W = O.x, I = O.y, $ = D && m === "grow" ? this.chainedTailPositions(t, n) : null, G = u < 1;
|
|
567
|
+
(G || C) && (s.save(), G && (s.globalAlpha *= u), C && (s.globalAlpha *= F));
|
|
568
|
+
const _ = c.length - 1, h = [];
|
|
569
|
+
let d = null;
|
|
570
|
+
for (let g = 0; g < _; g++) {
|
|
571
|
+
const S = c[g].value;
|
|
572
|
+
if (!o.isPlottable(S)) {
|
|
573
|
+
d = null;
|
|
497
574
|
continue;
|
|
498
575
|
}
|
|
499
|
-
|
|
500
|
-
const
|
|
501
|
-
if (
|
|
502
|
-
|
|
576
|
+
d || (d = [], h.push(d));
|
|
577
|
+
const M = $?.get(c[g].time);
|
|
578
|
+
if (M)
|
|
579
|
+
d.push({ x: M.x, y: M.y });
|
|
503
580
|
else {
|
|
504
|
-
const
|
|
505
|
-
|
|
581
|
+
const Y = o.valueToBitmapYExact(this.effectiveValue(t, n, c[g].time, S));
|
|
582
|
+
d.push({ x: i.timeToBitmapXExact(c[g].time), y: Y });
|
|
506
583
|
}
|
|
507
584
|
}
|
|
508
|
-
const
|
|
509
|
-
let
|
|
510
|
-
if (
|
|
511
|
-
|
|
512
|
-
for (const
|
|
513
|
-
|
|
514
|
-
|
|
585
|
+
const b = c[_]?.value, A = Number.isFinite(W) && Number.isFinite(I) && o.isPlottable(b), P = m === "grow" && F < 1;
|
|
586
|
+
let T = null;
|
|
587
|
+
if (A && (d ? (d.push({ x: W, y: I }), T = d) : h.push([{ x: W, y: I }])), f && h.some((g) => g.length >= 2)) {
|
|
588
|
+
s.beginPath();
|
|
589
|
+
for (const g of h)
|
|
590
|
+
g.length < 2 || p(v, { points: g, color: w, lineWidth: r, closing: !1, grew: P && g === T });
|
|
591
|
+
s.strokeStyle = B ? B.stroke : w, s.lineWidth = r, s.lineJoin = "round", s.lineCap = "round", s.stroke();
|
|
515
592
|
}
|
|
516
|
-
if (
|
|
517
|
-
const
|
|
518
|
-
let
|
|
519
|
-
for (const
|
|
520
|
-
|
|
521
|
-
|
|
593
|
+
if (f) {
|
|
594
|
+
const g = Math.max(1, r / 2);
|
|
595
|
+
let S = !1;
|
|
596
|
+
for (const M of h)
|
|
597
|
+
M.length === 1 && (S || (s.beginPath(), S = !0), s.moveTo(M[0].x + g, M[0].y), s.arc(M[0].x, M[0].y, g, 0, Math.PI * 2));
|
|
598
|
+
S && (s.fillStyle = w, s.fill());
|
|
522
599
|
}
|
|
523
600
|
if (this.options.area.visible && !this.introGhostPass) {
|
|
524
|
-
const
|
|
525
|
-
let
|
|
526
|
-
if (
|
|
527
|
-
|
|
601
|
+
const g = e.bitmapSize.height;
|
|
602
|
+
let S;
|
|
603
|
+
if (B)
|
|
604
|
+
S = B.area;
|
|
528
605
|
else {
|
|
529
|
-
const
|
|
530
|
-
|
|
606
|
+
const M = String(n), Y = this.areaGradientCache.get(M);
|
|
607
|
+
Y && Y.bottomY === g && Y.color === w ? S = Y.gradient : (S = s.createLinearGradient(0, 0, 0, g), S.addColorStop(0, X(w, 0.12)), S.addColorStop(1, X(w, 0.01)), this.areaGradientCache.set(M, { gradient: S, bottomY: g, color: w }));
|
|
531
608
|
}
|
|
532
|
-
|
|
533
|
-
for (const
|
|
534
|
-
|
|
609
|
+
s.fillStyle = S;
|
|
610
|
+
for (const M of h)
|
|
611
|
+
M.length < 2 || (s.beginPath(), p(v, { points: M, color: w, lineWidth: r, closing: !0, grew: P && M === T }), s.lineTo(M[M.length - 1].x, g), s.lineTo(M[0].x, g), s.closePath(), s.fill());
|
|
535
612
|
}
|
|
536
613
|
if (this.options.points?.visible) {
|
|
537
|
-
const
|
|
538
|
-
for (const
|
|
539
|
-
for (const
|
|
540
|
-
this.drawPointMarkers({ context:
|
|
614
|
+
const g = [];
|
|
615
|
+
for (const S of h)
|
|
616
|
+
for (const M of S) g.push(M);
|
|
617
|
+
this.drawPointMarkers({ context: s, points: g, pixelRatio: e.horizontalPixelRatio, color: w });
|
|
541
618
|
}
|
|
542
|
-
(
|
|
619
|
+
(C || G) && s.restore();
|
|
543
620
|
}
|
|
544
621
|
}
|
|
545
622
|
/** Stacked area rendering */
|
|
546
623
|
renderStacked(t, e) {
|
|
547
|
-
const { scope: i, timeScale:
|
|
548
|
-
if (this.getLayerAlpha(
|
|
549
|
-
let b =
|
|
550
|
-
return b.length >
|
|
551
|
-
}),
|
|
552
|
-
for (const
|
|
553
|
-
for (const
|
|
554
|
-
const
|
|
555
|
-
if (
|
|
556
|
-
|
|
624
|
+
const { scope: i, timeScale: o, yScale: s } = t, { context: l } = i, a = o.getRange(), { verticalPixelRatio: f } = i, r = this.options.strokeWidth > 0, m = Math.max(1, Math.round(this.options.strokeWidth * f)), p = this.options.curve ?? "straight", v = i.mediaSize.width, n = this.stores.map((h, d) => {
|
|
625
|
+
if (this.getLayerAlpha(d) <= 0) return [];
|
|
626
|
+
let b = h.getVisibleData(a.from, a.to);
|
|
627
|
+
return b.length > v * 2 && (b = q(b, Math.round(v * 1.5))), b;
|
|
628
|
+
}), u = /* @__PURE__ */ new Set();
|
|
629
|
+
for (const h of n)
|
|
630
|
+
for (const d of h) u.add(d.time);
|
|
631
|
+
const c = Array.from(u).sort((h, d) => h - d);
|
|
632
|
+
if (c.length < 2) {
|
|
633
|
+
this.stackedEdges = null;
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const y = this.options.entryAnimation ?? "grow", k = n.map((h, d) => {
|
|
557
637
|
const b = /* @__PURE__ */ new Map();
|
|
558
|
-
if (
|
|
559
|
-
const
|
|
560
|
-
for (const
|
|
561
|
-
if (
|
|
562
|
-
const
|
|
563
|
-
|
|
638
|
+
if (h.length === 0) return b;
|
|
639
|
+
const A = h[0].time, P = y === "grow" ? this.chainedTailValues(d, (g, S) => this.effectiveValue(t, d, g, S)) : null, T = (g) => P?.get(g.time) ?? this.effectiveValue(t, d, g.time, g.value);
|
|
640
|
+
for (const g of c) {
|
|
641
|
+
if (g < A) continue;
|
|
642
|
+
const S = j(h, g, { resolve: T });
|
|
643
|
+
S !== null && b.set(g, S);
|
|
564
644
|
}
|
|
565
645
|
return b;
|
|
566
|
-
}),
|
|
567
|
-
|
|
568
|
-
|
|
646
|
+
}), w = this.stores.map((h, d) => this.getLayerAlpha(d)), B = (h, d) => {
|
|
647
|
+
const b = k[h].get(d);
|
|
648
|
+
return b === void 0 ? void 0 : b * w[h];
|
|
649
|
+
}, L = s.getTransform() !== null && !e, z = Array.from({ length: this.stores.length }, () => new Array(c.length).fill(0));
|
|
650
|
+
for (let h = 0; h < c.length; h++) {
|
|
651
|
+
const d = c[h];
|
|
652
|
+
if (L) {
|
|
653
|
+
const P = new et(s);
|
|
654
|
+
for (let T = 0; T < this.stores.length; T++) {
|
|
655
|
+
const g = k[T].get(d);
|
|
656
|
+
g !== void 0 && s.isPlottable(g) && P.push(g, w[T]), z[T][h] = P.edge;
|
|
657
|
+
}
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
569
660
|
let b = 0;
|
|
570
661
|
if (e)
|
|
571
|
-
for (let
|
|
572
|
-
const T =
|
|
573
|
-
|
|
662
|
+
for (let P = 0; P < this.stores.length; P++) {
|
|
663
|
+
const T = B(P, d);
|
|
664
|
+
T !== void 0 && s.isPlottable(T) && (b += T);
|
|
574
665
|
}
|
|
575
|
-
let
|
|
576
|
-
for (let
|
|
577
|
-
const T =
|
|
578
|
-
|
|
666
|
+
let A = 0;
|
|
667
|
+
for (let P = 0; P < this.stores.length; P++) {
|
|
668
|
+
const T = B(P, d), g = T !== void 0 && s.isPlottable(T) ? T : 0;
|
|
669
|
+
A += e && b > 0 ? g / b * 100 : g, z[P][h] = A;
|
|
579
670
|
}
|
|
580
671
|
}
|
|
581
|
-
const
|
|
582
|
-
for (let
|
|
672
|
+
const D = /* @__PURE__ */ new Map();
|
|
673
|
+
for (let h = 0; h < c.length; h++) D.set(c[h], h);
|
|
583
674
|
const F = new Array(this.stores.length).fill(1);
|
|
584
|
-
for (let
|
|
585
|
-
if (this.getLayerAlpha(
|
|
586
|
-
const
|
|
675
|
+
for (let h = 0; h < this.stores.length; h++) {
|
|
676
|
+
if (this.getLayerAlpha(h) <= 0) continue;
|
|
677
|
+
const d = this.unsettledTail(h), b = d.length;
|
|
587
678
|
if (b === 0) continue;
|
|
588
|
-
let
|
|
589
|
-
for (let
|
|
590
|
-
if (
|
|
591
|
-
|
|
679
|
+
let A = !0;
|
|
680
|
+
for (let P = 0; P < b; P++)
|
|
681
|
+
if (D.get(d[P].time) !== c.length - b + P) {
|
|
682
|
+
A = !1;
|
|
592
683
|
break;
|
|
593
684
|
}
|
|
594
|
-
|
|
685
|
+
A && (F[h] = d[b - 1].progress);
|
|
595
686
|
}
|
|
596
|
-
const
|
|
597
|
-
if (
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
687
|
+
const C = [];
|
|
688
|
+
if (y === "grow") {
|
|
689
|
+
const h = n.map((d) => d.length - 1);
|
|
690
|
+
for (let d = c.length - 1; d >= 1; d--) {
|
|
691
|
+
const b = c[d];
|
|
692
|
+
let A = 1, P = !1;
|
|
693
|
+
for (let T = 0; T < n.length; T++) {
|
|
694
|
+
if (this.getLayerAlpha(T) <= 0) continue;
|
|
695
|
+
const g = n[T];
|
|
696
|
+
for (; h[T] >= 0 && g[h[T]].time > b; ) h[T]--;
|
|
697
|
+
if (h[T] < 0 || g[h[T]].time !== b) continue;
|
|
698
|
+
const S = this.entranceProgress(T, b);
|
|
699
|
+
(!P || S > A) && (A = S), P = !0;
|
|
605
700
|
}
|
|
606
|
-
if (!
|
|
607
|
-
|
|
701
|
+
if (!P || A >= 1) break;
|
|
702
|
+
C.unshift(U(A));
|
|
608
703
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
704
|
+
}
|
|
705
|
+
const O = (h, d) => {
|
|
706
|
+
const b = d.length;
|
|
707
|
+
if (!(b === 0 || h.length < b + 1))
|
|
708
|
+
for (let A = 0; A < b; A++) {
|
|
709
|
+
const P = h.length - b + A;
|
|
710
|
+
h[P][0] = N(h[P - 1][0], h[P][0], d[A]);
|
|
615
711
|
}
|
|
616
|
-
},
|
|
617
|
-
let
|
|
618
|
-
for (let
|
|
619
|
-
if (!(this.getLayerAlpha(
|
|
620
|
-
if (
|
|
621
|
-
|
|
712
|
+
}, W = i.bitmapSize.height;
|
|
713
|
+
let I = -1, $ = -1;
|
|
714
|
+
for (let h = 0; h < this.stores.length; h++)
|
|
715
|
+
if (!(this.getLayerAlpha(h) <= 0))
|
|
716
|
+
if (I < 0)
|
|
717
|
+
I = h;
|
|
622
718
|
else {
|
|
623
|
-
|
|
719
|
+
$ = h;
|
|
624
720
|
break;
|
|
625
721
|
}
|
|
626
|
-
const G =
|
|
627
|
-
for (let
|
|
628
|
-
const
|
|
629
|
-
if (
|
|
630
|
-
const b = this.stores[
|
|
631
|
-
for (let
|
|
632
|
-
const
|
|
633
|
-
let
|
|
634
|
-
|
|
722
|
+
const G = I >= 0 ? this.getLayerAlpha(I) : 1, _ = n.map((h, d) => d === I ? Math.min(1, this.getLayerAlpha(d)) : 1);
|
|
723
|
+
for (let h = this.stores.length - 1; h >= 0; h--) {
|
|
724
|
+
const d = this.getLayerAlpha(h);
|
|
725
|
+
if (d <= 0) continue;
|
|
726
|
+
const b = this.stores[h].last()?.value ?? 0, A = this.resolveLayerColor(h, b), P = h === I, T = $ >= 0 && h === $ && G < 1, g = [];
|
|
727
|
+
for (let R = 0; R < c.length; R++) {
|
|
728
|
+
const V = h > 0 ? s.valueToBitmapYExact(z[h - 1][R]) : W;
|
|
729
|
+
let H = V;
|
|
730
|
+
P ? H = W : T && (H = V + (W - V) * (1 - G)), g.push([o.timeToBitmapXExact(c[R]), H]);
|
|
635
731
|
}
|
|
636
|
-
|
|
637
|
-
const
|
|
638
|
-
for (let
|
|
639
|
-
let
|
|
640
|
-
|
|
732
|
+
y === "grow" && O(g, C);
|
|
733
|
+
const S = [];
|
|
734
|
+
for (let R = 0; R < c.length; R++) {
|
|
735
|
+
let V = s.valueToBitmapYExact(z[h][R]);
|
|
736
|
+
P && d < 1 && (V = W + (V - W) * d), S.push([o.timeToBitmapXExact(c[R]), V]);
|
|
641
737
|
}
|
|
642
|
-
|
|
643
|
-
const
|
|
644
|
-
if (
|
|
645
|
-
let
|
|
646
|
-
for (let
|
|
647
|
-
|
|
648
|
-
for (let
|
|
649
|
-
|
|
650
|
-
let
|
|
651
|
-
if (
|
|
652
|
-
const
|
|
653
|
-
|
|
738
|
+
y === "grow" && O(S, C);
|
|
739
|
+
const M = ot(S), Y = tt(M, p, y === "grow" && C.length > 0), K = y === "fade" && F[h] < 1;
|
|
740
|
+
if (K && (l.save(), l.globalAlpha *= F[h]), this.options.area.visible && !this.introGhostPass) {
|
|
741
|
+
let R = S[0][1], V = g[0][1];
|
|
742
|
+
for (let E = 1; E < S.length; E++)
|
|
743
|
+
S[E][1] < R && (R = S[E][1]);
|
|
744
|
+
for (let E = 1; E < g.length; E++)
|
|
745
|
+
g[E][1] > V && (V = g[E][1]);
|
|
746
|
+
let H = X(A, 0.25);
|
|
747
|
+
if (V > R + 0.5) {
|
|
748
|
+
const E = l.createLinearGradient(0, R, 0, V);
|
|
749
|
+
E.addColorStop(0, X(A, 0.25)), E.addColorStop(1, X(A, 0.05)), H = E;
|
|
654
750
|
}
|
|
655
|
-
if (
|
|
656
|
-
for (let
|
|
657
|
-
|
|
751
|
+
if (l.beginPath(), l.moveTo(M[0].x, M[0].y), st(l, Y), P)
|
|
752
|
+
for (let E = g.length - 1; E >= 0; E--)
|
|
753
|
+
l.lineTo(g[E][0], g[E][1]);
|
|
658
754
|
else {
|
|
659
|
-
const
|
|
660
|
-
|
|
755
|
+
const E = ot(g), ct = tt(E, p, y === "grow" && C.length > 0), Z = E[E.length - 1];
|
|
756
|
+
l.lineTo(Z.x, Z.y), yt(l, E, ct);
|
|
661
757
|
}
|
|
662
|
-
|
|
758
|
+
l.closePath(), l.fillStyle = H, l.fill();
|
|
663
759
|
}
|
|
664
|
-
const
|
|
665
|
-
if (
|
|
666
|
-
const
|
|
667
|
-
|
|
760
|
+
const Q = r && d < 1;
|
|
761
|
+
if (Q && (l.save(), l.globalAlpha *= d), r && (l.beginPath(), l.moveTo(M[0].x, M[0].y), st(l, Y), l.strokeStyle = A, l.lineWidth = m, l.lineJoin = "round", l.lineCap = "round", l.stroke()), Q && l.restore(), this.options.points?.visible) {
|
|
762
|
+
const R = d < 1;
|
|
763
|
+
R && (l.save(), l.globalAlpha *= d), this.drawPointMarkers({ context: l, points: M, pixelRatio: i.horizontalPixelRatio, color: A }), R && l.restore();
|
|
668
764
|
}
|
|
669
|
-
|
|
765
|
+
K && l.restore();
|
|
670
766
|
}
|
|
767
|
+
this.stackedEdges = { times: c, cumulative: z, growChain: C, collapse: _ };
|
|
671
768
|
}
|
|
672
769
|
/**
|
|
673
770
|
* Overlay hook: draws crosshair nearest-point dots and last-point pulse dots.
|
|
@@ -675,54 +772,55 @@ class mt extends rt {
|
|
|
675
772
|
*/
|
|
676
773
|
drawOverlay(t) {
|
|
677
774
|
this.tickAnimations(performance.now());
|
|
678
|
-
const { scope: e, timeScale: i, yScale:
|
|
679
|
-
if (
|
|
680
|
-
const
|
|
681
|
-
for (let
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
const
|
|
685
|
-
if (!
|
|
686
|
-
const
|
|
687
|
-
x: i.
|
|
688
|
-
y:
|
|
689
|
-
} : this.stackedPositionAt(t,
|
|
690
|
-
|
|
775
|
+
const { scope: e, timeScale: i, yScale: o, crosshair: s, dataInterval: l } = t, a = e, f = this.options.pulseMs, r = f > 0 ? performance.now() / (f * 2 * Math.PI) % 1 : 0;
|
|
776
|
+
if (s) {
|
|
777
|
+
const v = this.options.stacking, n = 4 * a.horizontalPixelRatio;
|
|
778
|
+
for (let u = 0; u < this.stores.length; u++) {
|
|
779
|
+
const c = this.getLayerAlpha(u);
|
|
780
|
+
if (c <= 0) continue;
|
|
781
|
+
const y = this.stores[u].findNearest(s.time, l);
|
|
782
|
+
if (!y || v === "off" && !o.isPlottable(y.value)) continue;
|
|
783
|
+
const k = this.resolveLayerColor(u, y.value), { x: w, y: B } = v === "off" ? {
|
|
784
|
+
x: i.timeToBitmapXExact(y.time),
|
|
785
|
+
y: o.valueToBitmapYExact(this.effectiveValue(t, u, y.time, y.value))
|
|
786
|
+
} : this.stackedPositionAt(t, u, y.time), L = c < 1;
|
|
787
|
+
L && (e.context.save(), e.context.globalAlpha *= c), e.context.save(), e.context.globalAlpha *= 0.25, e.context.beginPath(), e.context.arc(w, B, n + 3 * a.horizontalPixelRatio, 0, Math.PI * 2), e.context.fillStyle = k, e.context.fill(), e.context.restore(), e.context.beginPath(), e.context.arc(w, B, n, 0, Math.PI * 2), e.context.fillStyle = k, e.context.fill(), L && e.context.restore();
|
|
691
788
|
}
|
|
692
789
|
}
|
|
693
|
-
const
|
|
694
|
-
let
|
|
695
|
-
if (
|
|
696
|
-
const
|
|
697
|
-
for (let
|
|
698
|
-
const
|
|
699
|
-
if (
|
|
700
|
-
const
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
790
|
+
const m = this.introWave.active && this.introDirectives?.clip !== void 0;
|
|
791
|
+
let p = 1;
|
|
792
|
+
if (m && (p = Math.max(0, (this.introWave.linear() - (1 - J)) / J)), this.hasPulse && f > 0 && p > 0) {
|
|
793
|
+
const v = this.options.stacking;
|
|
794
|
+
for (let n = 0; n < this.stores.length; n++) {
|
|
795
|
+
const u = this.getLayerAlpha(n);
|
|
796
|
+
if (u <= 0) continue;
|
|
797
|
+
const c = this.stores[n].last()?.value ?? 0, y = this.resolveLayerColor(n, c);
|
|
798
|
+
if (v === "off") {
|
|
799
|
+
if (!o.isPlottable(c)) continue;
|
|
800
|
+
const L = this.trailingEndpoint(t, n);
|
|
801
|
+
if (!L) continue;
|
|
704
802
|
this.drawPulse({
|
|
705
803
|
ctx: e.context,
|
|
706
|
-
x:
|
|
707
|
-
y:
|
|
708
|
-
color:
|
|
709
|
-
pixelRatio:
|
|
710
|
-
phase:
|
|
711
|
-
alpha:
|
|
804
|
+
x: L.x,
|
|
805
|
+
y: L.y,
|
|
806
|
+
color: y,
|
|
807
|
+
pixelRatio: a.horizontalPixelRatio,
|
|
808
|
+
phase: r,
|
|
809
|
+
alpha: u * p
|
|
712
810
|
});
|
|
713
811
|
continue;
|
|
714
812
|
}
|
|
715
|
-
const
|
|
716
|
-
if (!
|
|
717
|
-
const { x:
|
|
813
|
+
const k = this.stores[n].last();
|
|
814
|
+
if (!k) continue;
|
|
815
|
+
const { x: w, y: B } = this.stackedPositionAt(t, n, k.time);
|
|
718
816
|
this.drawPulse({
|
|
719
817
|
ctx: e.context,
|
|
720
|
-
x:
|
|
721
|
-
y:
|
|
722
|
-
color:
|
|
723
|
-
pixelRatio:
|
|
724
|
-
phase:
|
|
725
|
-
alpha:
|
|
818
|
+
x: w,
|
|
819
|
+
y: B,
|
|
820
|
+
color: y,
|
|
821
|
+
pixelRatio: a.horizontalPixelRatio,
|
|
822
|
+
phase: r,
|
|
823
|
+
alpha: u * p
|
|
726
824
|
});
|
|
727
825
|
}
|
|
728
826
|
}
|
|
@@ -731,24 +829,24 @@ class mt extends rt {
|
|
|
731
829
|
ctx: t,
|
|
732
830
|
x: e,
|
|
733
831
|
y: i,
|
|
734
|
-
color:
|
|
735
|
-
pixelRatio:
|
|
736
|
-
phase:
|
|
737
|
-
alpha:
|
|
832
|
+
color: o,
|
|
833
|
+
pixelRatio: s,
|
|
834
|
+
phase: l,
|
|
835
|
+
alpha: a = 1
|
|
738
836
|
}) {
|
|
739
|
-
const
|
|
740
|
-
|
|
837
|
+
const f = 3 * s, r = 0.4 + 0.6 * Math.abs(Math.sin(l * 2 * Math.PI)), m = f + 4 * s * r, p = a < 1;
|
|
838
|
+
p && (t.save(), t.globalAlpha *= a), t.beginPath(), t.arc(e, i, m, 0, Math.PI * 2), t.fillStyle = X(o, r * 0.3), t.fill(), t.beginPath(), t.arc(e, i, f, 0, Math.PI * 2), t.fillStyle = o, t.fill(), p && t.restore();
|
|
741
839
|
}
|
|
742
840
|
}
|
|
743
|
-
const
|
|
841
|
+
const Bt = {
|
|
744
842
|
type: "line",
|
|
745
|
-
create: ({ theme:
|
|
746
|
-
colors: t === 1 ? [
|
|
747
|
-
strokeWidth:
|
|
843
|
+
create: ({ theme: x, layerCount: t }, e) => new bt(t, {
|
|
844
|
+
colors: t === 1 ? [x.line.color] : x.seriesColors.slice(0, t),
|
|
845
|
+
strokeWidth: x.line.width,
|
|
748
846
|
...e
|
|
749
847
|
})
|
|
750
848
|
};
|
|
751
849
|
export {
|
|
752
|
-
|
|
753
|
-
|
|
850
|
+
bt as LineRenderer,
|
|
851
|
+
Bt as LineSeriesDef
|
|
754
852
|
};
|