@wick-charts/vue 0.4.2 → 0.5.0
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 +5 -3
- package/dist/BarSeries.vue.js +44 -0
- package/dist/BarSeries.vue2.js +4 -0
- package/dist/CandlestickSeries.vue.js +45 -0
- package/dist/CandlestickSeries.vue2.js +4 -0
- package/dist/ChartContainer.vue.js +168 -0
- package/dist/ChartContainer.vue2.js +4 -0
- package/dist/LineSeries.vue.js +44 -0
- package/dist/LineSeries.vue2.js +4 -0
- package/dist/PieSeries.vue.js +34 -0
- package/dist/PieSeries.vue2.js +4 -0
- package/dist/composables.js +44 -0
- package/dist/context.js +25 -0
- package/dist/core/dist/animation/animator.js +72 -0
- package/dist/core/dist/animation/config.js +145 -0
- package/dist/core/dist/animation/easing.js +4 -0
- package/dist/core/dist/animation/scalar-spring.js +57 -0
- package/dist/core/dist/animation/spring.js +11 -0
- package/dist/core/dist/animation/time.js +19 -0
- package/dist/core/dist/animation/viewport-engine.js +174 -0
- package/dist/core/dist/animation/visible-range-spring.js +64 -0
- package/dist/core/dist/animation/y-range-hermite.js +72 -0
- package/dist/core/dist/animation/y-range-snap.js +31 -0
- package/dist/core/dist/animation/y-range-spring.js +59 -0
- package/dist/core/dist/axis/dom-labels.js +60 -0
- package/dist/core/dist/canvas-manager.js +109 -0
- package/dist/core/dist/chart/edge-indicators.js +26 -0
- package/dist/core/dist/chart/fit-to-data.js +9 -0
- package/dist/core/dist/chart/last-value.js +31 -0
- package/dist/core/dist/chart/options.js +35 -0
- package/dist/core/dist/chart/pan-zoom-math.js +66 -0
- package/dist/core/dist/chart/streaming-cadence.js +70 -0
- package/dist/core/dist/chart/streaming-target.js +22 -0
- package/dist/core/dist/chart/viewport-padding.js +6 -0
- package/dist/core/dist/chart/y-target.js +24 -0
- package/dist/core/dist/chart.js +1495 -0
- package/dist/core/dist/components/crosshair.js +9 -0
- package/dist/core/dist/components/edge-indicator.js +36 -0
- package/dist/core/dist/components/grid.js +22 -0
- package/dist/core/dist/components/marker.js +41 -0
- package/dist/core/dist/components/reference-line.js +48 -0
- package/dist/core/dist/components/time-region.js +35 -0
- package/dist/core/dist/data/decimation.js +54 -0
- package/dist/core/dist/data/store.js +76 -0
- package/dist/core/dist/data/sync.js +47 -0
- package/dist/core/dist/events.js +19 -0
- package/dist/core/dist/interactions/handler.js +84 -0
- package/dist/core/dist/interactions/pan.js +26 -0
- package/dist/core/dist/interactions/zoom.js +21 -0
- package/dist/core/dist/navigator/controller.js +374 -0
- package/dist/core/dist/navigator/decimate.js +44 -0
- package/dist/core/dist/navigator/interactions.js +28 -0
- package/dist/core/dist/navigator/render.js +68 -0
- package/dist/core/dist/perf/counting-context.js +19 -0
- package/dist/core/dist/perf/perf-hud.js +453 -0
- package/dist/core/dist/perf/perf-monitor.js +132 -0
- package/dist/core/dist/render-scheduler.js +31 -0
- package/dist/core/dist/scales/tick-tracker.js +110 -0
- package/dist/core/dist/scales/x-scale.js +145 -0
- package/dist/core/dist/scales/y-scale.js +156 -0
- package/dist/core/dist/series/bar.js +341 -0
- package/dist/core/dist/series/base-multi-layer.js +438 -0
- package/dist/core/dist/series/candlestick.js +481 -0
- package/dist/core/dist/series/definition.js +11 -0
- package/dist/core/dist/series/line.js +446 -0
- package/dist/core/dist/series/painters/builtins.js +36 -0
- package/dist/core/dist/series/painters/canvas-path.js +79 -0
- package/dist/core/dist/series/painters/resolve.js +32 -0
- package/dist/core/dist/series/pie.js +545 -0
- package/dist/core/dist/series/register-builtins.js +11 -0
- package/dist/core/dist/series/stack-math.js +17 -0
- package/dist/core/dist/snapshots.js +107 -0
- package/dist/core/dist/theme/create.js +176 -0
- package/dist/core/dist/theme/resolve.js +14 -0
- package/dist/core/dist/theme/themes/andromeda.js +33 -0
- package/dist/core/dist/theme/themes/ayu-mirage.js +33 -0
- package/dist/core/dist/theme/themes/catppuccin.js +33 -0
- package/dist/core/dist/theme/themes/dracula.js +35 -0
- package/dist/core/dist/theme/themes/github-light.js +34 -0
- package/dist/core/dist/theme/themes/gruvbox.js +33 -0
- package/dist/core/dist/theme/themes/handwritten.js +101 -0
- package/dist/core/dist/theme/themes/high-contrast.js +33 -0
- package/dist/core/dist/theme/themes/lavender-mist.js +33 -0
- package/dist/core/dist/theme/themes/light-pink.js +34 -0
- package/dist/core/dist/theme/themes/material-palenight.js +33 -0
- package/dist/core/dist/theme/themes/minimal-light.js +34 -0
- package/dist/core/dist/theme/themes/mint-breeze.js +33 -0
- package/dist/core/dist/theme/themes/monokai-pro.js +33 -0
- package/dist/core/dist/theme/themes/night-owl.js +35 -0
- package/dist/core/dist/theme/themes/one-dark-pro.js +33 -0
- package/dist/core/dist/theme/themes/panda.js +33 -0
- package/dist/core/dist/theme/themes/peach-cream.js +33 -0
- package/dist/core/dist/theme/themes/quiet-light.js +37 -0
- package/dist/core/dist/theme/themes/rose-pine-dawn.js +33 -0
- package/dist/core/dist/theme/themes/sand-dune.js +33 -0
- package/dist/core/dist/theme/themes/solarized-light.js +34 -0
- package/dist/core/dist/tooltip-position.js +10 -0
- package/dist/core/dist/utils/color.js +37 -0
- package/dist/core/dist/utils/format.js +29 -0
- package/dist/core/dist/utils/math.js +26 -0
- package/dist/core/dist/utils/poisoned-data-reporter.js +15 -0
- package/dist/core/dist/utils/time.js +41 -0
- package/dist/index.d.ts +827 -63
- package/dist/index.js +142 -8025
- package/dist/ui/Crosshair.vue.js +53 -0
- package/dist/ui/Crosshair.vue2.js +4 -0
- package/dist/ui/InfoBar.vue.js +143 -0
- package/dist/ui/InfoBar.vue2.js +4 -0
- package/dist/ui/Legend.vue.js +212 -0
- package/dist/ui/Legend.vue2.js +4 -0
- package/dist/ui/Marker.vue.js +47 -0
- package/dist/ui/Marker.vue2.js +4 -0
- package/dist/ui/Navigator.vue.js +58 -0
- package/dist/ui/Navigator.vue2.js +4 -0
- package/dist/ui/NumberFlow.vue.js +69 -0
- package/dist/ui/NumberFlow.vue2.js +4 -0
- package/dist/ui/PieLegend.vue.js +132 -0
- package/dist/ui/PieLegend.vue2.js +4 -0
- package/dist/ui/PieTooltip.vue.js +135 -0
- package/dist/ui/PieTooltip.vue2.js +4 -0
- package/dist/ui/ReferenceLine.vue.js +44 -0
- package/dist/ui/ReferenceLine.vue2.js +4 -0
- package/dist/ui/TimeAxis.vue.js +43 -0
- package/dist/ui/TimeAxis.vue2.js +4 -0
- package/dist/ui/TimeRegion.vue.js +41 -0
- package/dist/ui/TimeRegion.vue2.js +4 -0
- package/dist/ui/Title.vue.js +54 -0
- package/dist/ui/Title.vue2.js +4 -0
- package/dist/ui/Tooltip.vue.js +195 -0
- package/dist/ui/Tooltip.vue2.js +4 -0
- package/dist/ui/YAxis.vue.js +42 -0
- package/dist/ui/YAxis.vue2.js +4 -0
- package/dist/ui/YLabel.vue.js +105 -0
- package/dist/ui/YLabel.vue2.js +4 -0
- package/package.json +2 -2
- package/src/BarSeries.vue +12 -13
- package/src/CandlestickSeries.vue +17 -6
- package/src/LineSeries.vue +12 -13
- package/src/PieSeries.vue +2 -1
- package/src/index.ts +23 -0
- package/src/ui/Legend.vue +1 -2
- package/src/ui/Marker.vue +62 -0
- package/src/ui/ReferenceLine.vue +58 -0
- package/src/ui/TimeRegion.vue +54 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineComponent as m, ref as p, onMounted as r, watch as s, onUnmounted as o, openBlock as f, createElementBlock as b, normalizeStyle as y, unref as u } from "vue";
|
|
2
|
+
import { mountAxisLabels as x } from "../core/dist/axis/dom-labels.js";
|
|
3
|
+
import { useChartInstance as h } from "../context.js";
|
|
4
|
+
const _ = /* @__PURE__ */ m({
|
|
5
|
+
__name: "YAxis",
|
|
6
|
+
props: {
|
|
7
|
+
format: { type: Function },
|
|
8
|
+
labelCount: {},
|
|
9
|
+
minLabelSpacing: {}
|
|
10
|
+
},
|
|
11
|
+
setup(c) {
|
|
12
|
+
const e = c, n = h(), t = p(null), a = () => n.yScale.setFormat(e.format ?? null);
|
|
13
|
+
r(a), s(() => e.format, a), o(() => n.yScale.setFormat(null));
|
|
14
|
+
const i = () => {
|
|
15
|
+
n.setYAxisLabelDensity({
|
|
16
|
+
labelCount: e.labelCount ?? null,
|
|
17
|
+
minLabelSpacing: e.minLabelSpacing ?? null
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
i(), s(() => [e.labelCount, e.minLabelSpacing], i), o(() => n.setYAxisLabelDensity({ labelCount: null, minLabelSpacing: null }));
|
|
21
|
+
let l = null;
|
|
22
|
+
return r(() => {
|
|
23
|
+
t.value !== null && (l = x({ chart: n, container: t.value, axis: "y" }));
|
|
24
|
+
}), o(() => {
|
|
25
|
+
l?.(), l = null;
|
|
26
|
+
}), (L, S) => (f(), b("div", {
|
|
27
|
+
ref_key: "containerRef",
|
|
28
|
+
ref: t,
|
|
29
|
+
style: y({
|
|
30
|
+
position: "absolute",
|
|
31
|
+
right: "0",
|
|
32
|
+
top: "0",
|
|
33
|
+
bottom: u(n).xAxisHeight + "px",
|
|
34
|
+
width: u(n).yAxisWidth + "px",
|
|
35
|
+
pointerEvents: "none"
|
|
36
|
+
})
|
|
37
|
+
}, null, 4));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
export {
|
|
41
|
+
_ as default
|
|
42
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { defineComponent as B, useSlots as F, computed as n, ref as _, onMounted as T, onUnmounted as z, openBlock as h, createElementBlock as b, Fragment as x, renderSlot as Y, createElementVNode as C, normalizeStyle as L, unref as E, createVNode as N, createCommentVNode as V } from "vue";
|
|
2
|
+
import { useChartInstance as D } from "../context.js";
|
|
3
|
+
import O from "./NumberFlow.vue.js";
|
|
4
|
+
const A = /* @__PURE__ */ B({
|
|
5
|
+
__name: "YLabel",
|
|
6
|
+
props: {
|
|
7
|
+
seriesId: {},
|
|
8
|
+
color: {},
|
|
9
|
+
format: { type: Function }
|
|
10
|
+
},
|
|
11
|
+
setup(S) {
|
|
12
|
+
const u = S, e = D(), k = F(), I = n(() => typeof k.default == "function"), r = _(0), i = () => {
|
|
13
|
+
r.value++;
|
|
14
|
+
};
|
|
15
|
+
T(() => {
|
|
16
|
+
e.setYLabel(!0), e.on("overlayChange", i), e.on("viewportChange", i), e.getSeriesIds().length > 0 && r.value++;
|
|
17
|
+
}), z(() => {
|
|
18
|
+
e.setYLabel(!1), e.off("overlayChange", i), e.off("viewportChange", i);
|
|
19
|
+
});
|
|
20
|
+
function w(a, l) {
|
|
21
|
+
if (l !== void 0) return l;
|
|
22
|
+
const g = a.getSeriesIdsByType("time", { visibleOnly: !0, singleLayerOnly: !0 });
|
|
23
|
+
if (g.length > 0) return g[0];
|
|
24
|
+
const y = a.getSeriesIdsByType("time", { visibleOnly: !0 });
|
|
25
|
+
return y.length > 0 ? y[0] : null;
|
|
26
|
+
}
|
|
27
|
+
const s = n(() => (r.value, w(e, u.seriesId))), t = n(() => (r.value, s.value !== null ? e.getStackedLastValue(s.value) : null)), v = n(() => (r.value, s.value !== null ? e.getPreviousClose(s.value) : null)), o = n(() => (r.value, e.getTheme())), c = n(() => (r.value, t.value === null ? 0 : e.yScale.valueToY(t.value.value))), f = n(() => t.value === null || v.value === null ? "neutral" : t.value.value > v.value ? "up" : t.value.value < v.value ? "down" : "neutral"), d = n(() => {
|
|
28
|
+
if (t.value === null) return o.value.yLabel.neutralBackground;
|
|
29
|
+
if (!t.value.isLive) return o.value.axis.textColor;
|
|
30
|
+
if (u.color) return u.color;
|
|
31
|
+
switch (f.value) {
|
|
32
|
+
case "up":
|
|
33
|
+
return o.value.yLabel.upBackground;
|
|
34
|
+
case "down":
|
|
35
|
+
return o.value.yLabel.downBackground;
|
|
36
|
+
default:
|
|
37
|
+
return o.value.yLabel.neutralBackground;
|
|
38
|
+
}
|
|
39
|
+
}), m = n(() => {
|
|
40
|
+
r.value;
|
|
41
|
+
const a = e.yScale.getRange(), l = a.max - a.min;
|
|
42
|
+
return l < 0.1 ? 6 : l < 10 ? 4 : l < 1e3 ? 2 : 0;
|
|
43
|
+
}), p = n(() => {
|
|
44
|
+
if (u.format) return u.format;
|
|
45
|
+
const a = new Intl.NumberFormat("en-US", {
|
|
46
|
+
minimumFractionDigits: m.value,
|
|
47
|
+
maximumFractionDigits: m.value,
|
|
48
|
+
useGrouping: !1
|
|
49
|
+
});
|
|
50
|
+
return (l) => a.format(l);
|
|
51
|
+
});
|
|
52
|
+
return (a, l) => t.value !== null ? (h(), b(x, { key: 0 }, [
|
|
53
|
+
I.value ? Y(a.$slots, "default", {
|
|
54
|
+
key: 0,
|
|
55
|
+
value: t.value.value,
|
|
56
|
+
y: c.value,
|
|
57
|
+
bgColor: d.value,
|
|
58
|
+
isLive: t.value.isLive,
|
|
59
|
+
direction: f.value,
|
|
60
|
+
format: p.value
|
|
61
|
+
}) : (h(), b(x, { key: 1 }, [
|
|
62
|
+
C("div", {
|
|
63
|
+
style: L({
|
|
64
|
+
position: "absolute",
|
|
65
|
+
left: "0",
|
|
66
|
+
right: E(e).yAxisWidth + "px",
|
|
67
|
+
top: c.value + "px",
|
|
68
|
+
height: "0",
|
|
69
|
+
borderTop: "1px dashed " + d.value,
|
|
70
|
+
opacity: 0.5,
|
|
71
|
+
pointerEvents: "none",
|
|
72
|
+
zIndex: 2
|
|
73
|
+
})
|
|
74
|
+
}, null, 4),
|
|
75
|
+
C("div", {
|
|
76
|
+
style: L({
|
|
77
|
+
position: "absolute",
|
|
78
|
+
right: "4px",
|
|
79
|
+
top: c.value + "px",
|
|
80
|
+
transform: "translateY(-50%)",
|
|
81
|
+
pointerEvents: "auto",
|
|
82
|
+
zIndex: 3,
|
|
83
|
+
background: d.value,
|
|
84
|
+
color: o.value.yLabel.textColor,
|
|
85
|
+
fontSize: o.value.yLabel.fontSize + "px",
|
|
86
|
+
fontFamily: o.value.typography.fontFamily,
|
|
87
|
+
padding: "3px 8px",
|
|
88
|
+
borderRadius: "3px",
|
|
89
|
+
whiteSpace: "nowrap",
|
|
90
|
+
transition: "background-color 0.3s ease"
|
|
91
|
+
})
|
|
92
|
+
}, [
|
|
93
|
+
N(O, {
|
|
94
|
+
value: t.value.value,
|
|
95
|
+
format: p.value,
|
|
96
|
+
"spin-duration": 350
|
|
97
|
+
}, null, 8, ["value", "format"])
|
|
98
|
+
], 4)
|
|
99
|
+
], 64))
|
|
100
|
+
], 64)) : V("", !0);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
export {
|
|
104
|
+
A as default
|
|
105
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wick-charts/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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.5.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "vite build"
|
package/src/BarSeries.vue
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { BarSeriesOptions,
|
|
3
|
-
import { EMPTY_SYNC_STATE,
|
|
2
|
+
import type { BarSeriesOptions, MultiLayerData, SeriesSyncState } from '@wick-charts/core';
|
|
3
|
+
import { BarSeriesDef, EMPTY_SYNC_STATE, syncLayers, toLayers } from '@wick-charts/core';
|
|
4
4
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
5
5
|
|
|
6
6
|
import { useChartInstance } from './context';
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
|
-
|
|
9
|
+
/** Flat `TimePoint[]`, `TimePoint[][]`, or named `{ label, color?, data }` layers. Time accepts ms or `Date`. */
|
|
10
|
+
data: MultiLayerData;
|
|
10
11
|
options?: Partial<BarSeriesOptions>;
|
|
11
12
|
/** Stable series ID — same value across remounts. */
|
|
12
13
|
id?: string;
|
|
@@ -15,25 +16,23 @@ const props = defineProps<{
|
|
|
15
16
|
const chart = useChartInstance();
|
|
16
17
|
const seriesId = ref<string | null>(null);
|
|
17
18
|
// Per-layer sync state — drives the shared append/keepLast/update/replace
|
|
18
|
-
// reconciliation so streaming eases instead of
|
|
19
|
+
// reconciliation (plus per-layer labels/colors) so streaming eases instead of
|
|
20
|
+
// snapping Y every tick.
|
|
19
21
|
let prevSync: SeriesSyncState[] = [];
|
|
20
22
|
|
|
21
|
-
function applyData(id: string, data:
|
|
22
|
-
|
|
23
|
-
for (let i = 0; i < data.length; i++) {
|
|
24
|
-
prevSync[i] = syncSeriesLayer({ chart, id, data: data[i], prev: prevSync[i] ?? EMPTY_SYNC_STATE, layerIndex: i });
|
|
25
|
-
}
|
|
26
|
-
});
|
|
23
|
+
function applyData(id: string, data: MultiLayerData): void {
|
|
24
|
+
prevSync = syncLayers({ chart, id, data, prev: prevSync });
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
onMounted(() => {
|
|
30
|
-
const
|
|
28
|
+
const layerCount = toLayers(props.data).length;
|
|
29
|
+
const id = chart.addSeries(BarSeriesDef, {
|
|
31
30
|
...props.options,
|
|
32
|
-
layers:
|
|
31
|
+
layers: layerCount,
|
|
33
32
|
id: props.id,
|
|
34
33
|
});
|
|
35
34
|
seriesId.value = id;
|
|
36
|
-
prevSync =
|
|
35
|
+
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
37
36
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
38
37
|
applyData(id, props.data);
|
|
39
38
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { CandlestickSeriesOptions, OHLCInput, SeriesSyncState } from '@wick-charts/core';
|
|
3
|
-
import { EMPTY_SYNC_STATE, syncSeriesLayer } from '@wick-charts/core';
|
|
2
|
+
import type { CandlestickData, CandlestickSeriesOptions, OHLCInput, SeriesSyncState } from '@wick-charts/core';
|
|
3
|
+
import { CandlestickSeriesDef, EMPTY_SYNC_STATE, syncSeriesLayer, toLayers } from '@wick-charts/core';
|
|
4
4
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
5
5
|
|
|
6
6
|
import { useChartInstance } from './context';
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
|
-
|
|
9
|
+
/** Flat `OHLCInput[]`, or `{ label, data }` to name the stream. */
|
|
10
|
+
data: CandlestickData;
|
|
10
11
|
options?: Partial<CandlestickSeriesOptions>;
|
|
11
12
|
/** Stable series ID — same value across remounts. */
|
|
12
13
|
id?: string;
|
|
@@ -19,13 +20,23 @@ const seriesId = ref<string | null>(null);
|
|
|
19
20
|
// burst takes the smooth append path, matching React's 20-candle threshold).
|
|
20
21
|
let prevSync: SeriesSyncState = EMPTY_SYNC_STATE;
|
|
21
22
|
|
|
23
|
+
function applyData(id: string, data: CandlestickData): void {
|
|
24
|
+
const layer = toLayers<OHLCInput>(data)[0];
|
|
25
|
+
chart.setSeriesLabels(id, [layer.label]);
|
|
26
|
+
prevSync = syncSeriesLayer({ chart, id, data: layer.data, prev: prevSync });
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
onMounted(() => {
|
|
23
|
-
const id = chart.addSeries(
|
|
30
|
+
const id = chart.addSeries(CandlestickSeriesDef, {
|
|
31
|
+
...props.options,
|
|
32
|
+
id: props.id,
|
|
33
|
+
label: toLayers<OHLCInput>(props.data)[0].label,
|
|
34
|
+
});
|
|
24
35
|
seriesId.value = id;
|
|
25
36
|
// Initial data load — Vue's `watch` is lazy by default, so the watcher
|
|
26
37
|
// below only fires on subsequent `data` prop mutations. Explicitly apply
|
|
27
38
|
// the first value here so components with static data render immediately.
|
|
28
|
-
|
|
39
|
+
applyData(id, props.data);
|
|
29
40
|
});
|
|
30
41
|
|
|
31
42
|
onUnmounted(() => {
|
|
@@ -38,7 +49,7 @@ watch(
|
|
|
38
49
|
const id = seriesId.value;
|
|
39
50
|
if (!id) return;
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
applyData(id, data);
|
|
42
53
|
},
|
|
43
54
|
);
|
|
44
55
|
|
package/src/LineSeries.vue
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { LineSeriesOptions,
|
|
3
|
-
import { EMPTY_SYNC_STATE,
|
|
2
|
+
import type { LineSeriesOptions, MultiLayerData, SeriesSyncState } from '@wick-charts/core';
|
|
3
|
+
import { EMPTY_SYNC_STATE, LineSeriesDef, syncLayers, toLayers } from '@wick-charts/core';
|
|
4
4
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
5
5
|
|
|
6
6
|
import { useChartInstance } from './context';
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
|
-
|
|
9
|
+
/** Flat `TimePoint[]`, `TimePoint[][]`, or named `{ label, color?, data }` layers. Time accepts ms or `Date`. */
|
|
10
|
+
data: MultiLayerData;
|
|
10
11
|
options?: Partial<LineSeriesOptions>;
|
|
11
12
|
/** Stable series ID — same value across remounts. */
|
|
12
13
|
id?: string;
|
|
@@ -15,25 +16,23 @@ const props = defineProps<{
|
|
|
15
16
|
const chart = useChartInstance();
|
|
16
17
|
const seriesId = ref<string | null>(null);
|
|
17
18
|
// Per-layer sync state — drives the shared append/keepLast/update/replace
|
|
18
|
-
// reconciliation so streaming eases instead of
|
|
19
|
+
// reconciliation (plus per-layer labels/colors) so streaming eases instead of
|
|
20
|
+
// snapping Y every tick.
|
|
19
21
|
let prevSync: SeriesSyncState[] = [];
|
|
20
22
|
|
|
21
|
-
function applyData(id: string, data:
|
|
22
|
-
|
|
23
|
-
for (let i = 0; i < data.length; i++) {
|
|
24
|
-
prevSync[i] = syncSeriesLayer({ chart, id, data: data[i], prev: prevSync[i] ?? EMPTY_SYNC_STATE, layerIndex: i });
|
|
25
|
-
}
|
|
26
|
-
});
|
|
23
|
+
function applyData(id: string, data: MultiLayerData): void {
|
|
24
|
+
prevSync = syncLayers({ chart, id, data, prev: prevSync });
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
onMounted(() => {
|
|
30
|
-
const
|
|
28
|
+
const layerCount = toLayers(props.data).length;
|
|
29
|
+
const id = chart.addSeries(LineSeriesDef, {
|
|
31
30
|
...props.options,
|
|
32
|
-
layers:
|
|
31
|
+
layers: layerCount,
|
|
33
32
|
id: props.id,
|
|
34
33
|
});
|
|
35
34
|
seriesId.value = id;
|
|
36
|
-
prevSync =
|
|
35
|
+
prevSync = new Array(layerCount).fill(EMPTY_SYNC_STATE);
|
|
37
36
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
38
37
|
applyData(id, props.data);
|
|
39
38
|
});
|
package/src/PieSeries.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { PieSeriesOptions, PieSliceData } from '@wick-charts/core';
|
|
3
|
+
import { PieSeriesDef } from '@wick-charts/core';
|
|
3
4
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
|
4
5
|
|
|
5
6
|
import { useChartInstance } from './context';
|
|
@@ -15,7 +16,7 @@ const chart = useChartInstance();
|
|
|
15
16
|
const seriesId = ref<string | null>(null);
|
|
16
17
|
|
|
17
18
|
onMounted(() => {
|
|
18
|
-
const id = chart.addSeries(
|
|
19
|
+
const id = chart.addSeries(PieSeriesDef, { ...props.options, id: props.id });
|
|
19
20
|
seriesId.value = id;
|
|
20
21
|
// Lazy watcher — apply initial data here so static-data mounts render without a no-op first frame.
|
|
21
22
|
if (props.data.length > 0) {
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type {
|
|
|
32
32
|
LinePainter,
|
|
33
33
|
/** @deprecated Use {@link TimePoint} instead. */
|
|
34
34
|
LineSeriesOptions,
|
|
35
|
+
MarkerConfig,
|
|
36
|
+
MarkerShape,
|
|
35
37
|
NavigatorCandlePoint,
|
|
36
38
|
NavigatorControllerParams,
|
|
37
39
|
NavigatorData,
|
|
@@ -41,9 +43,17 @@ export type {
|
|
|
41
43
|
OHLCData,
|
|
42
44
|
OHLCInput,
|
|
43
45
|
PaintEnv,
|
|
46
|
+
PerfConfig,
|
|
47
|
+
PerfMonitorOptions,
|
|
48
|
+
PerfStats,
|
|
44
49
|
PieSeriesOptions,
|
|
45
50
|
PieSliceData,
|
|
51
|
+
ReferenceLineConfig,
|
|
52
|
+
ReferenceLineOrientation,
|
|
53
|
+
ReferenceLineStyle,
|
|
46
54
|
RoundedRectArgs,
|
|
55
|
+
SeriesCreateEnv,
|
|
56
|
+
SeriesDefinition,
|
|
47
57
|
SeriesSnapshot,
|
|
48
58
|
SeriesType,
|
|
49
59
|
SliceInfo,
|
|
@@ -53,6 +63,8 @@ export type {
|
|
|
53
63
|
ThemePreset,
|
|
54
64
|
TimePoint,
|
|
55
65
|
TimePointInput,
|
|
66
|
+
TimeRegionConfig,
|
|
67
|
+
TimeRegionEnd,
|
|
56
68
|
TimeValue,
|
|
57
69
|
TooltipField,
|
|
58
70
|
TooltipFormatter,
|
|
@@ -68,8 +80,13 @@ export type {
|
|
|
68
80
|
} from '@wick-charts/core';
|
|
69
81
|
// Painters — custom per-element drawing for bar / candle / line series.
|
|
70
82
|
export {
|
|
83
|
+
BarSeriesDef,
|
|
84
|
+
CandlestickSeriesDef,
|
|
71
85
|
ChartInstance,
|
|
86
|
+
LineSeriesDef,
|
|
72
87
|
NavigatorController,
|
|
88
|
+
PerfMonitor,
|
|
89
|
+
PieSeriesDef,
|
|
73
90
|
andromeda,
|
|
74
91
|
autoGradient,
|
|
75
92
|
ayuMirage,
|
|
@@ -100,7 +117,10 @@ export {
|
|
|
100
117
|
oneDarkPro,
|
|
101
118
|
panda,
|
|
102
119
|
peachCream,
|
|
120
|
+
perfHud,
|
|
103
121
|
quietLight,
|
|
122
|
+
registerBuiltinSeries,
|
|
123
|
+
registerSeriesDefinition,
|
|
104
124
|
resolveAxisFontSize,
|
|
105
125
|
resolveAxisTextColor,
|
|
106
126
|
resolveCandlestickBodyColor,
|
|
@@ -127,11 +147,14 @@ export { default as PieSeries } from './PieSeries.vue';
|
|
|
127
147
|
export { default as Crosshair } from './ui/Crosshair.vue';
|
|
128
148
|
export { default as InfoBar } from './ui/InfoBar.vue';
|
|
129
149
|
export { default as Legend } from './ui/Legend.vue';
|
|
150
|
+
export { default as Marker } from './ui/Marker.vue';
|
|
130
151
|
export { default as Navigator } from './ui/Navigator.vue';
|
|
131
152
|
export { default as NumberFlow } from './ui/NumberFlow.vue';
|
|
132
153
|
export { default as PieLegend } from './ui/PieLegend.vue';
|
|
133
154
|
export { default as PieTooltip } from './ui/PieTooltip.vue';
|
|
155
|
+
export { default as ReferenceLine } from './ui/ReferenceLine.vue';
|
|
134
156
|
export { default as TimeAxis } from './ui/TimeAxis.vue';
|
|
157
|
+
export { default as TimeRegion } from './ui/TimeRegion.vue';
|
|
135
158
|
export { default as Title } from './ui/Title.vue';
|
|
136
159
|
// UI overlays
|
|
137
160
|
export { default as Tooltip } from './ui/Tooltip.vue';
|
package/src/ui/Legend.vue
CHANGED
|
@@ -129,7 +129,6 @@ function buildLegendItems(c: ChartInstance): LegendItem[] {
|
|
|
129
129
|
for (const seriesId of c.getSeriesIds()) {
|
|
130
130
|
const layers = c.getSeriesLayers(seriesId);
|
|
131
131
|
if (layers) {
|
|
132
|
-
const baseLabel = c.getSeriesLabel(seriesId);
|
|
133
132
|
for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
|
|
134
133
|
const id = `${seriesId}_layer${layerIndex}`;
|
|
135
134
|
const visible = c.isSeriesVisible(seriesId) && c.isLayerVisible(seriesId, layerIndex);
|
|
@@ -138,7 +137,7 @@ function buildLegendItems(c: ChartInstance): LegendItem[] {
|
|
|
138
137
|
id,
|
|
139
138
|
seriesId,
|
|
140
139
|
layerIndex,
|
|
141
|
-
label:
|
|
140
|
+
label: c.getLayerLabel(seriesId, layerIndex) ?? `Series ${layerIndex + 1}`,
|
|
142
141
|
color: layers[layerIndex].color,
|
|
143
142
|
isDisabled: !visible,
|
|
144
143
|
}),
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { MarkerShape, TimeValue } from '@wick-charts/core';
|
|
3
|
+
import { onMounted, onUnmounted, watch } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { useChartInstance } from '../context';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
/** X anchor — epoch ms or a `Date`. */
|
|
9
|
+
time: TimeValue;
|
|
10
|
+
/** Y anchor as a data value. Omit and set `seriesId` to snap to that series' value at `time`. */
|
|
11
|
+
value?: number;
|
|
12
|
+
/** Snap Y to this series' value at `time` when `value` is omitted. Also the default color source. */
|
|
13
|
+
seriesId?: string;
|
|
14
|
+
/** Glyph at the anchor. Default: `'dot'`. Arrows point their tip at the anchor. */
|
|
15
|
+
shape?: MarkerShape;
|
|
16
|
+
/** Reuse the line pulse halo around the anchor. Default: `false`. */
|
|
17
|
+
pulse?: boolean;
|
|
18
|
+
/** Optional text label drawn in a pill next to the anchor. */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** Color override. Falls back to the series color (when `seriesId` is set), then the theme line color. */
|
|
21
|
+
color?: string;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const chart = useChartInstance();
|
|
25
|
+
let markerId: string | null = null;
|
|
26
|
+
|
|
27
|
+
onMounted(() => {
|
|
28
|
+
markerId = chart.addMarker({
|
|
29
|
+
time: props.time,
|
|
30
|
+
value: props.value,
|
|
31
|
+
seriesId: props.seriesId,
|
|
32
|
+
shape: props.shape,
|
|
33
|
+
pulse: props.pulse,
|
|
34
|
+
label: props.label,
|
|
35
|
+
color: props.color,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
onUnmounted(() => {
|
|
40
|
+
if (markerId !== null) chart.removeMarker(markerId);
|
|
41
|
+
markerId = null;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
watch(
|
|
45
|
+
() => [props.time, props.value, props.seriesId, props.shape, props.pulse, props.label, props.color],
|
|
46
|
+
() => {
|
|
47
|
+
if (markerId === null) return;
|
|
48
|
+
|
|
49
|
+
chart.updateMarker(markerId, {
|
|
50
|
+
time: props.time,
|
|
51
|
+
value: props.value,
|
|
52
|
+
seriesId: props.seriesId,
|
|
53
|
+
shape: props.shape,
|
|
54
|
+
pulse: props.pulse,
|
|
55
|
+
label: props.label,
|
|
56
|
+
color: props.color,
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template><span v-if="false" /></template>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ReferenceLineStyle, TimeValue } from '@wick-charts/core';
|
|
3
|
+
import { onMounted, onUnmounted, watch } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { useChartInstance } from '../context';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
/** Horizontal line at this Y data value. Mutually exclusive with `time`. */
|
|
9
|
+
value?: number;
|
|
10
|
+
/** Vertical line at this `time` (epoch ms or `Date`). Mutually exclusive with `value`. */
|
|
11
|
+
time?: TimeValue;
|
|
12
|
+
/** Line and label-pill color. Default: the theme line color. */
|
|
13
|
+
color?: string;
|
|
14
|
+
/** Optional text label drawn in a pill at the line's near end. */
|
|
15
|
+
label?: string;
|
|
16
|
+
/** Dash style. Default: `'dashed'`. */
|
|
17
|
+
style?: ReferenceLineStyle;
|
|
18
|
+
/** Stroke width in CSS pixels. Default: `1`. */
|
|
19
|
+
width?: number;
|
|
20
|
+
}>();
|
|
21
|
+
|
|
22
|
+
const chart = useChartInstance();
|
|
23
|
+
let lineId: string | null = null;
|
|
24
|
+
|
|
25
|
+
onMounted(() => {
|
|
26
|
+
lineId = chart.addLine({
|
|
27
|
+
value: props.value,
|
|
28
|
+
time: props.time,
|
|
29
|
+
color: props.color,
|
|
30
|
+
label: props.label,
|
|
31
|
+
style: props.style,
|
|
32
|
+
width: props.width,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
onUnmounted(() => {
|
|
37
|
+
if (lineId !== null) chart.removeLine(lineId);
|
|
38
|
+
lineId = null;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
watch(
|
|
42
|
+
() => [props.value, props.time, props.color, props.label, props.style, props.width],
|
|
43
|
+
() => {
|
|
44
|
+
if (lineId === null) return;
|
|
45
|
+
|
|
46
|
+
chart.updateLine(lineId, {
|
|
47
|
+
value: props.value,
|
|
48
|
+
time: props.time,
|
|
49
|
+
color: props.color,
|
|
50
|
+
label: props.label,
|
|
51
|
+
style: props.style,
|
|
52
|
+
width: props.width,
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<template><span v-if="false" /></template>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { TimeRegionEnd, TimeValue } from '@wick-charts/core';
|
|
3
|
+
import { onMounted, onUnmounted, watch } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { useChartInstance } from '../context';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
/** Left edge — epoch ms or a `Date`. */
|
|
9
|
+
from: TimeValue;
|
|
10
|
+
/** Right edge — epoch ms or a `Date`. Omit (or pass `'now'`) for an open-ended band to the right edge. */
|
|
11
|
+
to?: TimeRegionEnd;
|
|
12
|
+
/** Band fill — any CSS color, typically translucent. Default: a faint tint of `color`. */
|
|
13
|
+
fill?: string;
|
|
14
|
+
/** Optional text label drawn in a pill at the top of the band. */
|
|
15
|
+
label?: string;
|
|
16
|
+
/** Edge-line and label-pill accent. Default: the theme's muted axis text color. */
|
|
17
|
+
color?: string;
|
|
18
|
+
}>();
|
|
19
|
+
|
|
20
|
+
const chart = useChartInstance();
|
|
21
|
+
let regionId: string | null = null;
|
|
22
|
+
|
|
23
|
+
onMounted(() => {
|
|
24
|
+
regionId = chart.addRegion({
|
|
25
|
+
from: props.from,
|
|
26
|
+
to: props.to,
|
|
27
|
+
fill: props.fill,
|
|
28
|
+
label: props.label,
|
|
29
|
+
color: props.color,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
onUnmounted(() => {
|
|
34
|
+
if (regionId !== null) chart.removeRegion(regionId);
|
|
35
|
+
regionId = null;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
watch(
|
|
39
|
+
() => [props.from, props.to, props.fill, props.label, props.color],
|
|
40
|
+
() => {
|
|
41
|
+
if (regionId === null) return;
|
|
42
|
+
|
|
43
|
+
chart.updateRegion(regionId, {
|
|
44
|
+
from: props.from,
|
|
45
|
+
to: props.to,
|
|
46
|
+
fill: props.fill,
|
|
47
|
+
label: props.label,
|
|
48
|
+
color: props.color,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template><span v-if="false" /></template>
|