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