@wick-charts/vue 0.6.1 → 0.6.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.
- 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 +14 -14
- package/dist/core/dist/chart/badge-animator.js +15 -19
- package/dist/core/dist/chart.js +448 -417
- package/dist/core/dist/components/grid.js +21 -17
- package/dist/core/dist/navigator/controller.js +12 -12
- 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 +39 -21
- package/dist/core/dist/series/bar.js +24 -24
- package/dist/core/dist/series/candlestick.js +20 -20
- package/dist/core/dist/series/heatmap.js +16 -16
- package/dist/core/dist/series/line.js +461 -401
- package/dist/core/dist/utils/pixel-grid.js +10 -0
- package/dist/index.d.ts +33 -1
- package/dist/ui/YLabel.vue.js +19 -18
- package/package.json +2 -2
package/dist/core/dist/chart.js
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
import { Animator as Y } from "./animation/animator.js";
|
|
2
|
+
import { AnimationConfig as X, DEFAULT_LINE_PULSE as $ } from "./animation/config.js";
|
|
3
|
+
import { easeOutCubic as P } from "./animation/easing.js";
|
|
4
|
+
import { prefersReducedMotion as Z } from "./animation/reduced-motion.js";
|
|
5
|
+
import { createViewportEngine as _ } from "./animation/viewport-engine.js";
|
|
6
|
+
import { CanvasManager as G } from "./canvas-manager.js";
|
|
7
|
+
import { resolveEdgeAnchorValue as U, drawEdgeIndicators as K, resolveEdgeBoundary as j } from "./chart/edge-indicators.js";
|
|
8
|
+
import { computeFitToData as q } from "./chart/fit-to-data.js";
|
|
9
|
+
import { getLastValue as J, getPreviousClose as Q, getStackedLastValue as tt } from "./chart/last-value.js";
|
|
10
|
+
import { resolveFade as H, resolveMaxVisibleBars as it, resolvePadding as z, resolvePerfOptions as et, isSameHorizontalPadding as V } from "./chart/options.js";
|
|
11
|
+
import { computePan as st, computeZoom as rt } from "./chart/pan-zoom-math.js";
|
|
12
|
+
import { StreamingCadence as nt } from "./chart/streaming-cadence.js";
|
|
13
|
+
import { computeStreamingTarget as at } from "./chart/streaming-target.js";
|
|
14
|
+
import { resolvePaddingTime as W } from "./chart/viewport-padding.js";
|
|
15
|
+
import { computeTargetYRange as ht, resolveBound as F } from "./chart/y-target.js";
|
|
16
|
+
import { renderCrosshair as ot } from "./components/crosshair.js";
|
|
17
|
+
import { renderGrid as lt } from "./components/grid.js";
|
|
18
|
+
import { renderMarker as ct } from "./components/marker.js";
|
|
19
|
+
import { renderReferenceLine as dt } from "./components/reference-line.js";
|
|
20
|
+
import { resolveTimeRegionColors as mt, renderTimeRegion as ut } from "./components/time-region.js";
|
|
21
|
+
import { EventEmitter as ft } from "./events.js";
|
|
22
|
+
import { InteractionHandler as gt } from "./interactions/handler.js";
|
|
23
|
+
import { RenderScheduler as B } from "./render-scheduler.js";
|
|
24
|
+
import { XScale as pt } from "./scales/x-scale.js";
|
|
25
|
+
import { YScale as yt } from "./scales/y-scale.js";
|
|
26
|
+
import { resolveSeriesDefinition as vt } from "./series/definition.js";
|
|
27
|
+
import { isTimeSeriesRenderer as k } from "./series/types.js";
|
|
28
|
+
import { catppuccin as xt } from "./theme/themes/catppuccin.js";
|
|
29
|
+
import { clamp as bt } from "./utils/math.js";
|
|
30
|
+
import { crispLineWidth as St, crispCenterOffset as kt } from "./utils/pixel-grid.js";
|
|
31
|
+
import { normalizeTime as x, detectInterval as wt } from "./utils/time.js";
|
|
32
|
+
const At = 200, Lt = 1500, Tt = 48, Mt = 12, T = 9;
|
|
33
|
+
let Dt = 0, Rt = 0, Ct = 0, It = 0;
|
|
34
|
+
function N(p, t) {
|
|
35
|
+
return p === t ? !0 : !p || !t || p.length !== t.length ? !1 : p.every((i, e) => i === t[e]);
|
|
33
36
|
}
|
|
34
|
-
function
|
|
35
|
-
return
|
|
37
|
+
function Pt(p, t) {
|
|
38
|
+
return p === t ? !0 : !p || !t || p.length !== t.length ? !1 : p.every((i, e) => i === t[e]);
|
|
36
39
|
}
|
|
37
|
-
class
|
|
40
|
+
class ci extends ft {
|
|
38
41
|
/** Canvas lifecycle and DPR-aware sizing. */
|
|
39
42
|
#a;
|
|
40
43
|
/** Schedules main-layer redraws (background, grid, series). */
|
|
41
|
-
#
|
|
44
|
+
#i;
|
|
42
45
|
/** Schedules overlay redraws (crosshair). */
|
|
43
46
|
#h;
|
|
44
47
|
/** Maps time values to horizontal pixel coordinates. */
|
|
@@ -46,13 +49,13 @@ class ti extends lt {
|
|
|
46
49
|
/** Maps price/value to vertical pixel coordinates. */
|
|
47
50
|
yScale;
|
|
48
51
|
/** Zoom, pan, crosshair — null when interactive=false. */
|
|
49
|
-
#
|
|
52
|
+
#M;
|
|
50
53
|
/** All registered series (candlestick, line, bar, pie). */
|
|
51
54
|
#t = [];
|
|
52
55
|
/** Point annotations (event markers) drawn on the overlay layer, kept out of the series model. */
|
|
53
|
-
#
|
|
56
|
+
#u = [];
|
|
54
57
|
/** Time-region bands drawn on the main layer behind the series, kept out of the series model. */
|
|
55
|
-
#
|
|
58
|
+
#x = [];
|
|
56
59
|
/** Reference lines (horizontal threshold / vertical event) drawn on the overlay layer, kept out of the series model. */
|
|
57
60
|
#y = [];
|
|
58
61
|
/**
|
|
@@ -63,12 +66,19 @@ class ti extends lt {
|
|
|
63
66
|
* later — which re-arms `getIntroFront()`'s global min — can't blink settled
|
|
64
67
|
* markers / reference lines back out.
|
|
65
68
|
*/
|
|
66
|
-
#rt = !1;
|
|
67
69
|
#nt = !1;
|
|
70
|
+
#at = !1;
|
|
68
71
|
/** Active visual theme (colors, fonts, grid style). */
|
|
69
72
|
#n;
|
|
70
73
|
/** Whether to render the background grid. */
|
|
71
|
-
#
|
|
74
|
+
#F;
|
|
75
|
+
/**
|
|
76
|
+
* Gridline layer opacity, multiplied into every per-tick fade: `0 → 1` on
|
|
77
|
+
* the opening reveal, `1 → 0` when {@link setGrid} hides the grid. The
|
|
78
|
+
* per-tick fades stay snapped during mount (see the tracker's arming), so
|
|
79
|
+
* this is what keeps `fitToData` tick churn from flickering the reveal.
|
|
80
|
+
*/
|
|
81
|
+
#I;
|
|
72
82
|
/** Resolved edge-fade zones — `right: null` tracks the live Y-axis width. */
|
|
73
83
|
#k;
|
|
74
84
|
/** Memoized destination-out mask gradients, one per edge, keyed by the
|
|
@@ -78,7 +88,7 @@ class ti extends lt {
|
|
|
78
88
|
/** Detected time interval between data points (milliseconds). */
|
|
79
89
|
#r = 6e4;
|
|
80
90
|
/** Current crosshair position, null when cursor is outside the chart. */
|
|
81
|
-
#
|
|
91
|
+
#c = null;
|
|
82
92
|
/**
|
|
83
93
|
* What the crosshair is anchored to, deciding which half of the position
|
|
84
94
|
* survives a viewport move (see {@link #syncCrosshairToViewport}):
|
|
@@ -86,25 +96,25 @@ class ti extends lt {
|
|
|
86
96
|
* `time`/`y`; `'time'` (programmatic {@link setCrosshair}) keeps
|
|
87
97
|
* `time`/`y` and re-projects the pixel position.
|
|
88
98
|
*/
|
|
89
|
-
|
|
99
|
+
#$ = "pointer";
|
|
90
100
|
/** Whether the last overlay pass painted anything — gates the full-bitmap
|
|
91
101
|
* clear so an empty overlay isn't cleared again every main frame. */
|
|
92
|
-
#
|
|
102
|
+
#ht = !1;
|
|
93
103
|
/** User-specified Y-axis bounds (auto, fixed, percentage). */
|
|
94
|
-
#
|
|
104
|
+
#d = {};
|
|
95
105
|
/** Cached series ID list — invalidated on add/remove. */
|
|
96
106
|
#D = null;
|
|
97
107
|
/** Axis visibility and sizing configuration. */
|
|
98
|
-
#
|
|
108
|
+
#B = {};
|
|
99
109
|
/** Host-declared state per edge — drives the edge-indicator overlay. */
|
|
100
|
-
#
|
|
110
|
+
#b = { left: "idle", right: "idle" };
|
|
101
111
|
/** Wall-clock start of a `loading` exit fade per side — set when the host
|
|
102
112
|
* drops `loading` back to `idle`/`has-more`, so the indicator fades out
|
|
103
113
|
* over {@link EDGE_EXIT_FADE_MS} instead of vanishing the same frame the
|
|
104
114
|
* fetched data lands. `null` = no fade in flight. */
|
|
105
|
-
#
|
|
115
|
+
#N = { left: null, right: null };
|
|
106
116
|
/** Cached boundary timestamps from the last `edgeReached` emission, by side. */
|
|
107
|
-
#
|
|
117
|
+
#ot = { left: null, right: null };
|
|
108
118
|
/** Latest placeholder shapes a `loading` indicator reported per side —
|
|
109
119
|
* the morph hand-off candidate consumed by {@link prependData}. */
|
|
110
120
|
#Z = { left: null, right: null };
|
|
@@ -112,19 +122,19 @@ class ti extends lt {
|
|
|
112
122
|
* reveal owns those pixels now, so the still-`loading` indicator is hidden
|
|
113
123
|
* and the upcoming `loading → idle` transition skips its exit fade. Reset
|
|
114
124
|
* by the next {@link setEdgeState} call. */
|
|
115
|
-
#
|
|
125
|
+
#P = { left: !1, right: !1 };
|
|
116
126
|
/** Host-supplied callback fired when the user releases a pan/zoom past a data edge. */
|
|
117
|
-
#
|
|
127
|
+
#lt;
|
|
118
128
|
/** Per-side custom painter for the edge `loading` spinner. `null` falls back to the built-in dots. */
|
|
119
|
-
#
|
|
129
|
+
#ct = { left: null, right: null };
|
|
120
130
|
/** Nesting depth for batch updates. Suppresses recomputes while > 0. */
|
|
121
|
-
#
|
|
131
|
+
#L = 0;
|
|
122
132
|
/** True when batched operations include data changes (triggers full onDataChanged on end). */
|
|
123
|
-
|
|
133
|
+
#_ = !1;
|
|
124
134
|
/** True when batched operations include visibility changes (triggers Y-range + redraw on end). */
|
|
125
|
-
#
|
|
135
|
+
#H = !1;
|
|
126
136
|
/** True when batched operations bumped overlay version (emits a single overlayChange on flush). */
|
|
127
|
-
#
|
|
137
|
+
#G = !1;
|
|
128
138
|
/**
|
|
129
139
|
* Monotonic counter bumped on any mutation that affects overlay output —
|
|
130
140
|
* data, visibility, series options, theme. Used by snapshot helpers in
|
|
@@ -134,17 +144,17 @@ class ti extends lt {
|
|
|
134
144
|
*
|
|
135
145
|
* @internal
|
|
136
146
|
*/
|
|
137
|
-
#
|
|
147
|
+
#dt = 0;
|
|
138
148
|
get yAxisWidth() {
|
|
139
|
-
const t = this.#
|
|
149
|
+
const t = this.#B.y;
|
|
140
150
|
return t?.visible === !1 ? 0 : t?.width ?? 55;
|
|
141
151
|
}
|
|
142
152
|
get xAxisHeight() {
|
|
143
|
-
const t = this.#
|
|
153
|
+
const t = this.#B.x;
|
|
144
154
|
return t?.visible === !1 ? 0 : t?.height ?? 30;
|
|
145
155
|
}
|
|
146
156
|
/** Resolved animation config derived from `options.animations` at construction. */
|
|
147
|
-
#
|
|
157
|
+
#m;
|
|
148
158
|
/**
|
|
149
159
|
* Single source of truth for the chart's X / Y viewport animation.
|
|
150
160
|
* Push-model API: chart emits intent signals (`onPointAppended`,
|
|
@@ -169,31 +179,31 @@ class ti extends lt {
|
|
|
169
179
|
* field carries the decision across that gap. The closure also reads
|
|
170
180
|
* `#dataStart` / `#dataEnd` directly for the timestamps.
|
|
171
181
|
*/
|
|
172
|
-
#
|
|
182
|
+
#mt = !1;
|
|
173
183
|
/** Earliest data timestamp registered across all series, `null` before any data has arrived. */
|
|
174
184
|
#A = null;
|
|
175
185
|
/** Latest data timestamp registered across all series, `null` before any data has arrived. */
|
|
176
|
-
#
|
|
186
|
+
#e = null;
|
|
177
187
|
/**
|
|
178
188
|
* Previous {@link #dataEnd} value. Streaming-target math reads it to
|
|
179
189
|
* preserve any pan offset across ticks: a user who panned a few bars
|
|
180
190
|
* left of the tail keeps that offset as new bars arrive, instead of
|
|
181
191
|
* snapping back to the natural-pin position every frame.
|
|
182
192
|
*/
|
|
183
|
-
#
|
|
193
|
+
#O = null;
|
|
184
194
|
/**
|
|
185
195
|
* Warm-up window flag — `setVisibleRange({ from, bars })` arms it and
|
|
186
196
|
* the streaming-target math suppresses pan ticks while the data hasn't
|
|
187
197
|
* reached the right edge yet. Cleared by user interaction or once the
|
|
188
198
|
* data fills the window.
|
|
189
199
|
*/
|
|
190
|
-
#
|
|
200
|
+
#T = !1;
|
|
191
201
|
/**
|
|
192
202
|
* Cap for fit-to-data. When the data span exceeds this, the fit anchors
|
|
193
203
|
* the right edge and trims the left. Resolved once at construction from
|
|
194
204
|
* `options.viewport.maxVisibleBars`.
|
|
195
205
|
*/
|
|
196
|
-
#
|
|
206
|
+
#ut;
|
|
197
207
|
/**
|
|
198
208
|
* Committed logical X range — the "where X should be" target. Engine
|
|
199
209
|
* eases its visual toward this. Pan / zoom / setRange / fitContent /
|
|
@@ -202,29 +212,29 @@ class ti extends lt {
|
|
|
202
212
|
*/
|
|
203
213
|
#o = { from: 0, to: 0 };
|
|
204
214
|
/** Padded Y range — engine's raw Y target plus pixel padding from `#padding`. */
|
|
205
|
-
#
|
|
215
|
+
#z = { min: 0, max: 0 };
|
|
206
216
|
/**
|
|
207
217
|
* Auto-scroll flag — when `true`, streaming ticks slide X to track the
|
|
208
218
|
* data tail. Pan flips this off when the gesture pushes the tail off
|
|
209
219
|
* screen; chart's per-frame autoscroll check re-engages it when a
|
|
210
220
|
* follow-up pan brings the tail back into view.
|
|
211
221
|
*/
|
|
212
|
-
#
|
|
222
|
+
#f = !0;
|
|
213
223
|
/** Resolved viewport padding (top/bottom px + left/right pixels-or-intervals). */
|
|
214
|
-
#
|
|
224
|
+
#l;
|
|
215
225
|
/** Cached chart width — passed by interactions on every call; kept for the rare
|
|
216
226
|
* call that omits it (e.g. programmatic `chart.pan(...)` without explicit width). */
|
|
217
|
-
#
|
|
227
|
+
#E = 0;
|
|
218
228
|
/** Active performance monitor, or `null` when instrumentation is disabled (the default). */
|
|
219
229
|
#S;
|
|
220
230
|
/** When true, `destroy()` tears down the monitor; false for caller-supplied monitors we must not destroy. */
|
|
221
|
-
#
|
|
231
|
+
#U = !1;
|
|
222
232
|
/** Visible HUD overlay (mounted by the perf config); non-null only when the caller requested one. */
|
|
223
|
-
#
|
|
233
|
+
#K = null;
|
|
224
234
|
constructor(t, i) {
|
|
225
|
-
super(), i?.axis && (this.#
|
|
226
|
-
const e = this.#
|
|
227
|
-
this.#s =
|
|
235
|
+
super(), i?.axis && (this.#B = i.axis, this.#d = { min: i.axis.y?.min, max: i.axis.y?.max }), this.#n = i?.theme ?? xt.theme, this.#F = i?.grid?.visible !== !1, this.#k = H(i?.fade), this.#m = X.resolve(i?.animations), this.#ut = it(i?.viewport?.maxVisibleBars), this.#l = z(i?.padding), this.#R = new nt();
|
|
236
|
+
const e = this.#m.axis.y, s = this.#m.axis.x;
|
|
237
|
+
this.#s = _({
|
|
228
238
|
initial: { yRange: { min: 0, max: 0 }, xRange: { from: 0, to: 0 } },
|
|
229
239
|
y: {
|
|
230
240
|
curve: e.curve,
|
|
@@ -232,31 +242,35 @@ class ti extends lt {
|
|
|
232
242
|
stickyMs: e.stickyMs,
|
|
233
243
|
stickyFloorMs: e.stickyFloorMs,
|
|
234
244
|
gestureMs: e.gestureMs,
|
|
235
|
-
toggleMs: this.#
|
|
245
|
+
toggleMs: this.#m.toggleMs
|
|
236
246
|
},
|
|
237
247
|
x: {
|
|
238
248
|
curve: s.curve,
|
|
239
249
|
settleMs: s.settleMs,
|
|
240
250
|
gestureMs: s.gestureMs
|
|
241
251
|
},
|
|
242
|
-
computeXTarget: () => this.#
|
|
243
|
-
computeYTarget: ({ xTarget: h }) => this.#
|
|
244
|
-
onWake: () => this.#
|
|
245
|
-
}), this.#
|
|
246
|
-
const r =
|
|
247
|
-
this.#S = r.monitor, this.#
|
|
248
|
-
const n = this.#
|
|
249
|
-
this.timeScale.tickTracker.setFadeMs(n), this.yScale.tickTracker.setFadeMs(n), this.#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
+
computeXTarget: () => this.#Ft(),
|
|
253
|
+
computeYTarget: ({ xTarget: h }) => this.#St(h),
|
|
254
|
+
onWake: () => this.#i?.markDirty()
|
|
255
|
+
}), this.#lt = i?.onEdgeReached, this.#Y = i?.viewport?.initialRange;
|
|
256
|
+
const r = et(i?.perf);
|
|
257
|
+
this.#S = r.monitor, this.#U = r.ownsMonitor, this.#a = new G(t, this.#S ?? void 0), this.timeScale = new pt(), this.yScale = new yt(), this.timeScale.setLocale(i?.locale), this.timeScale.setTimeZone(i?.timeZone);
|
|
258
|
+
const n = this.#m.axis.ticksMs;
|
|
259
|
+
this.timeScale.tickTracker.setFadeMs(n), this.yScale.tickTracker.setFadeMs(n), this.#I = new Y({
|
|
260
|
+
initial: 0,
|
|
261
|
+
duration: this.#m.axis.gridMs,
|
|
262
|
+
lerp: (h, l, o) => h + (l - h) * o
|
|
263
|
+
}), this.#i = new B((h) => this.#st(h)), this.#h = new B(
|
|
264
|
+
(h) => this.#rt("overlay", h, () => this.renderOverlay(h))
|
|
265
|
+
), this.#S && r.hud && (this.#K = r.hud(t, this.#S));
|
|
252
266
|
const a = i?.interactive !== !1;
|
|
253
|
-
this.#
|
|
254
|
-
this.syncScales(), this.#
|
|
255
|
-
}), this.syncScales(), this.#
|
|
256
|
-
this
|
|
257
|
-
}), this.#
|
|
267
|
+
this.#M = a ? new gt(this.#a.canvas, this, this.timeScale, this.yScale) : null, this.#a.on("resize", () => {
|
|
268
|
+
this.syncScales(), this.#st(), this.emit("viewportChange");
|
|
269
|
+
}), this.syncScales(), this.#M?.on("crosshairMove", (h) => {
|
|
270
|
+
this.#$ = "pointer", this.#c = h, this.#h.markDirty(), this.emit("crosshairMove", h), this.#J(h);
|
|
271
|
+
}), this.#M?.on("click", (h) => {
|
|
258
272
|
this.emit("pointClick", { ...h, spatialHit: this.#bt(h) });
|
|
259
|
-
}), this.#
|
|
273
|
+
}), this.#M?.on("dblclick", (h) => {
|
|
260
274
|
this.fitContent(), this.emit("pointDoubleClick", { ...h, spatialHit: this.#bt(h) });
|
|
261
275
|
});
|
|
262
276
|
}
|
|
@@ -273,8 +287,8 @@ class ti extends lt {
|
|
|
273
287
|
* render instead of N.
|
|
274
288
|
*/
|
|
275
289
|
#p() {
|
|
276
|
-
if (this.#
|
|
277
|
-
this.#
|
|
290
|
+
if (this.#dt++, this.#L > 0) {
|
|
291
|
+
this.#G = !0;
|
|
278
292
|
return;
|
|
279
293
|
}
|
|
280
294
|
this.emit("overlayChange");
|
|
@@ -288,39 +302,39 @@ class ti extends lt {
|
|
|
288
302
|
* @internal
|
|
289
303
|
*/
|
|
290
304
|
getOverlayVersion() {
|
|
291
|
-
return this.#
|
|
305
|
+
return this.#dt;
|
|
292
306
|
}
|
|
293
307
|
/**
|
|
294
308
|
* Return a series ID: use the provided hint if it's non-empty and not already taken,
|
|
295
309
|
* otherwise generate a new auto ID. Auto-generated IDs never collide with each other
|
|
296
310
|
* or with user-provided IDs because they use a monotonically increasing counter.
|
|
297
311
|
*/
|
|
298
|
-
#
|
|
312
|
+
#Dt(t) {
|
|
299
313
|
if (t && !this.#t.some((e) => e.id === t))
|
|
300
314
|
return t;
|
|
301
315
|
let i;
|
|
302
316
|
do
|
|
303
|
-
i = `series_${++
|
|
317
|
+
i = `series_${++Dt}`;
|
|
304
318
|
while (this.#t.some((e) => e.id === i));
|
|
305
319
|
return i;
|
|
306
320
|
}
|
|
307
321
|
addSeries(t, i = {}) {
|
|
308
|
-
const e = typeof t == "string" ?
|
|
322
|
+
const e = typeof t == "string" ? vt(t) : t;
|
|
309
323
|
if (!e)
|
|
310
324
|
throw new Error(
|
|
311
325
|
`[wick-charts] Unknown series type '${String(t)}'. The string form of addSeries resolves through the series registry — call registerBuiltinSeries() once at startup, or pass the definition directly: chart.addSeries(LineSeriesDef, options).`
|
|
312
326
|
);
|
|
313
327
|
const { layers: s, id: r, label: n, labels: a, ...h } = i, l = s ?? 1, o = {
|
|
314
|
-
...this.#
|
|
328
|
+
...this.#m.defaults(e.type),
|
|
315
329
|
...h,
|
|
316
|
-
...this.#
|
|
317
|
-
},
|
|
318
|
-
return
|
|
330
|
+
...this.#m.overrides(e.type)
|
|
331
|
+
}, m = e.create({ theme: this.#n, layerCount: l }, o), u = a ?? (typeof n == "string" ? [n] : void 0), c = this.#Dt(r);
|
|
332
|
+
return m.onDataChanged?.(() => this.onDataChanged()), this.#t.push({ id: c, labels: u, renderer: m, visible: !0 }), this.#D = null, this.#q(), this.emit("seriesChange"), this.#p(), c;
|
|
319
333
|
}
|
|
320
334
|
/** Remove a series by ID and clean up its resources. */
|
|
321
335
|
removeSeries(t) {
|
|
322
336
|
const i = this.#t.findIndex((e) => e.id === t);
|
|
323
|
-
i >= 0 && (this.#t[i].renderer.dispose(), this.#t.splice(i, 1), this.#D = null, this.#
|
|
337
|
+
i >= 0 && (this.#t[i].renderer.dispose(), this.#t.splice(i, 1), this.#D = null, this.#q(), this.#i.markDirty(), this.emit("seriesChange"), this.#p());
|
|
324
338
|
}
|
|
325
339
|
// --- Markers (point annotations) -----------------------------------------
|
|
326
340
|
/**
|
|
@@ -333,27 +347,27 @@ class ti extends lt {
|
|
|
333
347
|
* appear in series queries.
|
|
334
348
|
*/
|
|
335
349
|
addMarker(t) {
|
|
336
|
-
const i = `marker_${++
|
|
337
|
-
return this.#
|
|
350
|
+
const i = `marker_${++Rt}`;
|
|
351
|
+
return this.#u.push(this.#ft(i, t)), this.#h.markDirty(), i;
|
|
338
352
|
}
|
|
339
353
|
/** Replace a marker's config in place. No-op when the id is unknown. */
|
|
340
354
|
updateMarker(t, i) {
|
|
341
|
-
const e = this.#
|
|
342
|
-
e !== -1 && (this.#
|
|
355
|
+
const e = this.#u.findIndex((s) => s.id === t);
|
|
356
|
+
e !== -1 && (this.#u[e] = this.#ft(t, i), this.#h.markDirty());
|
|
343
357
|
}
|
|
344
358
|
/** Remove a marker by id. No-op when the id is unknown. */
|
|
345
359
|
removeMarker(t) {
|
|
346
|
-
const i = this.#
|
|
347
|
-
i !== -1 && (this.#
|
|
360
|
+
const i = this.#u.findIndex((e) => e.id === t);
|
|
361
|
+
i !== -1 && (this.#u.splice(i, 1), this.#h.markDirty());
|
|
348
362
|
}
|
|
349
363
|
/** Read-only snapshot of the registered markers (normalized). Mutate via add / update / removeMarker. */
|
|
350
364
|
getMarkers() {
|
|
351
|
-
return this.#
|
|
365
|
+
return this.#u;
|
|
352
366
|
}
|
|
353
|
-
#
|
|
367
|
+
#ft(t, i) {
|
|
354
368
|
return {
|
|
355
369
|
id: t,
|
|
356
|
-
time:
|
|
370
|
+
time: x(i.time),
|
|
357
371
|
value: i.value,
|
|
358
372
|
seriesId: i.seriesId,
|
|
359
373
|
shape: i.shape ?? "dot",
|
|
@@ -363,14 +377,14 @@ class ti extends lt {
|
|
|
363
377
|
};
|
|
364
378
|
}
|
|
365
379
|
/** Resolve a marker's Y value: explicit `value`, else snapped to its series at `time`. Null when neither resolves. */
|
|
366
|
-
#
|
|
380
|
+
#Rt(t) {
|
|
367
381
|
if (t.value !== void 0 && Number.isFinite(t.value)) return t.value;
|
|
368
382
|
if (t.seriesId === void 0) return null;
|
|
369
383
|
const i = this.getDataAtTime(t.seriesId, t.time);
|
|
370
384
|
return i ? "close" in i ? i.close : i.value : null;
|
|
371
385
|
}
|
|
372
386
|
/** Resolve a marker's color: explicit `color`, else the series color, else the theme line color. */
|
|
373
|
-
#
|
|
387
|
+
#Ct(t) {
|
|
374
388
|
if (t.color !== void 0) return t.color;
|
|
375
389
|
if (t.seriesId !== void 0) {
|
|
376
390
|
const i = this.getSeriesColor(t.seriesId);
|
|
@@ -378,16 +392,16 @@ class ti extends lt {
|
|
|
378
392
|
}
|
|
379
393
|
return this.#n.line.color;
|
|
380
394
|
}
|
|
381
|
-
#
|
|
382
|
-
if (this.#
|
|
383
|
-
const s = performance.now() / (
|
|
384
|
-
for (const n of this.#
|
|
385
|
-
const a = this.#
|
|
395
|
+
#It(t, i, e) {
|
|
396
|
+
if (this.#u.length === 0) return;
|
|
397
|
+
const s = performance.now() / ($ * 2 * Math.PI) % 1, r = this.#j();
|
|
398
|
+
for (const n of this.#u) {
|
|
399
|
+
const a = this.#Rt(n);
|
|
386
400
|
if (a === null) continue;
|
|
387
|
-
const h = this.#
|
|
401
|
+
const h = this.#yt(r, n.time);
|
|
388
402
|
if (h <= 0) continue;
|
|
389
403
|
const l = t.context.globalAlpha;
|
|
390
|
-
h < 1 && (t.context.globalAlpha = l * h),
|
|
404
|
+
h < 1 && (t.context.globalAlpha = l * h), ct({
|
|
391
405
|
scope: t,
|
|
392
406
|
timeScale: this.timeScale,
|
|
393
407
|
yScale: this.yScale,
|
|
@@ -395,7 +409,7 @@ class ti extends lt {
|
|
|
395
409
|
marker: {
|
|
396
410
|
time: n.time,
|
|
397
411
|
value: a,
|
|
398
|
-
color: this.#
|
|
412
|
+
color: this.#Ct(n),
|
|
399
413
|
shape: n.shape,
|
|
400
414
|
pulse: n.pulse,
|
|
401
415
|
label: n.label
|
|
@@ -419,39 +433,39 @@ class ti extends lt {
|
|
|
419
433
|
* legend.
|
|
420
434
|
*/
|
|
421
435
|
addRegion(t) {
|
|
422
|
-
const i = `region_${++
|
|
423
|
-
return this.#
|
|
436
|
+
const i = `region_${++Ct}`;
|
|
437
|
+
return this.#x.push(this.#gt(i, t)), this.#i.markDirty(), i;
|
|
424
438
|
}
|
|
425
439
|
/** Replace a region's config in place. No-op when the id is unknown. */
|
|
426
440
|
updateRegion(t, i) {
|
|
427
|
-
const e = this.#
|
|
428
|
-
e !== -1 && (this.#
|
|
441
|
+
const e = this.#x.findIndex((s) => s.id === t);
|
|
442
|
+
e !== -1 && (this.#x[e] = this.#gt(t, i), this.#i.markDirty());
|
|
429
443
|
}
|
|
430
444
|
/** Remove a region by id. No-op when the id is unknown. */
|
|
431
445
|
removeRegion(t) {
|
|
432
|
-
const i = this.#
|
|
433
|
-
i !== -1 && (this.#
|
|
446
|
+
const i = this.#x.findIndex((e) => e.id === t);
|
|
447
|
+
i !== -1 && (this.#x.splice(i, 1), this.#i.markDirty());
|
|
434
448
|
}
|
|
435
449
|
/** Read-only snapshot of the registered regions (normalized). Mutate via add / update / removeRegion. */
|
|
436
450
|
getRegions() {
|
|
437
|
-
return this.#
|
|
451
|
+
return this.#x;
|
|
438
452
|
}
|
|
439
|
-
#
|
|
440
|
-
const { to: e } = i, s = e === void 0 || e === "now" ? null :
|
|
453
|
+
#gt(t, i) {
|
|
454
|
+
const { to: e } = i, s = e === void 0 || e === "now" ? null : x(e);
|
|
441
455
|
return {
|
|
442
456
|
id: t,
|
|
443
|
-
from:
|
|
457
|
+
from: x(i.from),
|
|
444
458
|
to: s,
|
|
445
459
|
fill: i.fill,
|
|
446
460
|
color: i.color,
|
|
447
461
|
label: i.label
|
|
448
462
|
};
|
|
449
463
|
}
|
|
450
|
-
#
|
|
451
|
-
if (this.#
|
|
452
|
-
for (const s of this.#
|
|
453
|
-
const { color: r, fill: n } =
|
|
454
|
-
|
|
464
|
+
#Pt(t, i, e) {
|
|
465
|
+
if (this.#x.length !== 0)
|
|
466
|
+
for (const s of this.#x) {
|
|
467
|
+
const { color: r, fill: n } = mt(s, this.#n);
|
|
468
|
+
ut({
|
|
455
469
|
scope: t,
|
|
456
470
|
timeScale: this.timeScale,
|
|
457
471
|
theme: this.#n,
|
|
@@ -473,13 +487,13 @@ class ti extends lt {
|
|
|
473
487
|
* legend.
|
|
474
488
|
*/
|
|
475
489
|
addLine(t) {
|
|
476
|
-
const i = `line_${++
|
|
477
|
-
return this.#y.push(this.#
|
|
490
|
+
const i = `line_${++It}`;
|
|
491
|
+
return this.#y.push(this.#pt(i, t)), this.#h.markDirty(), i;
|
|
478
492
|
}
|
|
479
493
|
/** Replace a reference line's config in place. No-op when the id is unknown. */
|
|
480
494
|
updateLine(t, i) {
|
|
481
495
|
const e = this.#y.findIndex((s) => s.id === t);
|
|
482
|
-
e !== -1 && (this.#y[e] = this.#
|
|
496
|
+
e !== -1 && (this.#y[e] = this.#pt(t, i), this.#h.markDirty());
|
|
483
497
|
}
|
|
484
498
|
/** Remove a reference line by id. No-op when the id is unknown. */
|
|
485
499
|
removeLine(t) {
|
|
@@ -490,7 +504,7 @@ class ti extends lt {
|
|
|
490
504
|
getLines() {
|
|
491
505
|
return this.#y;
|
|
492
506
|
}
|
|
493
|
-
#
|
|
507
|
+
#pt(t, i) {
|
|
494
508
|
const { time: e, value: s } = i, r = {
|
|
495
509
|
id: t,
|
|
496
510
|
color: i.color,
|
|
@@ -498,16 +512,16 @@ class ti extends lt {
|
|
|
498
512
|
style: i.style ?? "dashed",
|
|
499
513
|
width: i.width ?? 1
|
|
500
514
|
};
|
|
501
|
-
return e !== void 0 ? { ...r, orientation: "vertical", coord:
|
|
515
|
+
return e !== void 0 ? { ...r, orientation: "vertical", coord: x(e) } : { ...r, orientation: "horizontal", coord: s ?? Number.NaN };
|
|
502
516
|
}
|
|
503
|
-
#
|
|
517
|
+
#Ht(t, i, e) {
|
|
504
518
|
if (this.#y.length === 0) return;
|
|
505
|
-
const s = this.#
|
|
519
|
+
const s = this.#j();
|
|
506
520
|
for (const r of this.#y) {
|
|
507
|
-
const n = s >= 1 ? 1 : r.orientation === "vertical" ? this.#
|
|
521
|
+
const n = s >= 1 ? 1 : r.orientation === "vertical" ? this.#yt(s, r.coord) : P(s);
|
|
508
522
|
if (n <= 0) continue;
|
|
509
523
|
const a = t.context.globalAlpha;
|
|
510
|
-
n < 1 && (t.context.globalAlpha = a * n),
|
|
524
|
+
n < 1 && (t.context.globalAlpha = a * n), dt({
|
|
511
525
|
scope: t,
|
|
512
526
|
timeScale: this.timeScale,
|
|
513
527
|
yScale: this.yScale,
|
|
@@ -560,10 +574,10 @@ class ti extends lt {
|
|
|
560
574
|
* has actually been observed in progress, so an annotation drawn on a chart
|
|
561
575
|
* that has no data yet still rides the reveal once data arrives.
|
|
562
576
|
*/
|
|
563
|
-
#
|
|
564
|
-
if (this.#
|
|
577
|
+
#j() {
|
|
578
|
+
if (this.#at) return 1;
|
|
565
579
|
const t = this.getIntroFront();
|
|
566
|
-
return t < 1 ? (this.#
|
|
580
|
+
return t < 1 ? (this.#nt = !0, t) : (this.#nt && (this.#at = !0), 1);
|
|
567
581
|
}
|
|
568
582
|
/**
|
|
569
583
|
* Entrance alpha for an overlay pinned at `time`, given the intro reveal
|
|
@@ -571,10 +585,10 @@ class ti extends lt {
|
|
|
571
585
|
* then fades in over a short band — so annotations surface in step with the
|
|
572
586
|
* series drawing past them. `1` once the intro has settled.
|
|
573
587
|
*/
|
|
574
|
-
#
|
|
588
|
+
#yt(t, i) {
|
|
575
589
|
if (t >= 1) return 1;
|
|
576
590
|
const { from: e, to: s } = this.timeScale.getRange(), r = s - e, n = r > 0 ? (i - e) / r : 0;
|
|
577
|
-
return
|
|
591
|
+
return bt((t - n) / 0.12, 0, 1);
|
|
578
592
|
}
|
|
579
593
|
/**
|
|
580
594
|
* Replace all data for a series.
|
|
@@ -587,7 +601,7 @@ class ti extends lt {
|
|
|
587
601
|
*/
|
|
588
602
|
setSeriesData(t, i, e) {
|
|
589
603
|
const s = this.#t.find((r) => r.id === t);
|
|
590
|
-
s && (this.#
|
|
604
|
+
s && (this.#Q = !0, s.renderer.setData(i, e));
|
|
591
605
|
}
|
|
592
606
|
/** Append a new data point to the end of a series (real-time tick). */
|
|
593
607
|
appendData(t, i, e) {
|
|
@@ -611,7 +625,7 @@ class ti extends lt {
|
|
|
611
625
|
const s = this.#t.find((n) => n.id === t);
|
|
612
626
|
if (s === void 0 || s.renderer.prependPoints === void 0) return;
|
|
613
627
|
const r = this.#Z.left;
|
|
614
|
-
r !== null && s.renderer.setHistoryHandoff !== void 0 && performance.now() - r.at <
|
|
628
|
+
r !== null && s.renderer.setHistoryHandoff !== void 0 && performance.now() - r.at < Lt && (s.renderer.setHistoryHandoff(r.bars), this.#P.left = !0, this.#N.left = null, this.#Z.left = null, this.#h.markDirty()), s.renderer.prependPoints(i, e);
|
|
615
629
|
}
|
|
616
630
|
/** Update the last data point of a series in place (e.g. live candle update). */
|
|
617
631
|
updateData(t, i, e) {
|
|
@@ -637,9 +651,9 @@ class ti extends lt {
|
|
|
637
651
|
updateSeriesOptions(t, i) {
|
|
638
652
|
const e = this.#t.find((o) => o.id === t);
|
|
639
653
|
if (!e) return;
|
|
640
|
-
const s = e.labels, r = e.renderer.getLayerColors().slice(), n = this.#
|
|
641
|
-
e.renderer.updateOptions({ ...i, ...n }), "label" in i && typeof i.label == "string" && (e.labels = [i.label]), this.#
|
|
642
|
-
const a = e.renderer.getLayerColors(), h = r.length !== a.length || r.some((o,
|
|
654
|
+
const s = e.labels, r = e.renderer.getLayerColors().slice(), n = this.#m.overrides(e.renderer.kind);
|
|
655
|
+
e.renderer.updateOptions({ ...i, ...n }), "label" in i && typeof i.label == "string" && (e.labels = [i.label]), this.#i.markDirty();
|
|
656
|
+
const a = e.renderer.getLayerColors(), h = r.length !== a.length || r.some((o, m) => o !== a[m]), l = !N(s, e.labels);
|
|
643
657
|
(h || l) && this.#p();
|
|
644
658
|
}
|
|
645
659
|
/**
|
|
@@ -647,19 +661,19 @@ class ti extends lt {
|
|
|
647
661
|
* inside `fn` still flush the batch so counters don't leak across calls.
|
|
648
662
|
*/
|
|
649
663
|
batch(t) {
|
|
650
|
-
this.#
|
|
664
|
+
this.#L++;
|
|
651
665
|
try {
|
|
652
666
|
t();
|
|
653
667
|
} finally {
|
|
654
|
-
if (--this.#
|
|
655
|
-
if (this.#
|
|
656
|
-
this
|
|
657
|
-
else if (this.#
|
|
658
|
-
this.#
|
|
668
|
+
if (--this.#L <= 0) {
|
|
669
|
+
if (this.#L = 0, this.#_)
|
|
670
|
+
this.#_ = !1, this.#H = !1, this.onDataChanged();
|
|
671
|
+
else if (this.#H) {
|
|
672
|
+
this.#H = !1, this.#g = !0;
|
|
659
673
|
const i = performance.now();
|
|
660
|
-
this.#s.onAxisReconfig(i), this.#v(i), this.#
|
|
674
|
+
this.#s.onAxisReconfig(i), this.#v(i), this.#i.markDirty();
|
|
661
675
|
}
|
|
662
|
-
this.#
|
|
676
|
+
this.#G && (this.#G = !1, this.emit("overlayChange"));
|
|
663
677
|
}
|
|
664
678
|
}
|
|
665
679
|
}
|
|
@@ -673,13 +687,13 @@ class ti extends lt {
|
|
|
673
687
|
setSeriesVisible(t, i) {
|
|
674
688
|
const e = this.#t.find((n) => n.id === t);
|
|
675
689
|
if (!e || e.visible === i) return;
|
|
676
|
-
e.visible = i, this.#p(), this.#
|
|
677
|
-
const s = this.#
|
|
678
|
-
if (e.renderer.setAlpha?.(i ? 1 : 0, s), this.#
|
|
679
|
-
this.#
|
|
690
|
+
e.visible = i, this.#p(), this.#q();
|
|
691
|
+
const s = this.#m.toggleMs;
|
|
692
|
+
if (e.renderer.setAlpha?.(i ? 1 : 0, s), this.#i.markDirty(), this.#L > 0) {
|
|
693
|
+
this.#H = !0;
|
|
680
694
|
return;
|
|
681
695
|
}
|
|
682
|
-
this.#
|
|
696
|
+
this.#g = !0;
|
|
683
697
|
const r = performance.now();
|
|
684
698
|
this.#s.onSeriesVisibilityChanged(r), this.#v(r);
|
|
685
699
|
}
|
|
@@ -691,7 +705,7 @@ class ti extends lt {
|
|
|
691
705
|
* containing the tail.
|
|
692
706
|
*/
|
|
693
707
|
getAutoScroll() {
|
|
694
|
-
return this.#
|
|
708
|
+
return this.#f;
|
|
695
709
|
}
|
|
696
710
|
isSeriesVisible(t) {
|
|
697
711
|
return this.#t.find((i) => i.id === t)?.visible ?? !0;
|
|
@@ -710,12 +724,12 @@ class ti extends lt {
|
|
|
710
724
|
const s = this.#t.find((a) => a.id === t);
|
|
711
725
|
if (!s || s.renderer.getLayerCount() <= 1 || s.renderer.isLayerVisible(i) === e) return;
|
|
712
726
|
s.renderer.setLayerVisible(i, e), this.#p();
|
|
713
|
-
const r = this.#
|
|
714
|
-
if (s.renderer.setLayerAlpha?.(i, e ? 1 : 0, r), this.#
|
|
715
|
-
this.#
|
|
727
|
+
const r = this.#m.toggleMs;
|
|
728
|
+
if (s.renderer.setLayerAlpha?.(i, e ? 1 : 0, r), this.#i.markDirty(), this.#L > 0) {
|
|
729
|
+
this.#H = !0;
|
|
716
730
|
return;
|
|
717
731
|
}
|
|
718
|
-
this.#
|
|
732
|
+
this.#g = !0;
|
|
719
733
|
const n = performance.now();
|
|
720
734
|
this.#s.onSeriesVisibilityChanged(n), this.#v(n);
|
|
721
735
|
}
|
|
@@ -727,7 +741,7 @@ class ti extends lt {
|
|
|
727
741
|
const { first: t, last: i } = this.getDataBounds();
|
|
728
742
|
if (t === void 0 || i === void 0) return;
|
|
729
743
|
const e = this.#a.size.media.width - this.yAxisWidth;
|
|
730
|
-
this.#
|
|
744
|
+
this.#W(t, i, e), this.#X({ xEase: !0 });
|
|
731
745
|
}
|
|
732
746
|
getVisibleRange() {
|
|
733
747
|
return this.#o.from === 0 && this.#o.to === 0 ? this.#s.getAnimationState().xRange : this.#o;
|
|
@@ -738,7 +752,7 @@ class ti extends lt {
|
|
|
738
752
|
* tracking and is cheaper than recomputing from series stores.
|
|
739
753
|
*/
|
|
740
754
|
getDataRange() {
|
|
741
|
-
return this.#A === null || this.#
|
|
755
|
+
return this.#A === null || this.#e === null ? null : { from: this.#A, to: this.#e };
|
|
742
756
|
}
|
|
743
757
|
/**
|
|
744
758
|
* Imperatively set the visible time range. Three forms:
|
|
@@ -770,29 +784,29 @@ class ti extends lt {
|
|
|
770
784
|
const { first: n, last: a } = this.getDataBounds();
|
|
771
785
|
if (n === void 0 || a === void 0) return;
|
|
772
786
|
const h = Math.max(n, a - (t - 1) * this.#r), l = this.#a.size.media.width - this.yAxisWidth;
|
|
773
|
-
this.#
|
|
787
|
+
this.#W(h, a, l), this.#X();
|
|
774
788
|
return;
|
|
775
789
|
}
|
|
776
790
|
if ("bars" in t) {
|
|
777
791
|
if (!Number.isInteger(t.bars) || t.bars < 2) return;
|
|
778
|
-
const n =
|
|
779
|
-
this.#
|
|
792
|
+
const n = x(t.from), a = n + t.bars * this.#r;
|
|
793
|
+
this.#f = this.#e !== null && this.#e >= n && this.#e <= a, this.#C({ from: n, to: a }, { emitChange: !0 }), this.#T = !0, this.#X();
|
|
780
794
|
return;
|
|
781
795
|
}
|
|
782
|
-
const e =
|
|
783
|
-
this.#
|
|
796
|
+
const e = x(t.from), s = x(t.to);
|
|
797
|
+
this.#f = this.#e !== null && this.#e >= e && this.#e <= s, this.#T = !1;
|
|
784
798
|
const r = this.#C({ from: e, to: s }, { emitChange: !0 });
|
|
785
799
|
if (i?.gesture) {
|
|
786
800
|
r && this.#Bt();
|
|
787
801
|
return;
|
|
788
802
|
}
|
|
789
|
-
this.#
|
|
803
|
+
this.#X();
|
|
790
804
|
}
|
|
791
805
|
getYRange() {
|
|
792
|
-
return this.#
|
|
806
|
+
return this.#z;
|
|
793
807
|
}
|
|
794
808
|
getCrosshairPosition() {
|
|
795
|
-
return this.#
|
|
809
|
+
return this.#c;
|
|
796
810
|
}
|
|
797
811
|
/**
|
|
798
812
|
* Programmatically set or clear the crosshair. Same effect as the user
|
|
@@ -829,37 +843,37 @@ class ti extends lt {
|
|
|
829
843
|
*/
|
|
830
844
|
setCrosshair(t) {
|
|
831
845
|
if (t === null) {
|
|
832
|
-
if (this.#
|
|
833
|
-
this.#
|
|
846
|
+
if (this.#c === null) return;
|
|
847
|
+
this.#c = null, this.#h.markDirty(), this.emit("crosshairMove", null);
|
|
834
848
|
return;
|
|
835
849
|
}
|
|
836
850
|
const { time: i } = t;
|
|
837
851
|
if (!Number.isFinite(i)) return;
|
|
838
|
-
const e = this.#
|
|
852
|
+
const e = this.#c;
|
|
839
853
|
let s;
|
|
840
854
|
if (t.y !== void 0)
|
|
841
855
|
s = t.y;
|
|
842
856
|
else if (e !== null)
|
|
843
857
|
s = e.y;
|
|
844
858
|
else {
|
|
845
|
-
const a = this.#
|
|
859
|
+
const a = this.#z;
|
|
846
860
|
s = (a.min + a.max) / 2;
|
|
847
861
|
}
|
|
848
862
|
if (!Number.isFinite(s) || e !== null && e.time === i && e.y === s) return;
|
|
849
863
|
const r = this.timeScale.timeToX(i), n = this.yScale.valueToY(s);
|
|
850
|
-
this
|
|
864
|
+
this.#$ = "time", this.#c = { mediaX: r, mediaY: n, time: i, y: s }, this.#h.markDirty(), this.emit("crosshairMove", this.#c);
|
|
851
865
|
}
|
|
852
866
|
/** Get the last visible value and whether the absolute last point is on screen. */
|
|
853
867
|
getLastValue(t) {
|
|
854
|
-
return
|
|
868
|
+
return J(t, this.#t, this.#s.getAnimationState().xRange);
|
|
855
869
|
}
|
|
856
870
|
/** Get the second-to-last value, useful for computing change. */
|
|
857
871
|
getPreviousClose(t) {
|
|
858
|
-
return
|
|
872
|
+
return Q(t, this.#t);
|
|
859
873
|
}
|
|
860
874
|
getLastData(t) {
|
|
861
875
|
const i = this.#t.find((e) => e.id === t);
|
|
862
|
-
return !i || !
|
|
876
|
+
return !i || !k(i.renderer) ? null : i.renderer.getLastDataPoint();
|
|
863
877
|
}
|
|
864
878
|
/** Find the data point closest to the given timestamp within one data interval. */
|
|
865
879
|
getDataAtTime(t, i) {
|
|
@@ -885,9 +899,9 @@ class ti extends lt {
|
|
|
885
899
|
* has no meaningful x/y coordinate system, so the dashed hairlines would
|
|
886
900
|
* just be visual noise.
|
|
887
901
|
*/
|
|
888
|
-
#
|
|
902
|
+
#vt() {
|
|
889
903
|
for (const t of this.#t)
|
|
890
|
-
if (t.visible &&
|
|
904
|
+
if (t.visible && k(t.renderer))
|
|
891
905
|
return !0;
|
|
892
906
|
return !1;
|
|
893
907
|
}
|
|
@@ -898,7 +912,7 @@ class ti extends lt {
|
|
|
898
912
|
* wheel and touch events, so the page scrolls normally under the cursor.
|
|
899
913
|
*/
|
|
900
914
|
canPanZoom() {
|
|
901
|
-
return this.#
|
|
915
|
+
return this.#vt();
|
|
902
916
|
}
|
|
903
917
|
/**
|
|
904
918
|
* Push the current pan/zoom capability into the interaction layer (canvas
|
|
@@ -907,8 +921,8 @@ class ti extends lt {
|
|
|
907
921
|
* every mutation that can flip {@link canPanZoom}: series add/remove and
|
|
908
922
|
* series visibility.
|
|
909
923
|
*/
|
|
910
|
-
#
|
|
911
|
-
this.#
|
|
924
|
+
#q() {
|
|
925
|
+
this.#M?.syncPanZoomMode();
|
|
912
926
|
}
|
|
913
927
|
/**
|
|
914
928
|
* Filter `getSeriesIds()` by renderer type. A concrete kind (`'pie'`,
|
|
@@ -924,7 +938,7 @@ class ti extends lt {
|
|
|
924
938
|
getSeriesIdsByType(t, i) {
|
|
925
939
|
const e = i?.visibleOnly === !0, s = i?.singleLayerOnly === !0, r = [];
|
|
926
940
|
for (const n of this.#t) {
|
|
927
|
-
if (!(t === "time" ?
|
|
941
|
+
if (!(t === "time" ? k(n.renderer) : n.renderer.kind === t)) continue;
|
|
928
942
|
const a = n.renderer.getLayerCount();
|
|
929
943
|
if (!(s && a > 1)) {
|
|
930
944
|
if (e) {
|
|
@@ -951,7 +965,7 @@ class ti extends lt {
|
|
|
951
965
|
* Returns `null` for unknown ids or empty series.
|
|
952
966
|
*/
|
|
953
967
|
getStackedLastValue(t) {
|
|
954
|
-
return
|
|
968
|
+
return tt(t, this.#t, this.#s.getAnimationState().xRange);
|
|
955
969
|
}
|
|
956
970
|
/**
|
|
957
971
|
* Stacked value at an arbitrary `time` — the cumulative stack top at that
|
|
@@ -1008,7 +1022,7 @@ class ti extends lt {
|
|
|
1008
1022
|
*/
|
|
1009
1023
|
setSeriesLabels(t, i) {
|
|
1010
1024
|
const e = this.#t.find((s) => s.id === t);
|
|
1011
|
-
!e ||
|
|
1025
|
+
!e || N(e.labels, i) || (e.labels = i, this.#p());
|
|
1012
1026
|
}
|
|
1013
1027
|
/**
|
|
1014
1028
|
* Set the per-layer color overrides carried in `data` (sparse — `undefined`
|
|
@@ -1019,7 +1033,7 @@ class ti extends lt {
|
|
|
1019
1033
|
*/
|
|
1020
1034
|
setLayerColors(t, i) {
|
|
1021
1035
|
const e = this.#t.find((s) => s.id === t);
|
|
1022
|
-
!e ||
|
|
1036
|
+
!e || Pt(e.colorOverrides, i) || (e.colorOverrides = i, e.renderer.setColorOverrides?.(i), this.#i.markDirty(), this.#p());
|
|
1023
1037
|
}
|
|
1024
1038
|
/** Get per-layer colors for a series. Returns null for single-layer non-bar/line series. */
|
|
1025
1039
|
getSeriesLayers(t) {
|
|
@@ -1044,7 +1058,7 @@ class ti extends lt {
|
|
|
1044
1058
|
this.#n = t;
|
|
1045
1059
|
for (const e of this.#t)
|
|
1046
1060
|
e.renderer.applyTheme(t, i);
|
|
1047
|
-
this.#
|
|
1061
|
+
this.#i.markDirty(), this.#p();
|
|
1048
1062
|
}
|
|
1049
1063
|
getTheme() {
|
|
1050
1064
|
return this.#n;
|
|
@@ -1066,9 +1080,9 @@ class ti extends lt {
|
|
|
1066
1080
|
/** Update axis configuration and re-render. */
|
|
1067
1081
|
setAxis(t) {
|
|
1068
1082
|
const i = this.yAxisWidth, e = this.xAxisHeight;
|
|
1069
|
-
this.#
|
|
1083
|
+
this.#B = t, this.#d = { min: t.y?.min, max: t.y?.max }, this.#g = !0;
|
|
1070
1084
|
const s = performance.now();
|
|
1071
|
-
this.#s.onAxisReconfig(s), this.#v(s), (this.yAxisWidth !== i || this.xAxisHeight !== e) && this.syncScales(), this.#
|
|
1085
|
+
this.#s.onAxisReconfig(s), this.#v(s), (this.yAxisWidth !== i || this.xAxisHeight !== e) && this.syncScales(), this.#i.markDirty();
|
|
1072
1086
|
}
|
|
1073
1087
|
/**
|
|
1074
1088
|
* Apply label-density knobs driven by `<YAxis labelCount=… minLabelSpacing=…>`
|
|
@@ -1078,12 +1092,12 @@ class ti extends lt {
|
|
|
1078
1092
|
*/
|
|
1079
1093
|
setYAxisLabelDensity(t) {
|
|
1080
1094
|
let i = !1;
|
|
1081
|
-
"labelCount" in t && (this.yScale.setLabelCount(t.labelCount ?? null), i = !0), "minLabelSpacing" in t && (this.yScale.setMinSpacing(t.minLabelSpacing ?? null), i = !0), i && (this.syncScales(), this.emit("viewportChange"), this.#
|
|
1095
|
+
"labelCount" in t && (this.yScale.setLabelCount(t.labelCount ?? null), i = !0), "minLabelSpacing" in t && (this.yScale.setMinSpacing(t.minLabelSpacing ?? null), i = !0), i && (this.syncScales(), this.emit("viewportChange"), this.#i.markDirty());
|
|
1082
1096
|
}
|
|
1083
1097
|
/** Label-density knobs for the time axis — mirror of {@link setYAxisLabelDensity}. */
|
|
1084
1098
|
setTimeAxisLabelDensity(t) {
|
|
1085
1099
|
let i = !1;
|
|
1086
|
-
"labelCount" in t && (this.timeScale.setLabelCount(t.labelCount ?? null), i = !0), "minLabelSpacing" in t && (this.timeScale.setMinSpacing(t.minLabelSpacing ?? null), i = !0), i && (this.syncScales(), this.emit("viewportChange"), this.#
|
|
1100
|
+
"labelCount" in t && (this.timeScale.setLabelCount(t.labelCount ?? null), i = !0), "minLabelSpacing" in t && (this.timeScale.setMinSpacing(t.minLabelSpacing ?? null), i = !0), i && (this.syncScales(), this.emit("viewportChange"), this.#i.markDirty());
|
|
1087
1101
|
}
|
|
1088
1102
|
getMediaSize() {
|
|
1089
1103
|
return this.#a.size.media;
|
|
@@ -1109,26 +1123,26 @@ class ti extends lt {
|
|
|
1109
1123
|
* InfoBar ResizeObserver).
|
|
1110
1124
|
*/
|
|
1111
1125
|
setPadding(t) {
|
|
1112
|
-
const i = this.#
|
|
1113
|
-
this.#
|
|
1114
|
-
const e = this.#
|
|
1126
|
+
const i = this.#l;
|
|
1127
|
+
this.#l = z(t);
|
|
1128
|
+
const e = this.#l, s = !V(i.left, e.left) || !V(i.right, e.right), r = i.top !== e.top || i.bottom !== e.bottom;
|
|
1115
1129
|
if (s) {
|
|
1116
1130
|
const { first: n, last: a } = this.getDataBounds();
|
|
1117
1131
|
if (n !== void 0 && a !== void 0) {
|
|
1118
1132
|
const h = this.#a.size.media.width - this.yAxisWidth;
|
|
1119
|
-
this.#
|
|
1133
|
+
this.#W(n, a, h);
|
|
1120
1134
|
}
|
|
1121
1135
|
}
|
|
1122
1136
|
if (s || r) {
|
|
1123
|
-
this.#
|
|
1137
|
+
this.#g = !0;
|
|
1124
1138
|
const n = performance.now();
|
|
1125
1139
|
this.#s.onAxisReconfig(n), this.#v(n);
|
|
1126
1140
|
}
|
|
1127
|
-
this.syncScales(), this.#
|
|
1141
|
+
this.syncScales(), this.#i.markDirty(), r && this.emit("viewportChange");
|
|
1128
1142
|
}
|
|
1129
1143
|
/** Show or hide the background grid. Takes effect on the next render frame. */
|
|
1130
1144
|
setGrid(t) {
|
|
1131
|
-
this.#
|
|
1145
|
+
this.#F = t.visible, this.#i.markDirty();
|
|
1132
1146
|
}
|
|
1133
1147
|
/**
|
|
1134
1148
|
* Set or clear the edge fade masks (see {@link ChartOptions.fade}).
|
|
@@ -1138,8 +1152,8 @@ class ti extends lt {
|
|
|
1138
1152
|
* the next render frame.
|
|
1139
1153
|
*/
|
|
1140
1154
|
setFade(t) {
|
|
1141
|
-
const i =
|
|
1142
|
-
i.top === e.top && i.right === e.right && i.left === e.left || (this.#k = i, this.#
|
|
1155
|
+
const i = H(t), e = this.#k;
|
|
1156
|
+
i.top === e.top && i.right === e.right && i.left === e.left || (this.#k = i, this.#i.markDirty());
|
|
1143
1157
|
}
|
|
1144
1158
|
/**
|
|
1145
1159
|
* Set the visual state for one side of the chart. Typically called in
|
|
@@ -1151,23 +1165,23 @@ class ti extends lt {
|
|
|
1151
1165
|
* symmetry and currently renders identically to `idle`.
|
|
1152
1166
|
*/
|
|
1153
1167
|
setEdgeState(t, i) {
|
|
1154
|
-
if (this.#
|
|
1155
|
-
const e = this.#
|
|
1156
|
-
this.#
|
|
1168
|
+
if (this.#b[t] === i) return;
|
|
1169
|
+
const e = this.#b[t] === "loading", s = this.#P[t];
|
|
1170
|
+
this.#P[t] = !1, this.#N[t] = e && !s && (i === "idle" || i === "has-more") ? performance.now() : null, this.#b[t] = i, this.#h.markDirty();
|
|
1157
1171
|
}
|
|
1158
1172
|
/** Read the current host-declared state for a given edge. */
|
|
1159
1173
|
getEdgeState(t) {
|
|
1160
|
-
return this.#
|
|
1174
|
+
return this.#b[t];
|
|
1161
1175
|
}
|
|
1162
1176
|
/**
|
|
1163
1177
|
* Alpha for a side's `loading` exit fade, or `null` when none is in
|
|
1164
1178
|
* flight. Self-cleaning: an elapsed fade clears its start stamp.
|
|
1165
1179
|
*/
|
|
1166
|
-
#
|
|
1167
|
-
const i = this.#
|
|
1180
|
+
#xt(t) {
|
|
1181
|
+
const i = this.#N[t];
|
|
1168
1182
|
if (i === null) return null;
|
|
1169
|
-
const e = (performance.now() - i) /
|
|
1170
|
-
return e >= 1 ? (this.#
|
|
1183
|
+
const e = (performance.now() - i) / At;
|
|
1184
|
+
return e >= 1 ? (this.#N[t] = null, null) : 1 - P(Math.max(0, e));
|
|
1171
1185
|
}
|
|
1172
1186
|
/**
|
|
1173
1187
|
* Swap the painter used for a side's `loading` spinner — the same
|
|
@@ -1176,7 +1190,7 @@ class ti extends lt {
|
|
|
1176
1190
|
* immediately if that side is currently in the `loading` state.
|
|
1177
1191
|
*/
|
|
1178
1192
|
setEdgeIndicator(t, i) {
|
|
1179
|
-
this.#
|
|
1193
|
+
this.#ct[t] = i, this.#b[t] === "loading" && this.#h.markDirty();
|
|
1180
1194
|
}
|
|
1181
1195
|
/**
|
|
1182
1196
|
* Resolve the boundary point's Y position and series kind on the primary
|
|
@@ -1186,14 +1200,14 @@ class ti extends lt {
|
|
|
1186
1200
|
* `open` (the value immediately preceding the boundary); `right` from the
|
|
1187
1201
|
* last visible candle's `close`.
|
|
1188
1202
|
*/
|
|
1189
|
-
#
|
|
1203
|
+
#zt(t, i) {
|
|
1190
1204
|
const e = this.getSeriesIdsByType("time", { visibleOnly: !0, singleLayerOnly: !0 })[0] ?? this.getSeriesIdsByType("time", { visibleOnly: !0 })[0];
|
|
1191
1205
|
if (!e) return null;
|
|
1192
1206
|
const s = this.getDataAtTime(e, i);
|
|
1193
1207
|
if (!s) return null;
|
|
1194
1208
|
const r = this.#t.find((n) => n.id === e);
|
|
1195
1209
|
return r ? {
|
|
1196
|
-
valueY: this.yScale.valueToY(
|
|
1210
|
+
valueY: this.yScale.valueToY(U(t, s)),
|
|
1197
1211
|
seriesKind: r.renderer.kind
|
|
1198
1212
|
} : null;
|
|
1199
1213
|
}
|
|
@@ -1203,7 +1217,7 @@ class ti extends lt {
|
|
|
1203
1217
|
* placeholder shapes to match the real bars that will render once data
|
|
1204
1218
|
* lands. `null` when the viewport has no meaningful span yet.
|
|
1205
1219
|
*/
|
|
1206
|
-
#
|
|
1220
|
+
#Vt() {
|
|
1207
1221
|
const t = this.timeScale.barWidthMedia(this.#r);
|
|
1208
1222
|
return Number.isFinite(t) && t > 0 ? t : null;
|
|
1209
1223
|
}
|
|
@@ -1222,8 +1236,8 @@ class ti extends lt {
|
|
|
1222
1236
|
* probed, not kind-gated: a kind check here silently kills hover for the
|
|
1223
1237
|
* next spatial renderer.
|
|
1224
1238
|
*/
|
|
1225
|
-
#
|
|
1226
|
-
const i = this.#a.size, e = this.#
|
|
1239
|
+
#J(t) {
|
|
1240
|
+
const i = this.#a.size, e = this.#l, s = {
|
|
1227
1241
|
top: e.top * i.verticalPixelRatio,
|
|
1228
1242
|
bottom: e.bottom * i.verticalPixelRatio
|
|
1229
1243
|
};
|
|
@@ -1237,7 +1251,7 @@ class ti extends lt {
|
|
|
1237
1251
|
}
|
|
1238
1252
|
a.renderer.setHoverIndex(h) && (r = !0), h >= 0 && !n && (n = { seriesId: a.id, index: h, info: a.renderer.getHoverInfo?.(this.#n) ?? null });
|
|
1239
1253
|
}
|
|
1240
|
-
r && (this.#
|
|
1254
|
+
r && (this.#i.markDirty(), this.emit("seriesHover", n));
|
|
1241
1255
|
}
|
|
1242
1256
|
/**
|
|
1243
1257
|
* Read-only counterpart to {@link #updateHover} for `pointClick` — same
|
|
@@ -1247,7 +1261,7 @@ class ti extends lt {
|
|
|
1247
1261
|
* whose `hitTest` claims the position, or `null` if none does.
|
|
1248
1262
|
*/
|
|
1249
1263
|
#bt(t) {
|
|
1250
|
-
const i = this.#a.size, e = this.#
|
|
1264
|
+
const i = this.#a.size, e = this.#l, s = {
|
|
1251
1265
|
top: e.top * i.verticalPixelRatio,
|
|
1252
1266
|
bottom: e.bottom * i.verticalPixelRatio
|
|
1253
1267
|
}, r = t.mediaX * i.horizontalPixelRatio, n = t.mediaY * i.verticalPixelRatio;
|
|
@@ -1278,30 +1292,30 @@ class ti extends lt {
|
|
|
1278
1292
|
* viewport didn't move, the re-derived values are bit-identical and the
|
|
1279
1293
|
* method exits without emitting.
|
|
1280
1294
|
*/
|
|
1281
|
-
#
|
|
1282
|
-
const t = this.#
|
|
1295
|
+
#Wt() {
|
|
1296
|
+
const t = this.#c;
|
|
1283
1297
|
if (t === null) return;
|
|
1284
1298
|
const { from: i, to: e } = this.timeScale.getRange(), s = this.yScale.getRange(), r = Math.abs(e - i) * 1e-9, n = Math.abs(s.max - s.min) * 1e-9, a = 1e-6;
|
|
1285
1299
|
let h;
|
|
1286
|
-
if (this
|
|
1300
|
+
if (this.#$ === "pointer") {
|
|
1287
1301
|
const l = this.timeScale.xToTime(t.mediaX), o = this.yScale.yToValue(t.mediaY);
|
|
1288
1302
|
if (!Number.isFinite(l) || !Number.isFinite(o) || Math.abs(l - t.time) <= r && Math.abs(o - t.y) <= n) return;
|
|
1289
1303
|
h = { mediaX: t.mediaX, mediaY: t.mediaY, time: l, y: o };
|
|
1290
1304
|
} else {
|
|
1291
1305
|
if (t.time < i || t.time > e) {
|
|
1292
|
-
this.#
|
|
1306
|
+
this.#c = null, this.#h.markDirty(), this.emit("crosshairMove", null), this.#J(null);
|
|
1293
1307
|
return;
|
|
1294
1308
|
}
|
|
1295
1309
|
const l = this.timeScale.timeToX(t.time), o = this.yScale.valueToY(t.y);
|
|
1296
1310
|
if (!Number.isFinite(l) || !Number.isFinite(o) || Math.abs(l - t.mediaX) <= a && Math.abs(o - t.mediaY) <= a) return;
|
|
1297
1311
|
h = { mediaX: l, mediaY: o, time: t.time, y: t.y };
|
|
1298
1312
|
}
|
|
1299
|
-
this.#
|
|
1313
|
+
this.#c = h, this.#h.markDirty(), this.emit("crosshairMove", h), this.#J(h);
|
|
1300
1314
|
}
|
|
1301
1315
|
/** Tear down the chart: cancel animations, remove listeners, and detach the canvas. */
|
|
1302
1316
|
destroy() {
|
|
1303
1317
|
for (const t of this.#t) t.renderer.dispose();
|
|
1304
|
-
this.#t = [], this.#
|
|
1318
|
+
this.#t = [], this.#u = [], this.#x = [], this.#y = [], this.#D = null, this.#i.destroy(), this.#h.destroy(), this.#M?.destroy(), this.#a.destroy(), this.#K?.destroy(), this.#K = null, this.#U && this.#S?.destroy(), this.#S = null, this.#U = !1, this.removeAllListeners();
|
|
1305
1319
|
}
|
|
1306
1320
|
/** The attached performance monitor, or `null` when instrumentation is disabled. */
|
|
1307
1321
|
getPerfMonitor() {
|
|
@@ -1311,7 +1325,7 @@ class ti extends lt {
|
|
|
1311
1325
|
getDataBounds() {
|
|
1312
1326
|
let t, i;
|
|
1313
1327
|
for (const e of this.#t) {
|
|
1314
|
-
if (!e.visible || !
|
|
1328
|
+
if (!e.visible || !k(e.renderer)) continue;
|
|
1315
1329
|
const s = e.renderer.getTimeBounds();
|
|
1316
1330
|
s !== null && ((t === void 0 || s.first < t) && (t = s.first), (i === void 0 || s.last > i) && (i = s.last));
|
|
1317
1331
|
}
|
|
@@ -1320,28 +1334,28 @@ class ti extends lt {
|
|
|
1320
1334
|
/** Set by `setSeriesData`/bulk-replace paths so the next `onDataChanged`
|
|
1321
1335
|
* snaps the Y range (instead of easing) and `yScale.getRange()` reflects
|
|
1322
1336
|
* the new domain synchronously. Cleared by `onDataChanged` after each run. */
|
|
1323
|
-
#
|
|
1337
|
+
#Q = !1;
|
|
1324
1338
|
onDataChanged() {
|
|
1325
|
-
if (this.#
|
|
1326
|
-
this
|
|
1339
|
+
if (this.#L > 0) {
|
|
1340
|
+
this.#_ = !0;
|
|
1327
1341
|
return;
|
|
1328
1342
|
}
|
|
1329
1343
|
this.updateDataInterval();
|
|
1330
1344
|
const { first: t, last: i } = this.getDataBounds();
|
|
1331
|
-
t !== void 0 && (this.#A = t), i !== void 0 && (this.#
|
|
1332
|
-
const e = this.#
|
|
1333
|
-
this.#
|
|
1334
|
-
const s = !this.#
|
|
1335
|
-
e && (this.yScale.tickTracker.reset(), this.timeScale.tickTracker.reset()), this.#
|
|
1345
|
+
t !== void 0 && (this.#A = t), i !== void 0 && (this.#O = this.#e, this.#e = i);
|
|
1346
|
+
const e = this.#Q;
|
|
1347
|
+
this.#Q = !1;
|
|
1348
|
+
const s = !this.#g && t !== void 0;
|
|
1349
|
+
e && (this.yScale.tickTracker.reset(), this.timeScale.tickTracker.reset()), this.#mt = e;
|
|
1336
1350
|
const r = performance.now();
|
|
1337
|
-
e || s ? (this.#R.seed(r), this.#s.onDataReplaced(r)) : this.#s.onPointAppended(r), this.#s.lastXTarget !== null && (this.#
|
|
1351
|
+
e || s ? (this.#R.seed(r), this.#s.onDataReplaced(r)) : this.#s.onPointAppended(r), this.#s.lastXTarget !== null && (this.#V = !0), t !== void 0 && (this.#g = !0), this.#v(r), this.syncScales(), s ? this.#st() : this.#i.markDirty(), this.emit("dataUpdate"), this.#p();
|
|
1338
1352
|
}
|
|
1339
1353
|
updateDataInterval() {
|
|
1340
1354
|
for (const t of this.#t) {
|
|
1341
|
-
if (!
|
|
1355
|
+
if (!k(t.renderer)) continue;
|
|
1342
1356
|
const i = t.renderer.sampleTimes(20);
|
|
1343
1357
|
if (i.length >= 2) {
|
|
1344
|
-
this.#r =
|
|
1358
|
+
this.#r = wt(i);
|
|
1345
1359
|
break;
|
|
1346
1360
|
}
|
|
1347
1361
|
}
|
|
@@ -1351,28 +1365,28 @@ class ti extends lt {
|
|
|
1351
1365
|
* data regardless of the caller's requested kind. Also reset by paths
|
|
1352
1366
|
* that intentionally invalidate the current Y baseline (axis bound
|
|
1353
1367
|
* change, empty viewport). */
|
|
1354
|
-
#
|
|
1368
|
+
#g = !1;
|
|
1355
1369
|
/** Whether the engine's X slot has received its first emit. Pre-init X
|
|
1356
1370
|
* emits are forced to `instant` so first paint snaps to the fitted
|
|
1357
1371
|
* range — without this guard the engine would ease from `{0,0}` into
|
|
1358
1372
|
* the new target and the very first frame would render with a
|
|
1359
1373
|
* zero-width X domain. */
|
|
1360
|
-
#
|
|
1374
|
+
#V = !1;
|
|
1361
1375
|
/**
|
|
1362
1376
|
* One-shot `setVisibleRange` argument applied on the first data arrival.
|
|
1363
1377
|
* Captured at chart construction from {@link ChartOptions.viewport.initialRange};
|
|
1364
1378
|
* cleared the moment it's consumed so subsequent data swaps don't snap
|
|
1365
1379
|
* back to the initial window.
|
|
1366
1380
|
*/
|
|
1367
|
-
#
|
|
1381
|
+
#Y;
|
|
1368
1382
|
/** Last Y bounds the engine resolved into {@link AnimationState.yRange}.
|
|
1369
1383
|
* Used by {@link renderMain} to detect Y movement frame-to-frame so
|
|
1370
1384
|
* `viewportChange` only emits when the Y range actually shifted — DOM
|
|
1371
1385
|
* axis labels subscribe to that event and re-renders on every tick are
|
|
1372
1386
|
* expensive. Initialised to NaN so the first real Y emit always passes
|
|
1373
1387
|
* the change check. */
|
|
1374
|
-
#Q = Number.NaN;
|
|
1375
1388
|
#tt = Number.NaN;
|
|
1389
|
+
#it = Number.NaN;
|
|
1376
1390
|
/**
|
|
1377
1391
|
* Sample the visible data window and return the resolved Y bounds, or
|
|
1378
1392
|
* `null` when no series has data inside the X destination range.
|
|
@@ -1381,11 +1395,11 @@ class ti extends lt {
|
|
|
1381
1395
|
* converge together. Clears {@link #yInited} on empty so the next emit
|
|
1382
1396
|
* with valid data lands as an instant snap.
|
|
1383
1397
|
*/
|
|
1384
|
-
#
|
|
1385
|
-
const i = t ?? this.#o, e = this.#
|
|
1398
|
+
#St(t) {
|
|
1399
|
+
const i = t ?? this.#o, e = this.#d.min !== void 0 && this.#d.min !== "auto" && typeof this.#d.min != "number" || this.#d.max !== void 0 && this.#d.max !== "auto" && typeof this.#d.max != "number" ? [] : null, s = ht(i, this.#t, e);
|
|
1386
1400
|
if (s === null)
|
|
1387
|
-
return this.#
|
|
1388
|
-
const r =
|
|
1401
|
+
return this.#g = !1, null;
|
|
1402
|
+
const r = F(this.#d.min, s.min, s.max, e ?? [], "min"), n = F(this.#d.max, s.max, s.min, e ?? [], "max");
|
|
1389
1403
|
return { min: r, max: n };
|
|
1390
1404
|
}
|
|
1391
1405
|
/**
|
|
@@ -1406,29 +1420,29 @@ class ti extends lt {
|
|
|
1406
1420
|
* - **autoscroll off** → `null` (no X retarget; user has panned away
|
|
1407
1421
|
* from the tail).
|
|
1408
1422
|
*/
|
|
1409
|
-
#
|
|
1410
|
-
if (this.#A === null || this.#
|
|
1423
|
+
#Ft() {
|
|
1424
|
+
if (this.#A === null || this.#e === null) return null;
|
|
1411
1425
|
const { from: t, to: i } = this.#o, e = t === 0 && i === 0, s = this.#a.size.media.width - this.yAxisWidth;
|
|
1412
1426
|
if (e) {
|
|
1413
|
-
if (this.#
|
|
1427
|
+
if (this.#W(this.#A, this.#e, s), this.#Y !== void 0 && (this.setVisibleRange(this.#Y), this.#Y = void 0, !this.#f && this.#e !== null)) {
|
|
1414
1428
|
const { to: n } = this.#o;
|
|
1415
|
-
this.#
|
|
1429
|
+
this.#e >= n && this.#e - n <= this.#r * 1.5 && (this.#f = !0);
|
|
1416
1430
|
}
|
|
1417
1431
|
return this.#o;
|
|
1418
1432
|
}
|
|
1419
|
-
if (!this.#
|
|
1420
|
-
if (this.#
|
|
1421
|
-
return this.#
|
|
1422
|
-
const r =
|
|
1433
|
+
if (!this.#f) return null;
|
|
1434
|
+
if (this.#mt)
|
|
1435
|
+
return this.#W(this.#A, this.#e, s), this.#o;
|
|
1436
|
+
const r = at({
|
|
1423
1437
|
currentLogical: this.#o,
|
|
1424
|
-
lastTime: this.#
|
|
1425
|
-
prevDataEnd: this.#
|
|
1438
|
+
lastTime: this.#e,
|
|
1439
|
+
prevDataEnd: this.#O,
|
|
1426
1440
|
dataInterval: this.#r,
|
|
1427
|
-
paddingRight: this.#
|
|
1441
|
+
paddingRight: this.#l.right,
|
|
1428
1442
|
chartWidth: s,
|
|
1429
|
-
holdUntilFilled: this.#
|
|
1443
|
+
holdUntilFilled: this.#T
|
|
1430
1444
|
});
|
|
1431
|
-
return r.releaseHold && (this.#
|
|
1445
|
+
return r.releaseHold && (this.#T = !1), r.reengageAutoScroll && (this.#f = !0), r.newLogical === null ? null : (this.#R.observe(performance.now()), this.#s.setXSettleMs(this.#R.pickSettleMs(this.#m.axis.x.settleMs)), this.#C(r.newLogical, { emitChange: !1, skipValidation: !0 }), this.#O = this.#e, r.newLogical);
|
|
1432
1446
|
}
|
|
1433
1447
|
/**
|
|
1434
1448
|
* Fit the viewport's logical X range around a data span. Mirrors the
|
|
@@ -1436,16 +1450,16 @@ class ti extends lt {
|
|
|
1436
1450
|
* forces autoscroll on (data tail is in the new window by construction),
|
|
1437
1451
|
* commits the new range via `viewport.setRange` (which emits `change`).
|
|
1438
1452
|
*/
|
|
1439
|
-
#
|
|
1440
|
-
const s = this.#
|
|
1453
|
+
#W(t, i, e) {
|
|
1454
|
+
const s = this.#l, r = q({
|
|
1441
1455
|
firstTime: t,
|
|
1442
1456
|
lastTime: i,
|
|
1443
1457
|
dataInterval: this.#r,
|
|
1444
|
-
maxVisibleBars: this.#
|
|
1458
|
+
maxVisibleBars: this.#ut,
|
|
1445
1459
|
chartWidth: e,
|
|
1446
1460
|
padding: { left: s.left, right: s.right }
|
|
1447
1461
|
});
|
|
1448
|
-
this.#
|
|
1462
|
+
this.#T = !1, this.#f = !0, this.#C(r, { emitChange: !0 });
|
|
1449
1463
|
}
|
|
1450
1464
|
/**
|
|
1451
1465
|
* Commit a programmatic zoom — `fitContent` or `setVisibleRange`. Reads
|
|
@@ -1461,12 +1475,12 @@ class ti extends lt {
|
|
|
1461
1475
|
* passes `xEase: true` so X eases instead — viewport and axis converge
|
|
1462
1476
|
* on the same frame.
|
|
1463
1477
|
*/
|
|
1464
|
-
#
|
|
1478
|
+
#X(t) {
|
|
1465
1479
|
const i = this.#o;
|
|
1466
1480
|
if (i.to <= i.from) return;
|
|
1467
1481
|
const e = performance.now();
|
|
1468
|
-
if (!this.#
|
|
1469
|
-
this.#
|
|
1482
|
+
if (!this.#V || !this.#g) {
|
|
1483
|
+
this.#kt(e);
|
|
1470
1484
|
return;
|
|
1471
1485
|
}
|
|
1472
1486
|
this.#s.onProgrammaticZoom({ xTarget: i, xEase: t?.xEase }, e), this.#v(e);
|
|
@@ -1487,8 +1501,8 @@ class ti extends lt {
|
|
|
1487
1501
|
const t = this.#o;
|
|
1488
1502
|
if (t.to <= t.from) return;
|
|
1489
1503
|
const i = performance.now();
|
|
1490
|
-
if (!this.#
|
|
1491
|
-
this.#
|
|
1504
|
+
if (!this.#V || !this.#g) {
|
|
1505
|
+
this.#kt(i);
|
|
1492
1506
|
return;
|
|
1493
1507
|
}
|
|
1494
1508
|
this.#s.onPanZoom({ xTarget: t, yAuto: !0 }, i), this.#v(i);
|
|
@@ -1500,9 +1514,9 @@ class ti extends lt {
|
|
|
1500
1514
|
* commits — both must snap before the chart has painted once so a
|
|
1501
1515
|
* synchronous `getYRange()` / `getVisibleRange()` read sees final values.
|
|
1502
1516
|
*/
|
|
1503
|
-
#
|
|
1504
|
-
const i = this.#o, e = this.#
|
|
1505
|
-
this.#
|
|
1517
|
+
#kt(t) {
|
|
1518
|
+
const i = this.#o, e = this.#St(i);
|
|
1519
|
+
this.#V = !0, e !== null && (this.#g = !0), this.#s.snap({ x: i, y: e ?? void 0 }, t), this.#v(t);
|
|
1506
1520
|
}
|
|
1507
1521
|
/**
|
|
1508
1522
|
* Validate and commit a new logical X range. Mirrors the old
|
|
@@ -1524,7 +1538,7 @@ class ti extends lt {
|
|
|
1524
1538
|
*/
|
|
1525
1539
|
#C(t, i) {
|
|
1526
1540
|
const { from: e, to: s } = t;
|
|
1527
|
-
return !Number.isFinite(e) || !Number.isFinite(s) || s <= e || !i.skipValidation && (s - e) / this.#r < 2 || this.#o.from === e && this.#o.to === s ? !1 : (this.#o = { from: e, to: s }, i.emitChange && (this.syncScales(), this.#
|
|
1541
|
+
return !Number.isFinite(e) || !Number.isFinite(s) || s <= e || !i.skipValidation && (s - e) / this.#r < 2 || this.#o.from === e && this.#o.to === s ? !1 : (this.#o = { from: e, to: s }, i.emitChange && (this.syncScales(), this.#i?.markDirty(), this.emit("viewportChange")), !0);
|
|
1528
1542
|
}
|
|
1529
1543
|
/**
|
|
1530
1544
|
* Apply pixel-padding to the engine's raw Y target and store the
|
|
@@ -1532,11 +1546,18 @@ class ti extends lt {
|
|
|
1532
1546
|
* symmetric pad top / bottom from `#padding`, suppressed on the side
|
|
1533
1547
|
* that has an explicit (fixed) axis bound.
|
|
1534
1548
|
*/
|
|
1535
|
-
#
|
|
1536
|
-
const
|
|
1537
|
-
|
|
1538
|
-
min:
|
|
1539
|
-
max:
|
|
1549
|
+
#wt(t) {
|
|
1550
|
+
const { min: i, max: e, chartHeight: s } = t, { min: r, max: n } = this.#Nt(), a = e - i, h = s > 0 ? this.#l.top / s * a : 0, l = s > 0 ? this.#l.bottom / s * a : 0;
|
|
1551
|
+
return {
|
|
1552
|
+
min: r ? i : i - l,
|
|
1553
|
+
max: n ? e : e + h
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
/** Which Y edges the user pinned — a pinned edge takes no padding. */
|
|
1557
|
+
#Nt() {
|
|
1558
|
+
return {
|
|
1559
|
+
min: this.#d.min !== void 0 && this.#d.min !== "auto",
|
|
1560
|
+
max: this.#d.max !== void 0 && this.#d.max !== "auto"
|
|
1540
1561
|
};
|
|
1541
1562
|
}
|
|
1542
1563
|
/**
|
|
@@ -1549,18 +1570,18 @@ class ti extends lt {
|
|
|
1549
1570
|
* as a gesture for visual easing. Public so consumers can drive pan
|
|
1550
1571
|
* programmatically.
|
|
1551
1572
|
*/
|
|
1552
|
-
pan(t, i = this.#
|
|
1553
|
-
i > 0 && (this.#
|
|
1554
|
-
const e =
|
|
1573
|
+
pan(t, i = this.#E) {
|
|
1574
|
+
i > 0 && (this.#E = i), this.#T = !1;
|
|
1575
|
+
const e = st({
|
|
1555
1576
|
currentLogical: this.#o,
|
|
1556
1577
|
timeDelta: t,
|
|
1557
1578
|
chartWidth: i,
|
|
1558
1579
|
dataInterval: this.#r,
|
|
1559
|
-
padding: { left: this.#
|
|
1580
|
+
padding: { left: this.#l.left, right: this.#l.right },
|
|
1560
1581
|
dataStart: this.#A,
|
|
1561
|
-
dataEnd: this.#
|
|
1582
|
+
dataEnd: this.#e
|
|
1562
1583
|
});
|
|
1563
|
-
e.newLogical !== null && (this.#
|
|
1584
|
+
e.newLogical !== null && (this.#f = !e.autoScrollOff, this.#C(e.newLogical, { emitChange: !0 }), e.edgeReached !== null && (this.#ot[e.edgeReached.side] = e.edgeReached.boundaryTime, this.#lt?.(e.edgeReached)), this.#R.pause(), this.#At());
|
|
1564
1585
|
}
|
|
1565
1586
|
/**
|
|
1566
1587
|
* Zoom around a time anchor. `factor < 1` zooms in, `> 1` zooms out.
|
|
@@ -1577,35 +1598,35 @@ class ti extends lt {
|
|
|
1577
1598
|
* and produce a visible jump). Cursor-anchored zoom is intentionally
|
|
1578
1599
|
* sacrificed in follow-live mode — pan first to inspect history.
|
|
1579
1600
|
*/
|
|
1580
|
-
zoomAt(t, i, e = this.#
|
|
1581
|
-
e > 0 && (this.#
|
|
1582
|
-
const s =
|
|
1601
|
+
zoomAt(t, i, e = this.#E) {
|
|
1602
|
+
e > 0 && (this.#E = e), this.#T = !1;
|
|
1603
|
+
const s = rt({
|
|
1583
1604
|
currentLogical: this.#o,
|
|
1584
1605
|
centerTime: t,
|
|
1585
1606
|
factor: i,
|
|
1586
1607
|
chartWidth: e,
|
|
1587
1608
|
dataInterval: this.#r,
|
|
1588
|
-
padding: { left: this.#
|
|
1609
|
+
padding: { left: this.#l.left, right: this.#l.right },
|
|
1589
1610
|
dataStart: this.#A,
|
|
1590
|
-
dataEnd: this.#
|
|
1611
|
+
dataEnd: this.#e
|
|
1591
1612
|
});
|
|
1592
1613
|
if (s.newLogical === null) return;
|
|
1593
1614
|
let r = s.newLogical;
|
|
1594
|
-
if (this.#
|
|
1595
|
-
const n = r.to - r.from, a =
|
|
1596
|
-
r = { from: h - n, to: h }, this.#
|
|
1615
|
+
if (this.#f && this.#e !== null) {
|
|
1616
|
+
const n = r.to - r.from, a = W(this.#l.right, n, this.#r, e), h = this.#e + a;
|
|
1617
|
+
r = { from: h - n, to: h }, this.#O = this.#e;
|
|
1597
1618
|
}
|
|
1598
|
-
this.#C(r, { emitChange: !0 }), this.#R.pause(), this.#
|
|
1619
|
+
this.#C(r, { emitChange: !0 }), this.#R.pause(), this.#At();
|
|
1599
1620
|
}
|
|
1600
1621
|
/**
|
|
1601
1622
|
* Common tail for `pan` / `zoomAt`: routes the just-committed `#logical`
|
|
1602
1623
|
* to the engine as a gesture so the X spring retargets and the Y spring
|
|
1603
1624
|
* eases over `animations.axis.y.gesture`.
|
|
1604
1625
|
*/
|
|
1605
|
-
#
|
|
1626
|
+
#At() {
|
|
1606
1627
|
const t = this.#o;
|
|
1607
1628
|
if (t.to <= t.from) return;
|
|
1608
|
-
this.#
|
|
1629
|
+
this.#V = !0, this.#g = !0;
|
|
1609
1630
|
const i = performance.now();
|
|
1610
1631
|
this.#s.onPanZoom({ xTarget: t, yAuto: !0 }, i), this.#v(i);
|
|
1611
1632
|
}
|
|
@@ -1625,8 +1646,8 @@ class ti extends lt {
|
|
|
1625
1646
|
#v(t) {
|
|
1626
1647
|
const i = this.#s.tick(t), e = this.#a.size;
|
|
1627
1648
|
if (e.media.width === 0 || e.media.height === 0) return;
|
|
1628
|
-
const s =
|
|
1629
|
-
this.#
|
|
1649
|
+
const s = e.media.height - this.xAxisHeight;
|
|
1650
|
+
this.#z = this.#wt({ min: i.yRange.min, max: i.yRange.max, chartHeight: s }), this.#tt = i.yRange.min, this.#it = i.yRange.max, this.syncScales();
|
|
1630
1651
|
}
|
|
1631
1652
|
/**
|
|
1632
1653
|
* Lightweight scale sync: updates timeScale/yScale from current viewport state
|
|
@@ -1642,78 +1663,88 @@ class ti extends lt {
|
|
|
1642
1663
|
i,
|
|
1643
1664
|
t.horizontalPixelRatio,
|
|
1644
1665
|
this.#r
|
|
1645
|
-
), this.yScale.update(this.#
|
|
1666
|
+
), this.yScale.update(this.#z, e, t.verticalPixelRatio);
|
|
1646
1667
|
}
|
|
1647
1668
|
/** Expensive: background, grid, all series. Only on data/viewport/resize change. */
|
|
1648
1669
|
renderMain(t) {
|
|
1649
1670
|
const i = this.#a.size;
|
|
1650
1671
|
if (i.media.width === 0 || i.media.height === 0) return;
|
|
1651
1672
|
const e = typeof t == "number" ? t : performance.now(), s = this.#s.tick(e);
|
|
1652
|
-
s.animating && this.#
|
|
1653
|
-
const r = s.yRange.min, n = s.yRange.max, a = r !== this.#
|
|
1673
|
+
s.animating && this.#i.markDirty();
|
|
1674
|
+
const r = s.yRange.min, n = s.yRange.max, a = r !== this.#tt || n !== this.#it;
|
|
1654
1675
|
if (a) {
|
|
1655
|
-
const c =
|
|
1656
|
-
this.#
|
|
1676
|
+
const c = i.media.height - this.xAxisHeight;
|
|
1677
|
+
this.#z = this.#wt({ min: r, max: n, chartHeight: c }), this.#tt = r, this.#it = n;
|
|
1657
1678
|
}
|
|
1658
|
-
if (this.syncScales(), this.#
|
|
1659
|
-
const c = this.#s.lastXTarget ?? this.#o,
|
|
1660
|
-
if (
|
|
1661
|
-
const
|
|
1662
|
-
Math.abs(c.to - (this.#
|
|
1679
|
+
if (this.syncScales(), this.#Wt(), this.#e !== null && !this.#f) {
|
|
1680
|
+
const c = this.#s.lastXTarget ?? this.#o, f = c.to - c.from;
|
|
1681
|
+
if (f > 0) {
|
|
1682
|
+
const y = this.#a.size.media.width - this.yAxisWidth, d = W(this.#l.right, f, this.#r, y), g = this.#r * 0.5;
|
|
1683
|
+
Math.abs(c.to - (this.#e + d)) < g && (this.#f = !0);
|
|
1663
1684
|
}
|
|
1664
1685
|
}
|
|
1665
1686
|
a && this.emit("viewportChange");
|
|
1666
|
-
let h = !1, l = !1;
|
|
1687
|
+
let h = !1, l = !1, o = !1;
|
|
1667
1688
|
this.#a.useMainLayer((c) => {
|
|
1668
|
-
const { context:
|
|
1669
|
-
|
|
1670
|
-
const
|
|
1671
|
-
|
|
1689
|
+
const { context: f, bitmapSize: y } = c, d = (i.media.width - this.yAxisWidth) * i.horizontalPixelRatio, g = (i.media.height - this.xAxisHeight) * i.verticalPixelRatio;
|
|
1690
|
+
f.clearRect(0, 0, y.width, y.height), f.save(), f.beginPath();
|
|
1691
|
+
const b = this.#et(c, d);
|
|
1692
|
+
f.rect(0, 0, d + b.intrusion, g), f.clip(), this.yScale.tickTracker.setCurrentTicks(this.yScale.niceTickValues()), this.timeScale.tickTracker.setCurrentTicks(this.timeScale.niceTickValues(this.#r).ticks), this.yScale.tickTracker.tick(e), this.timeScale.tickTracker.tick(e);
|
|
1672
1693
|
const w = this.yScale.tickTracker.snapshot(), S = this.timeScale.tickTracker.snapshot();
|
|
1673
|
-
h = w.isAnimating, l = S.isAnimating, (w.isAnimating || S.isAnimating || s.animating) && this.emit("tickFrame")
|
|
1694
|
+
h = w.isAnimating, l = S.isAnimating, (w.isAnimating || S.isAnimating || s.animating) && this.emit("tickFrame");
|
|
1695
|
+
const L = this.#F ? 1 : 0;
|
|
1696
|
+
if ((L === 0 || w.entries.length > 0 || S.entries.length > 0) && L !== this.#I.target) {
|
|
1697
|
+
const v = Z() ? 0 : this.#m.axis.gridMs;
|
|
1698
|
+
this.#I.setTarget(L, { now: e, duration: v });
|
|
1699
|
+
}
|
|
1700
|
+
o = this.#I.tick(e);
|
|
1701
|
+
const M = this.#I.current;
|
|
1702
|
+
lt({
|
|
1674
1703
|
scope: c,
|
|
1675
1704
|
timeScale: this.timeScale,
|
|
1676
1705
|
yScale: this.yScale,
|
|
1677
1706
|
theme: this.#n,
|
|
1678
1707
|
yTicks: w,
|
|
1679
|
-
timeTicks: S
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1708
|
+
timeTicks: S,
|
|
1709
|
+
alpha: M
|
|
1710
|
+
}), this.#Pt(c, d, g);
|
|
1711
|
+
const D = this.#l, O = { top: D.top, bottom: D.bottom }, R = this.#S;
|
|
1712
|
+
for (const v of this.#t) {
|
|
1713
|
+
const A = v.renderer.getAlpha?.() ?? (v.visible ? 1 : 0);
|
|
1714
|
+
if (A <= 0) continue;
|
|
1715
|
+
const C = {
|
|
1686
1716
|
scope: c,
|
|
1687
1717
|
timeScale: this.timeScale,
|
|
1688
1718
|
yScale: this.yScale,
|
|
1689
1719
|
theme: this.#n,
|
|
1690
1720
|
dataInterval: this.#r,
|
|
1691
|
-
padding:
|
|
1721
|
+
padding: O,
|
|
1692
1722
|
state: s,
|
|
1693
|
-
seriesId:
|
|
1694
|
-
},
|
|
1695
|
-
if (
|
|
1696
|
-
const
|
|
1697
|
-
|
|
1723
|
+
seriesId: v.id
|
|
1724
|
+
}, I = f.globalAlpha;
|
|
1725
|
+
if (A < 1 && (f.globalAlpha = I * A), R) {
|
|
1726
|
+
const E = performance.now();
|
|
1727
|
+
v.renderer.render(C), R.recordSeries(v.id, performance.now() - E, e);
|
|
1698
1728
|
} else
|
|
1699
|
-
|
|
1700
|
-
|
|
1729
|
+
v.renderer.render(C);
|
|
1730
|
+
A < 1 && (f.globalAlpha = I);
|
|
1701
1731
|
}
|
|
1702
|
-
|
|
1732
|
+
f.restore(), this.#Ot({
|
|
1703
1733
|
scope: c,
|
|
1704
|
-
paneBitmapWidth:
|
|
1705
|
-
paneBitmapHeight:
|
|
1706
|
-
timeTicks: S
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1734
|
+
paneBitmapWidth: d,
|
|
1735
|
+
paneBitmapHeight: g,
|
|
1736
|
+
timeTicks: S,
|
|
1737
|
+
alpha: M
|
|
1738
|
+
}), this.#Lt(c, g), this.#Mt(c, d);
|
|
1739
|
+
}), this.#j();
|
|
1740
|
+
let m = !1;
|
|
1710
1741
|
for (const c of this.#t)
|
|
1711
1742
|
if (c.renderer.needsAnimation) {
|
|
1712
|
-
|
|
1743
|
+
m = !0, this.#i.markDirty();
|
|
1713
1744
|
break;
|
|
1714
1745
|
}
|
|
1715
1746
|
const u = h || l;
|
|
1716
|
-
!s.animating && !
|
|
1747
|
+
(u || o) && this.#i.markDirty(), !s.animating && !m && !u && (this.yScale.tickTracker.markArmed(), this.timeScale.tickTracker.markArmed());
|
|
1717
1748
|
}
|
|
1718
1749
|
/**
|
|
1719
1750
|
* Erase the main layer's alpha across the top fade zone so content
|
|
@@ -1722,12 +1753,12 @@ class ti extends lt {
|
|
|
1722
1753
|
* a paint-over — so the container background behind the canvas (solid or
|
|
1723
1754
|
* CSS gradient) shows through untouched.
|
|
1724
1755
|
*/
|
|
1725
|
-
#
|
|
1756
|
+
#Lt(t, i) {
|
|
1726
1757
|
if (this.#k.top <= 0) return;
|
|
1727
1758
|
const e = Math.min(Math.round(this.#k.top * t.verticalPixelRatio), Math.round(i));
|
|
1728
1759
|
if (e < 1) return;
|
|
1729
1760
|
const { context: s } = t;
|
|
1730
|
-
s.save(), s.globalCompositeOperation = "destination-out", s.fillStyle = this.#
|
|
1761
|
+
s.save(), s.globalCompositeOperation = "destination-out", s.fillStyle = this.#Yt(s, e), s.fillRect(0, 0, t.bitmapSize.width, e), s.restore();
|
|
1731
1762
|
}
|
|
1732
1763
|
/**
|
|
1733
1764
|
* Run the vertical gridlines a short stub past the pane floor, dissolving
|
|
@@ -1737,21 +1768,21 @@ class ti extends lt {
|
|
|
1737
1768
|
* nothing else paints) and faded with the same destination-out ramp the
|
|
1738
1769
|
* edge masks use, so the taper stays correct over any background.
|
|
1739
1770
|
*/
|
|
1740
|
-
#
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1771
|
+
#Ot(t) {
|
|
1772
|
+
const { scope: i, paneBitmapWidth: e, paneBitmapHeight: s, timeTicks: r, alpha: n } = t;
|
|
1773
|
+
if (!this.#F && n <= 0.01 || this.xAxisHeight === 0) return;
|
|
1774
|
+
const { context: a, horizontalPixelRatio: h, verticalPixelRatio: l } = i, o = Math.round(s), m = Math.round(T * l);
|
|
1775
|
+
if (m < 1) return;
|
|
1744
1776
|
const u = this.#n.grid;
|
|
1745
|
-
|
|
1746
|
-
const c =
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
y < 0 || y > p || (n.globalAlpha = m, n.beginPath(), n.moveTo(y, l), n.lineTo(y, l + o), n.stroke());
|
|
1777
|
+
a.save(), a.strokeStyle = u.color, u.style === "dashed" ? a.setLineDash([4 * h, 4 * h]) : u.style === "dotted" && a.setLineDash([1 * h, 3 * h]), a.lineDashOffset = o, a.lineWidth = St(h);
|
|
1778
|
+
const c = kt(h), f = Math.round(e);
|
|
1779
|
+
for (const { value: y, opacity: d } of r.entries) {
|
|
1780
|
+
const g = d * n;
|
|
1781
|
+
if (g <= 0.01) continue;
|
|
1782
|
+
const b = Math.round(this.timeScale.timeToBitmapX(y)) + c;
|
|
1783
|
+
b < 0 || b > f || (a.globalAlpha = g, a.beginPath(), a.moveTo(b, o), a.lineTo(b, o + m), a.stroke());
|
|
1753
1784
|
}
|
|
1754
|
-
|
|
1785
|
+
a.restore(), this.#Tt(i, s);
|
|
1755
1786
|
}
|
|
1756
1787
|
/**
|
|
1757
1788
|
* Erase ramp over the below-pane overrun strip — the gridline tail stubs
|
|
@@ -1759,12 +1790,12 @@ class ti extends lt {
|
|
|
1759
1790
|
* erased at the pane floor, total at the strip's bottom edge, so whatever
|
|
1760
1791
|
* crosses the floor tapers out short of the time-axis labels.
|
|
1761
1792
|
*/
|
|
1762
|
-
#
|
|
1793
|
+
#Tt(t, i) {
|
|
1763
1794
|
if (this.xAxisHeight === 0) return;
|
|
1764
|
-
const e = Math.round(i), s = Math.round(
|
|
1795
|
+
const e = Math.round(i), s = Math.round(T * t.verticalPixelRatio);
|
|
1765
1796
|
if (s < 1) return;
|
|
1766
1797
|
const { context: r } = t;
|
|
1767
|
-
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this
|
|
1798
|
+
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#$t({ context: r, start: e, height: s }), r.fillRect(0, e, t.bitmapSize.width, s), r.restore();
|
|
1768
1799
|
}
|
|
1769
1800
|
/**
|
|
1770
1801
|
* Crosshair hairlines with the same edge melt the main layer runs: the
|
|
@@ -1776,17 +1807,17 @@ class ti extends lt {
|
|
|
1776
1807
|
* edge. Erases alpha (destination-out), so it must run while the
|
|
1777
1808
|
* crosshair is the only content on the layer.
|
|
1778
1809
|
*/
|
|
1779
|
-
#
|
|
1780
|
-
const i = this.#
|
|
1810
|
+
#Et(t) {
|
|
1811
|
+
const i = this.#c;
|
|
1781
1812
|
if (i === null) return;
|
|
1782
|
-
const { scope: e, chartBitmapWidth: s, chartBitmapHeight: r } = t, { context: n } = e, a = this.#
|
|
1783
|
-
n.save(), n.beginPath(), n.rect(0, 0, s + a.intrusion, r + h), n.clip(),
|
|
1813
|
+
const { scope: e, chartBitmapWidth: s, chartBitmapHeight: r } = t, { context: n } = e, a = this.#et(e, s), h = this.xAxisHeight > 0 ? Math.round(T * e.verticalPixelRatio) : 0;
|
|
1814
|
+
n.save(), n.beginPath(), n.rect(0, 0, s + a.intrusion, r + h), n.clip(), ot({
|
|
1784
1815
|
scope: e,
|
|
1785
1816
|
bitmapX: i.mediaX * e.horizontalPixelRatio,
|
|
1786
1817
|
bitmapY: i.mediaY * e.verticalPixelRatio,
|
|
1787
1818
|
theme: this.#n,
|
|
1788
1819
|
pane: { width: s, height: r }
|
|
1789
|
-
}), n.restore(), this.#
|
|
1820
|
+
}), n.restore(), this.#Tt(e, r), this.#Lt(e, r), this.#Mt(e, s);
|
|
1790
1821
|
}
|
|
1791
1822
|
/**
|
|
1792
1823
|
* Horizontal companions to {@link #applyTopFade}: dissolve content that
|
|
@@ -1796,11 +1827,11 @@ class ti extends lt {
|
|
|
1796
1827
|
* Runs the full bitmap height so the below-pane gridline tail stubs melt
|
|
1797
1828
|
* at the edges in step with their lines above.
|
|
1798
1829
|
*/
|
|
1799
|
-
#
|
|
1800
|
-
const { context: e } = t, s = t.bitmapSize.height, r = this.#
|
|
1801
|
-
r.width >= 1 && (e.save(), e.globalCompositeOperation = "destination-out", e.fillStyle = this.#
|
|
1830
|
+
#Mt(t, i) {
|
|
1831
|
+
const { context: e } = t, s = t.bitmapSize.height, r = this.#et(t, i);
|
|
1832
|
+
r.width >= 1 && (e.save(), e.globalCompositeOperation = "destination-out", e.fillStyle = this.#Xt({ context: e, start: r.start, width: r.width }), e.fillRect(r.start, 0, r.width, s), e.restore());
|
|
1802
1833
|
const n = Math.min(Math.round(this.#k.left * t.horizontalPixelRatio), Math.round(i));
|
|
1803
|
-
n >= 1 && (e.save(), e.globalCompositeOperation = "destination-out", e.fillStyle = this.#
|
|
1834
|
+
n >= 1 && (e.save(), e.globalCompositeOperation = "destination-out", e.fillStyle = this.#Zt(e, n), e.fillRect(0, 0, n, s), e.restore());
|
|
1804
1835
|
}
|
|
1805
1836
|
/**
|
|
1806
1837
|
* Bitmap geometry of the right fade zone. The ramp finishes just inside
|
|
@@ -1812,10 +1843,10 @@ class ti extends lt {
|
|
|
1812
1843
|
* extends by (content past the ramp is total-erased anyway, so the clip
|
|
1813
1844
|
* stops with the ramp).
|
|
1814
1845
|
*/
|
|
1815
|
-
#
|
|
1846
|
+
#et(t, i) {
|
|
1816
1847
|
const e = { start: 0, width: 0, intrusion: 0 }, s = Math.max(0, Math.round(t.bitmapSize.width - i));
|
|
1817
1848
|
if (s === 0) return e;
|
|
1818
|
-
const r = t.horizontalPixelRatio, n = Math.min(Math.round(
|
|
1849
|
+
const r = t.horizontalPixelRatio, n = Math.min(Math.round(Mt * r), s), a = this.#k.right === null ? n + Math.round(Tt * r) : Math.round(this.#k.right * r);
|
|
1819
1850
|
if (a < 1) return e;
|
|
1820
1851
|
const h = i + n, l = Math.min(a, h);
|
|
1821
1852
|
return { start: h - l, width: l, intrusion: n };
|
|
@@ -1824,7 +1855,7 @@ class ti extends lt {
|
|
|
1824
1855
|
* changes (resize, DPR change, `setFade`). Ease-out ramp (`1 - t²`):
|
|
1825
1856
|
* near-total erasure across the upper half keeps a floating header
|
|
1826
1857
|
* legible, then a soft tail into full opacity at the zone's bottom. */
|
|
1827
|
-
#
|
|
1858
|
+
#Yt(t, i) {
|
|
1828
1859
|
const e = this.#w.top;
|
|
1829
1860
|
if (e !== null && e.height === i) return e.gradient;
|
|
1830
1861
|
const s = t.createLinearGradient(0, 0, 0, i);
|
|
@@ -1840,7 +1871,7 @@ class ti extends lt {
|
|
|
1840
1871
|
* candles at rest and the aggressive erasing all happens deep under the
|
|
1841
1872
|
* axis column. Nine stops keep the piecewise interpolation smooth across
|
|
1842
1873
|
* the zone. */
|
|
1843
|
-
#
|
|
1874
|
+
#Xt(t) {
|
|
1844
1875
|
const i = this.#w.right;
|
|
1845
1876
|
if (i !== null && i.start === t.start && i.width === t.width) return i.gradient;
|
|
1846
1877
|
const e = t.context.createLinearGradient(t.start, 0, t.start + t.width, 0);
|
|
@@ -1853,7 +1884,7 @@ class ti extends lt {
|
|
|
1853
1884
|
/** Erase ramp for the gridline tail stubs — nothing erased at the pane
|
|
1854
1885
|
* floor, total at the stub tip, ease-in (`t²`) so a stub holds strength
|
|
1855
1886
|
* briefly before melting away short of the label glyphs. */
|
|
1856
|
-
|
|
1887
|
+
#$t(t) {
|
|
1857
1888
|
const i = this.#w.tail;
|
|
1858
1889
|
if (i !== null && i.start === t.start && i.height === t.height) return i.gradient;
|
|
1859
1890
|
const e = t.context.createLinearGradient(0, t.start, 0, t.start + t.height);
|
|
@@ -1865,7 +1896,7 @@ class ti extends lt {
|
|
|
1865
1896
|
}
|
|
1866
1897
|
/** Left-zone mask — mirror of the top ramp: total erase at the canvas
|
|
1867
1898
|
* edge, fully opaque at the zone's inner boundary. */
|
|
1868
|
-
#
|
|
1899
|
+
#Zt(t, i) {
|
|
1869
1900
|
const e = this.#w.left;
|
|
1870
1901
|
if (e !== null && e.width === i) return e.gradient;
|
|
1871
1902
|
const s = t.createLinearGradient(0, 0, i, 0);
|
|
@@ -1884,12 +1915,12 @@ class ti extends lt {
|
|
|
1884
1915
|
* `markDirty` calls made *during* `renderOverlay` (pulse, edge spinner)
|
|
1885
1916
|
* land after the consume and re-arm cleanly for the next frame.
|
|
1886
1917
|
*/
|
|
1887
|
-
#
|
|
1888
|
-
this.#
|
|
1918
|
+
#st(t) {
|
|
1919
|
+
this.#rt("main", t, () => this.renderMain(t)), this.#h.consume(), this.#rt("overlay", t, () => this.renderOverlay(t));
|
|
1889
1920
|
}
|
|
1890
1921
|
/** Run a layer's paint, booking duration + draw calls to the perf monitor
|
|
1891
1922
|
* when one is attached — keeps overlay time out of the `main` samples. */
|
|
1892
|
-
#
|
|
1923
|
+
#rt(t, i, e) {
|
|
1893
1924
|
const s = this.#S;
|
|
1894
1925
|
if (!s) {
|
|
1895
1926
|
e();
|
|
@@ -1909,33 +1940,33 @@ class ti extends lt {
|
|
|
1909
1940
|
e = !0;
|
|
1910
1941
|
break;
|
|
1911
1942
|
}
|
|
1912
|
-
this.#
|
|
1943
|
+
this.#u.some((o) => o.pulse) && (e = !0);
|
|
1913
1944
|
const s = {
|
|
1914
|
-
left: this.#
|
|
1915
|
-
right: this.#
|
|
1945
|
+
left: this.#P.left && this.#b.left === "loading" ? "idle" : this.#b.left,
|
|
1946
|
+
right: this.#P.right && this.#b.right === "loading" ? "idle" : this.#b.right
|
|
1916
1947
|
}, r = {
|
|
1917
|
-
left: this.#
|
|
1918
|
-
right: this.#
|
|
1919
|
-
}, n = r.left !== null || r.right !== null, a = s.left === "loading" || s.right === "loading" || n, h = s.left !== "idle" || s.right !== "idle" || n, l = !!this.#
|
|
1920
|
-
if (!(!l && !this.#
|
|
1921
|
-
if (this.#
|
|
1948
|
+
left: this.#xt("left"),
|
|
1949
|
+
right: this.#xt("right")
|
|
1950
|
+
}, n = r.left !== null || r.right !== null, a = s.left === "loading" || s.right === "loading" || n, h = s.left !== "idle" || s.right !== "idle" || n, l = !!this.#c || e || h || this.#u.length > 0 || this.#y.length > 0;
|
|
1951
|
+
if (!(!l && !this.#ht)) {
|
|
1952
|
+
if (this.#ht = l, this.#a.useOverlayLayer((o) => {
|
|
1922
1953
|
if (!l) return;
|
|
1923
|
-
const
|
|
1924
|
-
this.#
|
|
1925
|
-
const
|
|
1926
|
-
for (const
|
|
1927
|
-
|
|
1954
|
+
const m = (i.media.width - this.yAxisWidth) * i.horizontalPixelRatio, u = (i.media.height - this.xAxisHeight) * i.verticalPixelRatio;
|
|
1955
|
+
this.#c && this.#vt() && this.#Et({ scope: o, chartBitmapWidth: m, chartBitmapHeight: u }), o.context.save(), o.context.beginPath(), o.context.rect(0, 0, m, u), o.context.clip();
|
|
1956
|
+
const c = this.#l, f = { top: c.top, bottom: c.bottom }, y = this.#s.getAnimationState();
|
|
1957
|
+
for (const d of this.#t)
|
|
1958
|
+
d.visible && d.renderer.drawOverlay?.({
|
|
1928
1959
|
scope: o,
|
|
1929
1960
|
timeScale: this.timeScale,
|
|
1930
1961
|
yScale: this.yScale,
|
|
1931
1962
|
theme: this.#n,
|
|
1932
1963
|
dataInterval: this.#r,
|
|
1933
|
-
padding:
|
|
1934
|
-
crosshair: this.#
|
|
1935
|
-
state:
|
|
1936
|
-
seriesId:
|
|
1964
|
+
padding: f,
|
|
1965
|
+
crosshair: this.#c,
|
|
1966
|
+
state: y,
|
|
1967
|
+
seriesId: d.id
|
|
1937
1968
|
});
|
|
1938
|
-
this.#
|
|
1969
|
+
this.#Ht(o, m, u), this.#It(o, m, u), h && K({
|
|
1939
1970
|
scope: o,
|
|
1940
1971
|
chartMediaWidth: i.media.width - this.yAxisWidth,
|
|
1941
1972
|
chartMediaHeight: i.media.height - this.xAxisHeight,
|
|
@@ -1943,35 +1974,35 @@ class ti extends lt {
|
|
|
1943
1974
|
theme: this.#n,
|
|
1944
1975
|
edgeStates: s,
|
|
1945
1976
|
edgeExitFades: r,
|
|
1946
|
-
edgeIndicatorFns: this.#
|
|
1947
|
-
resolveBoundary: (
|
|
1948
|
-
resolveEdgeAnchor: (
|
|
1949
|
-
resolveEdgeBarSpacing: () => this.#
|
|
1950
|
-
reportPlaceholders: (
|
|
1951
|
-
this.#Z[
|
|
1977
|
+
edgeIndicatorFns: this.#ct,
|
|
1978
|
+
resolveBoundary: (d) => j(d, this.#ot[d], this.getDataBounds()),
|
|
1979
|
+
resolveEdgeAnchor: (d, g) => this.#zt(d, g),
|
|
1980
|
+
resolveEdgeBarSpacing: () => this.#Vt(),
|
|
1981
|
+
reportPlaceholders: (d, g) => {
|
|
1982
|
+
this.#Z[d] = { bars: g, at: performance.now() };
|
|
1952
1983
|
}
|
|
1953
1984
|
}), o.context.restore();
|
|
1954
1985
|
}), e) {
|
|
1955
|
-
const { from: o, to:
|
|
1956
|
-
let
|
|
1957
|
-
for (const
|
|
1958
|
-
if (!(!
|
|
1959
|
-
|
|
1986
|
+
const { from: o, to: m } = this.timeScale.getRange();
|
|
1987
|
+
let u = !1;
|
|
1988
|
+
for (const c of this.#t)
|
|
1989
|
+
if (!(!c.visible || !c.renderer.overlayNeedsAnimation) && (c.renderer.hasOverlayContentInRange?.(o, m) ?? !0)) {
|
|
1990
|
+
u = !0;
|
|
1960
1991
|
break;
|
|
1961
1992
|
}
|
|
1962
|
-
if (!
|
|
1963
|
-
for (const
|
|
1964
|
-
if (
|
|
1965
|
-
|
|
1993
|
+
if (!u) {
|
|
1994
|
+
for (const c of this.#u)
|
|
1995
|
+
if (c.pulse && c.time >= o && c.time <= m) {
|
|
1996
|
+
u = !0;
|
|
1966
1997
|
break;
|
|
1967
1998
|
}
|
|
1968
1999
|
}
|
|
1969
|
-
|
|
2000
|
+
u && this.#h.markDirty();
|
|
1970
2001
|
}
|
|
1971
2002
|
a && this.#h.markDirty();
|
|
1972
2003
|
}
|
|
1973
2004
|
}
|
|
1974
2005
|
}
|
|
1975
2006
|
export {
|
|
1976
|
-
|
|
2007
|
+
ci as ChartInstance
|
|
1977
2008
|
};
|