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