@wick-charts/vue 0.5.1 → 0.6.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 +45 -6
- package/dist/BarSeries.vue.js +26 -20
- package/dist/CandlestickSeries.vue.js +30 -24
- package/dist/ChartContainer.vue.js +125 -72
- package/dist/HeatmapSeries.vue.js +40 -0
- package/dist/HeatmapSeries.vue2.js +4 -0
- package/dist/LineSeries.vue.js +26 -20
- package/dist/PieSeries.vue.js +24 -18
- package/dist/core/dist/animation/animator.js +21 -21
- package/dist/core/dist/animation/config.js +114 -87
- package/dist/core/dist/animation/easing.js +3 -1
- package/dist/core/dist/animation/intro-wave.js +68 -0
- package/dist/core/dist/axis/dom-labels.js +13 -14
- package/dist/core/dist/chart/badge-animator.js +56 -0
- package/dist/core/dist/chart/edge-indicators.js +28 -13
- package/dist/core/dist/chart/last-value.js +18 -17
- package/dist/core/dist/chart/options.js +27 -16
- package/dist/core/dist/chart/y-target.js +13 -12
- package/dist/core/dist/chart.js +868 -441
- package/dist/core/dist/components/annotation-chip.js +28 -0
- package/dist/core/dist/components/crosshair.js +8 -6
- package/dist/core/dist/components/edge-indicator.js +58 -26
- package/dist/core/dist/components/loading-indicator.js +46 -0
- package/dist/core/dist/components/marker.js +49 -31
- package/dist/core/dist/components/reference-line.js +27 -36
- package/dist/core/dist/components/time-region.js +30 -28
- package/dist/core/dist/data/store.js +38 -19
- package/dist/core/dist/data/sync.js +60 -38
- package/dist/core/dist/heatmap-tooltip.js +16 -0
- package/dist/core/dist/interactions/handler.js +86 -46
- package/dist/core/dist/perf/perf-hud.js +5 -5
- package/dist/core/dist/scales/x-scale.js +85 -37
- package/dist/core/dist/scales/y-scale.js +38 -27
- package/dist/core/dist/series/bar-intro.js +18 -0
- package/dist/core/dist/series/bar.js +337 -205
- package/dist/core/dist/series/base-multi-layer.js +224 -96
- package/dist/core/dist/series/candlestick-intro.js +57 -0
- package/dist/core/dist/series/candlestick.js +454 -276
- package/dist/core/dist/series/heatmap.js +387 -0
- package/dist/core/dist/series/line-intro.js +85 -0
- package/dist/core/dist/series/line.js +590 -282
- package/dist/core/dist/series/painters/builtins.js +2 -2
- package/dist/core/dist/series/pie.js +396 -259
- package/dist/core/dist/series/register-builtins.js +8 -7
- package/dist/core/dist/series/types.js +6 -0
- package/dist/core/dist/series/wave-intro.js +26 -0
- package/dist/core/dist/theme/create.js +69 -63
- package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
- package/dist/core/dist/theme/themes/sand-dune.js +2 -2
- package/dist/core/dist/utils/color.js +109 -34
- package/dist/core/dist/utils/deep-equal.js +18 -0
- package/dist/core/dist/utils/time.js +25 -19
- package/dist/index.d.ts +1494 -122
- package/dist/index.js +177 -130
- package/dist/ui/Crosshair.vue.js +20 -21
- package/dist/ui/HeatmapTooltip.vue.js +96 -0
- package/dist/ui/HeatmapTooltip.vue2.js +4 -0
- package/dist/ui/InfoBar.vue.js +46 -47
- package/dist/ui/Legend.vue.js +80 -79
- package/dist/ui/PieLegend.vue.js +5 -5
- package/dist/ui/PieTooltip.vue.js +77 -67
- package/dist/ui/Tooltip.vue.js +60 -60
- package/dist/ui/YAxis.vue.js +2 -2
- package/dist/ui/YLabel.vue.js +94 -61
- package/package.json +2 -2
- package/src/BarSeries.vue +23 -7
- package/src/CandlestickSeries.vue +23 -7
- package/src/ChartContainer.vue +250 -13
- package/src/HeatmapSeries.vue +69 -0
- package/src/LineSeries.vue +23 -7
- package/src/PieSeries.vue +22 -6
- package/src/index.ts +84 -3
- package/src/ui/Crosshair.vue +1 -2
- package/src/ui/HeatmapTooltip.vue +144 -0
- package/src/ui/InfoBar.vue +1 -2
- package/src/ui/Legend.vue +13 -0
- package/src/ui/Marker.vue +1 -1
- package/src/ui/PieTooltip.vue +10 -0
- package/src/ui/ReferenceLine.vue +2 -2
- package/src/ui/TimeRegion.vue +2 -2
- package/src/ui/Tooltip.vue +2 -2
- package/src/ui/YLabel.vue +123 -8
package/dist/ui/YLabel.vue.js
CHANGED
|
@@ -1,105 +1,138 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
1
|
+
import { defineComponent as q, useSlots as j, computed as n, ref as I, onMounted as G, onUnmounted as P, openBlock as w, createElementBlock as B, Fragment as A, renderSlot as W, createElementVNode as _, normalizeStyle as T, unref as H, createVNode as J, createCommentVNode as K } from "vue";
|
|
2
|
+
import { resolveAnimate as Q, prefersReducedMotion as X, firstVisibleValue as Z, BadgeAnimator as ee } from "../core/dist/chart/badge-animator.js";
|
|
3
|
+
import { useChartInstance as te } from "../context.js";
|
|
4
|
+
import ne from "./NumberFlow.vue.js";
|
|
5
|
+
const re = /* @__PURE__ */ q({
|
|
5
6
|
__name: "YLabel",
|
|
6
7
|
props: {
|
|
7
8
|
seriesId: {},
|
|
8
9
|
color: {},
|
|
9
|
-
format: { type: Function }
|
|
10
|
+
format: { type: Function },
|
|
11
|
+
animate: { type: [Boolean, Object] }
|
|
10
12
|
},
|
|
11
|
-
setup(
|
|
12
|
-
const
|
|
13
|
-
|
|
13
|
+
setup(z) {
|
|
14
|
+
const f = z, e = te(), Y = j(), E = n(() => typeof Y.default == "function"), i = I(0), u = I(null);
|
|
15
|
+
let m = null, g = null, o = null;
|
|
16
|
+
const M = n(() => Q(f.animate));
|
|
17
|
+
function S() {
|
|
18
|
+
o = null;
|
|
19
|
+
const t = s.value, l = t !== null ? e.getStackedLastValue(t) : null;
|
|
20
|
+
if (t === null || !l) {
|
|
21
|
+
m = null, g = null;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const v = l.value;
|
|
25
|
+
(m === null || g !== t) && (m = new ee(v), g = t);
|
|
26
|
+
const { glide: d, countUp: U, settleMs: $ } = M.value, F = e.getIntroFront(t), c = m.frame({
|
|
27
|
+
target: v,
|
|
28
|
+
// Only needed for the intro count-up; skip the visible-range binary search
|
|
29
|
+
// entirely once the reveal has settled (the hot streaming path).
|
|
30
|
+
firstVisible: F < 1 ? Z(e, t, v) : v,
|
|
31
|
+
introFront: F,
|
|
32
|
+
now: performance.now(),
|
|
33
|
+
glide: d,
|
|
34
|
+
countUp: U,
|
|
35
|
+
settleMs: $,
|
|
36
|
+
reducedMotion: X()
|
|
37
|
+
}), y = u.value;
|
|
38
|
+
(y === null || y.positionValue !== c.positionValue || y.textValue !== c.textValue || y.opacity !== c.opacity) && (u.value = { positionValue: c.positionValue, textValue: c.textValue, opacity: c.opacity }), c.animating && o === null && (o = requestAnimationFrame(S));
|
|
39
|
+
}
|
|
40
|
+
function N() {
|
|
41
|
+
o === null && (o = requestAnimationFrame(S));
|
|
42
|
+
}
|
|
43
|
+
const p = () => {
|
|
44
|
+
i.value++, N();
|
|
14
45
|
};
|
|
15
|
-
|
|
16
|
-
e.setYLabel(!0), e.on("overlayChange",
|
|
17
|
-
}),
|
|
18
|
-
e.setYLabel(!1), e.off("overlayChange",
|
|
46
|
+
G(() => {
|
|
47
|
+
e.setYLabel(!0), e.on("overlayChange", p), e.on("viewportChange", p), e.getSeriesIds().length > 0 && p();
|
|
48
|
+
}), P(() => {
|
|
49
|
+
e.setYLabel(!1), e.off("overlayChange", p), e.off("viewportChange", p), o !== null && cancelAnimationFrame(o), o = null;
|
|
19
50
|
});
|
|
20
|
-
function
|
|
51
|
+
function O(t, l) {
|
|
21
52
|
if (l !== void 0) return l;
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
const
|
|
25
|
-
return
|
|
53
|
+
const v = t.getSeriesIdsByType("time", { visibleOnly: !0, singleLayerOnly: !0 });
|
|
54
|
+
if (v.length > 0) return v[0];
|
|
55
|
+
const d = t.getSeriesIdsByType("time", { visibleOnly: !0 });
|
|
56
|
+
return d.length > 0 ? d[0] : null;
|
|
26
57
|
}
|
|
27
|
-
const s = n(() => (
|
|
28
|
-
if (
|
|
29
|
-
if (!
|
|
30
|
-
if (
|
|
31
|
-
switch (
|
|
58
|
+
const s = n(() => (i.value, O(e, f.seriesId))), a = n(() => (i.value, s.value !== null ? e.getStackedLastValue(s.value) : null)), b = n(() => (i.value, s.value !== null ? e.getPreviousClose(s.value) : null)), r = n(() => (i.value, e.getTheme())), R = n(() => u.value !== null ? u.value.positionValue : a.value?.value ?? 0), D = n(() => u.value !== null ? u.value.textValue : a.value?.value ?? 0), h = n(() => u.value !== null ? u.value.opacity : s.value === null ? 1 : e.getIntroFront(s.value) < 1 ? 0 : 1), x = n(() => (i.value, a.value === null ? 0 : e.yScale.valueToY(R.value))), L = n(() => a.value === null || b.value === null ? "neutral" : a.value.value > b.value ? "up" : a.value.value < b.value ? "down" : "neutral"), V = n(() => {
|
|
59
|
+
if (a.value === null) return r.value.yLabel.neutralBackground;
|
|
60
|
+
if (!a.value.isLive) return r.value.axis.textColor;
|
|
61
|
+
if (f.color) return f.color;
|
|
62
|
+
switch (L.value) {
|
|
32
63
|
case "up":
|
|
33
|
-
return
|
|
64
|
+
return r.value.yLabel.upBackground;
|
|
34
65
|
case "down":
|
|
35
|
-
return
|
|
66
|
+
return r.value.yLabel.downBackground;
|
|
36
67
|
default:
|
|
37
|
-
return
|
|
68
|
+
return r.value.yLabel.neutralBackground;
|
|
38
69
|
}
|
|
39
|
-
}),
|
|
40
|
-
|
|
41
|
-
const
|
|
70
|
+
}), k = n(() => {
|
|
71
|
+
i.value;
|
|
72
|
+
const t = e.yScale.getRange(), l = t.max - t.min;
|
|
42
73
|
return l < 0.1 ? 6 : l < 10 ? 4 : l < 1e3 ? 2 : 0;
|
|
43
|
-
}),
|
|
44
|
-
if (
|
|
45
|
-
const
|
|
46
|
-
minimumFractionDigits:
|
|
47
|
-
maximumFractionDigits:
|
|
74
|
+
}), C = n(() => {
|
|
75
|
+
if (f.format) return f.format;
|
|
76
|
+
const t = new Intl.NumberFormat("en-US", {
|
|
77
|
+
minimumFractionDigits: k.value,
|
|
78
|
+
maximumFractionDigits: k.value,
|
|
48
79
|
useGrouping: !1
|
|
49
80
|
});
|
|
50
|
-
return (l) =>
|
|
81
|
+
return (l) => t.format(l);
|
|
51
82
|
});
|
|
52
|
-
return (
|
|
53
|
-
|
|
83
|
+
return (t, l) => a.value !== null ? (w(), B(A, { key: 0 }, [
|
|
84
|
+
E.value ? W(t.$slots, "default", {
|
|
54
85
|
key: 0,
|
|
55
|
-
value:
|
|
56
|
-
y:
|
|
57
|
-
bgColor:
|
|
58
|
-
isLive:
|
|
59
|
-
direction:
|
|
60
|
-
format:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
86
|
+
value: a.value.value,
|
|
87
|
+
y: x.value,
|
|
88
|
+
bgColor: V.value,
|
|
89
|
+
isLive: a.value.isLive,
|
|
90
|
+
direction: L.value,
|
|
91
|
+
format: C.value,
|
|
92
|
+
opacity: h.value
|
|
93
|
+
}) : (w(), B(A, { key: 1 }, [
|
|
94
|
+
_("div", {
|
|
95
|
+
style: T({
|
|
64
96
|
position: "absolute",
|
|
65
97
|
left: "0",
|
|
66
|
-
right:
|
|
67
|
-
top:
|
|
98
|
+
right: H(e).yAxisWidth + "px",
|
|
99
|
+
top: x.value + "px",
|
|
68
100
|
height: "0",
|
|
69
|
-
borderTop: "1px dashed " +
|
|
70
|
-
opacity: 0.5,
|
|
101
|
+
borderTop: "1px dashed " + V.value,
|
|
102
|
+
opacity: h.value * 0.5,
|
|
71
103
|
pointerEvents: "none",
|
|
72
104
|
zIndex: 2
|
|
73
105
|
})
|
|
74
106
|
}, null, 4),
|
|
75
|
-
|
|
76
|
-
style:
|
|
107
|
+
_("div", {
|
|
108
|
+
style: T({
|
|
77
109
|
position: "absolute",
|
|
78
110
|
right: "4px",
|
|
79
|
-
top:
|
|
111
|
+
top: x.value + "px",
|
|
80
112
|
transform: "translateY(-50%)",
|
|
113
|
+
opacity: h.value,
|
|
81
114
|
pointerEvents: "auto",
|
|
82
115
|
zIndex: 3,
|
|
83
|
-
background:
|
|
84
|
-
color:
|
|
85
|
-
fontSize:
|
|
86
|
-
fontFamily:
|
|
116
|
+
background: V.value,
|
|
117
|
+
color: r.value.yLabel.textColor,
|
|
118
|
+
fontSize: r.value.yLabel.fontSize + "px",
|
|
119
|
+
fontFamily: r.value.typography.fontFamily,
|
|
87
120
|
padding: "3px 8px",
|
|
88
121
|
borderRadius: "3px",
|
|
89
122
|
whiteSpace: "nowrap",
|
|
90
123
|
transition: "background-color 0.3s ease"
|
|
91
124
|
})
|
|
92
125
|
}, [
|
|
93
|
-
|
|
94
|
-
value:
|
|
95
|
-
format:
|
|
126
|
+
J(ne, {
|
|
127
|
+
value: D.value,
|
|
128
|
+
format: C.value,
|
|
96
129
|
"spin-duration": 350
|
|
97
130
|
}, null, 8, ["value", "format"])
|
|
98
131
|
], 4)
|
|
99
132
|
], 64))
|
|
100
|
-
], 64)) :
|
|
133
|
+
], 64)) : K("", !0);
|
|
101
134
|
}
|
|
102
135
|
});
|
|
103
136
|
export {
|
|
104
|
-
|
|
137
|
+
re as default
|
|
105
138
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wick-charts/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "High-performance canvas timeseries charts for Vue — candlestick, line, bar, pie. Tree-shakeable, zero runtime deps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"vue": ">=3.3.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@wick-charts/core": "^0.
|
|
48
|
+
"@wick-charts/core": "^0.6.1"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "vite build"
|
package/src/BarSeries.vue
CHANGED
|
@@ -5,13 +5,21 @@ import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
|
5
5
|
|
|
6
6
|
import { useChartInstance } from './context';
|
|
7
7
|
|
|
8
|
-
const props =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
/** Flat `TimePoint[]`, `TimePoint[][]`, or named `{ label, color?, data }` layers. Time accepts ms or `Date`. */
|
|
11
|
+
data: MultiLayerData;
|
|
12
|
+
options?: Partial<BarSeriesOptions>;
|
|
13
|
+
/** Stable series ID — same value across remounts. */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Show/hide the series without unmounting it — excludes it from the Y-range fit and tooltip/legend. Default `true`. Live. */
|
|
16
|
+
visible?: boolean;
|
|
17
|
+
}>(),
|
|
18
|
+
// Vue's type-based `defineProps` casts an absent Boolean-typed prop to
|
|
19
|
+
// `false` (not `undefined`) without an explicit default — see the
|
|
20
|
+
// `interactive` fix in ChartContainer.vue for the full explanation.
|
|
21
|
+
{ visible: true },
|
|
22
|
+
);
|
|
15
23
|
|
|
16
24
|
const chart = useChartInstance();
|
|
17
25
|
const seriesId = ref<string | null>(null);
|
|
@@ -35,6 +43,7 @@ onMounted(() => {
|
|
|
35
43
|
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
36
44
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
37
45
|
applyData(id, props.data);
|
|
46
|
+
chart.setSeriesVisible(id, props.visible);
|
|
38
47
|
});
|
|
39
48
|
|
|
40
49
|
onUnmounted(() => {
|
|
@@ -60,6 +69,13 @@ watch(
|
|
|
60
69
|
},
|
|
61
70
|
{ deep: true },
|
|
62
71
|
);
|
|
72
|
+
|
|
73
|
+
watch(
|
|
74
|
+
() => props.visible,
|
|
75
|
+
(visible) => {
|
|
76
|
+
if (seriesId.value) chart.setSeriesVisible(seriesId.value, visible);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
63
79
|
</script>
|
|
64
80
|
|
|
65
81
|
<template><span v-if="false" /></template>
|
|
@@ -5,13 +5,21 @@ import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
|
5
5
|
|
|
6
6
|
import { useChartInstance } from './context';
|
|
7
7
|
|
|
8
|
-
const props =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
/** Flat `OHLCInput[]`, or `{ label, data }` to name the stream. */
|
|
11
|
+
data: CandlestickData;
|
|
12
|
+
options?: Partial<CandlestickSeriesOptions>;
|
|
13
|
+
/** Stable series ID — same value across remounts. */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Show/hide the series without unmounting it — excludes it from the Y-range fit and tooltip/legend. Default `true`. Live. */
|
|
16
|
+
visible?: boolean;
|
|
17
|
+
}>(),
|
|
18
|
+
// Vue's type-based `defineProps` casts an absent Boolean-typed prop to
|
|
19
|
+
// `false` (not `undefined`) without an explicit default — see the
|
|
20
|
+
// `interactive` fix in ChartContainer.vue for the full explanation.
|
|
21
|
+
{ visible: true },
|
|
22
|
+
);
|
|
15
23
|
|
|
16
24
|
const chart = useChartInstance();
|
|
17
25
|
const seriesId = ref<string | null>(null);
|
|
@@ -37,6 +45,7 @@ onMounted(() => {
|
|
|
37
45
|
// below only fires on subsequent `data` prop mutations. Explicitly apply
|
|
38
46
|
// the first value here so components with static data render immediately.
|
|
39
47
|
applyData(id, props.data);
|
|
48
|
+
chart.setSeriesVisible(id, props.visible);
|
|
40
49
|
});
|
|
41
50
|
|
|
42
51
|
onUnmounted(() => {
|
|
@@ -62,6 +71,13 @@ watch(
|
|
|
62
71
|
},
|
|
63
72
|
{ deep: true },
|
|
64
73
|
);
|
|
74
|
+
|
|
75
|
+
watch(
|
|
76
|
+
() => props.visible,
|
|
77
|
+
(visible) => {
|
|
78
|
+
if (seriesId.value) chart.setSeriesVisible(seriesId.value, visible);
|
|
79
|
+
},
|
|
80
|
+
);
|
|
65
81
|
</script>
|
|
66
82
|
|
|
67
83
|
<template><span v-if="false" /></template>
|