@wick-charts/vue 0.7.0 → 0.8.1
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 +19 -3
- package/dist/BandSeries.vue.js +40 -30
- package/dist/BarSeries.vue.js +39 -29
- package/dist/CandlestickSeries.vue.js +2 -2
- package/dist/ChartContainer.vue.js +1 -1
- package/dist/LineSeries.vue.js +40 -30
- package/dist/core/dist/chart/badge-animator.js +38 -28
- package/dist/core/dist/chart.js +801 -694
- package/dist/core/dist/data/sync.js +77 -50
- package/dist/core/dist/navigator/controller.js +11 -11
- 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 +82 -82
- package/dist/core/dist/series/bar.js +1 -1
- package/dist/core/dist/series/base-multi-layer.js +182 -152
- package/dist/core/dist/series/candlestick.js +96 -96
- package/dist/core/dist/series/line.js +297 -292
- package/dist/core/dist/snapshots.js +39 -35
- package/dist/core/dist/utils/point.js +4 -0
- package/dist/core/dist/utils/time.js +42 -26
- package/dist/index.d.ts +45 -24
- package/dist/ui/InfoBar.vue.js +13 -13
- package/dist/ui/Tooltip.vue.js +11 -11
- package/dist/ui/YLabel.vue.js +47 -47
- package/package.json +9 -3
- package/src/BandSeries.vue +16 -3
- package/src/BarSeries.vue +16 -3
- package/src/ChartContainer.vue +14 -8
- package/src/LineSeries.vue +16 -3
- package/src/ui/YLabel.vue +28 -27
package/dist/ui/YLabel.vue.js
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
import { defineComponent as O, useSlots as W, computed as t, ref as w, onMounted as H, onUnmounted as J, openBlock as A, createElementBlock as B, Fragment as Y, renderSlot as K, createElementVNode as _, normalizeStyle as z, unref as
|
|
1
|
+
import { defineComponent as O, useSlots as W, computed as t, ref as w, onMounted as H, onUnmounted as J, openBlock as A, createElementBlock as B, Fragment as Y, renderSlot as K, createElementVNode as _, normalizeStyle as z, unref as D, createVNode as Q, createCommentVNode as X } from "vue";
|
|
2
2
|
import { prefersReducedMotion as Z } from "../core/dist/animation/reduced-motion.js";
|
|
3
|
-
import { resolveAnimate as ee, resolveYLabelSeriesId as te,
|
|
4
|
-
import { useChartInstance as
|
|
5
|
-
import
|
|
6
|
-
const
|
|
3
|
+
import { resolveAnimate as ee, resolveYLabelSeriesId as te, yLabelFractionDigits as ae, firstVisibleValue as le, BadgeAnimator as ne } from "../core/dist/chart/badge-animator.js";
|
|
4
|
+
import { useChartInstance as oe } from "../context.js";
|
|
5
|
+
import ue from "./NumberFlow.vue.js";
|
|
6
|
+
const fe = /* @__PURE__ */ O({
|
|
7
7
|
__name: "YLabel",
|
|
8
8
|
props: {
|
|
9
9
|
seriesId: {},
|
|
10
10
|
color: {},
|
|
11
|
-
format: {
|
|
12
|
-
animate: { type: [Boolean, Object] },
|
|
11
|
+
format: {},
|
|
12
|
+
animate: { type: [Boolean, Object], default: void 0 },
|
|
13
13
|
scale: {}
|
|
14
14
|
},
|
|
15
15
|
setup(E) {
|
|
16
|
-
const
|
|
17
|
-
let m = null, g = null,
|
|
18
|
-
const
|
|
16
|
+
const u = E, e = oe(), M = W(), N = t(() => typeof M.default == "function"), l = w(0), r = w(null);
|
|
17
|
+
let m = null, g = null, i = null;
|
|
18
|
+
const R = t(() => ee(u.animate));
|
|
19
19
|
function S() {
|
|
20
|
-
|
|
21
|
-
const a = o.value,
|
|
22
|
-
if (a === null || !
|
|
20
|
+
i = null;
|
|
21
|
+
const a = o.value, d = a !== null ? e.getStackedLastValue(a) : null;
|
|
22
|
+
if (a === null || !d) {
|
|
23
23
|
m = null, g = null;
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
(m === null || g !== a) && (m = new
|
|
28
|
-
const { glide: $, countUp: j, settleMs: G } =
|
|
29
|
-
target:
|
|
26
|
+
const c = d.value;
|
|
27
|
+
(m === null || g !== a) && (m = new ne(c), g = a);
|
|
28
|
+
const { glide: $, countUp: j, settleMs: G } = R.value, I = e.getIntroFront(a), v = m.frame({
|
|
29
|
+
target: c,
|
|
30
30
|
// Only needed for the intro count-up; skip the visible-range binary search
|
|
31
31
|
// entirely once the reveal has settled (the hot streaming path).
|
|
32
|
-
firstVisible: I < 1 ?
|
|
32
|
+
firstVisible: I < 1 ? le(e, a, c) : c,
|
|
33
33
|
introFront: I,
|
|
34
34
|
now: performance.now(),
|
|
35
35
|
glide: $,
|
|
36
36
|
countUp: j,
|
|
37
37
|
settleMs: G,
|
|
38
38
|
reducedMotion: Z()
|
|
39
|
-
}),
|
|
40
|
-
(
|
|
39
|
+
}), p = r.value;
|
|
40
|
+
(p === null || p.positionValue !== v.positionValue || p.textValue !== v.textValue || p.opacity !== v.opacity) && (r.value = { positionValue: v.positionValue, textValue: v.textValue, opacity: v.opacity }), v.animating && i === null && (i = requestAnimationFrame(S));
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
42
|
+
function T() {
|
|
43
|
+
i === null && (i = requestAnimationFrame(S));
|
|
44
44
|
}
|
|
45
|
-
const
|
|
46
|
-
l.value++,
|
|
45
|
+
const f = () => {
|
|
46
|
+
l.value++, T();
|
|
47
47
|
};
|
|
48
48
|
H(() => {
|
|
49
|
-
e.setYLabel(!0), e.on("overlayChange",
|
|
49
|
+
e.setYLabel(!0), e.on("overlayChange", f), e.on("viewportChange", f), e.getSeriesIds().length > 0 && f();
|
|
50
50
|
}), J(() => {
|
|
51
|
-
e.setYLabel(!1), e.off("overlayChange",
|
|
51
|
+
e.setYLabel(!1), e.off("overlayChange", f), e.off("viewportChange", f), i !== null && cancelAnimationFrame(i), i = null;
|
|
52
52
|
});
|
|
53
|
-
const o = t(() => (l.value, te(e,
|
|
54
|
-
if (n.value === null) return
|
|
55
|
-
if (!n.value.isLive) return
|
|
56
|
-
if (
|
|
53
|
+
const o = t(() => (l.value, te(e, u.seriesId))), n = t(() => (l.value, o.value !== null ? e.getStackedLastValue(o.value) : null)), y = t(() => (l.value, o.value !== null ? e.getPreviousClose(o.value) : null)), s = t(() => (l.value, e.getTheme())), C = t(() => (l.value, u.scale !== void 0 ? u.scale : o.value !== null ? e.getSeriesScale(o.value) : void 0)), x = t(() => (l.value, e.getYScale(C.value))), U = t(() => (l.value, e.getYScaleColumn(C.value)?.position ?? e.yAxisPosition)), q = t(() => r.value !== null ? r.value.positionValue : n.value?.value ?? 0), P = t(() => r.value !== null ? r.value.textValue : n.value?.value ?? 0), b = t(() => r.value !== null ? r.value.opacity : o.value === null ? 1 : e.getIntroFront(o.value) < 1 ? 0 : 1), h = t(() => (l.value, n.value === null ? 0 : x.value.valueToY(q.value))), F = t(() => n.value === null || y.value === null ? "neutral" : n.value.value > y.value ? "up" : n.value.value < y.value ? "down" : "neutral"), V = t(() => {
|
|
54
|
+
if (n.value === null) return s.value.yLabel.neutralBackground;
|
|
55
|
+
if (!n.value.isLive) return s.value.axis.textColor;
|
|
56
|
+
if (u.color) return u.color;
|
|
57
57
|
switch (F.value) {
|
|
58
58
|
case "up":
|
|
59
|
-
return
|
|
59
|
+
return s.value.yLabel.upBackground;
|
|
60
60
|
case "down":
|
|
61
|
-
return
|
|
61
|
+
return s.value.yLabel.downBackground;
|
|
62
62
|
default:
|
|
63
|
-
return
|
|
63
|
+
return s.value.yLabel.neutralBackground;
|
|
64
64
|
}
|
|
65
65
|
}), L = t(() => {
|
|
66
66
|
l.value;
|
|
67
|
-
const a = x.value.getRange()
|
|
68
|
-
return
|
|
67
|
+
const a = x.value.getRange();
|
|
68
|
+
return ae(a.max - a.min);
|
|
69
69
|
}), k = t(() => {
|
|
70
|
-
if (
|
|
70
|
+
if (u.format) return u.format;
|
|
71
71
|
l.value;
|
|
72
72
|
const a = x.value.getFormat();
|
|
73
73
|
if (a) return a;
|
|
74
|
-
const
|
|
74
|
+
const d = new Intl.NumberFormat("en-US", {
|
|
75
75
|
minimumFractionDigits: L.value,
|
|
76
76
|
maximumFractionDigits: L.value,
|
|
77
77
|
useGrouping: !1
|
|
78
78
|
});
|
|
79
|
-
return (
|
|
79
|
+
return (c) => d.format(c);
|
|
80
80
|
});
|
|
81
|
-
return (a,
|
|
82
|
-
|
|
81
|
+
return (a, d) => n.value !== null ? (A(), B(Y, { key: 0 }, [
|
|
82
|
+
N.value ? K(a.$slots, "default", {
|
|
83
83
|
key: 0,
|
|
84
84
|
value: n.value.value,
|
|
85
85
|
y: h.value,
|
|
@@ -92,8 +92,8 @@ const ce = /* @__PURE__ */ O({
|
|
|
92
92
|
_("div", {
|
|
93
93
|
style: z({
|
|
94
94
|
position: "absolute",
|
|
95
|
-
left:
|
|
96
|
-
right:
|
|
95
|
+
left: D(e).plotLeft + "px",
|
|
96
|
+
right: D(e).getAxisColumnWidth("right") + "px",
|
|
97
97
|
top: h.value + "px",
|
|
98
98
|
height: "0",
|
|
99
99
|
borderTop: "1px dashed " + V.value,
|
|
@@ -112,16 +112,16 @@ const ce = /* @__PURE__ */ O({
|
|
|
112
112
|
pointerEvents: "auto",
|
|
113
113
|
zIndex: 3,
|
|
114
114
|
background: V.value,
|
|
115
|
-
color:
|
|
116
|
-
fontSize:
|
|
117
|
-
fontFamily:
|
|
115
|
+
color: s.value.yLabel.textColor,
|
|
116
|
+
fontSize: s.value.yLabel.fontSize + "px",
|
|
117
|
+
fontFamily: s.value.typography.fontFamily,
|
|
118
118
|
padding: "3px 8px",
|
|
119
119
|
borderRadius: "3px",
|
|
120
120
|
whiteSpace: "nowrap",
|
|
121
121
|
transition: "background-color 0.3s ease"
|
|
122
122
|
})
|
|
123
123
|
}, [
|
|
124
|
-
Q(
|
|
124
|
+
Q(ue, {
|
|
125
125
|
value: P.value,
|
|
126
126
|
format: k.value,
|
|
127
127
|
"spin-duration": 350
|
|
@@ -132,5 +132,5 @@ const ce = /* @__PURE__ */ O({
|
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
export {
|
|
135
|
-
|
|
135
|
+
fe as default
|
|
136
136
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wick-charts/vue",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Realtime, animated canvas charts for Vue: candlestick, line, bar, heatmap, pie and more. Tree-shakeable, zero runtime deps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -14,10 +14,16 @@
|
|
|
14
14
|
"charts",
|
|
15
15
|
"charting",
|
|
16
16
|
"canvas",
|
|
17
|
+
"realtime",
|
|
18
|
+
"streaming",
|
|
19
|
+
"animation",
|
|
17
20
|
"candlestick",
|
|
18
21
|
"line-chart",
|
|
22
|
+
"area-chart",
|
|
19
23
|
"bar-chart",
|
|
24
|
+
"heatmap",
|
|
20
25
|
"pie-chart",
|
|
26
|
+
"sparkline",
|
|
21
27
|
"timeseries",
|
|
22
28
|
"vue",
|
|
23
29
|
"visualization"
|
|
@@ -45,7 +51,7 @@
|
|
|
45
51
|
"vue": ">=3.3.0"
|
|
46
52
|
},
|
|
47
53
|
"devDependencies": {
|
|
48
|
-
"@wick-charts/core": "^0.
|
|
54
|
+
"@wick-charts/core": "^0.8.1"
|
|
49
55
|
},
|
|
50
56
|
"scripts": {
|
|
51
57
|
"build": "vite build"
|
package/src/BandSeries.vue
CHANGED
|
@@ -36,13 +36,14 @@ const seriesId = ref<string | null>(null);
|
|
|
36
36
|
// reconciliation (plus per-layer labels/colors) so streaming eases instead of
|
|
37
37
|
// snapping Y every tick.
|
|
38
38
|
let prevSync: SeriesSyncState[] = [];
|
|
39
|
+
let layerCount = 0;
|
|
39
40
|
|
|
40
41
|
function applyData(id: string, data: BandData): void {
|
|
41
42
|
prevSync = syncLayers({ chart, id, data, prev: prevSync });
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
function createSeries(data: BandData): void {
|
|
46
|
+
layerCount = toLayers(data).length;
|
|
46
47
|
const id = chart.addSeries(BandSeriesDef, {
|
|
47
48
|
...props.options,
|
|
48
49
|
scale: props.scale,
|
|
@@ -52,8 +53,12 @@ onMounted(() => {
|
|
|
52
53
|
seriesId.value = id;
|
|
53
54
|
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
54
55
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
55
|
-
applyData(id,
|
|
56
|
+
applyData(id, data);
|
|
56
57
|
chart.setSeriesVisible(id, props.visible);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
onMounted(() => {
|
|
61
|
+
createSeries(props.data);
|
|
57
62
|
});
|
|
58
63
|
|
|
59
64
|
onUnmounted(() => {
|
|
@@ -66,6 +71,14 @@ watch(
|
|
|
66
71
|
const id = seriesId.value;
|
|
67
72
|
if (!id) return;
|
|
68
73
|
|
|
74
|
+
// The layer count is fixed when a series is created; a new count re-creates it, as in React.
|
|
75
|
+
if (toLayers(data).length !== layerCount) {
|
|
76
|
+
chart.removeSeries(id);
|
|
77
|
+
createSeries(data);
|
|
78
|
+
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
69
82
|
applyData(id, data);
|
|
70
83
|
},
|
|
71
84
|
);
|
package/src/BarSeries.vue
CHANGED
|
@@ -32,13 +32,14 @@ const seriesId = ref<string | null>(null);
|
|
|
32
32
|
// reconciliation (plus per-layer labels/colors) so streaming eases instead of
|
|
33
33
|
// snapping Y every tick.
|
|
34
34
|
let prevSync: SeriesSyncState[] = [];
|
|
35
|
+
let layerCount = 0;
|
|
35
36
|
|
|
36
37
|
function applyData(id: string, data: MultiLayerData): void {
|
|
37
38
|
prevSync = syncLayers({ chart, id, data, prev: prevSync });
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
function createSeries(data: MultiLayerData): void {
|
|
42
|
+
layerCount = toLayers(data).length;
|
|
42
43
|
const id = chart.addSeries(BarSeriesDef, {
|
|
43
44
|
...props.options,
|
|
44
45
|
scale: props.scale,
|
|
@@ -48,8 +49,12 @@ onMounted(() => {
|
|
|
48
49
|
seriesId.value = id;
|
|
49
50
|
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
50
51
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
51
|
-
applyData(id,
|
|
52
|
+
applyData(id, data);
|
|
52
53
|
chart.setSeriesVisible(id, props.visible);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onMounted(() => {
|
|
57
|
+
createSeries(props.data);
|
|
53
58
|
});
|
|
54
59
|
|
|
55
60
|
onUnmounted(() => {
|
|
@@ -62,6 +67,14 @@ watch(
|
|
|
62
67
|
const id = seriesId.value;
|
|
63
68
|
if (!id) return;
|
|
64
69
|
|
|
70
|
+
// The layer count is fixed when a series is created; a new count re-creates it, as in React.
|
|
71
|
+
if (toLayers(data).length !== layerCount) {
|
|
72
|
+
chart.removeSeries(id);
|
|
73
|
+
createSeries(data);
|
|
74
|
+
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
applyData(id, data);
|
|
66
79
|
},
|
|
67
80
|
);
|
package/src/ChartContainer.vue
CHANGED
|
@@ -62,19 +62,23 @@ const props = withDefaults(
|
|
|
62
62
|
*/
|
|
63
63
|
viewport?: {
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
* to
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* Default: 200.
|
|
65
|
+
* Most bars the chart's own fit shows. The first data load fits every bar
|
|
66
|
+
* up to this count; while the data holds fewer, streamed bars widen the
|
|
67
|
+
* window, and once it is full the window keeps its width and follows the
|
|
68
|
+
* latest bar. `fitContent()` and an explicit bar count are not capped.
|
|
69
|
+
* Default: 200. Values below 2 are clamped.
|
|
71
70
|
*/
|
|
72
71
|
maxVisibleBars?: number;
|
|
73
72
|
/**
|
|
74
73
|
* Initial visible range applied before the first paint with data. Same
|
|
75
74
|
* shape as the imperative `chart.setVisibleRange` — pass a bar count
|
|
76
75
|
* (e.g. `35`), an explicit `{from, to}` window, or `{from, bars}` for
|
|
77
|
-
* a warm-up pair.
|
|
76
|
+
* a warm-up pair.
|
|
77
|
+
*
|
|
78
|
+
* It stays the chart's window until the user zooms or pans or the app
|
|
79
|
+
* sets a range, so a series that loads later or data set again keeps it.
|
|
80
|
+
* A bar count widens with streamed bars until it holds that many; a
|
|
81
|
+
* `{from, …}` window ends once streaming moves it. Captured at mount.
|
|
78
82
|
*/
|
|
79
83
|
initialRange?: VisibleRangeSpec;
|
|
80
84
|
};
|
|
@@ -86,7 +90,7 @@ const props = withDefaults(
|
|
|
86
90
|
* two-way binding; a same-value literal (compared structurally) is a
|
|
87
91
|
* no-op, so an inline object doesn't re-apply on every render.
|
|
88
92
|
*
|
|
89
|
-
* For
|
|
93
|
+
* For an initial window that isn't re-applied on every prop
|
|
90
94
|
* change, use `viewport.initialRange` instead.
|
|
91
95
|
*/
|
|
92
96
|
visibleRange?: VisibleRangeSpec;
|
|
@@ -211,6 +215,8 @@ const props = withDefaults(
|
|
|
211
215
|
// distinguishable from an explicit `:fade="false"` all-off opt-out.
|
|
212
216
|
// Declaring a default (even `undefined`) suppresses the cast.
|
|
213
217
|
fade: undefined,
|
|
218
|
+
// Absent must reach the core as `undefined` (animations on), as in React and Svelte.
|
|
219
|
+
animations: undefined,
|
|
214
220
|
},
|
|
215
221
|
);
|
|
216
222
|
|
package/src/LineSeries.vue
CHANGED
|
@@ -32,13 +32,14 @@ const seriesId = ref<string | null>(null);
|
|
|
32
32
|
// reconciliation (plus per-layer labels/colors) so streaming eases instead of
|
|
33
33
|
// snapping Y every tick.
|
|
34
34
|
let prevSync: SeriesSyncState[] = [];
|
|
35
|
+
let layerCount = 0;
|
|
35
36
|
|
|
36
37
|
function applyData(id: string, data: MultiLayerData): void {
|
|
37
38
|
prevSync = syncLayers({ chart, id, data, prev: prevSync });
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
function createSeries(data: MultiLayerData): void {
|
|
42
|
+
layerCount = toLayers(data).length;
|
|
42
43
|
const id = chart.addSeries(LineSeriesDef, {
|
|
43
44
|
...props.options,
|
|
44
45
|
scale: props.scale,
|
|
@@ -48,8 +49,12 @@ onMounted(() => {
|
|
|
48
49
|
seriesId.value = id;
|
|
49
50
|
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
50
51
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
51
|
-
applyData(id,
|
|
52
|
+
applyData(id, data);
|
|
52
53
|
chart.setSeriesVisible(id, props.visible);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onMounted(() => {
|
|
57
|
+
createSeries(props.data);
|
|
53
58
|
});
|
|
54
59
|
|
|
55
60
|
onUnmounted(() => {
|
|
@@ -62,6 +67,14 @@ watch(
|
|
|
62
67
|
const id = seriesId.value;
|
|
63
68
|
if (!id) return;
|
|
64
69
|
|
|
70
|
+
// The layer count is fixed when a series is created; a new count re-creates it, as in React.
|
|
71
|
+
if (toLayers(data).length !== layerCount) {
|
|
72
|
+
chart.removeSeries(id);
|
|
73
|
+
createSeries(data);
|
|
74
|
+
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
applyData(id, data);
|
|
66
79
|
},
|
|
67
80
|
);
|
package/src/ui/YLabel.vue
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
prefersReducedMotion,
|
|
8
8
|
resolveAnimate,
|
|
9
9
|
resolveYLabelSeriesId,
|
|
10
|
+
yLabelFractionDigits,
|
|
10
11
|
} from '@wick-charts/core';
|
|
11
12
|
import { computed, onMounted, onUnmounted, ref, useSlots } from 'vue';
|
|
12
13
|
|
|
@@ -21,28 +22,32 @@ export type { YLabelAnimate, YLabelAnimateOptions } from '@wick-charts/core';
|
|
|
21
22
|
/** Direction of the current value vs. previous close. Drives the badge color in the default UI. */
|
|
22
23
|
export type YLabelDirection = 'up' | 'down' | 'neutral';
|
|
23
24
|
|
|
24
|
-
const props =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
const props = withDefaults(
|
|
26
|
+
defineProps<{
|
|
27
|
+
/**
|
|
28
|
+
* Owning series id. **Optional** — when omitted, the first visible
|
|
29
|
+
* single-layer time series is picked, falling back to the first visible
|
|
30
|
+
* multi-layer time series.
|
|
31
|
+
*/
|
|
32
|
+
seriesId?: string;
|
|
33
|
+
color?: string;
|
|
34
|
+
/** Custom formatter; routed through NumberFlow's `formatter` so the digit animation still plays. Default: the scale's `<YAxis format>`, else a range-adaptive number. */
|
|
35
|
+
format?: ValueFormatter;
|
|
36
|
+
/**
|
|
37
|
+
* Badge motion. `true` (default) glides + counts up + fades in with the
|
|
38
|
+
* intro; `false` snaps with no easing; an object tunes individual parts.
|
|
39
|
+
*/
|
|
40
|
+
animate?: YLabelAnimate;
|
|
41
|
+
/**
|
|
42
|
+
* Named Y scale (`ChartContainer` `scales`) the value maps through. Default:
|
|
43
|
+
* the series' own scale. The badge sits on that scale's axis side — the
|
|
44
|
+
* default axis side for an overlay scale.
|
|
45
|
+
*/
|
|
46
|
+
scale?: string;
|
|
47
|
+
}>(),
|
|
48
|
+
// Vue casts an absent Boolean prop to `false`; an absent `animate` must stay `undefined` (on).
|
|
49
|
+
{ animate: undefined },
|
|
50
|
+
);
|
|
46
51
|
|
|
47
52
|
defineSlots<{
|
|
48
53
|
default?(ctx: {
|
|
@@ -250,12 +255,8 @@ const bgColor = computed<string>(() => {
|
|
|
250
255
|
const fractionDigits = computed(() => {
|
|
251
256
|
void bump.value;
|
|
252
257
|
const yRange = yScale.value.getRange();
|
|
253
|
-
const range = yRange.max - yRange.min;
|
|
254
|
-
if (range < 0.1) return 6;
|
|
255
|
-
if (range < 10) return 4;
|
|
256
|
-
if (range < 1000) return 2;
|
|
257
258
|
|
|
258
|
-
return
|
|
259
|
+
return yLabelFractionDigits(yRange.max - yRange.min);
|
|
259
260
|
});
|
|
260
261
|
|
|
261
262
|
const effectiveFormat = computed<ValueFormatter>(() => {
|