@wick-charts/vue 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ChartContainer.vue.js +43 -37
- package/dist/LineSeries.vue.js +2 -2
- package/dist/composables.js +39 -26
- package/dist/core/dist/animation/config.js +66 -64
- package/dist/core/dist/animation/intro-wave.js +19 -21
- package/dist/core/dist/animation/reduced-motion.js +6 -0
- package/dist/core/dist/axis/dom-labels.js +58 -45
- package/dist/core/dist/chart/badge-animator.js +15 -19
- package/dist/core/dist/chart/options.js +5 -5
- package/dist/core/dist/chart/scale-guards.js +26 -0
- package/dist/core/dist/chart/y-target.js +46 -19
- package/dist/core/dist/chart.js +752 -570
- package/dist/core/dist/components/crosshair.js +8 -8
- package/dist/core/dist/components/grid.js +28 -15
- package/dist/core/dist/components/marker.js +28 -28
- package/dist/core/dist/components/reference-line.js +16 -16
- package/dist/core/dist/interactions/handler.js +3 -2
- package/dist/core/dist/interactions/zoom.js +6 -5
- package/dist/core/dist/navigator/controller.js +43 -40
- package/dist/core/dist/perf/perf-hud.js +3 -3
- package/dist/core/dist/scales/log-scale.js +76 -0
- package/dist/core/dist/scales/tick-tracker.js +2 -2
- package/dist/core/dist/scales/x-scale.js +47 -32
- package/dist/core/dist/scales/y-scale.js +155 -38
- package/dist/core/dist/series/bar-intro.js +11 -11
- package/dist/core/dist/series/bar.js +299 -249
- package/dist/core/dist/series/base-multi-layer.js +100 -76
- package/dist/core/dist/series/candlestick.js +252 -249
- package/dist/core/dist/series/heatmap.js +16 -16
- package/dist/core/dist/series/line-intro.js +18 -18
- package/dist/core/dist/series/line.js +522 -424
- package/dist/core/dist/series/scale-stack.js +25 -0
- package/dist/core/dist/tooltip-position.js +5 -5
- package/dist/core/dist/utils/pixel-grid.js +10 -0
- package/dist/index.d.ts +279 -32
- package/dist/index.js +59 -57
- package/dist/ui/Crosshair.vue.js +14 -14
- package/dist/ui/HeatmapTooltip.vue.js +6 -6
- package/dist/ui/PieTooltip.vue.js +4 -4
- package/dist/ui/TimeAxis.vue.js +23 -22
- package/dist/ui/Tooltip.vue.js +71 -69
- package/dist/ui/YAxis.vue.js +25 -24
- package/dist/ui/YLabel.vue.js +50 -49
- package/package.json +2 -2
- package/src/ChartContainer.vue +20 -8
- package/src/composables.ts +35 -1
- package/src/index.ts +5 -0
- package/src/ui/Crosshair.vue +2 -2
- package/src/ui/TimeAxis.vue +7 -4
- package/src/ui/Tooltip.vue +4 -1
- package/src/ui/YAxis.vue +5 -3
- package/src/ui/YLabel.vue +3 -3
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { crispCenterOffset as m } from "../utils/pixel-grid.js";
|
|
2
|
+
import { formatTime as c, niceTimeIntervals as f } from "../utils/time.js";
|
|
3
|
+
import { AxisTickTracker as v } from "./tick-tracker.js";
|
|
4
|
+
const o = 50, d = 80;
|
|
5
|
+
class b {
|
|
5
6
|
/**
|
|
6
7
|
* Shared fade state for time ticks. Grid lines (canvas) and DOM tick labels
|
|
7
8
|
* read opacity from the same tracker, so a tick fading in/out looks
|
|
8
9
|
* identical on both surfaces.
|
|
9
10
|
*/
|
|
10
|
-
tickTracker = new
|
|
11
|
+
tickTracker = new v();
|
|
11
12
|
from = 0;
|
|
12
13
|
to = 0;
|
|
13
14
|
width = 1;
|
|
@@ -37,17 +38,17 @@ class p {
|
|
|
37
38
|
return this.labelCountHintValue;
|
|
38
39
|
}
|
|
39
40
|
get minLabelSpacing() {
|
|
40
|
-
return this.minSpacingValue ??
|
|
41
|
+
return this.minSpacingValue ?? d;
|
|
41
42
|
}
|
|
42
|
-
update(t, e, n,
|
|
43
|
-
if (this.from = t.from, this.to = t.to, this.width = e, this.pixelRatio = n,
|
|
44
|
-
const a = h(
|
|
45
|
-
this.lastBucketKey !== null && this.lastBucketKey !== a && this.resetHysteresis(), this.lastBucketKey = a, this.dataInterval =
|
|
43
|
+
update(t, e, n, l) {
|
|
44
|
+
if (this.from = t.from, this.to = t.to, this.width = e, this.pixelRatio = n, l !== void 0 && l > 0) {
|
|
45
|
+
const a = h(l);
|
|
46
|
+
this.lastBucketKey !== null && this.lastBucketKey !== a && this.resetHysteresis(), this.lastBucketKey = a, this.dataInterval = l;
|
|
46
47
|
}
|
|
47
48
|
this.resolveInterval();
|
|
48
49
|
}
|
|
49
50
|
setLabelCount(t) {
|
|
50
|
-
this.labelCountHintValue =
|
|
51
|
+
this.labelCountHintValue = p(t), this.resetHysteresis(), this.resolveInterval();
|
|
51
52
|
}
|
|
52
53
|
setMinSpacing(t) {
|
|
53
54
|
this.minSpacingValue = I(t), this.resetHysteresis(), this.resolveInterval();
|
|
@@ -88,7 +89,7 @@ class p {
|
|
|
88
89
|
* `formatTime`, applying the installed locale/timezone.
|
|
89
90
|
*/
|
|
90
91
|
formatX(t, e) {
|
|
91
|
-
return this.customFormat ? this.customFormat(t, e) :
|
|
92
|
+
return this.customFormat ? this.customFormat(t, e) : c(t, e, { locale: this.localeValue, timeZone: this.timeZoneValue });
|
|
92
93
|
}
|
|
93
94
|
resetHysteresis() {
|
|
94
95
|
this.lastInterval = null, this.lastWant = null;
|
|
@@ -96,8 +97,22 @@ class p {
|
|
|
96
97
|
timeToX(t) {
|
|
97
98
|
return this.to <= this.from ? 0 : (t - this.from) / (this.to - this.from) * this.width;
|
|
98
99
|
}
|
|
100
|
+
/** X in physical (bitmap) pixels, snapped to the pixel grid — for
|
|
101
|
+
* axis-aligned edges that have to stay crisp. */
|
|
99
102
|
timeToBitmapX(t) {
|
|
100
|
-
return Math.round(this.
|
|
103
|
+
return Math.round(this.timeToBitmapXExact(t));
|
|
104
|
+
}
|
|
105
|
+
/** Same in physical pixels, off the grid — see {@link YScale.valueToBitmapYExact}. */
|
|
106
|
+
timeToBitmapXExact(t) {
|
|
107
|
+
return this.timeToX(t) * this.pixelRatio;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* X position in CSS pixels of the *stroke center* the canvas grid draws for
|
|
111
|
+
* `time`. DOM axis labels position off this instead of raw {@link timeToX}
|
|
112
|
+
* so text and gridline share one pixel grid.
|
|
113
|
+
*/
|
|
114
|
+
timeToSnappedX(t) {
|
|
115
|
+
return (this.timeToBitmapX(t) + m(this.pixelRatio)) / this.pixelRatio;
|
|
101
116
|
}
|
|
102
117
|
xToTime(t) {
|
|
103
118
|
return this.to <= this.from ? this.from : this.from + t / this.width * (this.to - this.from);
|
|
@@ -119,16 +134,16 @@ class p {
|
|
|
119
134
|
niceTickValues(t) {
|
|
120
135
|
if (this.to <= this.from) return { ticks: [], tickInterval: 0 };
|
|
121
136
|
if (this.customTickGenerator) {
|
|
122
|
-
const i = this.customTickGenerator({ from: this.from, to: this.to }, t).slice(0, o),
|
|
123
|
-
return { ticks: i, tickInterval:
|
|
137
|
+
const i = this.customTickGenerator({ from: this.from, to: this.to }, t).slice(0, o), r = i.length >= 2 ? i[1] - i[0] : t;
|
|
138
|
+
return { ticks: i, tickInterval: r };
|
|
124
139
|
}
|
|
125
140
|
if (this.dataInterval !== t) {
|
|
126
141
|
const i = h(t);
|
|
127
142
|
this.lastBucketKey !== null && this.lastBucketKey !== i && this.resetHysteresis(), this.lastBucketKey = i, this.dataInterval = t, this.resolveInterval();
|
|
128
143
|
}
|
|
129
144
|
if (this.resolvedInterval == null) return { ticks: [], tickInterval: 0 };
|
|
130
|
-
const e = this.resolvedInterval, n = Math.ceil(this.from / e) * e,
|
|
131
|
-
for (let i = 0; i <
|
|
145
|
+
const e = this.resolvedInterval, n = Math.ceil(this.from / e) * e, l = Math.max(0, Math.min(o, Math.floor((this.to - n) / e) + 1)), a = [];
|
|
146
|
+
for (let i = 0; i < l; i++) a.push(n + i * e);
|
|
132
147
|
return { ticks: a, tickInterval: e };
|
|
133
148
|
}
|
|
134
149
|
getRange() {
|
|
@@ -147,31 +162,31 @@ class p {
|
|
|
147
162
|
this.resolvedInterval = null;
|
|
148
163
|
return;
|
|
149
164
|
}
|
|
150
|
-
const t =
|
|
151
|
-
let
|
|
165
|
+
const t = f(this.dataInterval), e = this.to - this.from, n = e / this.width * this.minLabelSpacing;
|
|
166
|
+
let l;
|
|
152
167
|
if (this.labelCountHint != null) {
|
|
153
|
-
const
|
|
154
|
-
|
|
168
|
+
const r = Math.max(1, this.labelCountHint);
|
|
169
|
+
l = Math.max(e / r, n);
|
|
155
170
|
} else
|
|
156
|
-
|
|
171
|
+
l = n;
|
|
157
172
|
if (this.lastInterval != null && this.lastWant != null && t.includes(this.lastInterval)) {
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
173
|
+
const r = l >= this.lastWant * 0.8 && l <= this.lastWant * 1.25, u = this.lastInterval >= n;
|
|
174
|
+
if (r && u) {
|
|
160
175
|
this.resolvedInterval = this.lastInterval;
|
|
161
176
|
return;
|
|
162
177
|
}
|
|
163
178
|
}
|
|
164
179
|
let a = t[t.length - 1], i = t.length - 1;
|
|
165
|
-
for (let
|
|
166
|
-
if (t[
|
|
167
|
-
a = t[
|
|
180
|
+
for (let r = 0; r < t.length; r++)
|
|
181
|
+
if (t[r] >= l) {
|
|
182
|
+
a = t[r], i = r;
|
|
168
183
|
break;
|
|
169
184
|
}
|
|
170
185
|
if (this.labelCountHint != null && i > 0 && this.countTicks(a) < this.labelCountHint) {
|
|
171
|
-
const
|
|
172
|
-
|
|
186
|
+
const r = t[i - 1];
|
|
187
|
+
r >= n && (a = r);
|
|
173
188
|
}
|
|
174
|
-
this.resolvedInterval = a, this.lastInterval = a, this.lastWant =
|
|
189
|
+
this.resolvedInterval = a, this.lastInterval = a, this.lastWant = l;
|
|
175
190
|
}
|
|
176
191
|
countTicks(t) {
|
|
177
192
|
if (!(t > 0)) return 0;
|
|
@@ -182,12 +197,12 @@ class p {
|
|
|
182
197
|
function h(s) {
|
|
183
198
|
return s < 6e4 ? 0 : s < 36e5 ? 1 : s < 864e5 ? 2 : 3;
|
|
184
199
|
}
|
|
185
|
-
function
|
|
200
|
+
function p(s) {
|
|
186
201
|
return typeof s == "number" && Number.isFinite(s) && s >= 2 ? Math.floor(s) : null;
|
|
187
202
|
}
|
|
188
203
|
function I(s) {
|
|
189
204
|
return typeof s == "number" && Number.isFinite(s) && s > 0 ? s : null;
|
|
190
205
|
}
|
|
191
206
|
export {
|
|
192
|
-
|
|
207
|
+
b as XScale
|
|
193
208
|
};
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
import { formatCompact as o } from "../utils/format.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { crispCenterOffset as u } from "../utils/pixel-grid.js";
|
|
3
|
+
import { AxisTickTracker as m } from "./tick-tracker.js";
|
|
4
|
+
function c(e) {
|
|
4
5
|
if (!Number.isFinite(e) || e <= 0) return 1;
|
|
5
6
|
const t = 10 ** Math.floor(Math.log10(e)), i = e / t;
|
|
6
7
|
return (i <= 1 ? 1 : i <= 2 ? 2 : i <= 5 ? 5 : 10) * t;
|
|
7
8
|
}
|
|
8
|
-
function
|
|
9
|
+
function f(e) {
|
|
9
10
|
if (!Number.isFinite(e) || e <= 0) return 1;
|
|
10
11
|
const t = 10 ** Math.floor(Math.log10(e)), i = e / t;
|
|
11
12
|
return (i >= 5 ? 5 : i >= 2 ? 2 : 1) * t;
|
|
12
13
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const a = 50, v = 50;
|
|
15
|
+
function g(e, t) {
|
|
16
|
+
return Number.isFinite(t) ? e?.isPlottable?.(t) ?? !0 : !1;
|
|
17
|
+
}
|
|
18
|
+
class d {
|
|
15
19
|
/** Shared fade state for Y ticks; see {@link TimeScale.tickTracker}. */
|
|
16
|
-
tickTracker = new
|
|
20
|
+
tickTracker = new m();
|
|
21
|
+
/** Non-linear value mapping (`axis.y.scale`); `null` is linear. */
|
|
22
|
+
transform = null;
|
|
17
23
|
min = 0;
|
|
18
24
|
max = 0;
|
|
25
|
+
/** Domain bounds in scale space — `transform.forward` of `min` / `max`. */
|
|
26
|
+
lo = 0;
|
|
27
|
+
hi = 0;
|
|
19
28
|
height = 1;
|
|
20
29
|
pixelRatio = 1;
|
|
21
30
|
// Label density knobs — written by <YAxis labelCount=… minLabelSpacing=…>.
|
|
@@ -33,6 +42,8 @@ class M {
|
|
|
33
42
|
* the boundary doesn't instantly flip back.
|
|
34
43
|
*/
|
|
35
44
|
lastRawInterval = null;
|
|
45
|
+
/** The transform's own ticks (e.g. powers of ten); `null` while linear ticks are in use. */
|
|
46
|
+
ownTicks = null;
|
|
36
47
|
/** Custom formatter (driven by `<YAxis format=…>`). */
|
|
37
48
|
customFormat = null;
|
|
38
49
|
/** Custom tick generator — bypasses {1,2,5}×10^k resolution in `niceTickValues` when set. */
|
|
@@ -44,20 +55,46 @@ class M {
|
|
|
44
55
|
return this.minSpacingValue ?? v;
|
|
45
56
|
}
|
|
46
57
|
/** Recalculate the scale with a new Y range, chart height, and device pixel ratio. */
|
|
47
|
-
update(t, i,
|
|
48
|
-
this.min = t.min, this.max = t.max, this.height = i, this.pixelRatio =
|
|
58
|
+
update(t, i, s) {
|
|
59
|
+
this.min = t.min, this.max = t.max, this.height = i, this.pixelRatio = s, this.updateDomain(), this.resolveTicks();
|
|
60
|
+
}
|
|
61
|
+
/** Install a non-linear value mapping, or `null` for linear. The range is kept as-is — the chart refits it. */
|
|
62
|
+
setTransform(t) {
|
|
63
|
+
t !== this.transform && (this.transform = t, this.resetHysteresis(), this.updateDomain(), this.resolveTicks());
|
|
64
|
+
}
|
|
65
|
+
getTransform() {
|
|
66
|
+
return this.transform;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Whether `value` has a position on this scale: finite, and inside the
|
|
70
|
+
* transform's domain (positive on log). Renderers skip values that fail —
|
|
71
|
+
* {@link valueToY} still maps them (to the plot floor) so nothing
|
|
72
|
+
* downstream sees NaN.
|
|
73
|
+
*/
|
|
74
|
+
isPlottable(t) {
|
|
75
|
+
return g(this.transform, t);
|
|
49
76
|
}
|
|
50
77
|
/** Desired label count. Invalid values (NaN, <2, Infinity) clear the hint. */
|
|
51
78
|
setLabelCount(t) {
|
|
52
|
-
this.labelCountHintValue =
|
|
79
|
+
this.labelCountHintValue = p(t), this.resetHysteresis(), this.resolveTicks();
|
|
53
80
|
}
|
|
54
81
|
/** Minimum pixel gap between adjacent labels. */
|
|
55
82
|
setMinSpacing(t) {
|
|
56
|
-
this.minSpacingValue =
|
|
83
|
+
this.minSpacingValue = x(t), this.resetHysteresis(), this.resolveTicks();
|
|
57
84
|
}
|
|
58
85
|
resetHysteresis() {
|
|
59
86
|
this.lastInterval = null, this.lastRawInterval = null;
|
|
60
87
|
}
|
|
88
|
+
/** A transformed domain needs both bounds plottable; anything else collapses to a flat one. */
|
|
89
|
+
updateDomain() {
|
|
90
|
+
const t = this.transform;
|
|
91
|
+
if (t === null) {
|
|
92
|
+
this.lo = this.min, this.hi = this.max;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const i = this.isPlottable(this.min) && this.isPlottable(this.max);
|
|
96
|
+
this.lo = i ? t.forward(this.min) : 0, this.hi = i ? t.forward(this.max) : 0;
|
|
97
|
+
}
|
|
61
98
|
/** Install (or clear) a custom formatter. */
|
|
62
99
|
setFormat(t) {
|
|
63
100
|
this.customFormat = t;
|
|
@@ -74,30 +111,73 @@ class M {
|
|
|
74
111
|
setTickGenerator(t) {
|
|
75
112
|
this.customTickGenerator = t, this.resetHysteresis();
|
|
76
113
|
}
|
|
77
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Convert a value to a Y position in CSS (media) pixels. A value the
|
|
116
|
+
* transform can't place (≤ 0 on log) lands on the plot floor.
|
|
117
|
+
*/
|
|
78
118
|
valueToY(t) {
|
|
79
|
-
const i = this.
|
|
80
|
-
|
|
119
|
+
const i = this.hi - this.lo;
|
|
120
|
+
if (i === 0) return this.height / 2;
|
|
121
|
+
const s = this.transform;
|
|
122
|
+
return s === null ? (1 - (t - this.lo) / i) * this.height : this.isPlottable(t) ? (1 - (s.forward(t) - this.lo) / i) * this.height : this.height;
|
|
81
123
|
}
|
|
82
|
-
/** Convert a value to a Y position in physical (bitmap) pixels
|
|
124
|
+
/** Convert a value to a Y position in physical (bitmap) pixels, snapped to
|
|
125
|
+
* the pixel grid — for axis-aligned edges that have to stay crisp. */
|
|
83
126
|
valueToBitmapY(t) {
|
|
84
|
-
return Math.round(this.
|
|
127
|
+
return Math.round(this.valueToBitmapYExact(t));
|
|
85
128
|
}
|
|
86
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* Same in physical pixels, off the grid. Anti-aliased geometry reads this
|
|
131
|
+
* one: snapping buys a diagonal stroke no sharpness, and during a slow
|
|
132
|
+
* animation it quantises the motion into whole-pixel jumps.
|
|
133
|
+
*/
|
|
134
|
+
valueToBitmapYExact(t) {
|
|
135
|
+
return this.valueToY(t) * this.pixelRatio;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Y position in CSS pixels of the *stroke center* the canvas grid draws for
|
|
139
|
+
* `value`. DOM axis labels position off this instead of raw {@link valueToY}
|
|
140
|
+
* so text and gridline share one pixel grid.
|
|
141
|
+
*/
|
|
142
|
+
valueToSnappedY(t) {
|
|
143
|
+
return (this.valueToBitmapY(t) + u(this.pixelRatio)) / this.pixelRatio;
|
|
144
|
+
}
|
|
145
|
+
/** Convert a Y position in CSS pixels back to a value — the exact inverse of {@link valueToY}. */
|
|
87
146
|
yToValue(t) {
|
|
88
|
-
const i = this.
|
|
89
|
-
|
|
147
|
+
const i = this.hi - this.lo;
|
|
148
|
+
if (i === 0) return this.min;
|
|
149
|
+
const s = this.hi - t / this.height * i;
|
|
150
|
+
return this.transform === null ? s : this.transform.inverse(s);
|
|
151
|
+
}
|
|
152
|
+
/** The value bars and stacks grow from: `0`, or the plot floor's value on a scale with no place for 0 (log). */
|
|
153
|
+
baselineValue() {
|
|
154
|
+
return this.isPlottable(0) ? 0 : this.min;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The value `t` of the way from `from` to `to` in pixels — a plain lerp on a
|
|
158
|
+
* linear axis, a geometric one on log. `t` past `[0, 1]` overshoots along the
|
|
159
|
+
* axis. An endpoint the transform can't place returns `to`, so a gap stays a gap.
|
|
160
|
+
*/
|
|
161
|
+
lerpValue(t, i, s) {
|
|
162
|
+
const n = this.transform;
|
|
163
|
+
if (n === null) return t + (i - t) * s;
|
|
164
|
+
if (!this.isPlottable(t) || !this.isPlottable(i)) return i;
|
|
165
|
+
const r = n.forward(t);
|
|
166
|
+
return n.inverse(r + (n.forward(i) - r) * s);
|
|
90
167
|
}
|
|
91
168
|
/**
|
|
92
169
|
* Generate evenly spaced "nice" tick values for the current range and
|
|
93
170
|
* chart height. Pure read — resolution happens in `update()`.
|
|
94
171
|
*/
|
|
95
172
|
niceTickValues() {
|
|
96
|
-
|
|
173
|
+
return this.customTickGenerator ? this.customTickGenerator({ min: this.min, max: this.max }).slice(0, a) : this.ownTicks !== null ? this.ownTicks.slice(0, a) : this.linearTickValues();
|
|
174
|
+
}
|
|
175
|
+
/** {1,2,5}×10^k ticks at the resolved interval, limited to what the transform can place. */
|
|
176
|
+
linearTickValues() {
|
|
97
177
|
if (this.resolvedInterval == null) return [];
|
|
98
|
-
const t = this.resolvedInterval, i = Math.ceil(this.min / t) * t,
|
|
99
|
-
for (let
|
|
100
|
-
return
|
|
178
|
+
const t = this.resolvedInterval, i = Math.ceil(this.min / t) * t, s = Math.max(0, Math.min(a, Math.floor((this.max - i) / t) + 1)), n = [];
|
|
179
|
+
for (let r = 0; r < s; r++) n.push(i + r * t);
|
|
180
|
+
return this.transform === null ? n : n.filter((r) => this.isPlottable(r));
|
|
101
181
|
}
|
|
102
182
|
getRange() {
|
|
103
183
|
return { min: this.min, max: this.max };
|
|
@@ -114,13 +194,49 @@ class M {
|
|
|
114
194
|
*/
|
|
115
195
|
formatY(t) {
|
|
116
196
|
if (this.customFormat) return this.customFormat(t);
|
|
197
|
+
const i = this.ownTicks !== null ? this.transform?.format : void 0;
|
|
198
|
+
if (i) return i(t);
|
|
117
199
|
if (this.max - this.min >= 1e6) return o(t);
|
|
118
|
-
const
|
|
119
|
-
return t.toFixed(
|
|
200
|
+
const s = this.resolvedInterval, n = s != null && s > 0 ? Math.max(0, -Math.floor(Math.log10(s))) : 1;
|
|
201
|
+
return t.toFixed(n);
|
|
202
|
+
}
|
|
203
|
+
resolveTicks() {
|
|
204
|
+
this.ownTicks = null;
|
|
205
|
+
const t = this.transform;
|
|
206
|
+
if (t === null) {
|
|
207
|
+
this.resolveInterval((this.max - this.min) * this.minLabelSpacing / this.height);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const i = this.hi - this.lo;
|
|
211
|
+
if (!(i > 0) || this.height <= 0) {
|
|
212
|
+
this.resolvedInterval = null;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (this.resolveInterval(this.transformedGapFloor(t, i)), !t.ticks) return;
|
|
216
|
+
const s = this.linearTickValues(), n = t.ticks({
|
|
217
|
+
min: this.min,
|
|
218
|
+
max: this.max,
|
|
219
|
+
height: this.height,
|
|
220
|
+
minSpacing: this.minLabelSpacing,
|
|
221
|
+
labelCount: this.labelCountHint,
|
|
222
|
+
linear: s
|
|
223
|
+
});
|
|
224
|
+
this.ownTicks = n === s ? null : n;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Smallest linear interval whose ticks stay `minLabelSpacing` apart on the
|
|
228
|
+
* transformed axis. A monotonic mapping squeezes its gaps hardest at one
|
|
229
|
+
* end — the top for log (concave), the bottom for a convex one — so
|
|
230
|
+
* checking both ends covers it.
|
|
231
|
+
*/
|
|
232
|
+
transformedGapFloor(t, i) {
|
|
233
|
+
const s = this.minLabelSpacing / this.height * i, n = this.max - t.inverse(Math.max(this.lo, this.hi - s)), r = t.inverse(Math.min(this.hi, this.lo + s)) - this.min;
|
|
234
|
+
return Math.max(n, r);
|
|
120
235
|
}
|
|
121
236
|
/**
|
|
122
237
|
* Resolve the interval to a {1,2,5}×10^k tick size that satisfies the pixel
|
|
123
|
-
* floor and (optionally) targets `labelCountHint` labels.
|
|
238
|
+
* floor and (optionally) targets `labelCountHint` labels. `gapFloorValue` is
|
|
239
|
+
* the smallest interval that clears `minLabelSpacing` anywhere on the axis.
|
|
124
240
|
*
|
|
125
241
|
* Hysteresis: the band [0.8×, 1.25×] is anchored to **rawInterval at last
|
|
126
242
|
* snap**, not to `lastInterval`. After an escalation (e.g. 100 → 200),
|
|
@@ -129,26 +245,26 @@ class M {
|
|
|
129
245
|
* *not* de-escalate. This prevents the 2-tier flicker users see when new
|
|
130
246
|
* candles nudge the Y range across a raw-interval threshold.
|
|
131
247
|
*/
|
|
132
|
-
resolveInterval() {
|
|
248
|
+
resolveInterval(t) {
|
|
133
249
|
if (this.max <= this.min || this.height <= 0) {
|
|
134
250
|
this.resolvedInterval = null;
|
|
135
251
|
return;
|
|
136
252
|
}
|
|
137
|
-
const
|
|
138
|
-
let
|
|
139
|
-
if (
|
|
140
|
-
const l =
|
|
253
|
+
const i = this.max - this.min, s = this.labelCountHint != null ? Math.max(1, this.labelCountHint) : Math.max(1, Math.floor(this.height / this.minLabelSpacing));
|
|
254
|
+
let n = i / s;
|
|
255
|
+
if (n < t && (n = t), this.lastInterval != null && this.lastRawInterval != null) {
|
|
256
|
+
const l = n >= this.lastRawInterval * 0.8 && n <= this.lastRawInterval * 1.25, h = this.lastInterval >= t;
|
|
141
257
|
if (l && h) {
|
|
142
258
|
this.resolvedInterval = this.lastInterval;
|
|
143
259
|
return;
|
|
144
260
|
}
|
|
145
261
|
}
|
|
146
|
-
let
|
|
147
|
-
if (this.labelCountHint != null && this.countTicks(
|
|
148
|
-
const l =
|
|
149
|
-
l >=
|
|
262
|
+
let r = c(n);
|
|
263
|
+
if (this.labelCountHint != null && this.countTicks(r) < this.labelCountHint) {
|
|
264
|
+
const l = f(n);
|
|
265
|
+
l >= t && l > 0 && (r = l);
|
|
150
266
|
}
|
|
151
|
-
this.resolvedInterval =
|
|
267
|
+
this.resolvedInterval = r, this.lastInterval = r, this.lastRawInterval = n;
|
|
152
268
|
}
|
|
153
269
|
countTicks(t) {
|
|
154
270
|
if (!(t > 0)) return 0;
|
|
@@ -156,12 +272,13 @@ class M {
|
|
|
156
272
|
return Math.max(0, Math.floor((this.max - i) / t) + 1);
|
|
157
273
|
}
|
|
158
274
|
}
|
|
159
|
-
function
|
|
275
|
+
function p(e) {
|
|
160
276
|
return typeof e == "number" && Number.isFinite(e) && e >= 2 ? Math.floor(e) : null;
|
|
161
277
|
}
|
|
162
|
-
function
|
|
278
|
+
function x(e) {
|
|
163
279
|
return typeof e == "number" && Number.isFinite(e) && e > 0 ? e : null;
|
|
164
280
|
}
|
|
165
281
|
export {
|
|
166
|
-
|
|
282
|
+
d as YScale,
|
|
283
|
+
g as isPlottableOn
|
|
167
284
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { easeOutBack as
|
|
2
|
-
function
|
|
3
|
-
return () => ({
|
|
4
|
-
value: ({ value: e, progress:
|
|
1
|
+
import { easeOutBack as s } from "../animation/easing.js";
|
|
2
|
+
function n() {
|
|
3
|
+
return (r) => ({
|
|
4
|
+
value: ({ value: e, progress: a }) => r.lerpValue(r.baseline, e, a),
|
|
5
5
|
element: (e) => ({ alpha: e.progress })
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
|
-
const
|
|
9
|
-
function
|
|
10
|
-
return () => ({
|
|
11
|
-
value: ({ value: e, progress:
|
|
12
|
-
element: (e) => ({ alpha: Math.min(1, e.progress /
|
|
8
|
+
const l = 0.3;
|
|
9
|
+
function t() {
|
|
10
|
+
return (r) => ({
|
|
11
|
+
value: ({ value: e, progress: a }) => r.lerpValue(r.baseline, e, s(a)),
|
|
12
|
+
element: (e) => ({ alpha: Math.min(1, e.progress / l) })
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
export {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
n as growIntro,
|
|
17
|
+
t as springIntro
|
|
18
18
|
};
|