@wick-charts/vue 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/BandSeries.vue.js +43 -32
- package/dist/BarSeries.vue.js +44 -33
- package/dist/CandlestickSeries.vue.js +24 -23
- package/dist/ChartContainer.vue.js +1 -1
- package/dist/HeatmapSeries.vue.js +21 -20
- package/dist/LineSeries.vue.js +43 -32
- package/dist/PieSeries.vue.js +25 -24
- package/dist/composables.js +63 -36
- package/dist/core/dist/axis/dom-labels.js +64 -53
- package/dist/core/dist/chart/badge-animator.js +38 -28
- package/dist/core/dist/chart/options.js +1 -1
- package/dist/core/dist/chart/y-target.js +38 -32
- package/dist/core/dist/chart.js +852 -709
- package/dist/core/dist/data/decimation.js +52 -51
- package/dist/core/dist/data/store.js +38 -20
- package/dist/core/dist/data/sync.js +97 -59
- package/dist/core/dist/navigator/controller.js +11 -11
- package/dist/core/dist/perf/perf-hud.js +3 -3
- package/dist/core/dist/scales/tick-tracker.js +2 -1
- package/dist/core/dist/scales/time-ticks.js +99 -0
- package/dist/core/dist/scales/x-scale.js +33 -27
- package/dist/core/dist/series/band.js +83 -83
- package/dist/core/dist/series/bar.js +240 -211
- package/dist/core/dist/series/base-multi-layer.js +288 -240
- package/dist/core/dist/series/candlestick.js +168 -168
- package/dist/core/dist/series/line.js +545 -455
- package/dist/core/dist/snapshots.js +109 -86
- package/dist/core/dist/utils/point.js +4 -0
- package/dist/core/dist/utils/time.js +42 -26
- package/dist/index.d.ts +67 -28
- package/dist/ui/InfoBar.vue.js +69 -69
- package/dist/ui/NumberFlow.vue.js +36 -27
- package/dist/ui/Tooltip.vue.js +128 -131
- package/dist/ui/YLabel.vue.js +47 -47
- package/package.json +2 -2
- package/src/BandSeries.vue +20 -5
- package/src/BarSeries.vue +20 -5
- package/src/CandlestickSeries.vue +5 -4
- package/src/ChartContainer.vue +15 -9
- package/src/HeatmapSeries.vue +5 -4
- package/src/LineSeries.vue +20 -5
- package/src/PieSeries.vue +6 -5
- package/src/composables.ts +64 -1
- package/src/ui/InfoBar.vue +11 -3
- package/src/ui/NumberFlow.vue +17 -3
- package/src/ui/Tooltip.vue +23 -12
- package/src/ui/YLabel.vue +28 -27
package/dist/core/dist/chart.js
CHANGED
|
@@ -1,100 +1,117 @@
|
|
|
1
|
-
import { Animator as
|
|
2
|
-
import { AnimationConfig as
|
|
3
|
-
import { easeOutCubic as
|
|
4
|
-
import { prefersReducedMotion as
|
|
5
|
-
import { createViewportEngine as
|
|
6
|
-
import { CanvasManager as
|
|
7
|
-
import { resolveEdgeAnchorValue as
|
|
8
|
-
import { computeFitToData as
|
|
9
|
-
import { getLastValue as
|
|
10
|
-
import { resolveFade as
|
|
11
|
-
import { computePan as
|
|
12
|
-
import { warnUnplottableBounds as
|
|
13
|
-
import { StreamingCadence as
|
|
14
|
-
import { computeStreamingTarget as
|
|
15
|
-
import { resolvePaddingTime as
|
|
16
|
-
import { assertSeriesFitsXAxis as
|
|
17
|
-
import { fromScaleSpace as
|
|
18
|
-
import { renderCrosshair as
|
|
19
|
-
import { renderGrid as
|
|
20
|
-
import { renderMarker as
|
|
21
|
-
import { renderReferenceLine as
|
|
22
|
-
import { resolveTimeRegionColors as
|
|
23
|
-
import { EventEmitter as
|
|
24
|
-
import { InteractionHandler as
|
|
25
|
-
import { RenderScheduler as
|
|
26
|
-
import { XScale as
|
|
27
|
-
import { YScale as
|
|
28
|
-
import { resolveSeriesDefinition as
|
|
29
|
-
import { isTimeSeriesRenderer as
|
|
30
|
-
import { catppuccin as
|
|
31
|
-
import { deepEqual as
|
|
32
|
-
import { clamp as
|
|
33
|
-
import { crispLineWidth as
|
|
34
|
-
import { pointValue as
|
|
35
|
-
import { normalizeTime as k, detectInterval as
|
|
36
|
-
const
|
|
37
|
-
function
|
|
1
|
+
import { Animator as gt } from "./animation/animator.js";
|
|
2
|
+
import { AnimationConfig as pt, DEFAULT_LINE_PULSE as yt } from "./animation/config.js";
|
|
3
|
+
import { easeOutCubic as X } from "./animation/easing.js";
|
|
4
|
+
import { prefersReducedMotion as xt } from "./animation/reduced-motion.js";
|
|
5
|
+
import { createViewportEngine as vt } from "./animation/viewport-engine.js";
|
|
6
|
+
import { CanvasManager as St } from "./canvas-manager.js";
|
|
7
|
+
import { resolveEdgeAnchorValue as bt, drawEdgeIndicators as kt, resolveEdgeBoundary as Tt } from "./chart/edge-indicators.js";
|
|
8
|
+
import { computeFitToData as Z } from "./chart/fit-to-data.js";
|
|
9
|
+
import { getLastValue as wt, getPreviousClose as Mt, getStackedLastValue as At } from "./chart/last-value.js";
|
|
10
|
+
import { resolveFade as _, resolveMaxVisibleBars as Pt, resolvePadding as U, resolvePerfOptions as Ct, isSameHorizontalPadding as G } from "./chart/options.js";
|
|
11
|
+
import { computePan as Lt, computeZoom as It } from "./chart/pan-zoom-math.js";
|
|
12
|
+
import { warnUnplottableBounds as D, assertStackingFitsScale as R, warnScaleSideTaken as Dt, warnUnknownScale as Rt, warnStackingOffScale as Vt, warnUnplottableValues as Ht } from "./chart/scale-guards.js";
|
|
13
|
+
import { StreamingCadence as Nt } from "./chart/streaming-cadence.js";
|
|
14
|
+
import { computeStreamingTarget as Ft } from "./chart/streaming-target.js";
|
|
15
|
+
import { resolvePaddingTime as j } from "./chart/viewport-padding.js";
|
|
16
|
+
import { assertSeriesFitsXAxis as Wt, warnXMisfit as $t, warnXTimeMixed as zt, warnTimeOnlyFeature as Ot, warnXTypeChange as Yt } from "./chart/x-guards.js";
|
|
17
|
+
import { fromScaleSpace as Et, computeTargetYRange as Bt, resolveYTarget as Xt, widenFlatRange as Zt } from "./chart/y-target.js";
|
|
18
|
+
import { renderCrosshair as _t } from "./components/crosshair.js";
|
|
19
|
+
import { renderGrid as K } from "./components/grid.js";
|
|
20
|
+
import { renderMarker as Ut } from "./components/marker.js";
|
|
21
|
+
import { renderReferenceLine as Gt } from "./components/reference-line.js";
|
|
22
|
+
import { resolveTimeRegionColors as jt, renderTimeRegion as Kt } from "./components/time-region.js";
|
|
23
|
+
import { EventEmitter as qt } from "./events.js";
|
|
24
|
+
import { InteractionHandler as Jt } from "./interactions/handler.js";
|
|
25
|
+
import { RenderScheduler as q } from "./render-scheduler.js";
|
|
26
|
+
import { XScale as Qt } from "./scales/x-scale.js";
|
|
27
|
+
import { YScale as J, isPlottableOn as Q } from "./scales/y-scale.js";
|
|
28
|
+
import { resolveSeriesDefinition as te } from "./series/definition.js";
|
|
29
|
+
import { isTimeSeriesRenderer as S } from "./series/types.js";
|
|
30
|
+
import { catppuccin as ee } from "./theme/themes/catppuccin.js";
|
|
31
|
+
import { deepEqual as ie } from "./utils/deep-equal.js";
|
|
32
|
+
import { clamp as se } from "./utils/math.js";
|
|
33
|
+
import { crispLineWidth as re, crispCenterOffset as ne } from "./utils/pixel-grid.js";
|
|
34
|
+
import { pointValue as tt, isBandPoint as ae } from "./utils/point.js";
|
|
35
|
+
import { normalizeTime as k, detectInterval as V } from "./utils/time.js";
|
|
36
|
+
const oe = 200, he = 1500, le = 48, et = 12, H = 9, ce = ["left", "right"], de = { entries: [], isAnimating: !1 }, ue = [], me = ["left"], fe = ["right"], ge = 55, it = 2e3, st = 20;
|
|
37
|
+
function A(d) {
|
|
38
|
+
return Number.isInteger(d) && d >= 2;
|
|
39
|
+
}
|
|
40
|
+
function pe(d) {
|
|
41
|
+
if (typeof d == "number") return A(d) ? d : void 0;
|
|
42
|
+
if (!(d !== void 0 && "bars" in d && !A(d.bars)))
|
|
43
|
+
return d;
|
|
44
|
+
}
|
|
45
|
+
function ye(d) {
|
|
46
|
+
return typeof d == "object" && "to" in d;
|
|
47
|
+
}
|
|
48
|
+
function rt(d, t) {
|
|
38
49
|
return {
|
|
39
|
-
yScale:
|
|
50
|
+
yScale: d,
|
|
40
51
|
bounds: { min: t?.min, max: t?.max },
|
|
41
52
|
range: { min: 0, max: 0 },
|
|
42
53
|
prevMin: Number.NaN,
|
|
43
|
-
prevMax: Number.NaN
|
|
54
|
+
prevMax: Number.NaN,
|
|
55
|
+
paintedMin: Number.NaN,
|
|
56
|
+
paintedMax: Number.NaN
|
|
44
57
|
};
|
|
45
58
|
}
|
|
46
|
-
function
|
|
47
|
-
|
|
59
|
+
function nt(d) {
|
|
60
|
+
const t = d.range.min !== d.paintedMin || d.range.max !== d.paintedMax;
|
|
61
|
+
return d.paintedMin = d.range.min, d.paintedMax = d.range.max, t;
|
|
62
|
+
}
|
|
63
|
+
function at(d) {
|
|
64
|
+
return d === "left" ? "right" : "left";
|
|
48
65
|
}
|
|
49
|
-
function
|
|
50
|
-
return
|
|
66
|
+
function ot(d, t) {
|
|
67
|
+
return d === void 0 || d === "auto" ? !1 : !(typeof d == "number" && !t.isPlottable(d));
|
|
51
68
|
}
|
|
52
|
-
let
|
|
53
|
-
function
|
|
54
|
-
return
|
|
69
|
+
let xe = 0, ve = 0, Se = 0, be = 0;
|
|
70
|
+
function ht(d, t) {
|
|
71
|
+
return d === t ? !0 : !d || !t || d.length !== t.length ? !1 : d.every((e, i) => e === t[i]);
|
|
55
72
|
}
|
|
56
|
-
function
|
|
57
|
-
return
|
|
73
|
+
function lt(d) {
|
|
74
|
+
return S(d) ? d.stacking : void 0;
|
|
58
75
|
}
|
|
59
|
-
function
|
|
60
|
-
return
|
|
76
|
+
function ke(d, t) {
|
|
77
|
+
return d === t ? !0 : !d || !t || d.length !== t.length ? !1 : d.every((e, i) => e === t[i]);
|
|
61
78
|
}
|
|
62
|
-
class
|
|
79
|
+
class ri extends qt {
|
|
63
80
|
/** Canvas lifecycle and DPR-aware sizing. */
|
|
64
|
-
#
|
|
81
|
+
#c;
|
|
65
82
|
/** Schedules main-layer redraws (background, grid, series). */
|
|
66
83
|
#i;
|
|
67
84
|
/** Schedules overlay redraws (crosshair). */
|
|
68
|
-
#
|
|
85
|
+
#d;
|
|
69
86
|
/** Maps time values to horizontal pixel coordinates. */
|
|
70
87
|
timeScale;
|
|
71
88
|
/** Maps price/value to vertical pixel coordinates — the default Y scale. */
|
|
72
89
|
yScale;
|
|
73
90
|
/** Default-scale Y state; `yScale` is its scale. */
|
|
74
|
-
#
|
|
91
|
+
#w;
|
|
75
92
|
/** Named Y scales from `options.scales`, in declaration order. */
|
|
76
|
-
#
|
|
93
|
+
#o = /* @__PURE__ */ new Map();
|
|
77
94
|
/** Copy of the `scales` option as last applied — `setScales` skips a deep-equal replay,
|
|
78
95
|
* and the copy keeps an in-place edit of the caller's object from comparing equal. */
|
|
79
|
-
#
|
|
96
|
+
#It = {};
|
|
80
97
|
/** Set when a named scale's range moved, so the crosshair re-emits for its axis label. */
|
|
81
|
-
#
|
|
98
|
+
#ot = !1;
|
|
82
99
|
/** Keys of dev warnings already printed, so each fires once. */
|
|
83
|
-
#
|
|
100
|
+
#Dt = /* @__PURE__ */ new Set();
|
|
84
101
|
/** What the X axis maps — read from `axis.x.type` once, at construction. */
|
|
85
|
-
#
|
|
102
|
+
#n;
|
|
86
103
|
/** Category axis: name → band index, in first-seen order across the series. */
|
|
87
|
-
#
|
|
104
|
+
#O = /* @__PURE__ */ new Map();
|
|
88
105
|
/** Zoom, pan, crosshair — null when interactive=false. */
|
|
89
|
-
#
|
|
106
|
+
#N;
|
|
90
107
|
/** All registered series (candlestick, line, bar, pie). */
|
|
91
108
|
#t = [];
|
|
92
109
|
/** Point annotations (event markers) drawn on the overlay layer, kept out of the series model. */
|
|
93
110
|
#y = [];
|
|
94
111
|
/** Time-region bands drawn on the main layer behind the series, kept out of the series model. */
|
|
95
|
-
#
|
|
112
|
+
#M = [];
|
|
96
113
|
/** Reference lines (horizontal threshold / vertical event) drawn on the overlay layer, kept out of the series model. */
|
|
97
|
-
#
|
|
114
|
+
#S = [];
|
|
98
115
|
/**
|
|
99
116
|
* Overlay-intro latch. Annotations ride the *initial* reveal, then stay put.
|
|
100
117
|
* `#overlayIntroSeen` flips once we've actually watched an intro in progress
|
|
@@ -103,29 +120,31 @@ class _e extends Et {
|
|
|
103
120
|
* later — which re-arms `getIntroFront()`'s global min — can't blink settled
|
|
104
121
|
* markers / reference lines back out.
|
|
105
122
|
*/
|
|
106
|
-
#
|
|
107
|
-
#
|
|
123
|
+
#Rt = !1;
|
|
124
|
+
#Vt = !1;
|
|
108
125
|
/** Active visual theme (colors, fonts, grid style). */
|
|
109
|
-
#
|
|
126
|
+
#h;
|
|
110
127
|
/** Whether to render the background grid. */
|
|
111
|
-
#
|
|
128
|
+
#j;
|
|
112
129
|
/**
|
|
113
130
|
* Gridline layer opacity, multiplied into every per-tick fade: `0 → 1` on
|
|
114
131
|
* the opening reveal, `1 → 0` when {@link setGrid} hides the grid. The
|
|
115
132
|
* per-tick fades stay snapped during mount (see the tracker's arming), so
|
|
116
133
|
* this is what keeps `fitToData` tick churn from flickering the reveal.
|
|
117
134
|
*/
|
|
118
|
-
#
|
|
135
|
+
#Y;
|
|
136
|
+
/** Whether a tick fade ran on the last main frame — the frame it settles on still owes the DOM labels a sync. */
|
|
137
|
+
#Ht = !1;
|
|
119
138
|
/** Resolved edge-fade zones — a `null` side is auto: the axis-column ramp on the Y-axis side, off on the other. */
|
|
120
139
|
#C;
|
|
121
140
|
/** See {@link headerHeight}. */
|
|
122
|
-
#
|
|
141
|
+
#ht = 0;
|
|
123
142
|
/** Memoized destination-out mask gradients, one per edge, keyed by the
|
|
124
143
|
* zone's bitmap geometry so a resize / DPR change / `setFade` rebuilds
|
|
125
144
|
* them and steady frames reuse them. */
|
|
126
|
-
#
|
|
145
|
+
#b = { top: null, axis: { left: null, right: null }, edge: { left: null, right: null }, tail: null, overhang: null };
|
|
127
146
|
/** Detected time interval between data points (milliseconds). */
|
|
128
|
-
#
|
|
147
|
+
#r = 6e4;
|
|
129
148
|
/** Current crosshair position, null when cursor is outside the chart. */
|
|
130
149
|
#f = null;
|
|
131
150
|
/**
|
|
@@ -135,12 +154,12 @@ class _e extends Et {
|
|
|
135
154
|
* `time`/`y`; `'time'` (programmatic {@link setCrosshair}) keeps
|
|
136
155
|
* `time`/`y` and re-projects the pixel position.
|
|
137
156
|
*/
|
|
138
|
-
#
|
|
157
|
+
#lt = "pointer";
|
|
139
158
|
/** Whether the last overlay pass painted anything — gates the full-bitmap
|
|
140
159
|
* clear so an empty overlay isn't cleared again every main frame. */
|
|
141
|
-
#
|
|
160
|
+
#Nt = !1;
|
|
142
161
|
/** Cached series ID list — invalidated on add/remove. */
|
|
143
|
-
#
|
|
162
|
+
#F = null;
|
|
144
163
|
/** Axis visibility and sizing configuration. */
|
|
145
164
|
#v = {};
|
|
146
165
|
/** Host-declared state per edge — drives the edge-indicator overlay. */
|
|
@@ -151,27 +170,27 @@ class _e extends Et {
|
|
|
151
170
|
* fetched data lands. `null` = no fade in flight. */
|
|
152
171
|
#K = { left: null, right: null };
|
|
153
172
|
/** Cached boundary timestamps from the last `edgeReached` emission, by side. */
|
|
154
|
-
#
|
|
173
|
+
#Ft = { left: null, right: null };
|
|
155
174
|
/** Latest placeholder shapes a `loading` indicator reported per side —
|
|
156
175
|
* the morph hand-off candidate consumed by {@link prependData}. */
|
|
157
|
-
#
|
|
176
|
+
#ct = { left: null, right: null };
|
|
158
177
|
/** True after a prepend consumed a side's placeholder snapshot: the series'
|
|
159
178
|
* reveal owns those pixels now, so the still-`loading` indicator is hidden
|
|
160
179
|
* and the upcoming `loading → idle` transition skips its exit fade. Reset
|
|
161
180
|
* by the next {@link setEdgeState} call. */
|
|
162
|
-
#
|
|
181
|
+
#E = { left: !1, right: !1 };
|
|
163
182
|
/** Host-supplied callback fired when the user releases a pan/zoom past a data edge. */
|
|
164
|
-
#
|
|
183
|
+
#Wt;
|
|
165
184
|
/** Per-side custom painter for the edge `loading` spinner. `null` falls back to the built-in dots. */
|
|
166
|
-
|
|
185
|
+
#$t = { left: null, right: null };
|
|
167
186
|
/** Nesting depth for batch updates. Suppresses recomputes while > 0. */
|
|
168
187
|
#R = 0;
|
|
169
188
|
/** True when batched operations include data changes (triggers full onDataChanged on end). */
|
|
170
|
-
#
|
|
189
|
+
#dt = !1;
|
|
171
190
|
/** True when batched operations include visibility changes (triggers Y-range + redraw on end). */
|
|
172
|
-
#
|
|
191
|
+
#B = !1;
|
|
173
192
|
/** True when batched operations bumped overlay version (emits a single overlayChange on flush). */
|
|
174
|
-
#
|
|
193
|
+
#ut = !1;
|
|
175
194
|
/**
|
|
176
195
|
* Monotonic counter bumped on any mutation that affects overlay output —
|
|
177
196
|
* data, visibility, series options, theme. Used by snapshot helpers in
|
|
@@ -181,10 +200,13 @@ class _e extends Et {
|
|
|
181
200
|
*
|
|
182
201
|
* @internal
|
|
183
202
|
*/
|
|
184
|
-
#
|
|
203
|
+
#mt = 0;
|
|
204
|
+
/** Main frames that moved a series' animated values; see `seriesFrame`. */
|
|
205
|
+
#zt = 0;
|
|
206
|
+
#Ot = !1;
|
|
185
207
|
/** CSS px of the default Y-axis column. The default collapses to `0` on a spatial-only chart. */
|
|
186
208
|
get yAxisWidth() {
|
|
187
|
-
return this.#
|
|
209
|
+
return this.#q(this.#v.y);
|
|
188
210
|
}
|
|
189
211
|
/** Side of the plot area the default Y-axis column sits on. */
|
|
190
212
|
get yAxisPosition() {
|
|
@@ -204,33 +226,33 @@ class _e extends Et {
|
|
|
204
226
|
*/
|
|
205
227
|
getAxisColumnWidth(t) {
|
|
206
228
|
if (t === this.yAxisPosition && this.yAxisWidth > 0) return this.yAxisWidth;
|
|
207
|
-
for (const e of this.#
|
|
208
|
-
if (e.column === t) return this.#
|
|
229
|
+
for (const e of this.#o.values())
|
|
230
|
+
if (e.column === t) return this.#q(e.config);
|
|
209
231
|
return 0;
|
|
210
232
|
}
|
|
211
233
|
/** The named scale whose axis column sits on `side`, `null` when the default axis's does or none. */
|
|
212
234
|
getAxisColumnScale(t) {
|
|
213
|
-
for (const [e, i] of this.#
|
|
235
|
+
for (const [e, i] of this.#o)
|
|
214
236
|
if (i.column === t) return e;
|
|
215
237
|
return null;
|
|
216
238
|
}
|
|
217
239
|
/** Both Y-axis columns together — the plot area is the canvas width minus this. */
|
|
218
|
-
#
|
|
240
|
+
#k() {
|
|
219
241
|
return this.getAxisColumnWidth("left") + this.getAxisColumnWidth("right");
|
|
220
242
|
}
|
|
221
243
|
/** Column width a Y-axis config asks for; `0` when hidden, and by default on a spatial-only chart. */
|
|
222
|
-
#
|
|
223
|
-
return t?.visible === !1 ? 0 : t?.width !== void 0 ? t.width : this.#
|
|
244
|
+
#q(t) {
|
|
245
|
+
return t?.visible === !1 ? 0 : t?.width !== void 0 ? t.width : this.#it() ? 0 : ge;
|
|
224
246
|
}
|
|
225
247
|
/** CSS px height of the floating Title / InfoBar header, `0` without one. A left
|
|
226
248
|
* axis shares its column with it, so tick labels fade out underneath. */
|
|
227
249
|
get headerHeight() {
|
|
228
|
-
return this.#
|
|
250
|
+
return this.#ht;
|
|
229
251
|
}
|
|
230
252
|
/** CSS px of the time-axis row. The default collapses to `0` on a spatial-only chart. */
|
|
231
253
|
get xAxisHeight() {
|
|
232
254
|
const t = this.#v.x;
|
|
233
|
-
return t?.visible === !1 ? 0 : t?.height !== void 0 ? t.height : this.#
|
|
255
|
+
return t?.visible === !1 ? 0 : t?.height !== void 0 ? t.height : this.#it() ? 0 : 30;
|
|
234
256
|
}
|
|
235
257
|
/** Resolved animation config derived from `options.animations` at construction. */
|
|
236
258
|
#g;
|
|
@@ -248,7 +270,7 @@ class _e extends Et {
|
|
|
248
270
|
* longer than the producer's tick interval — the spring never quite
|
|
249
271
|
* settles between ticks, so velocity carries continuously and the slide
|
|
250
272
|
* doesn't pulse. */
|
|
251
|
-
#
|
|
273
|
+
#W;
|
|
252
274
|
/**
|
|
253
275
|
* Mirrors `#dataReplaceSnapPending` for the engine signal that follows
|
|
254
276
|
* inside the same `onDataChanged` call. `#dataReplaceSnapPending` is
|
|
@@ -258,9 +280,9 @@ class _e extends Et {
|
|
|
258
280
|
* field carries the decision across that gap. The closure also reads
|
|
259
281
|
* `#dataStart` / `#dataEnd` directly for the timestamps.
|
|
260
282
|
*/
|
|
261
|
-
#
|
|
283
|
+
#Yt = !1;
|
|
262
284
|
/** Earliest data timestamp registered across all series, `null` before any data has arrived. */
|
|
263
|
-
#
|
|
285
|
+
#T = null;
|
|
264
286
|
/** Latest data timestamp registered across all series, `null` before any data has arrived. */
|
|
265
287
|
#s = null;
|
|
266
288
|
/**
|
|
@@ -269,7 +291,7 @@ class _e extends Et {
|
|
|
269
291
|
* left of the tail keeps that offset as new bars arrive, instead of
|
|
270
292
|
* snapping back to the natural-pin position every frame.
|
|
271
293
|
*/
|
|
272
|
-
#
|
|
294
|
+
#J = null;
|
|
273
295
|
/**
|
|
274
296
|
* Warm-up window flag — `setVisibleRange({ from, bars })` arms it and
|
|
275
297
|
* the streaming-target math suppresses pan ticks while the data hasn't
|
|
@@ -282,14 +304,14 @@ class _e extends Et {
|
|
|
282
304
|
* the right edge and trims the left. Resolved once at construction from
|
|
283
305
|
* `options.viewport.maxVisibleBars`.
|
|
284
306
|
*/
|
|
285
|
-
#
|
|
307
|
+
#ft;
|
|
286
308
|
/**
|
|
287
309
|
* Committed logical X range — the "where X should be" target. Engine
|
|
288
310
|
* eases its visual toward this. Pan / zoom / setRange / fitContent /
|
|
289
311
|
* streaming-target writes go here. Initialized to `{0,0}` and treated
|
|
290
312
|
* as "uninitialized" by `#computeXTarget` until first paint.
|
|
291
313
|
*/
|
|
292
|
-
#
|
|
314
|
+
#a = { from: 0, to: 0 };
|
|
293
315
|
/**
|
|
294
316
|
* Auto-scroll flag — when `true`, streaming ticks slide X to track the
|
|
295
317
|
* data tail. Pan flips this off when the gesture pushes the tail off
|
|
@@ -298,20 +320,22 @@ class _e extends Et {
|
|
|
298
320
|
*/
|
|
299
321
|
#p = !0;
|
|
300
322
|
/** Resolved viewport padding (top/bottom px + left/right pixels-or-intervals). */
|
|
301
|
-
#
|
|
323
|
+
#l;
|
|
302
324
|
/** Cached chart width — passed by interactions on every call; kept for the rare
|
|
303
325
|
* call that omits it (e.g. programmatic `chart.pan(...)` without explicit width). */
|
|
304
|
-
#
|
|
326
|
+
#Q = 0;
|
|
327
|
+
/** X range the last main paint drew. */
|
|
328
|
+
#tt = { from: Number.NaN, to: Number.NaN };
|
|
305
329
|
/** Active performance monitor, or `null` when instrumentation is disabled (the default). */
|
|
306
|
-
#
|
|
330
|
+
#P;
|
|
307
331
|
/** When true, `destroy()` tears down the monitor; false for caller-supplied monitors we must not destroy. */
|
|
308
|
-
#
|
|
332
|
+
#gt = !1;
|
|
309
333
|
/** Visible HUD overlay (mounted by the perf config); non-null only when the caller requested one. */
|
|
310
|
-
#
|
|
334
|
+
#pt = null;
|
|
311
335
|
constructor(t, e) {
|
|
312
|
-
super(), e?.axis && (this.#v = e.axis), this.#
|
|
336
|
+
super(), e?.axis && (this.#v = e.axis), this.#n = this.#v.x?.type ?? "time", this.#h = e?.theme ?? ee.theme, this.#j = e?.grid?.visible !== !1, this.#C = _(e?.fade), this.#g = pt.resolve(e?.animations), this.#ft = Pt(e?.viewport?.maxVisibleBars), this.#l = U(e?.padding), this.#W = new Nt();
|
|
313
337
|
const i = this.#g.axis.y, s = this.#g.axis.x;
|
|
314
|
-
this.#e =
|
|
338
|
+
this.#e = vt({
|
|
315
339
|
initial: { yRange: { min: 0, max: 0 }, xRange: { from: 0, to: 0 } },
|
|
316
340
|
y: {
|
|
317
341
|
curve: i.curve,
|
|
@@ -326,36 +350,36 @@ class _e extends Et {
|
|
|
326
350
|
settleMs: s.settleMs,
|
|
327
351
|
gestureMs: s.gestureMs
|
|
328
352
|
},
|
|
329
|
-
computeXTarget: () => this.#
|
|
330
|
-
computeYTarget: ({ xTarget: o, scale: h }) => this.#
|
|
353
|
+
computeXTarget: () => this.#Ne(),
|
|
354
|
+
computeYTarget: ({ xTarget: o, scale: h }) => this.#G(o, h),
|
|
331
355
|
onWake: () => this.#i?.markDirty()
|
|
332
|
-
}), e?.onEdgeReached && this.checkTimeOnlyFeature("onEdgeReached") && (this.#
|
|
333
|
-
const r =
|
|
334
|
-
this.#
|
|
356
|
+
}), e?.onEdgeReached && this.checkTimeOnlyFeature("onEdgeReached") && (this.#Wt = e.onEdgeReached), this.#H = pe(e?.viewport?.initialRange);
|
|
357
|
+
const r = Ct(e?.perf);
|
|
358
|
+
this.#P = r.monitor, this.#gt = r.ownsMonitor, this.#c = new St(t, this.#P ?? void 0), this.timeScale = new Qt(), this.timeScale.setType(this.#n), this.timeScale.setBandPadding(this.#v.x?.padding), this.yScale = new J(), this.#w = rt(this.yScale, this.#v.y), this.yScale.setTransform(this.#v.y?.scale ?? null), D({ y: this.#v.y, isPlottable: this.#vt(void 0) }), this.timeScale.setLocale(e?.locale), this.timeScale.setTimeZone(e?.timeZone);
|
|
335
359
|
const n = this.#g.axis.ticksMs;
|
|
336
|
-
this.timeScale.tickTracker.setFadeMs(n), this.yScale.tickTracker.setFadeMs(n), this.#
|
|
360
|
+
this.timeScale.tickTracker.setFadeMs(n), this.yScale.tickTracker.setFadeMs(n), this.#qt(e?.scales ?? {}), this.#wt(), this.#Y = new gt({
|
|
337
361
|
initial: 0,
|
|
338
362
|
duration: this.#g.axis.gridMs,
|
|
339
363
|
lerp: (o, h, l) => o + (h - o) * l
|
|
340
|
-
}), this.#i = new
|
|
341
|
-
(o) => this.#
|
|
342
|
-
), this.#
|
|
364
|
+
}), this.#i = new q((o) => this.#Ct(o)), this.#d = new q(
|
|
365
|
+
(o) => this.#Lt("overlay", o, () => this.renderOverlay(o))
|
|
366
|
+
), this.#P && r.hud && (this.#pt = r.hud(t, this.#P));
|
|
343
367
|
const a = e?.interactive !== !1;
|
|
344
|
-
this.#
|
|
345
|
-
this.syncScales(), this.#
|
|
346
|
-
}), this.syncScales(), this.#
|
|
347
|
-
const h = o === null ? null : this.#
|
|
348
|
-
this.#
|
|
349
|
-
}), this.#
|
|
350
|
-
const h = this.#
|
|
351
|
-
this.emit("pointClick", { ...h, spatialHit: this.#
|
|
352
|
-
}), this.#
|
|
353
|
-
const h = this.#
|
|
354
|
-
this.fitContent(), this.emit("pointDoubleClick", { ...h, spatialHit: this.#
|
|
368
|
+
this.#N = a ? new Jt(this.#c.canvas, this, this.timeScale, this.yScale) : null, this.#c.on("resize", () => {
|
|
369
|
+
this.syncScales(), this.#Ct(), this.emit("viewportChange");
|
|
370
|
+
}), this.syncScales(), this.#N?.on("crosshairMove", (o) => {
|
|
371
|
+
const h = o === null ? null : this.#yt(o);
|
|
372
|
+
this.#lt = "pointer", this.#f = h, this.#d.markDirty(), this.emit("crosshairMove", h), this.#Mt(h);
|
|
373
|
+
}), this.#N?.on("click", (o) => {
|
|
374
|
+
const h = this.#yt(o);
|
|
375
|
+
this.emit("pointClick", { ...h, spatialHit: this.#Qt(h) });
|
|
376
|
+
}), this.#N?.on("dblclick", (o) => {
|
|
377
|
+
const h = this.#yt(o);
|
|
378
|
+
this.fitContent(), this.emit("pointDoubleClick", { ...h, spatialHit: this.#Qt(h) });
|
|
355
379
|
});
|
|
356
380
|
}
|
|
357
381
|
/** A pointer position on a category axis snaps to the nearest band; `x` is the coordinate in the axis domain. */
|
|
358
|
-
#
|
|
382
|
+
#yt(t) {
|
|
359
383
|
const e = this.timeScale.snapToBand(t.time);
|
|
360
384
|
return { ...t, time: e, x: this.timeScale.domainValue(e) };
|
|
361
385
|
}
|
|
@@ -371,9 +395,9 @@ class _e extends Et {
|
|
|
371
395
|
* `setSeriesVisible` / `setLayerVisible` calls — produce one overlay
|
|
372
396
|
* render instead of N.
|
|
373
397
|
*/
|
|
374
|
-
#
|
|
375
|
-
if (this.#
|
|
376
|
-
this.#
|
|
398
|
+
#m() {
|
|
399
|
+
if (this.#mt++, this.#R > 0) {
|
|
400
|
+
this.#ut = !0;
|
|
377
401
|
return;
|
|
378
402
|
}
|
|
379
403
|
this.emit("overlayChange");
|
|
@@ -387,59 +411,86 @@ class _e extends Et {
|
|
|
387
411
|
* @internal
|
|
388
412
|
*/
|
|
389
413
|
getOverlayVersion() {
|
|
390
|
-
return this.#
|
|
414
|
+
return this.#mt;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* {@link getOverlayVersion} that also advances on every `seriesFrame`: the
|
|
418
|
+
* snapshot helpers key their cache on it, since a snapshot reads the
|
|
419
|
+
* animated values a frame moves.
|
|
420
|
+
*
|
|
421
|
+
* @internal
|
|
422
|
+
*/
|
|
423
|
+
getSnapshotVersion() {
|
|
424
|
+
return this.#mt + this.#zt;
|
|
391
425
|
}
|
|
392
426
|
/**
|
|
393
427
|
* Return a series ID: use the provided hint if it's non-empty and not already taken,
|
|
394
428
|
* otherwise generate a new auto ID. Auto-generated IDs never collide with each other
|
|
395
429
|
* or with user-provided IDs because they use a monotonically increasing counter.
|
|
396
430
|
*/
|
|
397
|
-
#
|
|
431
|
+
#ge(t) {
|
|
398
432
|
if (t && !this.#t.some((i) => i.id === t))
|
|
399
433
|
return t;
|
|
400
434
|
let e;
|
|
401
435
|
do
|
|
402
|
-
e = `series_${++
|
|
436
|
+
e = `series_${++xe}`;
|
|
403
437
|
while (this.#t.some((i) => i.id === e));
|
|
404
438
|
return e;
|
|
405
439
|
}
|
|
406
440
|
addSeries(t, e = {}) {
|
|
407
|
-
const i = typeof t == "string" ?
|
|
441
|
+
const i = typeof t == "string" ? te(t) : t;
|
|
408
442
|
if (!i)
|
|
409
443
|
throw new Error(
|
|
410
444
|
`[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).`
|
|
411
445
|
);
|
|
412
446
|
const { layers: s, id: r, label: n, labels: a, scale: o, ...h } = e, l = s ?? 1;
|
|
413
|
-
o === void 0 &&
|
|
447
|
+
o === void 0 && R({
|
|
414
448
|
seriesId: r ?? i.type,
|
|
415
449
|
stacking: h.stacking,
|
|
416
|
-
isPlottable: this.#
|
|
450
|
+
isPlottable: this.#vt(o)
|
|
417
451
|
});
|
|
418
|
-
const
|
|
452
|
+
const c = {
|
|
419
453
|
...this.#g.defaults(i.type),
|
|
420
454
|
...h,
|
|
421
455
|
...this.#g.overrides(i.type)
|
|
422
|
-
}, f = i.create({ theme: this.#
|
|
423
|
-
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
const
|
|
456
|
+
}, f = this.#pe({ type: i.type, count: l }), g = i.create({ theme: this.#h, layerCount: l, paletteIndex: f }, c);
|
|
457
|
+
S(g) && Wt({ seriesType: i.type, axisType: this.#n, supported: i.xTypes ?? ["time"] });
|
|
458
|
+
const y = a ?? (typeof n == "string" ? [n] : void 0), u = this.#ge(r);
|
|
459
|
+
g.onDataChanged?.(() => this.onDataChanged());
|
|
460
|
+
const m = this.#Z();
|
|
427
461
|
return this.#t.push({
|
|
428
|
-
id:
|
|
429
|
-
labels:
|
|
430
|
-
renderer:
|
|
462
|
+
id: u,
|
|
463
|
+
labels: y,
|
|
464
|
+
renderer: g,
|
|
431
465
|
visible: !0,
|
|
432
466
|
scale: o,
|
|
433
467
|
xKeys: { x: !1, time: !1 },
|
|
434
|
-
categoryPoints: []
|
|
435
|
-
|
|
468
|
+
categoryPoints: [],
|
|
469
|
+
palette: { type: i.type, start: f, count: l }
|
|
470
|
+
}), this.#F = null, this.#rt(), this.#st(m), this.emit("seriesChange"), this.#m(), u;
|
|
471
|
+
}
|
|
472
|
+
/** The lowest run of `count` palette slots that no other series of `type` holds. */
|
|
473
|
+
#pe(t) {
|
|
474
|
+
const e = /* @__PURE__ */ new Set();
|
|
475
|
+
for (const r of this.#t)
|
|
476
|
+
if (r.palette.type === t.type)
|
|
477
|
+
for (let n = 0; n < r.palette.count; n++)
|
|
478
|
+
e.add(r.palette.start + n);
|
|
479
|
+
const i = (r) => {
|
|
480
|
+
for (let n = r; n < r + t.count; n++)
|
|
481
|
+
if (e.has(n)) return !0;
|
|
482
|
+
return !1;
|
|
483
|
+
};
|
|
484
|
+
let s = 0;
|
|
485
|
+
for (; i(s); ) s++;
|
|
486
|
+
return s;
|
|
436
487
|
}
|
|
437
488
|
/** Remove a series by ID and clean up its resources. */
|
|
438
489
|
removeSeries(t) {
|
|
439
490
|
const e = this.#t.findIndex((i) => i.id === t);
|
|
440
491
|
if (e >= 0) {
|
|
441
492
|
const i = this.#Z();
|
|
442
|
-
this.#t[e].renderer.dispose(), this.#t.splice(e, 1), this.#
|
|
493
|
+
this.#t[e].renderer.dispose(), this.#t.splice(e, 1), this.#F = null, this.#n === "category" && this.#Gt(), this.#rt(), this.#st(i), this.#i.markDirty(), this.emit("seriesChange"), this.#m();
|
|
443
494
|
}
|
|
444
495
|
}
|
|
445
496
|
// --- Markers (point annotations) -----------------------------------------
|
|
@@ -453,24 +504,24 @@ class _e extends Et {
|
|
|
453
504
|
* appear in series queries.
|
|
454
505
|
*/
|
|
455
506
|
addMarker(t) {
|
|
456
|
-
const e = `marker_${++
|
|
457
|
-
return this.#y.push(this.#
|
|
507
|
+
const e = `marker_${++ve}`;
|
|
508
|
+
return this.#y.push(this.#Et(e, t)), this.#d.markDirty(), e;
|
|
458
509
|
}
|
|
459
510
|
/** Replace a marker's config in place. No-op when the id is unknown. */
|
|
460
511
|
updateMarker(t, e) {
|
|
461
512
|
const i = this.#y.findIndex((s) => s.id === t);
|
|
462
|
-
i !== -1 && (this.#y[i] = this.#
|
|
513
|
+
i !== -1 && (this.#y[i] = this.#Et(t, e), this.#d.markDirty());
|
|
463
514
|
}
|
|
464
515
|
/** Remove a marker by id. No-op when the id is unknown. */
|
|
465
516
|
removeMarker(t) {
|
|
466
517
|
const e = this.#y.findIndex((i) => i.id === t);
|
|
467
|
-
e !== -1 && (this.#y.splice(e, 1), this.#
|
|
518
|
+
e !== -1 && (this.#y.splice(e, 1), this.#d.markDirty());
|
|
468
519
|
}
|
|
469
520
|
/** Read-only snapshot of the registered markers (normalized). Mutate via add / update / removeMarker. */
|
|
470
521
|
getMarkers() {
|
|
471
522
|
return this.#y;
|
|
472
523
|
}
|
|
473
|
-
#
|
|
524
|
+
#Et(t, e) {
|
|
474
525
|
return {
|
|
475
526
|
id: t,
|
|
476
527
|
time: k(e.time),
|
|
@@ -484,43 +535,43 @@ class _e extends Et {
|
|
|
484
535
|
};
|
|
485
536
|
}
|
|
486
537
|
/** The scale a marker's value maps through: its own `scale`, else its series' scale. */
|
|
487
|
-
#
|
|
538
|
+
#ye(t) {
|
|
488
539
|
return t.scale !== void 0 || t.seriesId === void 0 ? this.getYScale(t.scale) : this.getYScale(this.getSeriesScale(t.seriesId));
|
|
489
540
|
}
|
|
490
541
|
/** Resolve a marker's Y value: explicit `value`, else snapped to its series at `time`. Null when neither resolves. */
|
|
491
|
-
#
|
|
542
|
+
#xe(t) {
|
|
492
543
|
if (t.value !== void 0 && Number.isFinite(t.value)) return t.value;
|
|
493
544
|
if (t.seriesId === void 0) return null;
|
|
494
545
|
const e = this.getDataAtTime(t.seriesId, t.time);
|
|
495
|
-
return e ?
|
|
546
|
+
return e ? tt(e) : null;
|
|
496
547
|
}
|
|
497
548
|
/** Resolve a marker's color: explicit `color`, else the series color, else the theme line color. */
|
|
498
|
-
#
|
|
549
|
+
#ve(t) {
|
|
499
550
|
if (t.color !== void 0) return t.color;
|
|
500
551
|
if (t.seriesId !== void 0) {
|
|
501
552
|
const e = this.getSeriesColor(t.seriesId);
|
|
502
553
|
if (e !== null) return e;
|
|
503
554
|
}
|
|
504
|
-
return this.#
|
|
555
|
+
return this.#h.line.color;
|
|
505
556
|
}
|
|
506
|
-
#
|
|
557
|
+
#Se(t, e, i) {
|
|
507
558
|
if (this.#y.length === 0) return;
|
|
508
|
-
const s = performance.now() / (
|
|
559
|
+
const s = performance.now() / (yt * 2 * Math.PI) % 1, r = this.#St();
|
|
509
560
|
for (const n of this.#y) {
|
|
510
|
-
const a = this.#
|
|
561
|
+
const a = this.#xe(n);
|
|
511
562
|
if (a === null) continue;
|
|
512
|
-
const o = this.#
|
|
563
|
+
const o = this.#_t(r, n.time);
|
|
513
564
|
if (o <= 0) continue;
|
|
514
565
|
const h = t.context.globalAlpha;
|
|
515
|
-
o < 1 && (t.context.globalAlpha = h * o),
|
|
566
|
+
o < 1 && (t.context.globalAlpha = h * o), Ut({
|
|
516
567
|
scope: t,
|
|
517
568
|
timeScale: this.timeScale,
|
|
518
|
-
yScale: this.#
|
|
519
|
-
theme: this.#
|
|
569
|
+
yScale: this.#ye(n),
|
|
570
|
+
theme: this.#h,
|
|
520
571
|
marker: {
|
|
521
572
|
time: n.time,
|
|
522
573
|
value: a,
|
|
523
|
-
color: this.#
|
|
574
|
+
color: this.#ve(n),
|
|
524
575
|
shape: n.shape,
|
|
525
576
|
pulse: n.pulse,
|
|
526
577
|
label: n.label
|
|
@@ -544,24 +595,24 @@ class _e extends Et {
|
|
|
544
595
|
* legend.
|
|
545
596
|
*/
|
|
546
597
|
addRegion(t) {
|
|
547
|
-
const e = `region_${++
|
|
548
|
-
return this.checkTimeOnlyFeature("TimeRegion") && (this.#
|
|
598
|
+
const e = `region_${++Se}`;
|
|
599
|
+
return this.checkTimeOnlyFeature("TimeRegion") && (this.#M.push(this.#Bt(e, t)), this.#i.markDirty()), e;
|
|
549
600
|
}
|
|
550
601
|
/** Replace a region's config in place. No-op when the id is unknown. */
|
|
551
602
|
updateRegion(t, e) {
|
|
552
|
-
const i = this.#
|
|
553
|
-
i !== -1 && (this.#
|
|
603
|
+
const i = this.#M.findIndex((s) => s.id === t);
|
|
604
|
+
i !== -1 && (this.#M[i] = this.#Bt(t, e), this.#i.markDirty());
|
|
554
605
|
}
|
|
555
606
|
/** Remove a region by id. No-op when the id is unknown. */
|
|
556
607
|
removeRegion(t) {
|
|
557
|
-
const e = this.#
|
|
558
|
-
e !== -1 && (this.#
|
|
608
|
+
const e = this.#M.findIndex((i) => i.id === t);
|
|
609
|
+
e !== -1 && (this.#M.splice(e, 1), this.#i.markDirty());
|
|
559
610
|
}
|
|
560
611
|
/** Read-only snapshot of the registered regions (normalized). Mutate via add / update / removeRegion. */
|
|
561
612
|
getRegions() {
|
|
562
|
-
return this.#
|
|
613
|
+
return this.#M;
|
|
563
614
|
}
|
|
564
|
-
#
|
|
615
|
+
#Bt(t, e) {
|
|
565
616
|
const { to: i } = e, s = i === void 0 || i === "now" ? null : k(i);
|
|
566
617
|
return {
|
|
567
618
|
id: t,
|
|
@@ -572,14 +623,14 @@ class _e extends Et {
|
|
|
572
623
|
label: e.label
|
|
573
624
|
};
|
|
574
625
|
}
|
|
575
|
-
#
|
|
576
|
-
if (this.#
|
|
577
|
-
for (const s of this.#
|
|
578
|
-
const { color: r, fill: n } =
|
|
579
|
-
|
|
626
|
+
#be(t, e, i) {
|
|
627
|
+
if (this.#M.length !== 0)
|
|
628
|
+
for (const s of this.#M) {
|
|
629
|
+
const { color: r, fill: n } = jt(s, this.#h);
|
|
630
|
+
Kt({
|
|
580
631
|
scope: t,
|
|
581
632
|
timeScale: this.timeScale,
|
|
582
|
-
theme: this.#
|
|
633
|
+
theme: this.#h,
|
|
583
634
|
region: { from: s.from, to: s.to, fill: n, color: r, label: s.label },
|
|
584
635
|
plotWidth: e,
|
|
585
636
|
plotHeight: i
|
|
@@ -598,24 +649,24 @@ class _e extends Et {
|
|
|
598
649
|
* legend.
|
|
599
650
|
*/
|
|
600
651
|
addLine(t) {
|
|
601
|
-
const e = `line_${++
|
|
602
|
-
return this.#
|
|
652
|
+
const e = `line_${++be}`;
|
|
653
|
+
return this.#S.push(this.#Xt(e, t)), this.#d.markDirty(), e;
|
|
603
654
|
}
|
|
604
655
|
/** Replace a reference line's config in place. No-op when the id is unknown. */
|
|
605
656
|
updateLine(t, e) {
|
|
606
|
-
const i = this.#
|
|
607
|
-
i !== -1 && (this.#
|
|
657
|
+
const i = this.#S.findIndex((s) => s.id === t);
|
|
658
|
+
i !== -1 && (this.#S[i] = this.#Xt(t, e), this.#d.markDirty());
|
|
608
659
|
}
|
|
609
660
|
/** Remove a reference line by id. No-op when the id is unknown. */
|
|
610
661
|
removeLine(t) {
|
|
611
|
-
const e = this.#
|
|
612
|
-
e !== -1 && (this.#
|
|
662
|
+
const e = this.#S.findIndex((i) => i.id === t);
|
|
663
|
+
e !== -1 && (this.#S.splice(e, 1), this.#d.markDirty());
|
|
613
664
|
}
|
|
614
665
|
/** Read-only snapshot of the registered reference lines (normalized). Mutate via add / update / removeLine. */
|
|
615
666
|
getLines() {
|
|
616
|
-
return this.#
|
|
667
|
+
return this.#S;
|
|
617
668
|
}
|
|
618
|
-
|
|
669
|
+
#Xt(t, e) {
|
|
619
670
|
const { time: i, value: s } = e, r = {
|
|
620
671
|
id: t,
|
|
621
672
|
color: e.color,
|
|
@@ -626,22 +677,22 @@ class _e extends Et {
|
|
|
626
677
|
};
|
|
627
678
|
return i !== void 0 ? { ...r, orientation: "vertical", coord: k(i) } : { ...r, orientation: "horizontal", coord: s ?? Number.NaN };
|
|
628
679
|
}
|
|
629
|
-
#
|
|
630
|
-
if (this.#
|
|
631
|
-
const s = this.#
|
|
632
|
-
for (const r of this.#
|
|
633
|
-
const n = s >= 1 ? 1 : r.orientation === "vertical" ? this.#
|
|
680
|
+
#ke(t, e, i) {
|
|
681
|
+
if (this.#S.length === 0) return;
|
|
682
|
+
const s = this.#St();
|
|
683
|
+
for (const r of this.#S) {
|
|
684
|
+
const n = s >= 1 ? 1 : r.orientation === "vertical" ? this.#_t(s, r.coord) : X(s);
|
|
634
685
|
if (n <= 0) continue;
|
|
635
686
|
const a = t.context.globalAlpha;
|
|
636
|
-
n < 1 && (t.context.globalAlpha = a * n),
|
|
687
|
+
n < 1 && (t.context.globalAlpha = a * n), Gt({
|
|
637
688
|
scope: t,
|
|
638
689
|
timeScale: this.timeScale,
|
|
639
690
|
yScale: this.getYScale(r.scale),
|
|
640
|
-
theme: this.#
|
|
691
|
+
theme: this.#h,
|
|
641
692
|
line: {
|
|
642
693
|
orientation: r.orientation,
|
|
643
694
|
coord: r.coord,
|
|
644
|
-
color: r.color ?? this.#
|
|
695
|
+
color: r.color ?? this.#h.line.color,
|
|
645
696
|
style: r.style,
|
|
646
697
|
width: r.width,
|
|
647
698
|
label: r.label
|
|
@@ -658,20 +709,20 @@ class _e extends Et {
|
|
|
658
709
|
* underlying animator mutates between frames.
|
|
659
710
|
*/
|
|
660
711
|
getAnimationState() {
|
|
661
|
-
return this.#
|
|
712
|
+
return this.#xt(this.#e.getAnimationState());
|
|
662
713
|
}
|
|
663
714
|
/** The engine animates Y in scale space (the scale's forward); readers outside it get values. */
|
|
664
|
-
#
|
|
715
|
+
#xt(t, e = this.yScale) {
|
|
665
716
|
const i = e.getTransform();
|
|
666
|
-
return i === null ? t : { ...t, yRange:
|
|
717
|
+
return i === null ? t : { ...t, yRange: Et(t.yRange, i) };
|
|
667
718
|
}
|
|
668
719
|
/** The animation state as a named scale's series see it: its own Y, in values. */
|
|
669
|
-
#
|
|
720
|
+
#Zt(t, e) {
|
|
670
721
|
const i = this.#e.getScaleYRange(e) ?? t.yRange;
|
|
671
|
-
return this.#
|
|
722
|
+
return this.#xt({ ...t, yRange: i }, this.getYScale(e));
|
|
672
723
|
}
|
|
673
724
|
/** `isPlottable` of a scale (`undefined` = default), as a predicate for the guard helpers. */
|
|
674
|
-
#
|
|
725
|
+
#vt(t) {
|
|
675
726
|
const e = this.getYScale(t);
|
|
676
727
|
return (i) => e.isPlottable(i);
|
|
677
728
|
}
|
|
@@ -701,10 +752,10 @@ class _e extends Et {
|
|
|
701
752
|
* has actually been observed in progress, so an annotation drawn on a chart
|
|
702
753
|
* that has no data yet still rides the reveal once data arrives.
|
|
703
754
|
*/
|
|
704
|
-
#
|
|
705
|
-
if (this.#
|
|
755
|
+
#St() {
|
|
756
|
+
if (this.#Vt) return 1;
|
|
706
757
|
const t = this.getIntroFront();
|
|
707
|
-
return t < 1 ? (this.#
|
|
758
|
+
return t < 1 ? (this.#Rt = !0, t) : (this.#Rt && (this.#Vt = !0), 1);
|
|
708
759
|
}
|
|
709
760
|
/**
|
|
710
761
|
* Entrance alpha for an overlay pinned at `time`, given the intro reveal
|
|
@@ -712,10 +763,10 @@ class _e extends Et {
|
|
|
712
763
|
* then fades in over a short band — so annotations surface in step with the
|
|
713
764
|
* series drawing past them. `1` once the intro has settled.
|
|
714
765
|
*/
|
|
715
|
-
#
|
|
766
|
+
#_t(t, e) {
|
|
716
767
|
if (t >= 1) return 1;
|
|
717
768
|
const { from: i, to: s } = this.timeScale.getRange(), r = s - i, n = r > 0 ? (e - i) / r : 0;
|
|
718
|
-
return
|
|
769
|
+
return se((t - n) / 0.12, 0, 1);
|
|
719
770
|
}
|
|
720
771
|
/**
|
|
721
772
|
* Replace all data for a series.
|
|
@@ -732,24 +783,24 @@ class _e extends Et {
|
|
|
732
783
|
setSeriesData(t, e, i) {
|
|
733
784
|
const s = this.#t.find((a) => a.id === t);
|
|
734
785
|
if (!s) return;
|
|
735
|
-
const r = this.#
|
|
736
|
-
if (this.#
|
|
786
|
+
const r = this.#n === "category" && this.#Tt(s);
|
|
787
|
+
if (this.#nt = !r, !this.#Tt(s)) {
|
|
737
788
|
s.renderer.setData(e, i);
|
|
738
789
|
return;
|
|
739
790
|
}
|
|
740
|
-
const n = this.#
|
|
791
|
+
const n = this.#Ut(s, e ?? []);
|
|
741
792
|
if (!r) {
|
|
742
793
|
s.renderer.setData(n, i);
|
|
743
794
|
return;
|
|
744
795
|
}
|
|
745
|
-
this.#
|
|
796
|
+
this.#kt({ entry: s, layerIndex: i, mutate: () => n });
|
|
746
797
|
}
|
|
747
798
|
/** Append a new data point to the end of a series (real-time tick). */
|
|
748
799
|
appendData(t, e, i) {
|
|
749
800
|
const s = this.#t.find((n) => n.id === t);
|
|
750
801
|
if (s === void 0 || s.renderer.appendPoint === void 0) return;
|
|
751
802
|
const r = s.renderer.appendPoint.bind(s.renderer);
|
|
752
|
-
this.#
|
|
803
|
+
this.#bt({
|
|
753
804
|
entry: s,
|
|
754
805
|
layerIndex: i,
|
|
755
806
|
points: [e],
|
|
@@ -763,19 +814,19 @@ class _e extends Et {
|
|
|
763
814
|
* category axis applies `mutateCategory` to the layer's input-order points
|
|
764
815
|
* instead, then re-sets the store from them.
|
|
765
816
|
*/
|
|
766
|
-
#
|
|
817
|
+
#bt(t) {
|
|
767
818
|
const { entry: e, apply: i } = t;
|
|
768
|
-
if (!this.#
|
|
819
|
+
if (!this.#Tt(e)) {
|
|
769
820
|
i(t.points.slice());
|
|
770
821
|
return;
|
|
771
822
|
}
|
|
772
|
-
const s = this.#
|
|
823
|
+
const s = this.#Ut(e, t.points);
|
|
773
824
|
if (s.length !== 0) {
|
|
774
|
-
if (this.#
|
|
825
|
+
if (this.#n === "numeric") {
|
|
775
826
|
i(s);
|
|
776
827
|
return;
|
|
777
828
|
}
|
|
778
|
-
this.#
|
|
829
|
+
this.#kt({
|
|
779
830
|
entry: e,
|
|
780
831
|
layerIndex: t.layerIndex,
|
|
781
832
|
mutate: (r) => t.mutateCategory(r, s)
|
|
@@ -783,66 +834,66 @@ class _e extends Et {
|
|
|
783
834
|
}
|
|
784
835
|
}
|
|
785
836
|
/** Replace a category layer's input-order points with `mutate`'s result and sync the categories and stores. */
|
|
786
|
-
#
|
|
837
|
+
#kt(t) {
|
|
787
838
|
const { entry: e } = t, i = t.layerIndex ?? 0;
|
|
788
|
-
e.categoryPoints[i] = t.mutate(e.categoryPoints[i] ?? []), this.#
|
|
839
|
+
e.categoryPoints[i] = t.mutate(e.categoryPoints[i] ?? []), this.#Gt({ entry: e, layerIndex: i });
|
|
789
840
|
}
|
|
790
841
|
/** Whether `entry`'s points go through the numeric / category ingest. */
|
|
791
|
-
#
|
|
792
|
-
return this.#
|
|
842
|
+
#Tt(t) {
|
|
843
|
+
return this.#n !== "time" && S(t.renderer);
|
|
793
844
|
}
|
|
794
845
|
/**
|
|
795
846
|
* Points that fit the X axis, a numeric one with its `x` copied to `time`.
|
|
796
847
|
* The rest are skipped with a dev warning, as is a series mixing `x` and `time`.
|
|
797
848
|
*/
|
|
798
|
-
#
|
|
849
|
+
#Ut(t, e) {
|
|
799
850
|
const i = [];
|
|
800
851
|
for (const s of e) {
|
|
801
852
|
const r = s.x !== void 0;
|
|
802
|
-
if (r && (t.xKeys.x = !0), s.time !== void 0 && (t.xKeys.time = !0), !(this.#
|
|
803
|
-
this.#
|
|
853
|
+
if (r && (t.xKeys.x = !0), s.time !== void 0 && (t.xKeys.time = !0), !(this.#n === "category" ? typeof s.x == "string" : !r || typeof s.x == "number")) {
|
|
854
|
+
this.#V(
|
|
804
855
|
`x-misfit:${t.id}`,
|
|
805
|
-
() =>
|
|
856
|
+
() => $t({ seriesId: t.id, axisType: this.#n, x: s.x })
|
|
806
857
|
);
|
|
807
858
|
continue;
|
|
808
859
|
}
|
|
809
|
-
i.push(r && this.#
|
|
860
|
+
i.push(r && this.#n === "numeric" ? { ...s, time: s.x } : s);
|
|
810
861
|
}
|
|
811
|
-
return t.xKeys.x && t.xKeys.time && this.#
|
|
862
|
+
return t.xKeys.x && t.xKeys.time && this.#V(`x-mixed:${t.id}`, () => zt({ seriesId: t.id })), i;
|
|
812
863
|
}
|
|
813
864
|
/** Category points with `time` set to their band index. */
|
|
814
|
-
#
|
|
815
|
-
return t.map((e) => ({ ...e, time: this.#
|
|
865
|
+
#Te(t) {
|
|
866
|
+
return t.map((e) => ({ ...e, time: this.#O.get(e.x) }));
|
|
816
867
|
}
|
|
817
868
|
/**
|
|
818
869
|
* Re-derive the categories — first-seen order across the series (mount
|
|
819
870
|
* order, then layers, then points in input order) — and re-set every store
|
|
820
871
|
* whose band indices moved, plus the `changed` layer.
|
|
821
872
|
*/
|
|
822
|
-
#
|
|
873
|
+
#Gt(t) {
|
|
823
874
|
const e = /* @__PURE__ */ new Set();
|
|
824
875
|
for (const a of this.#t)
|
|
825
876
|
for (const o of a.categoryPoints)
|
|
826
877
|
for (const h of o ?? [])
|
|
827
878
|
e.add(h.x);
|
|
828
|
-
const i = [...e], s = this.timeScale.getCategories(), r = i.length !== s.length || i.some((a, o) => a !== s[o]), n = this.#
|
|
829
|
-
this.#
|
|
879
|
+
const i = [...e], s = this.timeScale.getCategories(), r = i.length !== s.length || i.some((a, o) => a !== s[o]), n = this.#O;
|
|
880
|
+
this.#O = new Map(i.map((a, o) => [a, o])), this.timeScale.setCategories(i), this.batch(() => {
|
|
830
881
|
for (const a of this.#t)
|
|
831
|
-
this.#
|
|
882
|
+
this.#we({ entry: a, previous: n, changed: t });
|
|
832
883
|
r && this.onDataChanged();
|
|
833
884
|
});
|
|
834
885
|
}
|
|
835
886
|
/** Re-set `entry`'s layers whose points moved band, or that `changed` names, from their input-order points. */
|
|
836
|
-
#
|
|
887
|
+
#we(t) {
|
|
837
888
|
const { entry: e, previous: i, changed: s } = t;
|
|
838
889
|
for (let r = 0; r < e.categoryPoints.length; r++) {
|
|
839
890
|
const n = e.categoryPoints[r] ?? [], a = s?.entry === e && s.layerIndex === r, o = n.some(
|
|
840
|
-
(
|
|
891
|
+
(c) => i.get(c.x) !== this.#O.get(c.x)
|
|
841
892
|
);
|
|
842
893
|
if (!a && !o) continue;
|
|
843
|
-
const h = this.#
|
|
844
|
-
const f = i.get(
|
|
845
|
-
return f !== void 0 && f !== this.#
|
|
894
|
+
const h = this.#Te(n).sort((c, f) => c.time - f.time), l = n.some((c) => {
|
|
895
|
+
const f = i.get(c.x);
|
|
896
|
+
return f !== void 0 && f !== this.#O.get(c.x);
|
|
846
897
|
});
|
|
847
898
|
a && !l && e.renderer.morphData !== void 0 ? e.renderer.morphData(h, r) : e.renderer.setData(h, r);
|
|
848
899
|
}
|
|
@@ -863,10 +914,10 @@ class _e extends Et {
|
|
|
863
914
|
prependData(t, e, i) {
|
|
864
915
|
const s = this.#t.find((a) => a.id === t);
|
|
865
916
|
if (s === void 0 || s.renderer.prependPoints === void 0) return;
|
|
866
|
-
const r = this.#
|
|
867
|
-
r !== null && s.renderer.setHistoryHandoff !== void 0 && performance.now() - r.at <
|
|
917
|
+
const r = this.#ct.left;
|
|
918
|
+
r !== null && s.renderer.setHistoryHandoff !== void 0 && performance.now() - r.at < he && (s.renderer.setHistoryHandoff(r.bars), this.#E.left = !0, this.#K.left = null, this.#ct.left = null, this.#d.markDirty());
|
|
868
919
|
const n = s.renderer.prependPoints.bind(s.renderer);
|
|
869
|
-
this.#
|
|
920
|
+
this.#bt({
|
|
870
921
|
entry: s,
|
|
871
922
|
layerIndex: i,
|
|
872
923
|
points: e,
|
|
@@ -879,7 +930,7 @@ class _e extends Et {
|
|
|
879
930
|
const s = this.#t.find((n) => n.id === t);
|
|
880
931
|
if (s === void 0 || s.renderer.updateLastPoint === void 0) return;
|
|
881
932
|
const r = s.renderer.updateLastPoint.bind(s.renderer);
|
|
882
|
-
this.#
|
|
933
|
+
this.#bt({
|
|
883
934
|
entry: s,
|
|
884
935
|
layerIndex: i,
|
|
885
936
|
points: [e],
|
|
@@ -904,11 +955,11 @@ class _e extends Et {
|
|
|
904
955
|
keepLast(t, e, i) {
|
|
905
956
|
const s = this.#t.find((r) => r.id === t);
|
|
906
957
|
if (s?.renderer.keepLast !== void 0) {
|
|
907
|
-
if (this.#
|
|
958
|
+
if (this.#n !== "category") {
|
|
908
959
|
s.renderer.keepLast(e, i);
|
|
909
960
|
return;
|
|
910
961
|
}
|
|
911
|
-
this.#
|
|
962
|
+
this.#kt({
|
|
912
963
|
entry: s,
|
|
913
964
|
layerIndex: i,
|
|
914
965
|
mutate: (r) => e < 0 ? [...r] : r.slice(Math.max(0, r.length - e))
|
|
@@ -920,21 +971,21 @@ class _e extends Et {
|
|
|
920
971
|
* (time series) moves it onto a named Y scale, `undefined` back to the default.
|
|
921
972
|
*/
|
|
922
973
|
updateSeriesOptions(t, e) {
|
|
923
|
-
const i = this.#t.find((
|
|
974
|
+
const i = this.#t.find((m) => m.id === t);
|
|
924
975
|
if (!i) return;
|
|
925
976
|
const { scale: s, ...r } = e, n = "scale" in e, a = n ? s : i.scale;
|
|
926
977
|
if (("stacking" in e || n) && a === void 0) {
|
|
927
|
-
const
|
|
928
|
-
|
|
978
|
+
const m = "stacking" in e ? e.stacking : lt(i.renderer);
|
|
979
|
+
R({ seriesId: t, stacking: m, isPlottable: this.#vt(a) });
|
|
929
980
|
}
|
|
930
981
|
const o = i.labels, h = i.renderer.getLayerColors().slice(), l = this.#g.overrides(i.renderer.kind);
|
|
931
982
|
i.renderer.updateOptions({ ...r, ...l }), "label" in e && typeof e.label == "string" && (i.labels = [e.label]), this.#i.markDirty();
|
|
932
|
-
const
|
|
983
|
+
const c = this.#I(i);
|
|
933
984
|
i.scale = a;
|
|
934
|
-
const f = this.#
|
|
935
|
-
f && this.#
|
|
936
|
-
const
|
|
937
|
-
(
|
|
985
|
+
const f = this.#I(i) !== c;
|
|
986
|
+
f && this.#Le();
|
|
987
|
+
const g = i.renderer.getLayerColors(), y = h.length !== g.length || h.some((m, p) => m !== g[p]), u = !ht(o, i.labels);
|
|
988
|
+
(y || u || f) && this.#m();
|
|
938
989
|
}
|
|
939
990
|
/**
|
|
940
991
|
* Batch multiple updates: suppress recomputes until `fn` returns. Exceptions
|
|
@@ -946,14 +997,14 @@ class _e extends Et {
|
|
|
946
997
|
t();
|
|
947
998
|
} finally {
|
|
948
999
|
if (--this.#R <= 0) {
|
|
949
|
-
if (this.#R = 0, this.#
|
|
950
|
-
this.#
|
|
951
|
-
else if (this.#
|
|
952
|
-
this.#
|
|
1000
|
+
if (this.#R = 0, this.#dt)
|
|
1001
|
+
this.#dt = !1, this.#B = !1, this.onDataChanged();
|
|
1002
|
+
else if (this.#B) {
|
|
1003
|
+
this.#B = !1, this.#u = !0;
|
|
953
1004
|
const e = performance.now();
|
|
954
1005
|
this.#e.onSeriesVisibilityChanged(e), this.#x(e), this.#i.markDirty();
|
|
955
1006
|
}
|
|
956
|
-
this.#
|
|
1007
|
+
this.#ut && (this.#ut = !1, this.emit("overlayChange"));
|
|
957
1008
|
}
|
|
958
1009
|
}
|
|
959
1010
|
}
|
|
@@ -967,13 +1018,13 @@ class _e extends Et {
|
|
|
967
1018
|
setSeriesVisible(t, e) {
|
|
968
1019
|
const i = this.#t.find((n) => n.id === t);
|
|
969
1020
|
if (!i || i.visible === e) return;
|
|
970
|
-
i.visible = e, this.#
|
|
1021
|
+
i.visible = e, this.#m(), this.#rt();
|
|
971
1022
|
const s = this.#g.toggleMs;
|
|
972
1023
|
if (i.renderer.setAlpha?.(e ? 1 : 0, s), this.#i.markDirty(), this.#R > 0) {
|
|
973
|
-
this.#
|
|
1024
|
+
this.#B = !0;
|
|
974
1025
|
return;
|
|
975
1026
|
}
|
|
976
|
-
this.#
|
|
1027
|
+
this.#u = !0;
|
|
977
1028
|
const r = performance.now();
|
|
978
1029
|
this.#e.onSeriesVisibilityChanged(r), this.#x(r);
|
|
979
1030
|
}
|
|
@@ -1003,28 +1054,28 @@ class _e extends Et {
|
|
|
1003
1054
|
setLayerVisible(t, e, i) {
|
|
1004
1055
|
const s = this.#t.find((a) => a.id === t);
|
|
1005
1056
|
if (!s || s.renderer.getLayerCount() <= 1 || s.renderer.isLayerVisible(e) === i) return;
|
|
1006
|
-
s.renderer.setLayerVisible(e, i), this.#
|
|
1057
|
+
s.renderer.setLayerVisible(e, i), this.#m();
|
|
1007
1058
|
const r = this.#g.toggleMs;
|
|
1008
1059
|
if (s.renderer.setLayerAlpha?.(e, i ? 1 : 0, r), this.#i.markDirty(), this.#R > 0) {
|
|
1009
|
-
this.#
|
|
1060
|
+
this.#B = !0;
|
|
1010
1061
|
return;
|
|
1011
1062
|
}
|
|
1012
|
-
this.#
|
|
1063
|
+
this.#u = !0;
|
|
1013
1064
|
const n = performance.now();
|
|
1014
1065
|
this.#e.onSeriesVisibilityChanged(n), this.#x(n);
|
|
1015
1066
|
}
|
|
1016
1067
|
isLayerVisible(t, e) {
|
|
1017
1068
|
return this.#t.find((i) => i.id === t)?.renderer.isLayerVisible(e) ?? !0;
|
|
1018
1069
|
}
|
|
1019
|
-
/** Auto-fit the viewport to show all data across every series. */
|
|
1070
|
+
/** Auto-fit the viewport to show all data across every series, however many bars that is. */
|
|
1020
1071
|
fitContent() {
|
|
1021
1072
|
const { first: t, last: e } = this.getDataBounds();
|
|
1022
1073
|
if (t === void 0 || e === void 0) return;
|
|
1023
|
-
const i = this.#
|
|
1024
|
-
this.#
|
|
1074
|
+
const i = this.#c.size.media.width - this.#k();
|
|
1075
|
+
this.#et(), this.#Pt({ firstTime: t, lastTime: e, chartWidth: i }), this.#se({ xEase: !0 });
|
|
1025
1076
|
}
|
|
1026
1077
|
getVisibleRange() {
|
|
1027
|
-
return this.#
|
|
1078
|
+
return this.#a.from === 0 && this.#a.to === 0 ? this.#e.getAnimationState().xRange : this.#a;
|
|
1028
1079
|
}
|
|
1029
1080
|
/**
|
|
1030
1081
|
* Return the full span of registered data, or `null` before any data has
|
|
@@ -1032,7 +1083,7 @@ class _e extends Et {
|
|
|
1032
1083
|
* tracking and is cheaper than recomputing from series stores.
|
|
1033
1084
|
*/
|
|
1034
1085
|
getDataRange() {
|
|
1035
|
-
return this.#
|
|
1086
|
+
return this.#T === null || this.#s === null ? null : { from: this.#T, to: this.#s };
|
|
1036
1087
|
}
|
|
1037
1088
|
/**
|
|
1038
1089
|
* Imperatively set the visible time range. Three forms:
|
|
@@ -1059,31 +1110,44 @@ class _e extends Et {
|
|
|
1059
1110
|
* lockstep rather than lagging behind on the long sticky contract.
|
|
1060
1111
|
*/
|
|
1061
1112
|
setVisibleRange(t, e) {
|
|
1113
|
+
const i = this.#jt(t);
|
|
1114
|
+
if (i !== null) {
|
|
1115
|
+
if (this.#et(), e?.gesture && ye(t)) {
|
|
1116
|
+
i && this.#$e();
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
this.#se();
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Write `spec` into the logical X range, the autoscroll flag and the warm-up
|
|
1124
|
+
* hold, without touching the engine. Returns whether the range changed, or
|
|
1125
|
+
* `null` when the spec is invalid or a bar count has no data to count back from.
|
|
1126
|
+
*/
|
|
1127
|
+
#jt(t) {
|
|
1062
1128
|
if (typeof t == "number") {
|
|
1063
|
-
if (!
|
|
1064
|
-
const { first:
|
|
1065
|
-
if (
|
|
1066
|
-
const
|
|
1067
|
-
this.#
|
|
1068
|
-
return;
|
|
1129
|
+
if (!A(t)) return null;
|
|
1130
|
+
const { first: s, last: r } = this.getDataBounds();
|
|
1131
|
+
if (s === void 0 || r === void 0) return null;
|
|
1132
|
+
const n = Math.max(s, r - (t - 1) * this.#r), a = this.#c.size.media.width - this.#k();
|
|
1133
|
+
return this.#Pt({ firstTime: n, lastTime: r, chartWidth: a });
|
|
1069
1134
|
}
|
|
1070
1135
|
if ("bars" in t) {
|
|
1071
|
-
if (!
|
|
1072
|
-
const
|
|
1073
|
-
this.#p = this.#s !== null && this.#s >=
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
const i = k(t.from), s = k(t.to);
|
|
1077
|
-
this.#p = this.#s !== null && this.#s >= i && this.#s <= s, this.#L = !1;
|
|
1078
|
-
const r = this.#H({ from: i, to: s }, { emitChange: !0 });
|
|
1079
|
-
if (e?.gesture) {
|
|
1080
|
-
r && this.#Te();
|
|
1081
|
-
return;
|
|
1136
|
+
if (!A(t.bars)) return null;
|
|
1137
|
+
const s = k(t.from), r = s + t.bars * this.#r;
|
|
1138
|
+
this.#p = this.#s !== null && this.#s >= s && this.#s <= r;
|
|
1139
|
+
const n = this.#D({ from: s, to: r }, { emitChange: !0 });
|
|
1140
|
+
return this.#L = !0, n;
|
|
1082
1141
|
}
|
|
1083
|
-
|
|
1142
|
+
const e = k(t.from), i = k(t.to);
|
|
1143
|
+
return this.#p = this.#s !== null && this.#s >= e && this.#s <= i, this.#L = !1, this.#D({ from: e, to: i }, { emitChange: !0 });
|
|
1144
|
+
}
|
|
1145
|
+
/** The user or the app took over the view: drop `initialRange` and stop growing the chart's own fit. */
|
|
1146
|
+
#et() {
|
|
1147
|
+
this.#H = void 0, this.#U = !1;
|
|
1084
1148
|
}
|
|
1085
1149
|
getYRange() {
|
|
1086
|
-
return this.#
|
|
1150
|
+
return this.#w.range;
|
|
1087
1151
|
}
|
|
1088
1152
|
getCrosshairPosition() {
|
|
1089
1153
|
return this.#f;
|
|
@@ -1124,7 +1188,7 @@ class _e extends Et {
|
|
|
1124
1188
|
setCrosshair(t) {
|
|
1125
1189
|
if (t === null) {
|
|
1126
1190
|
if (this.#f === null) return;
|
|
1127
|
-
this.#f = null, this.#
|
|
1191
|
+
this.#f = null, this.#d.markDirty(), this.emit("crosshairMove", null);
|
|
1128
1192
|
return;
|
|
1129
1193
|
}
|
|
1130
1194
|
const { time: e } = t;
|
|
@@ -1133,19 +1197,19 @@ class _e extends Et {
|
|
|
1133
1197
|
let s;
|
|
1134
1198
|
if (t.y !== void 0 ? s = t.y : i !== null ? s = i.y : s = this.yScale.yToValue(this.yScale.getMediaHeight() / 2), !Number.isFinite(s) || i !== null && i.time === e && i.y === s) return;
|
|
1135
1199
|
const r = this.plotLeft + this.timeScale.timeToX(e), n = this.yScale.valueToY(s);
|
|
1136
|
-
this.#
|
|
1200
|
+
this.#lt = "time", this.#f = { mediaX: r, mediaY: n, time: e, x: this.timeScale.domainValue(e), y: s }, this.#d.markDirty(), this.emit("crosshairMove", this.#f);
|
|
1137
1201
|
}
|
|
1138
1202
|
/** Get the last visible value and whether the absolute last point is on screen. */
|
|
1139
1203
|
getLastValue(t) {
|
|
1140
|
-
return
|
|
1204
|
+
return wt(t, this.#t, this.#e.getAnimationState().xRange);
|
|
1141
1205
|
}
|
|
1142
1206
|
/** Get the second-to-last value, useful for computing change. */
|
|
1143
1207
|
getPreviousClose(t) {
|
|
1144
|
-
return
|
|
1208
|
+
return Mt(t, this.#t);
|
|
1145
1209
|
}
|
|
1146
1210
|
getLastData(t) {
|
|
1147
1211
|
const e = this.#t.find((i) => i.id === t);
|
|
1148
|
-
return !e || !
|
|
1212
|
+
return !e || !S(e.renderer) ? null : e.renderer.getLastDataPoint();
|
|
1149
1213
|
}
|
|
1150
1214
|
/** Find the data point closest to the given timestamp within one data interval. */
|
|
1151
1215
|
getDataAtTime(t, e) {
|
|
@@ -1169,10 +1233,10 @@ class _e extends Et {
|
|
|
1169
1233
|
* past a wide gap is still the nearest.
|
|
1170
1234
|
*/
|
|
1171
1235
|
#X() {
|
|
1172
|
-
return this.#
|
|
1236
|
+
return this.#n === "category" ? 0.5 : this.#n === "time" || this.#T === null || this.#s === null ? this.#r : Math.max(this.#r, this.#s - this.#T);
|
|
1173
1237
|
}
|
|
1174
1238
|
getSeriesIds() {
|
|
1175
|
-
return this.#
|
|
1239
|
+
return this.#F || (this.#F = this.#t.map((t) => t.id)), this.#F.slice();
|
|
1176
1240
|
}
|
|
1177
1241
|
/**
|
|
1178
1242
|
* True if any visible series has a time axis (line / bar / candlestick).
|
|
@@ -1180,9 +1244,9 @@ class _e extends Et {
|
|
|
1180
1244
|
* has no meaningful x/y coordinate system, so the dashed hairlines would
|
|
1181
1245
|
* just be visual noise.
|
|
1182
1246
|
*/
|
|
1183
|
-
#
|
|
1247
|
+
#Kt() {
|
|
1184
1248
|
for (const t of this.#t)
|
|
1185
|
-
if (t.visible &&
|
|
1249
|
+
if (t.visible && S(t.renderer))
|
|
1186
1250
|
return !0;
|
|
1187
1251
|
return !1;
|
|
1188
1252
|
}
|
|
@@ -1192,8 +1256,8 @@ class _e extends Et {
|
|
|
1192
1256
|
* to reserve and nothing slides under an axis column. Reads registration,
|
|
1193
1257
|
* not visibility — a legend toggle must not shift the layout.
|
|
1194
1258
|
*/
|
|
1195
|
-
#
|
|
1196
|
-
return this.#t.length === 0 ? !1 : this.#t.every((t) => !
|
|
1259
|
+
#it() {
|
|
1260
|
+
return this.#t.length === 0 ? !1 : this.#t.every((t) => !S(t.renderer));
|
|
1197
1261
|
}
|
|
1198
1262
|
#Z() {
|
|
1199
1263
|
return {
|
|
@@ -1206,8 +1270,8 @@ class _e extends Et {
|
|
|
1206
1270
|
}
|
|
1207
1271
|
/** Reassign the Y-axis columns, then resync the scales if the gutters moved
|
|
1208
1272
|
* and let DOM axis / label components re-read the layout, as they do after a resize. */
|
|
1209
|
-
#
|
|
1210
|
-
this.#
|
|
1273
|
+
#st(t) {
|
|
1274
|
+
this.#wt();
|
|
1211
1275
|
const e = this.#Z();
|
|
1212
1276
|
(e.yAxisWidth !== t.yAxisWidth || e.xAxisHeight !== t.xAxisHeight || e.yAxisPosition !== t.yAxisPosition || e.leftWidth !== t.leftWidth || e.rightWidth !== t.rightWidth) && (this.syncScales(), this.emit("viewportChange"), this.#i.markDirty());
|
|
1213
1277
|
}
|
|
@@ -1218,7 +1282,7 @@ class _e extends Et {
|
|
|
1218
1282
|
* capturing wheel and touch events, so the page scrolls normally under the cursor.
|
|
1219
1283
|
*/
|
|
1220
1284
|
canPanZoom() {
|
|
1221
|
-
return (this.#v.x?.panZoom ?? this.#
|
|
1285
|
+
return (this.#v.x?.panZoom ?? this.#n !== "category") && this.#Kt();
|
|
1222
1286
|
}
|
|
1223
1287
|
/**
|
|
1224
1288
|
* Whether a time-only feature (Navigator, EdgeLoader, TimeRegion) can run
|
|
@@ -1228,7 +1292,7 @@ class _e extends Et {
|
|
|
1228
1292
|
* @internal
|
|
1229
1293
|
*/
|
|
1230
1294
|
checkTimeOnlyFeature(t) {
|
|
1231
|
-
return this.#
|
|
1295
|
+
return this.#n === "time" ? !0 : (this.#V(`time-only:${t}`, () => Ot({ feature: t, axisType: this.#n })), !1);
|
|
1232
1296
|
}
|
|
1233
1297
|
/**
|
|
1234
1298
|
* Push the current pan/zoom capability into the interaction layer (canvas
|
|
@@ -1237,8 +1301,8 @@ class _e extends Et {
|
|
|
1237
1301
|
* every mutation that can flip {@link canPanZoom}: series add/remove and
|
|
1238
1302
|
* series visibility.
|
|
1239
1303
|
*/
|
|
1240
|
-
#
|
|
1241
|
-
this.#
|
|
1304
|
+
#rt() {
|
|
1305
|
+
this.#N?.syncPanZoomMode();
|
|
1242
1306
|
}
|
|
1243
1307
|
/**
|
|
1244
1308
|
* Filter `getSeriesIds()` by renderer type. A concrete kind (`'pie'`,
|
|
@@ -1254,7 +1318,7 @@ class _e extends Et {
|
|
|
1254
1318
|
getSeriesIdsByType(t, e) {
|
|
1255
1319
|
const i = e?.visibleOnly === !0, s = e?.singleLayerOnly === !0, r = [];
|
|
1256
1320
|
for (const n of this.#t) {
|
|
1257
|
-
if (!(t === "time" ?
|
|
1321
|
+
if (!(t === "time" ? S(n.renderer) : n.renderer.kind === t)) continue;
|
|
1258
1322
|
const a = n.renderer.getLayerCount();
|
|
1259
1323
|
if (!(s && a > 1)) {
|
|
1260
1324
|
if (i) {
|
|
@@ -1281,7 +1345,7 @@ class _e extends Et {
|
|
|
1281
1345
|
* Returns `null` for unknown ids or empty series.
|
|
1282
1346
|
*/
|
|
1283
1347
|
getStackedLastValue(t) {
|
|
1284
|
-
return
|
|
1348
|
+
return At(t, this.#t, this.#e.getAnimationState().xRange);
|
|
1285
1349
|
}
|
|
1286
1350
|
/**
|
|
1287
1351
|
* Stacked value at an arbitrary `time` — the cumulative stack top at that
|
|
@@ -1296,7 +1360,7 @@ class _e extends Et {
|
|
|
1296
1360
|
const s = i.renderer.getStackedValueAtTime?.(e, this.#X());
|
|
1297
1361
|
if (s != null) return s;
|
|
1298
1362
|
const r = i.renderer.getDataAtTime?.(e, this.#X());
|
|
1299
|
-
return !r ||
|
|
1363
|
+
return !r || ae(r) ? null : tt(r);
|
|
1300
1364
|
}
|
|
1301
1365
|
/**
|
|
1302
1366
|
* Per-layer last snapshots with each layer's own `time`. Returns `null`
|
|
@@ -1320,7 +1384,7 @@ class _e extends Et {
|
|
|
1320
1384
|
/** Get the primary display color for a series. */
|
|
1321
1385
|
getSeriesColor(t) {
|
|
1322
1386
|
const e = this.#t.find((i) => i.id === t);
|
|
1323
|
-
return e ? e.renderer.getLayerColors()[0] ?? this.#
|
|
1387
|
+
return e ? e.renderer.getLayerColors()[0] ?? this.#h.line.color : null;
|
|
1324
1388
|
}
|
|
1325
1389
|
/** The series' primary name (first layer). Used for single-layer overlays. */
|
|
1326
1390
|
getSeriesLabel(t) {
|
|
@@ -1338,7 +1402,7 @@ class _e extends Et {
|
|
|
1338
1402
|
*/
|
|
1339
1403
|
setSeriesLabels(t, e) {
|
|
1340
1404
|
const i = this.#t.find((s) => s.id === t);
|
|
1341
|
-
!i ||
|
|
1405
|
+
!i || ht(i.labels, e) || (i.labels = e, this.#m());
|
|
1342
1406
|
}
|
|
1343
1407
|
/**
|
|
1344
1408
|
* Set the per-layer color overrides carried in `data` (sparse — `undefined`
|
|
@@ -1349,7 +1413,7 @@ class _e extends Et {
|
|
|
1349
1413
|
*/
|
|
1350
1414
|
setLayerColors(t, e) {
|
|
1351
1415
|
const i = this.#t.find((s) => s.id === t);
|
|
1352
|
-
!i ||
|
|
1416
|
+
!i || ke(i.colorOverrides, e) || (i.colorOverrides = e, i.renderer.setColorOverrides?.(e), this.#i.markDirty(), this.#m());
|
|
1353
1417
|
}
|
|
1354
1418
|
/** Get per-layer colors for a series. Returns null for single-layer non-bar/line series. */
|
|
1355
1419
|
getSeriesLayers(t) {
|
|
@@ -1362,50 +1426,50 @@ class _e extends Et {
|
|
|
1362
1426
|
}
|
|
1363
1427
|
/** Get all slices with computed colors and percentages. Returns null for series without slice data (e.g. candlestick, line, bar). */
|
|
1364
1428
|
getSliceInfo(t) {
|
|
1365
|
-
return this.#t.find((e) => e.id === t)?.renderer.getSliceInfo?.(this.#
|
|
1429
|
+
return this.#t.find((e) => e.id === t)?.renderer.getSliceInfo?.(this.#h) ?? null;
|
|
1366
1430
|
}
|
|
1367
1431
|
/** Get hover info (label/value/percent/color) for the currently hovered element, or null. */
|
|
1368
1432
|
getHoverInfo(t) {
|
|
1369
|
-
return this.#t.find((e) => e.id === t)?.renderer.getHoverInfo?.(this.#
|
|
1433
|
+
return this.#t.find((e) => e.id === t)?.renderer.getHoverInfo?.(this.#h) ?? null;
|
|
1370
1434
|
}
|
|
1371
1435
|
/** Apply a new theme and update series colors where appropriate. */
|
|
1372
1436
|
setTheme(t) {
|
|
1373
|
-
const e = this.#
|
|
1374
|
-
this.#
|
|
1437
|
+
const e = this.#h;
|
|
1438
|
+
this.#h = t;
|
|
1375
1439
|
for (const i of this.#t)
|
|
1376
1440
|
i.renderer.applyTheme(t, e);
|
|
1377
|
-
this.#i.markDirty(), this.#
|
|
1441
|
+
this.#i.markDirty(), this.#m();
|
|
1378
1442
|
}
|
|
1379
1443
|
getTheme() {
|
|
1380
|
-
return this.#
|
|
1444
|
+
return this.#h;
|
|
1381
1445
|
}
|
|
1382
1446
|
/** BCP 47 locale applied to the built-in time-axis / tooltip / crosshair formatting. */
|
|
1383
1447
|
setLocale(t) {
|
|
1384
|
-
this.timeScale.setLocale(t), this.#
|
|
1448
|
+
this.timeScale.setLocale(t), this.#m();
|
|
1385
1449
|
}
|
|
1386
1450
|
getLocale() {
|
|
1387
1451
|
return this.timeScale.getLocale();
|
|
1388
1452
|
}
|
|
1389
1453
|
/** IANA timezone applied to the same built-in date-time formatting. */
|
|
1390
1454
|
setTimeZone(t) {
|
|
1391
|
-
this.timeScale.setTimeZone(t), this.#
|
|
1455
|
+
this.timeScale.setTimeZone(t), this.#m();
|
|
1392
1456
|
}
|
|
1393
1457
|
getTimeZone() {
|
|
1394
1458
|
return this.timeScale.getTimeZone();
|
|
1395
1459
|
}
|
|
1396
1460
|
/** Update axis configuration and re-render. */
|
|
1397
1461
|
setAxis(t) {
|
|
1398
|
-
const e = t.y?.scale ?? null, i = (
|
|
1399
|
-
for (const
|
|
1400
|
-
!
|
|
1462
|
+
const e = t.y?.scale ?? null, i = (c) => Q(e, c);
|
|
1463
|
+
for (const c of this.#t)
|
|
1464
|
+
!S(c.renderer) || c.scale !== void 0 || R({ seriesId: c.id, stacking: c.renderer.stacking, isPlottable: i });
|
|
1401
1465
|
const s = this.#Z(), r = e !== this.yScale.getTransform(), n = t.x?.type ?? "time";
|
|
1402
|
-
n !== this.#
|
|
1466
|
+
n !== this.#n && this.#V("x-type", () => Yt({ from: this.#n, to: n }));
|
|
1403
1467
|
const a = this.timeScale.getBandPadding();
|
|
1404
1468
|
this.timeScale.setBandPadding(t.x?.padding);
|
|
1405
1469
|
const o = this.timeScale.getBandPadding(), h = a.inner !== o.inner || a.outer !== o.outer;
|
|
1406
|
-
this.#v = t, this.#
|
|
1470
|
+
this.#v = t, this.#w.bounds = { min: t.y?.min, max: t.y?.max }, D({ y: t.y, isPlottable: i });
|
|
1407
1471
|
const l = performance.now();
|
|
1408
|
-
r && (this.yScale.setTransform(e), this.yScale.tickTracker.reset(), this.#
|
|
1472
|
+
r && (this.yScale.setTransform(e), this.yScale.tickTracker.reset(), this.#G() === null && this.#e.snap({ y: { min: 0, max: 0 } }, l)), this.#u = !0, this.#e.onAxisReconfig(l), this.#x(l), this.#st(s), this.#rt(), h && this.#n === "category" && this.fitContent(), this.#i.markDirty();
|
|
1409
1473
|
}
|
|
1410
1474
|
/**
|
|
1411
1475
|
* Replace the named Y scales (see {@link ChartOptions.scales}). Added,
|
|
@@ -1414,69 +1478,69 @@ class _e extends Et {
|
|
|
1414
1478
|
*/
|
|
1415
1479
|
setScales(t) {
|
|
1416
1480
|
const e = t ?? {};
|
|
1417
|
-
if (
|
|
1418
|
-
const i = this.#Z(), s = this.#
|
|
1419
|
-
this.#
|
|
1481
|
+
if (ie(e, this.#It)) return;
|
|
1482
|
+
const i = this.#Z(), s = this.#qt(e);
|
|
1483
|
+
this.#wt();
|
|
1420
1484
|
const r = performance.now(), n = {};
|
|
1421
1485
|
for (const a of s)
|
|
1422
|
-
this.#
|
|
1423
|
-
this.#e.snap({ scales: n }, r), this.#
|
|
1486
|
+
this.#G(void 0, a) === null && (n[a] = { min: 0, max: 0 });
|
|
1487
|
+
this.#e.snap({ scales: n }, r), this.#u = !0, this.#e.onAxisReconfig(r), this.#x(r), this.#st(i), this.emit("viewportChange"), this.#m(), this.#i.markDirty();
|
|
1424
1488
|
}
|
|
1425
1489
|
/**
|
|
1426
1490
|
* Create, update and drop named-scale slots to match `next`, in its key
|
|
1427
1491
|
* order. Returns the ids of existing scales whose transform changed.
|
|
1428
1492
|
*/
|
|
1429
|
-
#
|
|
1493
|
+
#qt(t) {
|
|
1430
1494
|
const e = /* @__PURE__ */ new Map(), i = [];
|
|
1431
1495
|
for (const [s, r] of Object.entries(t)) {
|
|
1432
1496
|
const n = r.scale ?? null;
|
|
1433
|
-
let a = this.#
|
|
1497
|
+
let a = this.#o.get(s);
|
|
1434
1498
|
if (a === void 0) {
|
|
1435
|
-
const o = new
|
|
1436
|
-
o.setTransform(n), o.tickTracker.setFadeMs(this.#g.axis.ticksMs), a = { ...
|
|
1499
|
+
const o = new J();
|
|
1500
|
+
o.setTransform(n), o.tickTracker.setFadeMs(this.#g.axis.ticksMs), a = { ...rt(o, r), config: r, column: null };
|
|
1437
1501
|
} else n !== a.yScale.getTransform() && (a.yScale.setTransform(n), a.yScale.tickTracker.reset(), i.push(s));
|
|
1438
|
-
a.config = { ...r }, a.bounds = { min: r.min, max: r.max },
|
|
1502
|
+
a.config = { ...r }, a.bounds = { min: r.min, max: r.max }, D({
|
|
1439
1503
|
y: r,
|
|
1440
|
-
isPlottable: (o) =>
|
|
1504
|
+
isPlottable: (o) => Q(n, o),
|
|
1441
1505
|
path: `scales.${s}`
|
|
1442
1506
|
}), e.set(s, a);
|
|
1443
1507
|
}
|
|
1444
|
-
return this.#
|
|
1508
|
+
return this.#o = e, this.#It = Object.fromEntries([...e].map(([s, r]) => [s, r.config])), this.#e.setYScales([...e.keys()]), i;
|
|
1445
1509
|
}
|
|
1446
1510
|
/**
|
|
1447
1511
|
* Hand out the Y-axis columns: the default axis keeps its side, and each
|
|
1448
1512
|
* visible named scale takes its side unless an earlier one holds it —
|
|
1449
1513
|
* that one becomes an overlay scale (dev warning).
|
|
1450
1514
|
*/
|
|
1451
|
-
#
|
|
1515
|
+
#wt() {
|
|
1452
1516
|
const t = /* @__PURE__ */ new Set();
|
|
1453
1517
|
this.yAxisWidth > 0 && t.add(this.yAxisPosition);
|
|
1454
|
-
const e =
|
|
1455
|
-
for (const [i, s] of this.#
|
|
1456
|
-
if (s.column = null, this.#
|
|
1518
|
+
const e = at(this.yAxisPosition);
|
|
1519
|
+
for (const [i, s] of this.#o) {
|
|
1520
|
+
if (s.column = null, this.#q(s.config) <= 0) continue;
|
|
1457
1521
|
const r = s.config.position ?? e;
|
|
1458
1522
|
if (t.has(r)) {
|
|
1459
|
-
this.#
|
|
1523
|
+
this.#V(`side:${i}`, () => Dt({ scaleId: i, side: r }));
|
|
1460
1524
|
continue;
|
|
1461
1525
|
}
|
|
1462
1526
|
t.add(r), s.column = r;
|
|
1463
1527
|
}
|
|
1464
1528
|
}
|
|
1465
1529
|
/** Dev warnings for a series' `scale`: an id `scales` doesn't define, a percent stack on a scale without 0. */
|
|
1466
|
-
#
|
|
1530
|
+
#Me(t) {
|
|
1467
1531
|
const e = t.scale;
|
|
1468
|
-
e !== void 0 && (this.#
|
|
1532
|
+
e !== void 0 && (this.#o.has(e) || this.#V(`unknown:${e}`, () => Rt({ seriesId: t.id, scaleId: e })), lt(t.renderer) === "percent" && !this.getYScale(this.#I(t)).isPlottable(0) && this.#V(`percent:${t.id}`, () => Vt({ seriesId: t.id })));
|
|
1469
1533
|
}
|
|
1470
|
-
#
|
|
1471
|
-
this.#
|
|
1534
|
+
#V(t, e) {
|
|
1535
|
+
this.#Dt.has(t) || (this.#Dt.add(t), e());
|
|
1472
1536
|
}
|
|
1473
1537
|
/** Ids of the named Y scales, in declaration order. */
|
|
1474
1538
|
getYScaleIds() {
|
|
1475
|
-
return [...this.#
|
|
1539
|
+
return [...this.#o.keys()];
|
|
1476
1540
|
}
|
|
1477
1541
|
/** The Y scale named `scaleId`; the default scale for `undefined` or an id `scales` doesn't define. */
|
|
1478
1542
|
getYScale(t) {
|
|
1479
|
-
return t === void 0 ? this.yScale : this.#
|
|
1543
|
+
return t === void 0 ? this.yScale : this.#o.get(t)?.yScale ?? this.yScale;
|
|
1480
1544
|
}
|
|
1481
1545
|
/**
|
|
1482
1546
|
* The column a scale's axis sits in — always the default axis's for
|
|
@@ -1484,31 +1548,31 @@ class _e extends Et {
|
|
|
1484
1548
|
*/
|
|
1485
1549
|
getYScaleColumn(t) {
|
|
1486
1550
|
if (t === void 0) return { position: this.yAxisPosition, width: this.yAxisWidth };
|
|
1487
|
-
const e = this.#
|
|
1488
|
-
return e === void 0 || e.column === null ? null : { position: e.column, width: this.#
|
|
1551
|
+
const e = this.#o.get(t);
|
|
1552
|
+
return e === void 0 || e.column === null ? null : { position: e.column, width: this.#q(e.config) };
|
|
1489
1553
|
}
|
|
1490
1554
|
/** The named scale a series maps through, `undefined` for the default scale. */
|
|
1491
1555
|
getSeriesScale(t) {
|
|
1492
1556
|
const e = this.#t.find((i) => i.id === t);
|
|
1493
|
-
return e === void 0 ? void 0 : this.#
|
|
1557
|
+
return e === void 0 ? void 0 : this.#I(e);
|
|
1494
1558
|
}
|
|
1495
1559
|
/** `scale` if `options.scales` defines it, else `undefined` (the default scale). */
|
|
1496
|
-
#
|
|
1497
|
-
return t !== void 0 && this.#
|
|
1560
|
+
#Ae(t) {
|
|
1561
|
+
return t !== void 0 && this.#o.has(t) ? t : void 0;
|
|
1498
1562
|
}
|
|
1499
|
-
#
|
|
1500
|
-
return this.#
|
|
1563
|
+
#I(t) {
|
|
1564
|
+
return this.#Ae(t.scale);
|
|
1501
1565
|
}
|
|
1502
|
-
#
|
|
1503
|
-
return t === void 0 ? this.#
|
|
1566
|
+
#Pe(t) {
|
|
1567
|
+
return t === void 0 ? this.#w : this.#o.get(t) ?? this.#w;
|
|
1504
1568
|
}
|
|
1505
1569
|
/** The series a scale autoscales from. */
|
|
1506
|
-
#
|
|
1507
|
-
return this.#
|
|
1570
|
+
#Ce(t) {
|
|
1571
|
+
return this.#o.size === 0 ? this.#t : this.#t.filter((e) => this.#I(e) === t);
|
|
1508
1572
|
}
|
|
1509
1573
|
/** Snap every scale to a fresh fit — what each one holds just changed. */
|
|
1510
|
-
#
|
|
1511
|
-
this.#
|
|
1574
|
+
#Le() {
|
|
1575
|
+
this.#u = !0;
|
|
1512
1576
|
const t = performance.now();
|
|
1513
1577
|
this.#e.onAxisReconfig(t), this.#x(t), this.emit("viewportChange"), this.#i.markDirty();
|
|
1514
1578
|
}
|
|
@@ -1518,7 +1582,7 @@ class _e extends Et {
|
|
|
1518
1582
|
* picks a named scale; an id `scales` doesn't define is a no-op.
|
|
1519
1583
|
*/
|
|
1520
1584
|
setYAxisFormat(t) {
|
|
1521
|
-
t.scale !== void 0 && !this.#
|
|
1585
|
+
t.scale !== void 0 && !this.#o.has(t.scale) || (this.getYScale(t.scale).setFormat(t.format), this.#m());
|
|
1522
1586
|
}
|
|
1523
1587
|
/**
|
|
1524
1588
|
* Apply label-density knobs driven by `<YAxis labelCount=… minLabelSpacing=…>`
|
|
@@ -1528,7 +1592,7 @@ class _e extends Et {
|
|
|
1528
1592
|
* charts react without waiting for pan/zoom.
|
|
1529
1593
|
*/
|
|
1530
1594
|
setYAxisLabelDensity(t) {
|
|
1531
|
-
if (t.scale !== void 0 && !this.#
|
|
1595
|
+
if (t.scale !== void 0 && !this.#o.has(t.scale)) return;
|
|
1532
1596
|
const e = this.getYScale(t.scale);
|
|
1533
1597
|
let i = !1;
|
|
1534
1598
|
"labelCount" in t && (e.setLabelCount(t.labelCount ?? null), i = !0), "minLabelSpacing" in t && (e.setMinSpacing(t.minLabelSpacing ?? null), i = !0), i && (this.syncScales(), this.emit("viewportChange"), this.#i.markDirty());
|
|
@@ -1539,7 +1603,7 @@ class _e extends Et {
|
|
|
1539
1603
|
* info-bar headers read it.
|
|
1540
1604
|
*/
|
|
1541
1605
|
setXAxisFormat(t) {
|
|
1542
|
-
this.timeScale.setFormat(t), this.#
|
|
1606
|
+
this.timeScale.setFormat(t), this.#m();
|
|
1543
1607
|
}
|
|
1544
1608
|
/** Label-density knobs for the X axis — mirror of {@link setYAxisLabelDensity}. */
|
|
1545
1609
|
setTimeAxisLabelDensity(t) {
|
|
@@ -1547,11 +1611,11 @@ class _e extends Et {
|
|
|
1547
1611
|
"labelCount" in t && (this.timeScale.setLabelCount(t.labelCount ?? null), e = !0), "minLabelSpacing" in t && (this.timeScale.setMinSpacing(t.minLabelSpacing ?? null), e = !0), e && (this.syncScales(), this.emit("viewportChange"), this.#i.markDirty());
|
|
1548
1612
|
}
|
|
1549
1613
|
getMediaSize() {
|
|
1550
|
-
return this.#
|
|
1614
|
+
return this.#c.size.media;
|
|
1551
1615
|
}
|
|
1552
1616
|
/** Returns layout metrics for the chart area, Y axis, and time axis. */
|
|
1553
1617
|
getLayout() {
|
|
1554
|
-
const t = this.#
|
|
1618
|
+
const t = this.#c.size.media, e = this.yAxisWidth, i = this.xAxisHeight, s = t.width - this.#k();
|
|
1555
1619
|
return {
|
|
1556
1620
|
chartArea: { x: this.plotLeft, y: 0, width: s, height: t.height - i },
|
|
1557
1621
|
yAxisWidth: e,
|
|
@@ -1560,7 +1624,7 @@ class _e extends Et {
|
|
|
1560
1624
|
};
|
|
1561
1625
|
}
|
|
1562
1626
|
getDataInterval() {
|
|
1563
|
-
return this.#
|
|
1627
|
+
return this.#r;
|
|
1564
1628
|
}
|
|
1565
1629
|
/**
|
|
1566
1630
|
* Update viewport padding at runtime. Refits the visible time range to
|
|
@@ -1571,18 +1635,15 @@ class _e extends Et {
|
|
|
1571
1635
|
* InfoBar ResizeObserver).
|
|
1572
1636
|
*/
|
|
1573
1637
|
setPadding(t) {
|
|
1574
|
-
const e = this.#
|
|
1575
|
-
this.#
|
|
1576
|
-
const i = this.#
|
|
1638
|
+
const e = this.#l;
|
|
1639
|
+
this.#l = U(t);
|
|
1640
|
+
const i = this.#l, s = !G(e.left, i.left) || !G(e.right, i.right), r = e.top !== i.top || e.bottom !== i.bottom;
|
|
1577
1641
|
if (s) {
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
const o = this.#l.size.media.width - this.#w();
|
|
1581
|
-
this.#O(n, a, o);
|
|
1582
|
-
}
|
|
1642
|
+
const n = this.#c.size.media.width - this.#k();
|
|
1643
|
+
this.#At(n);
|
|
1583
1644
|
}
|
|
1584
1645
|
if (s || r) {
|
|
1585
|
-
this.#
|
|
1646
|
+
this.#u = !0;
|
|
1586
1647
|
const n = performance.now();
|
|
1587
1648
|
this.#e.onAxisReconfig(n), this.#x(n);
|
|
1588
1649
|
}
|
|
@@ -1590,7 +1651,7 @@ class _e extends Et {
|
|
|
1590
1651
|
}
|
|
1591
1652
|
/** Show or hide the background grid. Takes effect on the next render frame. */
|
|
1592
1653
|
setGrid(t) {
|
|
1593
|
-
this.#
|
|
1654
|
+
this.#j = t.visible, this.#i.markDirty();
|
|
1594
1655
|
}
|
|
1595
1656
|
/**
|
|
1596
1657
|
* Set or clear the edge fade masks (see {@link ChartOptions.fade}).
|
|
@@ -1600,14 +1661,14 @@ class _e extends Et {
|
|
|
1600
1661
|
* the next render frame.
|
|
1601
1662
|
*/
|
|
1602
1663
|
setFade(t) {
|
|
1603
|
-
const e =
|
|
1664
|
+
const e = _(t), i = this.#C;
|
|
1604
1665
|
e.top === i.top && e.right === i.right && e.left === i.left || (this.#C = e, this.#i.markDirty());
|
|
1605
1666
|
}
|
|
1606
1667
|
/** Report the floating header's height (see {@link headerHeight}). The
|
|
1607
1668
|
* framework wrappers keep it in sync with the measured Title / InfoBar. */
|
|
1608
1669
|
setHeaderHeight(t) {
|
|
1609
1670
|
const e = Number.isFinite(t) && t > 0 ? t : 0;
|
|
1610
|
-
e !== this.#
|
|
1671
|
+
e !== this.#ht && (this.#ht = e, this.#m());
|
|
1611
1672
|
}
|
|
1612
1673
|
/**
|
|
1613
1674
|
* Set the visual state for one side of the chart. Typically called in
|
|
@@ -1620,8 +1681,8 @@ class _e extends Et {
|
|
|
1620
1681
|
*/
|
|
1621
1682
|
setEdgeState(t, e) {
|
|
1622
1683
|
if (this.#A[t] === e || !this.checkTimeOnlyFeature("EdgeLoader")) return;
|
|
1623
|
-
const i = this.#A[t] === "loading", s = this.#
|
|
1624
|
-
this.#
|
|
1684
|
+
const i = this.#A[t] === "loading", s = this.#E[t];
|
|
1685
|
+
this.#E[t] = !1, this.#K[t] = i && !s && (e === "idle" || e === "has-more") ? performance.now() : null, this.#A[t] = e, this.#d.markDirty();
|
|
1625
1686
|
}
|
|
1626
1687
|
/** Read the current host-declared state for a given edge. */
|
|
1627
1688
|
getEdgeState(t) {
|
|
@@ -1631,11 +1692,11 @@ class _e extends Et {
|
|
|
1631
1692
|
* Alpha for a side's `loading` exit fade, or `null` when none is in
|
|
1632
1693
|
* flight. Self-cleaning: an elapsed fade clears its start stamp.
|
|
1633
1694
|
*/
|
|
1634
|
-
#
|
|
1695
|
+
#Jt(t) {
|
|
1635
1696
|
const e = this.#K[t];
|
|
1636
1697
|
if (e === null) return null;
|
|
1637
|
-
const i = (performance.now() - e) /
|
|
1638
|
-
return i >= 1 ? (this.#K[t] = null, null) : 1 -
|
|
1698
|
+
const i = (performance.now() - e) / oe;
|
|
1699
|
+
return i >= 1 ? (this.#K[t] = null, null) : 1 - X(Math.max(0, i));
|
|
1639
1700
|
}
|
|
1640
1701
|
/**
|
|
1641
1702
|
* Swap the painter used for a side's `loading` spinner — the same
|
|
@@ -1644,7 +1705,7 @@ class _e extends Et {
|
|
|
1644
1705
|
* immediately if that side is currently in the `loading` state.
|
|
1645
1706
|
*/
|
|
1646
1707
|
setEdgeIndicator(t, e) {
|
|
1647
|
-
e !== null && !this.checkTimeOnlyFeature("EdgeLoader") || (this
|
|
1708
|
+
e !== null && !this.checkTimeOnlyFeature("EdgeLoader") || (this.#$t[t] = e, this.#A[t] === "loading" && this.#d.markDirty());
|
|
1648
1709
|
}
|
|
1649
1710
|
/**
|
|
1650
1711
|
* Resolve the boundary point's Y position and series kind on the primary
|
|
@@ -1654,14 +1715,14 @@ class _e extends Et {
|
|
|
1654
1715
|
* `open` (the value immediately preceding the boundary); `right` from the
|
|
1655
1716
|
* last visible candle's `close`.
|
|
1656
1717
|
*/
|
|
1657
|
-
#
|
|
1718
|
+
#Ie(t, e) {
|
|
1658
1719
|
const i = this.getSeriesIdsByType("time", { visibleOnly: !0, singleLayerOnly: !0 })[0] ?? this.getSeriesIdsByType("time", { visibleOnly: !0 })[0];
|
|
1659
1720
|
if (!i) return null;
|
|
1660
1721
|
const s = this.getDataAtTime(i, e);
|
|
1661
1722
|
if (!s) return null;
|
|
1662
1723
|
const r = this.#t.find((n) => n.id === i);
|
|
1663
1724
|
return r ? {
|
|
1664
|
-
valueY: this.getYScale(this.#
|
|
1725
|
+
valueY: this.getYScale(this.#I(r)).valueToY(bt(t, s)),
|
|
1665
1726
|
seriesKind: r.renderer.kind
|
|
1666
1727
|
} : null;
|
|
1667
1728
|
}
|
|
@@ -1671,8 +1732,8 @@ class _e extends Et {
|
|
|
1671
1732
|
* placeholder shapes to match the real bars that will render once data
|
|
1672
1733
|
* lands. `null` when the viewport has no meaningful span yet.
|
|
1673
1734
|
*/
|
|
1674
|
-
#
|
|
1675
|
-
const t = this.timeScale.barWidthMedia(this.#
|
|
1735
|
+
#De() {
|
|
1736
|
+
const t = this.timeScale.barWidthMedia(this.#r);
|
|
1676
1737
|
return Number.isFinite(t) && t > 0 ? t : null;
|
|
1677
1738
|
}
|
|
1678
1739
|
/**
|
|
@@ -1690,8 +1751,8 @@ class _e extends Et {
|
|
|
1690
1751
|
* probed, not kind-gated: a kind check here silently kills hover for the
|
|
1691
1752
|
* next spatial renderer.
|
|
1692
1753
|
*/
|
|
1693
|
-
#
|
|
1694
|
-
const e = this.#
|
|
1754
|
+
#Mt(t) {
|
|
1755
|
+
const e = this.#c.size, i = this.#l, s = {
|
|
1695
1756
|
top: i.top * e.verticalPixelRatio,
|
|
1696
1757
|
bottom: i.bottom * e.verticalPixelRatio
|
|
1697
1758
|
};
|
|
@@ -1703,7 +1764,7 @@ class _e extends Et {
|
|
|
1703
1764
|
const h = (t.mediaX - this.plotLeft) * e.horizontalPixelRatio, l = t.mediaY * e.verticalPixelRatio;
|
|
1704
1765
|
o = a.renderer.hitTest(h, l, e.bitmap.width, e.bitmap.height, s);
|
|
1705
1766
|
}
|
|
1706
|
-
a.renderer.setHoverIndex(o) && (r = !0), o >= 0 && !n && (n = { seriesId: a.id, index: o, info: a.renderer.getHoverInfo?.(this.#
|
|
1767
|
+
a.renderer.setHoverIndex(o) && (r = !0), o >= 0 && !n && (n = { seriesId: a.id, index: o, info: a.renderer.getHoverInfo?.(this.#h) ?? null });
|
|
1707
1768
|
}
|
|
1708
1769
|
r && (this.#i.markDirty(), this.emit("seriesHover", n));
|
|
1709
1770
|
}
|
|
@@ -1714,8 +1775,8 @@ class _e extends Et {
|
|
|
1714
1775
|
* Returns the first spatial series (pie, heatmap, or a custom spatial kind)
|
|
1715
1776
|
* whose `hitTest` claims the position, or `null` if none does.
|
|
1716
1777
|
*/
|
|
1717
|
-
#
|
|
1718
|
-
const e = this.#
|
|
1778
|
+
#Qt(t) {
|
|
1779
|
+
const e = this.#c.size, i = this.#l, s = {
|
|
1719
1780
|
top: i.top * e.verticalPixelRatio,
|
|
1720
1781
|
bottom: i.bottom * e.verticalPixelRatio
|
|
1721
1782
|
}, r = (t.mediaX - this.plotLeft) * e.horizontalPixelRatio, n = t.mediaY * e.verticalPixelRatio;
|
|
@@ -1746,42 +1807,42 @@ class _e extends Et {
|
|
|
1746
1807
|
* viewport didn't move, the re-derived values are bit-identical and the
|
|
1747
1808
|
* method exits without emitting.
|
|
1748
1809
|
*/
|
|
1749
|
-
#
|
|
1750
|
-
const t = this.#
|
|
1751
|
-
this.#
|
|
1810
|
+
#Re() {
|
|
1811
|
+
const t = this.#ot;
|
|
1812
|
+
this.#ot = !1;
|
|
1752
1813
|
const e = this.#f;
|
|
1753
1814
|
if (e === null) return;
|
|
1754
1815
|
const { from: i, to: s } = this.timeScale.getRange(), r = this.yScale.getRange(), n = Math.abs(s - i) * 1e-9, a = Math.abs(r.max - r.min) * 1e-9, o = 1e-6;
|
|
1755
1816
|
let h;
|
|
1756
|
-
if (this.#
|
|
1757
|
-
const l = this.timeScale.snapToBand(this.timeScale.xToTime(e.mediaX - this.plotLeft)),
|
|
1758
|
-
if (!Number.isFinite(l) || !Number.isFinite(
|
|
1759
|
-
h = { mediaX: e.mediaX, mediaY: e.mediaY, time: l, x: this.timeScale.domainValue(l), y:
|
|
1817
|
+
if (this.#lt === "pointer") {
|
|
1818
|
+
const l = this.timeScale.snapToBand(this.timeScale.xToTime(e.mediaX - this.plotLeft)), c = this.yScale.yToValue(e.mediaY);
|
|
1819
|
+
if (!Number.isFinite(l) || !Number.isFinite(c) || Math.abs(l - e.time) <= n && Math.abs(c - e.y) <= a && !t && e.x === this.timeScale.domainValue(e.time)) return;
|
|
1820
|
+
h = { mediaX: e.mediaX, mediaY: e.mediaY, time: l, x: this.timeScale.domainValue(l), y: c };
|
|
1760
1821
|
} else {
|
|
1761
1822
|
if (e.time < i || e.time > s) {
|
|
1762
|
-
this.#f = null, this.#
|
|
1823
|
+
this.#f = null, this.#d.markDirty(), this.emit("crosshairMove", null), this.#Mt(null);
|
|
1763
1824
|
return;
|
|
1764
1825
|
}
|
|
1765
|
-
const l = this.plotLeft + this.timeScale.timeToX(e.time),
|
|
1766
|
-
if (!Number.isFinite(l) || !Number.isFinite(
|
|
1767
|
-
h = { mediaX: l, mediaY:
|
|
1826
|
+
const l = this.plotLeft + this.timeScale.timeToX(e.time), c = this.yScale.valueToY(e.y);
|
|
1827
|
+
if (!Number.isFinite(l) || !Number.isFinite(c) || Math.abs(l - e.mediaX) <= o && Math.abs(c - e.mediaY) <= o && !t && e.x === this.timeScale.domainValue(e.time)) return;
|
|
1828
|
+
h = { mediaX: l, mediaY: c, time: e.time, x: this.timeScale.domainValue(e.time), y: e.y };
|
|
1768
1829
|
}
|
|
1769
|
-
this.#f = h, this.#
|
|
1830
|
+
this.#f = h, this.#d.markDirty(), this.emit("crosshairMove", h), this.#Mt(h);
|
|
1770
1831
|
}
|
|
1771
1832
|
/** Tear down the chart: cancel animations, remove listeners, and detach the canvas. */
|
|
1772
1833
|
destroy() {
|
|
1773
1834
|
for (const t of this.#t) t.renderer.dispose();
|
|
1774
|
-
this.#t = [], this.#y = [], this.#
|
|
1835
|
+
this.#t = [], this.#y = [], this.#M = [], this.#S = [], this.#F = null, this.#i.destroy(), this.#d.destroy(), this.#N?.destroy(), this.#c.destroy(), this.#pt?.destroy(), this.#pt = null, this.#gt && this.#P?.destroy(), this.#P = null, this.#gt = !1, this.removeAllListeners();
|
|
1775
1836
|
}
|
|
1776
1837
|
/** The attached performance monitor, or `null` when instrumentation is disabled. */
|
|
1777
1838
|
getPerfMonitor() {
|
|
1778
|
-
return this.#
|
|
1839
|
+
return this.#P;
|
|
1779
1840
|
}
|
|
1780
1841
|
/** Compute the earliest and latest timestamps across all series. */
|
|
1781
1842
|
getDataBounds() {
|
|
1782
1843
|
let t, e;
|
|
1783
1844
|
for (const i of this.#t) {
|
|
1784
|
-
if (!i.visible || !
|
|
1845
|
+
if (!i.visible || !S(i.renderer)) continue;
|
|
1785
1846
|
const s = i.renderer.getTimeBounds();
|
|
1786
1847
|
s !== null && ((t === void 0 || s.first < t) && (t = s.first), (e === void 0 || s.last > e) && (e = s.last));
|
|
1787
1848
|
}
|
|
@@ -1790,62 +1851,72 @@ class _e extends Et {
|
|
|
1790
1851
|
/** Set by `setSeriesData`/bulk-replace paths so the next `onDataChanged`
|
|
1791
1852
|
* snaps the Y range (instead of easing) and `yScale.getRange()` reflects
|
|
1792
1853
|
* the new domain synchronously. Cleared by `onDataChanged` after each run. */
|
|
1793
|
-
#
|
|
1854
|
+
#nt = !1;
|
|
1794
1855
|
onDataChanged() {
|
|
1795
1856
|
if (this.#R > 0) {
|
|
1796
|
-
this.#
|
|
1857
|
+
this.#dt = !0;
|
|
1797
1858
|
return;
|
|
1798
1859
|
}
|
|
1799
|
-
this.updateDataInterval();
|
|
1860
|
+
this.updateDataInterval({ full: this.#nt || !this.#u });
|
|
1800
1861
|
const { first: t, last: e } = this.getDataBounds();
|
|
1801
|
-
t !== void 0 && (this.#
|
|
1802
|
-
const i = this.#
|
|
1803
|
-
this.#
|
|
1804
|
-
const s = !this.#
|
|
1862
|
+
t !== void 0 && (this.#T = t), e !== void 0 && (this.#J = this.#s, this.#s = e);
|
|
1863
|
+
const i = this.#nt;
|
|
1864
|
+
this.#nt = !1;
|
|
1865
|
+
const s = !this.#u && t !== void 0;
|
|
1805
1866
|
if (i) {
|
|
1806
1867
|
this.yScale.tickTracker.reset(), this.timeScale.tickTracker.reset();
|
|
1807
|
-
for (const n of this.#
|
|
1868
|
+
for (const n of this.#o.values())
|
|
1808
1869
|
n.yScale.tickTracker.reset();
|
|
1809
1870
|
}
|
|
1810
|
-
this.#
|
|
1871
|
+
this.#Yt = i;
|
|
1811
1872
|
const r = performance.now();
|
|
1812
|
-
i || s ? (this.#
|
|
1873
|
+
i || s ? (this.#W.seed(r), this.#e.onDataReplaced(r)) : this.#e.onPointAppended(r), this.#e.lastXTarget !== null && (this.#_ = !0), t !== void 0 && (this.#u = !0), this.#x(r), this.syncScales(), s ? this.#Ct() : this.#i.markDirty(), this.emit("dataUpdate"), this.#m();
|
|
1813
1874
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1875
|
+
/** `full`: the data was replaced, so a long series is read whole instead of from its tail. */
|
|
1876
|
+
updateDataInterval(t) {
|
|
1877
|
+
if (this.#n === "category") {
|
|
1878
|
+
this.#r = 1;
|
|
1817
1879
|
return;
|
|
1818
1880
|
}
|
|
1819
|
-
for (const
|
|
1820
|
-
if (!
|
|
1821
|
-
const
|
|
1822
|
-
if (
|
|
1823
|
-
this.#
|
|
1824
|
-
|
|
1881
|
+
for (const e of this.#t) {
|
|
1882
|
+
if (!S(e.renderer)) continue;
|
|
1883
|
+
const i = e.renderer.sampleTimes(it + 1);
|
|
1884
|
+
if (!(i.length < 2)) {
|
|
1885
|
+
this.#r = this.#Ve({ renderer: e.renderer, head: i, full: t.full });
|
|
1886
|
+
return;
|
|
1825
1887
|
}
|
|
1826
1888
|
}
|
|
1827
1889
|
}
|
|
1890
|
+
/** The step of one series. Past {@link FULL_INTERVAL_SCAN_POINTS}, an append can only refine it from the tail. */
|
|
1891
|
+
#Ve(t) {
|
|
1892
|
+
const { renderer: e, head: i, full: s } = t;
|
|
1893
|
+
if (i.length <= it) return V(i);
|
|
1894
|
+
if (s) return V(e.sampleTimes(Number.POSITIVE_INFINITY));
|
|
1895
|
+
const r = e.sampleTimes(st, "end");
|
|
1896
|
+
return r.length < st ? this.#r : Math.min(this.#r, V(r));
|
|
1897
|
+
}
|
|
1828
1898
|
/** Whether the Y range has been initialized (first snap vs smooth lerp).
|
|
1829
1899
|
* Pre-init Y emits are forced to `instant` so the first paint snaps to
|
|
1830
1900
|
* data regardless of the caller's requested kind. Also reset by paths
|
|
1831
1901
|
* that intentionally invalidate the current Y baseline (axis bound
|
|
1832
1902
|
* change, empty viewport). */
|
|
1833
|
-
#
|
|
1903
|
+
#u = !1;
|
|
1834
1904
|
/** Whether the engine's X slot has received its first emit. Pre-init X
|
|
1835
1905
|
* emits are forced to `instant` so first paint snaps to the fitted
|
|
1836
1906
|
* range — without this guard the engine would ease from `{0,0}` into
|
|
1837
1907
|
* the new target and the very first frame would render with a
|
|
1838
1908
|
* zero-width X domain. */
|
|
1839
|
-
#
|
|
1909
|
+
#_ = !1;
|
|
1840
1910
|
/**
|
|
1841
|
-
*
|
|
1842
|
-
*
|
|
1843
|
-
*
|
|
1844
|
-
* back to the initial window.
|
|
1911
|
+
* {@link ChartOptions.viewport.initialRange}: the chart's own window until the
|
|
1912
|
+
* user or the app moves the view, so more series or a re-seed keep it. A
|
|
1913
|
+
* `{ from, to }` or `{ from, bars }` window also ends once streaming moves it.
|
|
1845
1914
|
*/
|
|
1846
|
-
#
|
|
1915
|
+
#H;
|
|
1916
|
+
/** The chart's own fit holds fewer bars than it asks for, so appends widen it until it is full. */
|
|
1917
|
+
#U = !1;
|
|
1847
1918
|
/** Dev warning for values the Y scale can't place — fires once per chart. */
|
|
1848
|
-
#
|
|
1919
|
+
#te = !1;
|
|
1849
1920
|
/**
|
|
1850
1921
|
* Sample the visible data window and return the resolved Y bounds of one
|
|
1851
1922
|
* scale (`undefined` = default) in its scale space (see {@link resolveYTarget}),
|
|
@@ -1855,23 +1926,23 @@ class _e extends Et {
|
|
|
1855
1926
|
* converge together. Clears {@link #yInited} on empty so the next emit
|
|
1856
1927
|
* with valid data lands as an instant snap.
|
|
1857
1928
|
*/
|
|
1858
|
-
#
|
|
1859
|
-
const i = t ?? this.#
|
|
1860
|
-
h && this.#
|
|
1861
|
-
const l =
|
|
1862
|
-
return l === null ? (e === void 0 && (this.#
|
|
1929
|
+
#G(t, e) {
|
|
1930
|
+
const i = t ?? this.#a, { yScale: s, bounds: r } = this.#Pe(e), n = r.min !== void 0 && r.min !== "auto" && typeof r.min != "number" || r.max !== void 0 && r.max !== "auto" && typeof r.max != "number" ? [] : null, a = this.#Ce(e), o = s.getTransform(), h = o === null ? void 0 : (c) => s.isPlottable(c);
|
|
1931
|
+
h && this.#He({ window: i, series: a, yScale: s });
|
|
1932
|
+
const l = Bt({ targetVisible: i, series: a, allValues: n, plottable: h });
|
|
1933
|
+
return l === null ? (e === void 0 && (this.#u = !1), null) : (e !== void 0 && (this.#u = !0), Xt({ raw: Zt(l), bounds: r, allValues: n ?? [], transform: o }));
|
|
1863
1934
|
}
|
|
1864
1935
|
/** Dev-only sweep behind {@link warnUnplottableValues}; stops once it has warned. */
|
|
1865
|
-
#
|
|
1866
|
-
if (this.#
|
|
1936
|
+
#He(t) {
|
|
1937
|
+
if (this.#te || process.env.NODE_ENV === "production") return;
|
|
1867
1938
|
const { window: e, series: i, yScale: s } = t;
|
|
1868
1939
|
for (const r of i) {
|
|
1869
|
-
if (!r.visible || !
|
|
1940
|
+
if (!r.visible || !S(r.renderer)) continue;
|
|
1870
1941
|
const n = r.renderer.getValueRange(e.from, e.to);
|
|
1871
1942
|
if (n === null) continue;
|
|
1872
1943
|
const a = (r.renderer.stacking === "normal" || r.renderer.stacking === "percent" ? n.min < 0 && !s.isPlottable(n.min) : !s.isPlottable(n.min)) ? n.min : s.isPlottable(n.max) ? null : n.max;
|
|
1873
1944
|
if (a !== null) {
|
|
1874
|
-
this.#
|
|
1945
|
+
this.#te = !0, Ht({ seriesId: r.id, value: a });
|
|
1875
1946
|
return;
|
|
1876
1947
|
}
|
|
1877
1948
|
}
|
|
@@ -1894,53 +1965,112 @@ class _e extends Et {
|
|
|
1894
1965
|
* - **autoscroll off** → `null` (no X retarget; user has panned away
|
|
1895
1966
|
* from the tail).
|
|
1896
1967
|
*/
|
|
1897
|
-
#
|
|
1898
|
-
if (this.#
|
|
1899
|
-
const { from: t, to: e } = this.#
|
|
1900
|
-
if (this.#
|
|
1901
|
-
return this.#
|
|
1902
|
-
if (i)
|
|
1903
|
-
|
|
1904
|
-
const { to: n } = this.#h;
|
|
1905
|
-
this.#s >= n && this.#s - n <= this.#o * 1.5 && (this.#p = !0);
|
|
1906
|
-
}
|
|
1907
|
-
return this.#h;
|
|
1908
|
-
}
|
|
1968
|
+
#Ne() {
|
|
1969
|
+
if (this.#T === null || this.#s === null) return null;
|
|
1970
|
+
const { from: t, to: e } = this.#a, i = t === 0 && e === 0, s = this.#c.size.media.width - this.#k();
|
|
1971
|
+
if (this.#n === "category")
|
|
1972
|
+
return this.#Pt({ firstTime: this.#T, lastTime: this.#s, chartWidth: s }), this.#a;
|
|
1973
|
+
if (i)
|
|
1974
|
+
return this.#At(s), this.#a;
|
|
1909
1975
|
if (!this.#p) return null;
|
|
1910
|
-
if (this.#
|
|
1911
|
-
return this.#
|
|
1912
|
-
|
|
1913
|
-
|
|
1976
|
+
if (this.#Yt)
|
|
1977
|
+
return this.#At(s), this.#a;
|
|
1978
|
+
if (this.#U) {
|
|
1979
|
+
const n = this.#ie(s);
|
|
1980
|
+
if (n !== null) return this.#Fe(n);
|
|
1981
|
+
}
|
|
1982
|
+
const r = Ft({
|
|
1983
|
+
currentLogical: this.#a,
|
|
1914
1984
|
lastTime: this.#s,
|
|
1915
|
-
prevDataEnd: this.#
|
|
1916
|
-
dataInterval: this.#
|
|
1917
|
-
paddingRight: this.#
|
|
1985
|
+
prevDataEnd: this.#J,
|
|
1986
|
+
dataInterval: this.#r,
|
|
1987
|
+
paddingRight: this.#l.right,
|
|
1918
1988
|
chartWidth: s,
|
|
1919
1989
|
holdUntilFilled: this.#L
|
|
1920
1990
|
});
|
|
1921
|
-
return r.releaseHold && (this.#L = !1), r.reengageAutoScroll && (this.#p = !0), r.newLogical === null ? null : (this.#
|
|
1991
|
+
return r.releaseHold && (this.#L = !1), r.reengageAutoScroll && (this.#p = !0), r.newLogical === null ? null : (typeof this.#H == "object" && (this.#H = void 0), this.#ee(r.newLogical));
|
|
1992
|
+
}
|
|
1993
|
+
/** Commit an X target that follows the data tail; the engine eases there. */
|
|
1994
|
+
#ee(t) {
|
|
1995
|
+
return this.#W.observe(performance.now()), this.#e.setXSettleMs(this.#W.pickSettleMs(this.#g.axis.x.settleMs)), this.#D(t, { emitChange: !1, skipValidation: !0 }), this.#J = this.#s, t;
|
|
1922
1996
|
}
|
|
1923
1997
|
/**
|
|
1924
|
-
* Fit the
|
|
1925
|
-
*
|
|
1926
|
-
*
|
|
1927
|
-
* commits the new range via `viewport.setRange` (which emits `change`).
|
|
1998
|
+
* Fit X to the window the chart picks for itself: `initialRange` while it
|
|
1999
|
+
* holds, else every bar up to `maxVisibleBars`. Runs on the first data, on a
|
|
2000
|
+
* bulk replace and on a horizontal padding change.
|
|
1928
2001
|
*/
|
|
1929
|
-
#
|
|
1930
|
-
const
|
|
1931
|
-
if (
|
|
1932
|
-
this.#
|
|
1933
|
-
|
|
2002
|
+
#At(t) {
|
|
2003
|
+
const e = this.#H;
|
|
2004
|
+
if (typeof e == "object") {
|
|
2005
|
+
if (this.#U = !1, this.#jt(e), this.#a.from !== 0 || this.#a.to !== 0) {
|
|
2006
|
+
this.#We();
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
this.#H = void 0;
|
|
1934
2010
|
}
|
|
1935
|
-
const
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2011
|
+
const i = this.#ie(t);
|
|
2012
|
+
i !== null && (this.#L = !1, this.#p = !0, this.#U = i.filling, this.#D(i.range, { emitChange: !0 }));
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* The chart's own window over the current data: the last `initialRange`
|
|
2016
|
+
* bars, else every bar up to `maxVisibleBars`. `filling` while the data holds
|
|
2017
|
+
* fewer bars than that. `null` before data, or for a `{ from, … }` window.
|
|
2018
|
+
*/
|
|
2019
|
+
#ie(t) {
|
|
2020
|
+
const e = this.#H, i = this.#T, s = this.#s;
|
|
2021
|
+
if (i === null || s === null || typeof e == "object") return null;
|
|
2022
|
+
const r = e ?? this.#ft, n = Math.max(i, s - (r - 1) * this.#r);
|
|
2023
|
+
return { range: Z({
|
|
2024
|
+
firstTime: e === void 0 ? i : n,
|
|
2025
|
+
lastTime: s,
|
|
2026
|
+
dataInterval: this.#r,
|
|
2027
|
+
// An explicit bar count is shown whole; only the default fit is capped.
|
|
2028
|
+
maxVisibleBars: e === void 0 ? this.#ft : Number.POSITIVE_INFINITY,
|
|
2029
|
+
chartWidth: t,
|
|
2030
|
+
padding: { left: this.#l.left, right: this.#l.right }
|
|
2031
|
+
}), filling: n === i };
|
|
2032
|
+
}
|
|
2033
|
+
/** Widen the chart's own fit to the data tail. A trimmed head never narrows it (`keepLast`). */
|
|
2034
|
+
#Fe(t) {
|
|
2035
|
+
this.#U = t.filling;
|
|
2036
|
+
const e = this.#a, i = e.to - e.from, s = t.range.to - t.range.from;
|
|
2037
|
+
if (t.range.to === e.to && s <= i) return null;
|
|
2038
|
+
const r = Math.max(s, i);
|
|
2039
|
+
return this.#ee({ from: t.range.to - r, to: t.range.to });
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* `setVisibleRange` reads a window that ends before the data tail as
|
|
2043
|
+
* "panned into history" and drops tail-follow. That is wrong for a streaming
|
|
2044
|
+
* lead-in that parks the seed just past the right edge so the first tick
|
|
2045
|
+
* scrolls it into view (the Sparkline `flow.align: 'offscreen'` drive-in) —
|
|
2046
|
+
* without follow-live the stream accumulates off-canvas forever. Re-arm when
|
|
2047
|
+
* the tail sits within ~one interval past the window.
|
|
2048
|
+
*/
|
|
2049
|
+
#We() {
|
|
2050
|
+
if (this.#p || this.#s === null) return;
|
|
2051
|
+
const { to: t } = this.#a;
|
|
2052
|
+
this.#s >= t && this.#s - t <= this.#r * 1.5 && (this.#p = !0);
|
|
2053
|
+
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Fit the viewport's logical X range around a data span, padding included.
|
|
2056
|
+
* Clears the warm-up hold, forces autoscroll on (the data tail is in the new
|
|
2057
|
+
* window by construction) and emits `viewportChange`. Returns whether the range changed.
|
|
2058
|
+
*/
|
|
2059
|
+
#Pt(t) {
|
|
2060
|
+
const { firstTime: e, lastTime: i, chartWidth: s } = t;
|
|
2061
|
+
this.#L = !1, this.#p = !0;
|
|
2062
|
+
const r = this.timeScale.bandRange();
|
|
2063
|
+
if (this.#n === "category" && r !== null)
|
|
2064
|
+
return this.#D(r, { emitChange: !0, skipValidation: !0 });
|
|
2065
|
+
const n = Z({
|
|
2066
|
+
firstTime: e,
|
|
2067
|
+
lastTime: i,
|
|
2068
|
+
dataInterval: this.#r,
|
|
2069
|
+
maxVisibleBars: Number.POSITIVE_INFINITY,
|
|
2070
|
+
chartWidth: s,
|
|
2071
|
+
padding: { left: this.#l.left, right: this.#l.right }
|
|
1942
2072
|
});
|
|
1943
|
-
|
|
2073
|
+
return this.#D(n, { emitChange: !0 });
|
|
1944
2074
|
}
|
|
1945
2075
|
/**
|
|
1946
2076
|
* Commit a programmatic zoom — `fitContent` or `setVisibleRange`. Reads
|
|
@@ -1956,12 +2086,12 @@ class _e extends Et {
|
|
|
1956
2086
|
* passes `xEase: true` so X eases instead — viewport and axis converge
|
|
1957
2087
|
* on the same frame.
|
|
1958
2088
|
*/
|
|
1959
|
-
#
|
|
1960
|
-
const e = this.#
|
|
2089
|
+
#se(t) {
|
|
2090
|
+
const e = this.#a;
|
|
1961
2091
|
if (e.to <= e.from) return;
|
|
1962
2092
|
const i = performance.now();
|
|
1963
|
-
if (!this.#
|
|
1964
|
-
this.#
|
|
2093
|
+
if (!this.#_ || !this.#u) {
|
|
2094
|
+
this.#re(i);
|
|
1965
2095
|
return;
|
|
1966
2096
|
}
|
|
1967
2097
|
this.#e.onProgrammaticZoom({ xTarget: e, xEase: t?.xEase }, i), this.#x(i);
|
|
@@ -1978,12 +2108,12 @@ class _e extends Et {
|
|
|
1978
2108
|
* instead of lagging on the long sticky contract. First paint still snaps
|
|
1979
2109
|
* (same as the programmatic path) so synchronous readers see final values.
|
|
1980
2110
|
*/
|
|
1981
|
-
|
|
1982
|
-
const t = this.#
|
|
2111
|
+
#$e() {
|
|
2112
|
+
const t = this.#a;
|
|
1983
2113
|
if (t.to <= t.from) return;
|
|
1984
2114
|
const e = performance.now();
|
|
1985
|
-
if (!this.#
|
|
1986
|
-
this.#
|
|
2115
|
+
if (!this.#_ || !this.#u) {
|
|
2116
|
+
this.#re(e);
|
|
1987
2117
|
return;
|
|
1988
2118
|
}
|
|
1989
2119
|
this.#e.onPanZoom({ xTarget: t, yAuto: !0 }, e), this.#x(e);
|
|
@@ -1995,13 +2125,13 @@ class _e extends Et {
|
|
|
1995
2125
|
* commits — both must snap before the chart has painted once so a
|
|
1996
2126
|
* synchronous `getYRange()` / `getVisibleRange()` read sees final values.
|
|
1997
2127
|
*/
|
|
1998
|
-
#
|
|
1999
|
-
const e = this.#
|
|
2000
|
-
for (const r of this.#
|
|
2001
|
-
const n = this.#
|
|
2128
|
+
#re(t) {
|
|
2129
|
+
const e = this.#a, i = this.#G(e), s = {};
|
|
2130
|
+
for (const r of this.#o.keys()) {
|
|
2131
|
+
const n = this.#G(e, r);
|
|
2002
2132
|
n !== null && (s[r] = n);
|
|
2003
2133
|
}
|
|
2004
|
-
this.#
|
|
2134
|
+
this.#_ = !0, i !== null && (this.#u = !0), this.#e.snap({ x: e, y: i ?? void 0, scales: s }, t), this.#x(t);
|
|
2005
2135
|
}
|
|
2006
2136
|
/**
|
|
2007
2137
|
* Validate and commit a new logical X range. Mirrors the old
|
|
@@ -2021,9 +2151,9 @@ class _e extends Et {
|
|
|
2021
2151
|
* see `setVisibleRange`'s gesture path, where a per-frame echo would
|
|
2022
2152
|
* otherwise re-arm and stall the in-flight Y ease.
|
|
2023
2153
|
*/
|
|
2024
|
-
#
|
|
2154
|
+
#D(t, e) {
|
|
2025
2155
|
const { from: i, to: s } = t;
|
|
2026
|
-
return !Number.isFinite(i) || !Number.isFinite(s) || s <= i || !e.skipValidation && (s - i) / this.#
|
|
2156
|
+
return !Number.isFinite(i) || !Number.isFinite(s) || s <= i || !e.skipValidation && (s - i) / this.#r < 2 || this.#a.from === i && this.#a.to === s ? !1 : (this.#a = { from: i, to: s }, e.emitChange && (this.syncScales(), this.#i?.markDirty(), this.emit("viewportChange")), !0);
|
|
2027
2157
|
}
|
|
2028
2158
|
/**
|
|
2029
2159
|
* Apply pixel-padding to the engine's Y (scale space) and return it as
|
|
@@ -2032,23 +2162,23 @@ class _e extends Et {
|
|
|
2032
2162
|
* that has an explicit (fixed) axis bound. Padding in scale space keeps
|
|
2033
2163
|
* the pixel gutters even on a log axis.
|
|
2034
2164
|
*/
|
|
2035
|
-
#
|
|
2036
|
-
const { slot: e, min: i, max: s, chartHeight: r } = t, { yScale: n } = e, { min: a, max: o } = this.#
|
|
2037
|
-
min: a ? i : i -
|
|
2165
|
+
#ze(t) {
|
|
2166
|
+
const { slot: e, min: i, max: s, chartHeight: r } = t, { yScale: n } = e, { min: a, max: o } = this.#Oe(e), h = s - i, l = r > 0 ? this.#l.top / r * h : 0, c = r > 0 ? this.#l.bottom / r * h : 0, f = {
|
|
2167
|
+
min: a ? i : i - c,
|
|
2038
2168
|
max: o ? s : s + l
|
|
2039
|
-
},
|
|
2040
|
-
if (
|
|
2041
|
-
const
|
|
2169
|
+
}, g = n.getTransform();
|
|
2170
|
+
if (g === null) return f;
|
|
2171
|
+
const y = g.inverse(f.min), u = g.inverse(f.max), m = n.isPlottable(y) && y <= g.inverse(i), p = n.isPlottable(u) && u >= g.inverse(s);
|
|
2042
2172
|
return {
|
|
2043
|
-
min:
|
|
2044
|
-
max:
|
|
2173
|
+
min: m ? y : g.inverse(i),
|
|
2174
|
+
max: p ? u : g.inverse(s)
|
|
2045
2175
|
};
|
|
2046
2176
|
}
|
|
2047
2177
|
/** Which Y edges of a scale the user pinned — a pinned edge takes no padding. */
|
|
2048
|
-
#
|
|
2178
|
+
#Oe(t) {
|
|
2049
2179
|
return {
|
|
2050
|
-
min:
|
|
2051
|
-
max:
|
|
2180
|
+
min: ot(t.bounds.min, t.yScale),
|
|
2181
|
+
max: ot(t.bounds.max, t.yScale)
|
|
2052
2182
|
};
|
|
2053
2183
|
}
|
|
2054
2184
|
/**
|
|
@@ -2061,18 +2191,18 @@ class _e extends Et {
|
|
|
2061
2191
|
* as a gesture for visual easing. Public so consumers can drive pan
|
|
2062
2192
|
* programmatically.
|
|
2063
2193
|
*/
|
|
2064
|
-
pan(t, e = this.#
|
|
2065
|
-
e > 0 && (this.#
|
|
2066
|
-
const i =
|
|
2067
|
-
currentLogical: this.#
|
|
2194
|
+
pan(t, e = this.#Q) {
|
|
2195
|
+
e > 0 && (this.#Q = e), this.#L = !1, this.#et();
|
|
2196
|
+
const i = Lt({
|
|
2197
|
+
currentLogical: this.#a,
|
|
2068
2198
|
timeDelta: t,
|
|
2069
2199
|
chartWidth: e,
|
|
2070
|
-
dataInterval: this.#
|
|
2071
|
-
padding: { left: this.#
|
|
2072
|
-
dataStart: this.#
|
|
2200
|
+
dataInterval: this.#r,
|
|
2201
|
+
padding: { left: this.#l.left, right: this.#l.right },
|
|
2202
|
+
dataStart: this.#T,
|
|
2073
2203
|
dataEnd: this.#s
|
|
2074
2204
|
});
|
|
2075
|
-
i.newLogical !== null && (this.#p = !i.autoScrollOff, this.#
|
|
2205
|
+
i.newLogical !== null && (this.#p = !i.autoScrollOff, this.#D(i.newLogical, { emitChange: !0 }), i.edgeReached !== null && (this.#Ft[i.edgeReached.side] = i.edgeReached.boundaryTime, this.#Wt?.(i.edgeReached)), this.#W.pause(), this.#ne());
|
|
2076
2206
|
}
|
|
2077
2207
|
/**
|
|
2078
2208
|
* Zoom around a time anchor. `factor < 1` zooms in, `> 1` zooms out.
|
|
@@ -2089,35 +2219,35 @@ class _e extends Et {
|
|
|
2089
2219
|
* and produce a visible jump). Cursor-anchored zoom is intentionally
|
|
2090
2220
|
* sacrificed in follow-live mode — pan first to inspect history.
|
|
2091
2221
|
*/
|
|
2092
|
-
zoomAt(t, e, i = this.#
|
|
2093
|
-
i > 0 && (this.#
|
|
2094
|
-
const s =
|
|
2095
|
-
currentLogical: this.#
|
|
2222
|
+
zoomAt(t, e, i = this.#Q) {
|
|
2223
|
+
i > 0 && (this.#Q = i), this.#L = !1, this.#et();
|
|
2224
|
+
const s = It({
|
|
2225
|
+
currentLogical: this.#a,
|
|
2096
2226
|
centerTime: t,
|
|
2097
2227
|
factor: e,
|
|
2098
2228
|
chartWidth: i,
|
|
2099
|
-
dataInterval: this.#
|
|
2100
|
-
padding: { left: this.#
|
|
2101
|
-
dataStart: this.#
|
|
2229
|
+
dataInterval: this.#r,
|
|
2230
|
+
padding: { left: this.#l.left, right: this.#l.right },
|
|
2231
|
+
dataStart: this.#T,
|
|
2102
2232
|
dataEnd: this.#s
|
|
2103
2233
|
});
|
|
2104
2234
|
if (s.newLogical === null) return;
|
|
2105
2235
|
let r = s.newLogical;
|
|
2106
2236
|
if (this.#p && this.#s !== null) {
|
|
2107
|
-
const n = r.to - r.from, a =
|
|
2108
|
-
r = { from: o - n, to: o }, this.#
|
|
2237
|
+
const n = r.to - r.from, a = j(this.#l.right, n, this.#r, i), o = this.#s + a;
|
|
2238
|
+
r = { from: o - n, to: o }, this.#J = this.#s;
|
|
2109
2239
|
}
|
|
2110
|
-
this.#
|
|
2240
|
+
this.#D(r, { emitChange: !0 }), this.#W.pause(), this.#ne();
|
|
2111
2241
|
}
|
|
2112
2242
|
/**
|
|
2113
2243
|
* Common tail for `pan` / `zoomAt`: routes the just-committed `#logical`
|
|
2114
2244
|
* to the engine as a gesture so the X spring retargets and the Y spring
|
|
2115
2245
|
* eases over `animations.axis.y.gesture`.
|
|
2116
2246
|
*/
|
|
2117
|
-
#
|
|
2118
|
-
const t = this.#
|
|
2247
|
+
#ne() {
|
|
2248
|
+
const t = this.#a;
|
|
2119
2249
|
if (t.to <= t.from) return;
|
|
2120
|
-
this.#
|
|
2250
|
+
this.#_ = !0, this.#u = !0;
|
|
2121
2251
|
const e = performance.now();
|
|
2122
2252
|
this.#e.onPanZoom({ xTarget: t, yAuto: !0 }, e), this.#x(e);
|
|
2123
2253
|
}
|
|
@@ -2135,26 +2265,34 @@ class _e extends Et {
|
|
|
2135
2265
|
* events long enough for the slot processor to snap them.
|
|
2136
2266
|
*/
|
|
2137
2267
|
#x(t) {
|
|
2138
|
-
const e = this.#e.tick(t), i = this.#
|
|
2268
|
+
const e = this.#e.tick(t), i = this.#c.size;
|
|
2139
2269
|
if (i.media.width === 0 || i.media.height === 0) return;
|
|
2140
2270
|
const s = i.media.height - this.xAxisHeight;
|
|
2141
|
-
for (const { slot: r, range: n } of this.#
|
|
2142
|
-
this.#
|
|
2271
|
+
for (const { slot: r, range: n } of this.#ae(e))
|
|
2272
|
+
this.#oe({ slot: r, range: n, chartHeight: s });
|
|
2143
2273
|
this.syncScales();
|
|
2144
2274
|
}
|
|
2275
|
+
/** Record the X and Y ranges this paint draws; `true` when any moved since the last paint. */
|
|
2276
|
+
#Ye(t) {
|
|
2277
|
+
let e = t.from !== this.#tt.from || t.to !== this.#tt.to;
|
|
2278
|
+
this.#tt.from = t.from, this.#tt.to = t.to, nt(this.#w) && (e = !0);
|
|
2279
|
+
for (const i of this.#o.values())
|
|
2280
|
+
nt(i) && (e = !0);
|
|
2281
|
+
return e;
|
|
2282
|
+
}
|
|
2145
2283
|
/** Each scale's slot with the engine's current Y (scale space) for it. */
|
|
2146
|
-
#
|
|
2147
|
-
const e = [{ slot: this.#
|
|
2148
|
-
for (const [i, s] of this.#
|
|
2284
|
+
#ae(t) {
|
|
2285
|
+
const e = [{ slot: this.#w, range: t.yRange }];
|
|
2286
|
+
for (const [i, s] of this.#o) {
|
|
2149
2287
|
const r = this.#e.getScaleYRange(i);
|
|
2150
2288
|
r !== null && e.push({ slot: s, range: r });
|
|
2151
2289
|
}
|
|
2152
2290
|
return e;
|
|
2153
2291
|
}
|
|
2154
2292
|
/** Pad an engine Y (scale space) into the slot's value range and remember it. */
|
|
2155
|
-
#
|
|
2293
|
+
#oe(t) {
|
|
2156
2294
|
const { slot: e, range: i, chartHeight: s } = t, r = e.range;
|
|
2157
|
-
e.range = this.#
|
|
2295
|
+
e.range = this.#ze({ slot: e, min: i.min, max: i.max, chartHeight: s }), e.prevMin = i.min, e.prevMax = i.max, (r.min !== e.range.min || r.max !== e.range.max) && e !== this.#w && (this.#ot = !0);
|
|
2158
2296
|
}
|
|
2159
2297
|
/**
|
|
2160
2298
|
* Lightweight scale sync: updates timeScale/yScale from current viewport state
|
|
@@ -2162,99 +2300,104 @@ class _e extends Et {
|
|
|
2162
2300
|
* handler, so DOM axis components always read fresh coordinates on re-render.
|
|
2163
2301
|
*/
|
|
2164
2302
|
syncScales() {
|
|
2165
|
-
const t = this.#
|
|
2303
|
+
const t = this.#c.size;
|
|
2166
2304
|
if (t.media.width === 0 || t.media.height === 0) return;
|
|
2167
|
-
const e = t.media.width - this.#
|
|
2305
|
+
const e = t.media.width - this.#k(), i = t.media.height - this.xAxisHeight;
|
|
2168
2306
|
this.timeScale.update(
|
|
2169
2307
|
this.#e.getAnimationState().xRange,
|
|
2170
2308
|
e,
|
|
2171
2309
|
t.horizontalPixelRatio,
|
|
2172
|
-
this.#
|
|
2173
|
-
), this.yScale.update(this.#
|
|
2174
|
-
for (const s of this.#
|
|
2310
|
+
this.#r
|
|
2311
|
+
), this.yScale.update(this.#w.range, i, t.verticalPixelRatio);
|
|
2312
|
+
for (const s of this.#o.values())
|
|
2175
2313
|
s.yScale.update(s.range, i, t.verticalPixelRatio);
|
|
2176
2314
|
}
|
|
2177
2315
|
/** Expensive: background, grid, all series. Only on data/viewport/resize change. */
|
|
2178
2316
|
renderMain(t) {
|
|
2179
|
-
const e = this.#
|
|
2317
|
+
const e = this.#c.size;
|
|
2180
2318
|
if (e.media.width === 0 || e.media.height === 0) return;
|
|
2181
2319
|
const i = typeof t == "number" ? t : performance.now(), s = this.#e.tick(i);
|
|
2182
2320
|
s.animating && this.#i.markDirty();
|
|
2183
2321
|
const r = e.media.height - this.xAxisHeight;
|
|
2184
2322
|
let n = !1;
|
|
2185
|
-
for (const { slot:
|
|
2186
|
-
m.min ===
|
|
2187
|
-
if (this.syncScales(), this.#
|
|
2188
|
-
const
|
|
2323
|
+
for (const { slot: u, range: m } of this.#ae(s))
|
|
2324
|
+
m.min === u.prevMin && m.max === u.prevMax || (this.#oe({ slot: u, range: m, chartHeight: r }), n = !0);
|
|
2325
|
+
if (this.syncScales(), this.#Re(), this.#s !== null && !this.#p) {
|
|
2326
|
+
const u = this.#e.lastXTarget ?? this.#a, m = u.to - u.from;
|
|
2189
2327
|
if (m > 0) {
|
|
2190
|
-
const
|
|
2191
|
-
Math.abs(
|
|
2328
|
+
const p = this.#c.size.media.width - this.#k(), x = j(this.#l.right, m, this.#r, p), T = this.#r * 0.5;
|
|
2329
|
+
Math.abs(u.to - (this.#s + x)) < T && (this.#p = !0);
|
|
2192
2330
|
}
|
|
2193
2331
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
m
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2332
|
+
const a = this.#Ye(s.xRange);
|
|
2333
|
+
(n || a && !s.animating) && this.emit("viewportChange");
|
|
2334
|
+
let o = !1, h = !1, l = !1, c = !1;
|
|
2335
|
+
this.#c.useMainLayer((u) => {
|
|
2336
|
+
const { context: m, bitmapSize: p } = u, x = (e.media.width - this.#k()) * e.horizontalPixelRatio, T = (e.media.height - this.xAxisHeight) * e.verticalPixelRatio, N = this.#z(u);
|
|
2337
|
+
m.clearRect(0, 0, p.width, p.height), m.save(), m.translate(N, 0), m.beginPath(), m.rect(0, 0, this.#fe(u, x), T), m.clip(), this.yScale.tickTracker.setCurrentTicks(this.yScale.niceTickValues()), this.timeScale.tickTracker.setCurrentTicks(this.timeScale.niceTickValues(this.#r).ticks), this.yScale.tickTracker.tick(i), this.timeScale.tickTracker.tick(i);
|
|
2338
|
+
for (const v of this.#o.values()) {
|
|
2339
|
+
const b = v.yScale.tickTracker;
|
|
2340
|
+
b.setCurrentTicks(v.yScale.niceTickValues()), b.tick(i) && (l = !0);
|
|
2202
2341
|
}
|
|
2203
|
-
const w = this.yScale.tickTracker.snapshot(),
|
|
2204
|
-
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2342
|
+
const w = this.yScale.tickTracker.snapshot(), M = this.timeScale.tickTracker.snapshot();
|
|
2343
|
+
o = w.isAnimating, h = M.isAnimating;
|
|
2344
|
+
const P = w.isAnimating || M.isAnimating || l, ct = this.#Ht && !P;
|
|
2345
|
+
this.#Ht = P, (P || ct || s.animating) && this.emit("tickFrame");
|
|
2346
|
+
const C = this.#j ? 1 : 0;
|
|
2347
|
+
if ((C === 0 || w.entries.length > 0 || M.entries.length > 0) && C !== this.#Y.target) {
|
|
2348
|
+
const v = xt() ? 0 : this.#g.axis.gridMs;
|
|
2349
|
+
this.#Y.setTarget(C, { now: i, duration: v });
|
|
2209
2350
|
}
|
|
2210
|
-
|
|
2211
|
-
const
|
|
2212
|
-
scope:
|
|
2351
|
+
c = this.#Y.tick(i);
|
|
2352
|
+
const F = this.#Y.current, W = this.#n === "category" ? de : M, $ = {
|
|
2353
|
+
scope: u,
|
|
2213
2354
|
timeScale: this.timeScale,
|
|
2214
2355
|
yScale: this.yScale,
|
|
2215
|
-
theme: this.#
|
|
2356
|
+
theme: this.#h,
|
|
2216
2357
|
yTicks: w,
|
|
2217
|
-
timeTicks:
|
|
2218
|
-
alpha:
|
|
2219
|
-
},
|
|
2220
|
-
|
|
2221
|
-
const
|
|
2222
|
-
for (const
|
|
2223
|
-
this.#
|
|
2224
|
-
const b =
|
|
2358
|
+
timeTicks: W,
|
|
2359
|
+
alpha: F
|
|
2360
|
+
}, L = this.#ue(u, x);
|
|
2361
|
+
L === 0 && K($), this.#be(u, x, T);
|
|
2362
|
+
const z = this.#l, dt = { top: z.top, bottom: z.bottom }, ut = this.#xt(s), O = this.#P;
|
|
2363
|
+
for (const v of this.#t) {
|
|
2364
|
+
this.#Me(v);
|
|
2365
|
+
const b = v.renderer.getAlpha?.() ?? (v.visible ? 1 : 0);
|
|
2225
2366
|
if (b <= 0) continue;
|
|
2226
|
-
const
|
|
2227
|
-
scope:
|
|
2367
|
+
const I = this.#I(v), mt = this.getYScale(I), E = {
|
|
2368
|
+
scope: u,
|
|
2228
2369
|
timeScale: this.timeScale,
|
|
2229
|
-
yScale:
|
|
2230
|
-
theme: this.#
|
|
2231
|
-
dataInterval: this.#
|
|
2232
|
-
padding:
|
|
2233
|
-
state:
|
|
2234
|
-
seriesId:
|
|
2235
|
-
},
|
|
2236
|
-
if (b < 1 && (m.globalAlpha =
|
|
2237
|
-
const
|
|
2238
|
-
|
|
2370
|
+
yScale: mt,
|
|
2371
|
+
theme: this.#h,
|
|
2372
|
+
dataInterval: this.#r,
|
|
2373
|
+
padding: dt,
|
|
2374
|
+
state: I === void 0 ? ut : this.#Zt(s, I),
|
|
2375
|
+
seriesId: v.id
|
|
2376
|
+
}, B = m.globalAlpha;
|
|
2377
|
+
if (b < 1 && (m.globalAlpha = B * b), O) {
|
|
2378
|
+
const ft = performance.now();
|
|
2379
|
+
v.renderer.render(E), O.recordSeries(v.id, performance.now() - ft, i);
|
|
2239
2380
|
} else
|
|
2240
|
-
|
|
2241
|
-
b < 1 && (m.globalAlpha =
|
|
2381
|
+
v.renderer.render(E);
|
|
2382
|
+
b < 1 && (m.globalAlpha = B);
|
|
2242
2383
|
}
|
|
2243
2384
|
m.restore();
|
|
2244
|
-
const
|
|
2245
|
-
|
|
2246
|
-
}), this.#
|
|
2247
|
-
let
|
|
2248
|
-
for (const
|
|
2249
|
-
if (
|
|
2250
|
-
|
|
2385
|
+
const Y = { left: N, width: x, height: T };
|
|
2386
|
+
L === 0 ? (this.#le({ scope: u, pane: Y, timeTicks: W, alpha: F }), this.#$(u, x, "left"), this.#$(u, x, "right")) : (this.#$(u, x, "left"), this.#Xe({ grid: $, pane: Y, overhang: L }), this.#$(u, x, "right")), this.#de(u, x), this.#he(u, T);
|
|
2387
|
+
}), this.#St();
|
|
2388
|
+
let f = !1;
|
|
2389
|
+
for (const u of this.#t)
|
|
2390
|
+
if (u.renderer.needsAnimation) {
|
|
2391
|
+
f = !0, this.#i.markDirty();
|
|
2251
2392
|
break;
|
|
2252
2393
|
}
|
|
2253
|
-
const
|
|
2254
|
-
|
|
2394
|
+
const g = f || this.#Ot;
|
|
2395
|
+
this.#Ot = f, g && (this.#zt++, this.emit("seriesFrame"));
|
|
2396
|
+
const y = o || h || l;
|
|
2397
|
+
if ((y || c) && this.#i.markDirty(), !s.animating && !f && !y) {
|
|
2255
2398
|
this.yScale.tickTracker.markArmed(), this.timeScale.tickTracker.markArmed();
|
|
2256
|
-
for (const
|
|
2257
|
-
|
|
2399
|
+
for (const u of this.#o.values())
|
|
2400
|
+
u.yScale.tickTracker.markArmed();
|
|
2258
2401
|
}
|
|
2259
2402
|
}
|
|
2260
2403
|
/**
|
|
@@ -2264,12 +2407,12 @@ class _e extends Et {
|
|
|
2264
2407
|
* a paint-over — so the container background behind the canvas (solid or
|
|
2265
2408
|
* CSS gradient) shows through untouched.
|
|
2266
2409
|
*/
|
|
2267
|
-
#
|
|
2410
|
+
#he(t, e) {
|
|
2268
2411
|
if (this.#C.top <= 0) return;
|
|
2269
2412
|
const i = Math.min(Math.round(this.#C.top * t.verticalPixelRatio), Math.round(e));
|
|
2270
2413
|
if (i < 1) return;
|
|
2271
2414
|
const { context: s } = t;
|
|
2272
|
-
s.save(), s.globalCompositeOperation = "destination-out", s.fillStyle = this.#
|
|
2415
|
+
s.save(), s.globalCompositeOperation = "destination-out", s.fillStyle = this.#_e(s, i), s.fillRect(0, 0, t.bitmapSize.width, i), s.restore();
|
|
2273
2416
|
}
|
|
2274
2417
|
/**
|
|
2275
2418
|
* Run the vertical gridlines a short stub past the pane floor, dissolving
|
|
@@ -2279,23 +2422,23 @@ class _e extends Et {
|
|
|
2279
2422
|
* nothing else paints) and faded with the same destination-out ramp the
|
|
2280
2423
|
* edge masks use, so the taper stays correct over any background.
|
|
2281
2424
|
*/
|
|
2282
|
-
#
|
|
2425
|
+
#le(t) {
|
|
2283
2426
|
const { scope: e, pane: i, timeTicks: s, alpha: r } = t;
|
|
2284
|
-
if (!this.#
|
|
2285
|
-
const { context: n, horizontalPixelRatio: a, verticalPixelRatio: o } = e, h = Math.round(i.height), l = Math.round(
|
|
2427
|
+
if (!this.#j && r <= 0.01 || this.xAxisHeight === 0) return;
|
|
2428
|
+
const { context: n, horizontalPixelRatio: a, verticalPixelRatio: o } = e, h = Math.round(i.height), l = Math.round(H * o);
|
|
2286
2429
|
if (l < 1) return;
|
|
2287
|
-
const
|
|
2288
|
-
n.save(), n.strokeStyle =
|
|
2289
|
-
const f =
|
|
2290
|
-
for (const { value:
|
|
2291
|
-
const
|
|
2292
|
-
if (
|
|
2293
|
-
const
|
|
2294
|
-
if (
|
|
2295
|
-
const
|
|
2296
|
-
n.globalAlpha =
|
|
2430
|
+
const c = this.#h.grid;
|
|
2431
|
+
n.save(), n.strokeStyle = c.color, c.style === "dashed" ? n.setLineDash([4 * a, 4 * a]) : c.style === "dotted" && n.setLineDash([1 * a, 3 * a]), n.lineDashOffset = h, n.lineWidth = re(a);
|
|
2432
|
+
const f = ne(a), g = Math.round(i.width);
|
|
2433
|
+
for (const { value: y, opacity: u } of s.entries) {
|
|
2434
|
+
const m = u * r;
|
|
2435
|
+
if (m <= 0.01) continue;
|
|
2436
|
+
const p = Math.round(this.timeScale.timeToBitmapX(y)) + f;
|
|
2437
|
+
if (p < 0 || p > g) continue;
|
|
2438
|
+
const x = i.left + p;
|
|
2439
|
+
n.globalAlpha = m, n.beginPath(), n.moveTo(x, h), n.lineTo(x, h + l), n.stroke();
|
|
2297
2440
|
}
|
|
2298
|
-
n.restore(), this.#
|
|
2441
|
+
n.restore(), this.#ce(e, i.height);
|
|
2299
2442
|
}
|
|
2300
2443
|
/**
|
|
2301
2444
|
* Erase ramp over the below-pane overrun strip — the gridline tail stubs
|
|
@@ -2303,12 +2446,12 @@ class _e extends Et {
|
|
|
2303
2446
|
* erased at the pane floor, total at the strip's bottom edge, so whatever
|
|
2304
2447
|
* crosses the floor tapers out short of the time-axis labels.
|
|
2305
2448
|
*/
|
|
2306
|
-
#
|
|
2449
|
+
#ce(t, e) {
|
|
2307
2450
|
if (this.xAxisHeight === 0) return;
|
|
2308
|
-
const i = Math.round(e), s = Math.round(
|
|
2451
|
+
const i = Math.round(e), s = Math.round(H * t.verticalPixelRatio);
|
|
2309
2452
|
if (s < 1) return;
|
|
2310
2453
|
const { context: r } = t;
|
|
2311
|
-
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#
|
|
2454
|
+
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#Ge({ context: r, start: i, height: s }), r.fillRect(0, i, t.bitmapSize.width, s), r.restore();
|
|
2312
2455
|
}
|
|
2313
2456
|
/**
|
|
2314
2457
|
* Crosshair hairlines with the same edge melt the main layer runs: the
|
|
@@ -2320,18 +2463,18 @@ class _e extends Et {
|
|
|
2320
2463
|
* edge. Erases alpha (destination-out), so it must run while the
|
|
2321
2464
|
* crosshair is the only content on the layer.
|
|
2322
2465
|
*/
|
|
2323
|
-
#
|
|
2466
|
+
#Ee(t) {
|
|
2324
2467
|
const e = this.#f;
|
|
2325
2468
|
if (e === null) return;
|
|
2326
|
-
const { scope: i, chartBitmapWidth: s, chartBitmapHeight: r } = t, { context: n } = i, a = this.#
|
|
2327
|
-
n.save(), n.translate(a, 0), n.beginPath(), n.rect(-h, 0, o + h, r + l), n.clip(),
|
|
2469
|
+
const { scope: i, chartBitmapWidth: s, chartBitmapHeight: r } = t, { context: n } = i, a = this.#z(i), o = this.#fe(i, s), h = this.#ue(i, s), l = this.xAxisHeight > 0 ? Math.round(H * i.verticalPixelRatio) : 0;
|
|
2470
|
+
n.save(), n.translate(a, 0), n.beginPath(), n.rect(-h, 0, o + h, r + l), n.clip(), _t({
|
|
2328
2471
|
scope: i,
|
|
2329
2472
|
bitmapX: e.mediaX * i.horizontalPixelRatio - a,
|
|
2330
2473
|
bitmapY: e.mediaY * i.verticalPixelRatio,
|
|
2331
|
-
theme: this.#
|
|
2474
|
+
theme: this.#h,
|
|
2332
2475
|
pane: { width: s, height: r },
|
|
2333
2476
|
leftOverhang: h
|
|
2334
|
-
}), n.restore(), this.#
|
|
2477
|
+
}), n.restore(), this.#ce(i, r), h === 0 ? this.#$(i, s, "left") : this.#me(i, h), this.#$(i, s, "right"), this.#de(i, s), this.#he(i, r);
|
|
2335
2478
|
}
|
|
2336
2479
|
/**
|
|
2337
2480
|
* Horizontal companion to {@link #applyTopFade}: dissolve content that
|
|
@@ -2341,57 +2484,57 @@ class _e extends Et {
|
|
|
2341
2484
|
* at the edges in step with their lines above.
|
|
2342
2485
|
*/
|
|
2343
2486
|
#$(t, e, i) {
|
|
2344
|
-
const s = this.#
|
|
2487
|
+
const s = this.#at(t, e, i);
|
|
2345
2488
|
if (s === null) return;
|
|
2346
2489
|
const { context: r } = t, n = Math.min(s.inner, s.outer), a = Math.abs(s.outer - s.inner);
|
|
2347
|
-
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#
|
|
2490
|
+
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#Ue({ context: r, side: i, zone: s }), r.fillRect(n, 0, a, t.bitmapSize.height), r.restore();
|
|
2348
2491
|
}
|
|
2349
2492
|
/** Dissolve content leaving through a plain canvas edge — the side opposite
|
|
2350
2493
|
* the Y axis, or either side on a spatial-only chart — when configured. */
|
|
2351
|
-
#
|
|
2494
|
+
#de(t, e) {
|
|
2352
2495
|
const { context: i } = t;
|
|
2353
|
-
for (const s of this.#
|
|
2354
|
-
const r = this.#
|
|
2496
|
+
for (const s of this.#Be()) {
|
|
2497
|
+
const r = this.#Ze({ scope: t, paneBitmapWidth: e, side: s });
|
|
2355
2498
|
if (r === null) continue;
|
|
2356
2499
|
const n = Math.min(r.edge, r.inner), a = Math.abs(r.inner - r.edge);
|
|
2357
|
-
i.save(), i.globalCompositeOperation = "destination-out", i.fillStyle = this.#
|
|
2500
|
+
i.save(), i.globalCompositeOperation = "destination-out", i.fillStyle = this.#Ke({ context: i, side: s, zone: r }), i.fillRect(n, 0, a, t.bitmapSize.height), i.restore();
|
|
2358
2501
|
}
|
|
2359
2502
|
}
|
|
2360
2503
|
/** Sides whose fade is a plain edge zone rather than the axis-column ramp —
|
|
2361
2504
|
* neither the default axis's side nor one a named scale's column holds. */
|
|
2362
|
-
#
|
|
2363
|
-
if (this.#
|
|
2364
|
-
const t =
|
|
2365
|
-
return this.getAxisColumnWidth(t) > 0 ?
|
|
2505
|
+
#Be() {
|
|
2506
|
+
if (this.#it()) return ce;
|
|
2507
|
+
const t = at(this.yAxisPosition);
|
|
2508
|
+
return this.getAxisColumnWidth(t) > 0 ? ue : t === "left" ? me : fe;
|
|
2366
2509
|
}
|
|
2367
2510
|
/** Bitmap px the gridlines and crosshair run under a left Y-axis column, where
|
|
2368
2511
|
* data can't follow (see {@link #axisFadeZone}). `0` without one or with its fade off. */
|
|
2369
|
-
#
|
|
2370
|
-
return this.#
|
|
2512
|
+
#ue(t, e) {
|
|
2513
|
+
return this.#at(t, e, "left") === null ? 0 : Math.min(Math.round(et * t.horizontalPixelRatio), this.#z(t));
|
|
2371
2514
|
}
|
|
2372
2515
|
/** Left-axis grid pass, run after the axis fade: `destination-over` keeps the
|
|
2373
2516
|
* gridlines out of the data ramp, then they taper out under the column. */
|
|
2374
|
-
#
|
|
2517
|
+
#Xe(t) {
|
|
2375
2518
|
const { grid: e, pane: i, overhang: s } = t, { scope: r } = e, { context: n } = r;
|
|
2376
2519
|
n.save(), n.globalCompositeOperation = "destination-over";
|
|
2377
|
-
const a = this.#
|
|
2378
|
-
n.save(), n.translate(i.left, 0), n.beginPath(), n.rect(-s, 0, i.width + s + a, i.height), n.clip(),
|
|
2520
|
+
const a = this.#at(r, i.width, "right")?.intrusion ?? 0;
|
|
2521
|
+
n.save(), n.translate(i.left, 0), n.beginPath(), n.rect(-s, 0, i.width + s + a, i.height), n.clip(), K({ ...e, leftOverhang: s }), n.restore(), this.#le({ scope: r, pane: i, timeTicks: e.timeTicks, alpha: e.alpha ?? 1 }), n.restore(), this.#me(r, s);
|
|
2379
2522
|
}
|
|
2380
2523
|
/** Erase the {@link #gridOverhang} strip: none at the pane edge, total at its outer end. */
|
|
2381
|
-
#
|
|
2382
|
-
const i = this.#
|
|
2383
|
-
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#
|
|
2524
|
+
#me(t, e) {
|
|
2525
|
+
const i = this.#z(t), s = i - e, { context: r } = t;
|
|
2526
|
+
r.save(), r.globalCompositeOperation = "destination-out", r.fillStyle = this.#je({ context: r, start: s, end: i }), r.fillRect(s, 0, e, t.bitmapSize.height), r.restore();
|
|
2384
2527
|
}
|
|
2385
2528
|
/** Canvas bitmap x of the pane's left edge — whole device pixels, so the
|
|
2386
2529
|
* translated pane keeps crisp strokes. */
|
|
2387
|
-
#
|
|
2530
|
+
#z(t) {
|
|
2388
2531
|
return Math.round(this.plotLeft * t.horizontalPixelRatio);
|
|
2389
2532
|
}
|
|
2390
2533
|
/** Pane-local width of the pane clip: the pane plus the right fade
|
|
2391
2534
|
* intrusion, so content can slide under a right Y-axis column before the
|
|
2392
2535
|
* mask dissolves it. */
|
|
2393
|
-
#
|
|
2394
|
-
const i = this.#
|
|
2536
|
+
#fe(t, e) {
|
|
2537
|
+
const i = this.#at(t, e, "right")?.intrusion ?? 0;
|
|
2395
2538
|
return e + i;
|
|
2396
2539
|
}
|
|
2397
2540
|
/**
|
|
@@ -2405,22 +2548,22 @@ class _e extends Et {
|
|
|
2405
2548
|
* total-erased anyway). `null` when no column sits on `side`, its fade
|
|
2406
2549
|
* is `0`, or the chart is spatial-only.
|
|
2407
2550
|
*/
|
|
2408
|
-
#
|
|
2409
|
-
if (this.#
|
|
2410
|
-
const s = i === "left", r = t.bitmapSize.width, n = this.#
|
|
2551
|
+
#at(t, e, i) {
|
|
2552
|
+
if (this.#it()) return null;
|
|
2553
|
+
const s = i === "left", r = t.bitmapSize.width, n = this.#z(t), a = s ? n : Math.max(0, Math.round(r - n - e));
|
|
2411
2554
|
if (a === 0) return null;
|
|
2412
|
-
const o = t.horizontalPixelRatio, h = Math.round(
|
|
2413
|
-
if (
|
|
2555
|
+
const o = t.horizontalPixelRatio, h = Math.round(et * o), l = Math.round(le * o), c = s ? 0 : Math.min(h, a), f = s ? h + l : c + l, g = s ? this.#C.left : this.#C.right, y = g === null ? f : Math.round(g * o);
|
|
2556
|
+
if (y < 1) return null;
|
|
2414
2557
|
if (s) {
|
|
2415
|
-
const
|
|
2416
|
-
return { inner:
|
|
2558
|
+
const p = a, x = Math.min(y, r - p);
|
|
2559
|
+
return { inner: p + x, outer: p, intrusion: c };
|
|
2417
2560
|
}
|
|
2418
|
-
const
|
|
2419
|
-
return { inner:
|
|
2561
|
+
const u = n + e + c, m = Math.min(y, u);
|
|
2562
|
+
return { inner: u - m, outer: u, intrusion: c };
|
|
2420
2563
|
}
|
|
2421
2564
|
/** Bitmap geometry of a plain fade at the `side` canvas edge — total erase
|
|
2422
2565
|
* at `edge`, none at `inner`. Off unless that side's fade is configured. */
|
|
2423
|
-
#
|
|
2566
|
+
#Ze(t) {
|
|
2424
2567
|
const { scope: e, paneBitmapWidth: i, side: s } = t, r = this.#C[s];
|
|
2425
2568
|
if (r === null) return null;
|
|
2426
2569
|
const n = Math.min(Math.round(r * e.horizontalPixelRatio), Math.round(i));
|
|
@@ -2435,15 +2578,15 @@ class _e extends Et {
|
|
|
2435
2578
|
* changes (resize, DPR change, `setFade`). Ease-out ramp (`1 - t²`):
|
|
2436
2579
|
* near-total erasure across the upper half keeps a floating header
|
|
2437
2580
|
* legible, then a soft tail into full opacity at the zone's bottom. */
|
|
2438
|
-
#
|
|
2439
|
-
const i = this.#
|
|
2581
|
+
#_e(t, e) {
|
|
2582
|
+
const i = this.#b.top;
|
|
2440
2583
|
if (i !== null && i.height === e) return i.gradient;
|
|
2441
2584
|
const s = t.createLinearGradient(0, 0, 0, e);
|
|
2442
2585
|
for (let r = 0; r <= 4; r++) {
|
|
2443
2586
|
const n = r / 4;
|
|
2444
2587
|
s.addColorStop(n, `rgba(0, 0, 0, ${1 - n * n})`);
|
|
2445
2588
|
}
|
|
2446
|
-
return this.#
|
|
2589
|
+
return this.#b.top = { height: e, gradient: s }, s;
|
|
2447
2590
|
}
|
|
2448
2591
|
/** Axis-column mask — erase grows from 0 at the ramp's inner start to
|
|
2449
2592
|
* total at its outer end on an ease-in (`s³`): zero slope *and* zero
|
|
@@ -2451,51 +2594,51 @@ class _e extends Et {
|
|
|
2451
2594
|
* candles at rest and the aggressive erasing all happens deep under the
|
|
2452
2595
|
* axis column. Nine stops keep the piecewise interpolation smooth across
|
|
2453
2596
|
* the zone. */
|
|
2454
|
-
#
|
|
2455
|
-
const { context: e, side: i, zone: s } = t, r = this.#
|
|
2597
|
+
#Ue(t) {
|
|
2598
|
+
const { context: e, side: i, zone: s } = t, r = this.#b.axis[i];
|
|
2456
2599
|
if (r !== null && r.inner === s.inner && r.outer === s.outer) return r.gradient;
|
|
2457
2600
|
const n = e.createLinearGradient(s.inner, 0, s.outer, 0);
|
|
2458
2601
|
for (let a = 0; a <= 8; a++) {
|
|
2459
2602
|
const o = a / 8;
|
|
2460
2603
|
n.addColorStop(o, `rgba(0, 0, 0, ${o * o * o})`);
|
|
2461
2604
|
}
|
|
2462
|
-
return this.#
|
|
2605
|
+
return this.#b.axis[i] = { inner: s.inner, outer: s.outer, gradient: n }, n;
|
|
2463
2606
|
}
|
|
2464
2607
|
/** Erase ramp for the gridline tail stubs — nothing erased at the pane
|
|
2465
2608
|
* floor, total at the stub tip, ease-in (`t²`) so a stub holds strength
|
|
2466
2609
|
* briefly before melting away short of the label glyphs. */
|
|
2467
|
-
#
|
|
2468
|
-
const e = this.#
|
|
2610
|
+
#Ge(t) {
|
|
2611
|
+
const e = this.#b.tail;
|
|
2469
2612
|
if (e !== null && e.start === t.start && e.height === t.height) return e.gradient;
|
|
2470
2613
|
const i = t.context.createLinearGradient(0, t.start, 0, t.start + t.height);
|
|
2471
2614
|
for (let s = 0; s <= 4; s++) {
|
|
2472
2615
|
const r = s / 4;
|
|
2473
2616
|
i.addColorStop(r, `rgba(0, 0, 0, ${r * r})`);
|
|
2474
2617
|
}
|
|
2475
|
-
return this.#
|
|
2618
|
+
return this.#b.tail = { start: t.start, height: t.height, gradient: i }, i;
|
|
2476
2619
|
}
|
|
2477
2620
|
/** Gridline overhang ramp — ease-in (`t²`) like the tail stubs. */
|
|
2478
|
-
#
|
|
2479
|
-
const e = this.#
|
|
2621
|
+
#je(t) {
|
|
2622
|
+
const e = this.#b.overhang;
|
|
2480
2623
|
if (e !== null && e.start === t.start && e.end === t.end) return e.gradient;
|
|
2481
2624
|
const i = t.context.createLinearGradient(t.end, 0, t.start, 0);
|
|
2482
2625
|
for (let s = 0; s <= 4; s++) {
|
|
2483
2626
|
const r = s / 4;
|
|
2484
2627
|
i.addColorStop(r, `rgba(0, 0, 0, ${r * r})`);
|
|
2485
2628
|
}
|
|
2486
|
-
return this.#
|
|
2629
|
+
return this.#b.overhang = { start: t.start, end: t.end, gradient: i }, i;
|
|
2487
2630
|
}
|
|
2488
2631
|
/** Opposite-edge mask — mirror of the top ramp: total erase at the
|
|
2489
2632
|
* canvas edge, fully opaque at the zone's inner boundary. */
|
|
2490
|
-
#
|
|
2491
|
-
const { context: e, side: i, zone: s } = t, r = this.#
|
|
2633
|
+
#Ke(t) {
|
|
2634
|
+
const { context: e, side: i, zone: s } = t, r = this.#b.edge[i];
|
|
2492
2635
|
if (r !== null && r.edge === s.edge && r.inner === s.inner) return r.gradient;
|
|
2493
2636
|
const n = e.createLinearGradient(s.edge, 0, s.inner, 0);
|
|
2494
2637
|
for (let a = 0; a <= 4; a++) {
|
|
2495
2638
|
const o = a / 4;
|
|
2496
2639
|
n.addColorStop(o, `rgba(0, 0, 0, ${1 - o * o})`);
|
|
2497
2640
|
}
|
|
2498
|
-
return this.#
|
|
2641
|
+
return this.#b.edge[i] = { edge: s.edge, inner: s.inner, gradient: n }, n;
|
|
2499
2642
|
}
|
|
2500
2643
|
/**
|
|
2501
2644
|
* Paint a full frame: the main layer, then the overlay synchronously on
|
|
@@ -2506,13 +2649,13 @@ class _e extends Et {
|
|
|
2506
2649
|
* `markDirty` calls made *during* `renderOverlay` (pulse, edge spinner)
|
|
2507
2650
|
* land after the consume and re-arm cleanly for the next frame.
|
|
2508
2651
|
*/
|
|
2509
|
-
#
|
|
2510
|
-
this.#
|
|
2652
|
+
#Ct(t) {
|
|
2653
|
+
this.#Lt("main", t, () => this.renderMain(t)), this.#d.consume(), this.#Lt("overlay", t, () => this.renderOverlay(t));
|
|
2511
2654
|
}
|
|
2512
2655
|
/** Run a layer's paint, booking duration + draw calls to the perf monitor
|
|
2513
2656
|
* when one is attached — keeps overlay time out of the `main` samples. */
|
|
2514
|
-
#
|
|
2515
|
-
const s = this.#
|
|
2657
|
+
#Lt(t, e, i) {
|
|
2658
|
+
const s = this.#P;
|
|
2516
2659
|
if (!s) {
|
|
2517
2660
|
i();
|
|
2518
2661
|
return;
|
|
@@ -2523,7 +2666,7 @@ class _e extends Et {
|
|
|
2523
2666
|
}
|
|
2524
2667
|
/** Cheap overlay: crosshair, nearest-point dots, pulse animation, edge indicator. */
|
|
2525
2668
|
renderOverlay(t) {
|
|
2526
|
-
const e = this.#
|
|
2669
|
+
const e = this.#c.size;
|
|
2527
2670
|
if (e.media.width === 0 || e.media.height === 0) return;
|
|
2528
2671
|
let i = !1;
|
|
2529
2672
|
for (const l of this.#t)
|
|
@@ -2533,71 +2676,71 @@ class _e extends Et {
|
|
|
2533
2676
|
}
|
|
2534
2677
|
this.#y.some((l) => l.pulse) && (i = !0);
|
|
2535
2678
|
const s = {
|
|
2536
|
-
left: this.#
|
|
2537
|
-
right: this.#
|
|
2679
|
+
left: this.#E.left && this.#A.left === "loading" ? "idle" : this.#A.left,
|
|
2680
|
+
right: this.#E.right && this.#A.right === "loading" ? "idle" : this.#A.right
|
|
2538
2681
|
}, r = {
|
|
2539
|
-
left: this.#
|
|
2540
|
-
right: this.#
|
|
2541
|
-
}, n = r.left !== null || r.right !== null, a = s.left === "loading" || s.right === "loading" || n, o = s.left !== "idle" || s.right !== "idle" || n, h = !!this.#f || i || o || this.#y.length > 0 || this.#
|
|
2542
|
-
if (!(!h && !this.#
|
|
2543
|
-
if (this.#
|
|
2682
|
+
left: this.#Jt("left"),
|
|
2683
|
+
right: this.#Jt("right")
|
|
2684
|
+
}, n = r.left !== null || r.right !== null, a = s.left === "loading" || s.right === "loading" || n, o = s.left !== "idle" || s.right !== "idle" || n, h = !!this.#f || i || o || this.#y.length > 0 || this.#S.length > 0;
|
|
2685
|
+
if (!(!h && !this.#Nt)) {
|
|
2686
|
+
if (this.#Nt = h, this.#c.useOverlayLayer((l) => {
|
|
2544
2687
|
if (!h) return;
|
|
2545
|
-
const
|
|
2546
|
-
this.#f && this.#
|
|
2547
|
-
const
|
|
2548
|
-
for (const
|
|
2549
|
-
if (!
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2688
|
+
const c = (e.media.width - this.#k()) * e.horizontalPixelRatio, f = (e.media.height - this.xAxisHeight) * e.verticalPixelRatio;
|
|
2689
|
+
this.#f && this.#Kt() && this.#Ee({ scope: l, chartBitmapWidth: c, chartBitmapHeight: f }), l.context.save(), l.context.translate(this.#z(l), 0), l.context.beginPath(), l.context.rect(0, 0, c, f), l.context.clip();
|
|
2690
|
+
const g = this.#l, y = { top: g.top, bottom: g.bottom }, u = this.getAnimationState();
|
|
2691
|
+
for (const m of this.#t) {
|
|
2692
|
+
if (!m.visible) continue;
|
|
2693
|
+
const p = this.#I(m);
|
|
2694
|
+
m.renderer.drawOverlay?.({
|
|
2552
2695
|
scope: l,
|
|
2553
2696
|
timeScale: this.timeScale,
|
|
2554
|
-
yScale: this.getYScale(
|
|
2555
|
-
theme: this.#
|
|
2697
|
+
yScale: this.getYScale(p),
|
|
2698
|
+
theme: this.#h,
|
|
2556
2699
|
// Overlays only snap the crosshair dots with it.
|
|
2557
2700
|
dataInterval: this.#X(),
|
|
2558
|
-
padding:
|
|
2701
|
+
padding: y,
|
|
2559
2702
|
crosshair: this.#f,
|
|
2560
|
-
state:
|
|
2561
|
-
seriesId:
|
|
2703
|
+
state: p === void 0 ? u : this.#Zt(u, p),
|
|
2704
|
+
seriesId: m.id
|
|
2562
2705
|
});
|
|
2563
2706
|
}
|
|
2564
|
-
this.#
|
|
2707
|
+
this.#ke(l, c, f), this.#Se(l, c, f), o && kt({
|
|
2565
2708
|
scope: l,
|
|
2566
|
-
chartMediaWidth: e.media.width - this.#
|
|
2709
|
+
chartMediaWidth: e.media.width - this.#k(),
|
|
2567
2710
|
chartMediaHeight: e.media.height - this.xAxisHeight,
|
|
2568
2711
|
timeScale: this.timeScale,
|
|
2569
|
-
theme: this.#
|
|
2712
|
+
theme: this.#h,
|
|
2570
2713
|
edgeStates: s,
|
|
2571
2714
|
edgeExitFades: r,
|
|
2572
|
-
edgeIndicatorFns: this
|
|
2573
|
-
resolveBoundary: (
|
|
2574
|
-
resolveEdgeAnchor: (
|
|
2575
|
-
resolveEdgeBarSpacing: () => this.#
|
|
2576
|
-
reportPlaceholders: (
|
|
2577
|
-
this.#
|
|
2715
|
+
edgeIndicatorFns: this.#$t,
|
|
2716
|
+
resolveBoundary: (m) => Tt(m, this.#Ft[m], this.getDataBounds()),
|
|
2717
|
+
resolveEdgeAnchor: (m, p) => this.#Ie(m, p),
|
|
2718
|
+
resolveEdgeBarSpacing: () => this.#De(),
|
|
2719
|
+
reportPlaceholders: (m, p) => {
|
|
2720
|
+
this.#ct[m] = { bars: p, at: performance.now() };
|
|
2578
2721
|
}
|
|
2579
2722
|
}), l.context.restore();
|
|
2580
2723
|
}), i) {
|
|
2581
|
-
const { from: l, to:
|
|
2724
|
+
const { from: l, to: c } = this.timeScale.getRange();
|
|
2582
2725
|
let f = !1;
|
|
2583
|
-
for (const
|
|
2584
|
-
if (!(!
|
|
2726
|
+
for (const g of this.#t)
|
|
2727
|
+
if (!(!g.visible || !g.renderer.overlayNeedsAnimation) && (g.renderer.hasOverlayContentInRange?.(l, c) ?? !0)) {
|
|
2585
2728
|
f = !0;
|
|
2586
2729
|
break;
|
|
2587
2730
|
}
|
|
2588
2731
|
if (!f) {
|
|
2589
|
-
for (const
|
|
2590
|
-
if (
|
|
2732
|
+
for (const g of this.#y)
|
|
2733
|
+
if (g.pulse && g.time >= l && g.time <= c) {
|
|
2591
2734
|
f = !0;
|
|
2592
2735
|
break;
|
|
2593
2736
|
}
|
|
2594
2737
|
}
|
|
2595
|
-
f && this.#
|
|
2738
|
+
f && this.#d.markDirty();
|
|
2596
2739
|
}
|
|
2597
|
-
a && this.#
|
|
2740
|
+
a && this.#d.markDirty();
|
|
2598
2741
|
}
|
|
2599
2742
|
}
|
|
2600
2743
|
}
|
|
2601
2744
|
export {
|
|
2602
|
-
|
|
2745
|
+
ri as ChartInstance
|
|
2603
2746
|
};
|