@wick-charts/vue 0.4.2 → 0.5.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.
Files changed (144) hide show
  1. package/README.md +5 -3
  2. package/dist/BarSeries.vue.js +44 -0
  3. package/dist/BarSeries.vue2.js +4 -0
  4. package/dist/CandlestickSeries.vue.js +45 -0
  5. package/dist/CandlestickSeries.vue2.js +4 -0
  6. package/dist/ChartContainer.vue.js +168 -0
  7. package/dist/ChartContainer.vue2.js +4 -0
  8. package/dist/LineSeries.vue.js +44 -0
  9. package/dist/LineSeries.vue2.js +4 -0
  10. package/dist/PieSeries.vue.js +34 -0
  11. package/dist/PieSeries.vue2.js +4 -0
  12. package/dist/composables.js +44 -0
  13. package/dist/context.js +25 -0
  14. package/dist/core/dist/animation/animator.js +72 -0
  15. package/dist/core/dist/animation/config.js +145 -0
  16. package/dist/core/dist/animation/easing.js +4 -0
  17. package/dist/core/dist/animation/scalar-spring.js +57 -0
  18. package/dist/core/dist/animation/spring.js +11 -0
  19. package/dist/core/dist/animation/time.js +19 -0
  20. package/dist/core/dist/animation/viewport-engine.js +174 -0
  21. package/dist/core/dist/animation/visible-range-spring.js +64 -0
  22. package/dist/core/dist/animation/y-range-hermite.js +72 -0
  23. package/dist/core/dist/animation/y-range-snap.js +31 -0
  24. package/dist/core/dist/animation/y-range-spring.js +59 -0
  25. package/dist/core/dist/axis/dom-labels.js +60 -0
  26. package/dist/core/dist/canvas-manager.js +109 -0
  27. package/dist/core/dist/chart/edge-indicators.js +26 -0
  28. package/dist/core/dist/chart/fit-to-data.js +9 -0
  29. package/dist/core/dist/chart/last-value.js +31 -0
  30. package/dist/core/dist/chart/options.js +35 -0
  31. package/dist/core/dist/chart/pan-zoom-math.js +66 -0
  32. package/dist/core/dist/chart/streaming-cadence.js +70 -0
  33. package/dist/core/dist/chart/streaming-target.js +22 -0
  34. package/dist/core/dist/chart/viewport-padding.js +6 -0
  35. package/dist/core/dist/chart/y-target.js +24 -0
  36. package/dist/core/dist/chart.js +1550 -0
  37. package/dist/core/dist/components/crosshair.js +9 -0
  38. package/dist/core/dist/components/edge-indicator.js +36 -0
  39. package/dist/core/dist/components/grid.js +22 -0
  40. package/dist/core/dist/components/marker.js +41 -0
  41. package/dist/core/dist/components/reference-line.js +48 -0
  42. package/dist/core/dist/components/time-region.js +35 -0
  43. package/dist/core/dist/data/decimation.js +54 -0
  44. package/dist/core/dist/data/store.js +76 -0
  45. package/dist/core/dist/data/sync.js +47 -0
  46. package/dist/core/dist/events.js +19 -0
  47. package/dist/core/dist/interactions/handler.js +84 -0
  48. package/dist/core/dist/interactions/pan.js +26 -0
  49. package/dist/core/dist/interactions/zoom.js +21 -0
  50. package/dist/core/dist/navigator/controller.js +374 -0
  51. package/dist/core/dist/navigator/decimate.js +44 -0
  52. package/dist/core/dist/navigator/interactions.js +28 -0
  53. package/dist/core/dist/navigator/render.js +68 -0
  54. package/dist/core/dist/perf/counting-context.js +19 -0
  55. package/dist/core/dist/perf/perf-hud.js +453 -0
  56. package/dist/core/dist/perf/perf-monitor.js +132 -0
  57. package/dist/core/dist/render-scheduler.js +31 -0
  58. package/dist/core/dist/scales/tick-tracker.js +110 -0
  59. package/dist/core/dist/scales/x-scale.js +145 -0
  60. package/dist/core/dist/scales/y-scale.js +156 -0
  61. package/dist/core/dist/series/bar.js +341 -0
  62. package/dist/core/dist/series/base-multi-layer.js +438 -0
  63. package/dist/core/dist/series/candlestick.js +481 -0
  64. package/dist/core/dist/series/definition.js +11 -0
  65. package/dist/core/dist/series/line.js +446 -0
  66. package/dist/core/dist/series/painters/builtins.js +36 -0
  67. package/dist/core/dist/series/painters/canvas-path.js +79 -0
  68. package/dist/core/dist/series/painters/resolve.js +32 -0
  69. package/dist/core/dist/series/pie.js +545 -0
  70. package/dist/core/dist/series/register-builtins.js +11 -0
  71. package/dist/core/dist/series/stack-math.js +17 -0
  72. package/dist/core/dist/snapshots.js +107 -0
  73. package/dist/core/dist/theme/create.js +176 -0
  74. package/dist/core/dist/theme/resolve.js +14 -0
  75. package/dist/core/dist/theme/themes/andromeda.js +33 -0
  76. package/dist/core/dist/theme/themes/ayu-mirage.js +33 -0
  77. package/dist/core/dist/theme/themes/catppuccin.js +33 -0
  78. package/dist/core/dist/theme/themes/dracula.js +35 -0
  79. package/dist/core/dist/theme/themes/github-light.js +34 -0
  80. package/dist/core/dist/theme/themes/gruvbox.js +33 -0
  81. package/dist/core/dist/theme/themes/handwritten.js +101 -0
  82. package/dist/core/dist/theme/themes/high-contrast.js +33 -0
  83. package/dist/core/dist/theme/themes/lavender-mist.js +33 -0
  84. package/dist/core/dist/theme/themes/light-pink.js +34 -0
  85. package/dist/core/dist/theme/themes/material-palenight.js +33 -0
  86. package/dist/core/dist/theme/themes/minimal-light.js +34 -0
  87. package/dist/core/dist/theme/themes/mint-breeze.js +33 -0
  88. package/dist/core/dist/theme/themes/monokai-pro.js +33 -0
  89. package/dist/core/dist/theme/themes/night-owl.js +35 -0
  90. package/dist/core/dist/theme/themes/one-dark-pro.js +33 -0
  91. package/dist/core/dist/theme/themes/panda.js +33 -0
  92. package/dist/core/dist/theme/themes/peach-cream.js +33 -0
  93. package/dist/core/dist/theme/themes/quiet-light.js +37 -0
  94. package/dist/core/dist/theme/themes/rose-pine-dawn.js +33 -0
  95. package/dist/core/dist/theme/themes/sand-dune.js +33 -0
  96. package/dist/core/dist/theme/themes/solarized-light.js +34 -0
  97. package/dist/core/dist/tooltip-position.js +10 -0
  98. package/dist/core/dist/utils/color.js +37 -0
  99. package/dist/core/dist/utils/format.js +29 -0
  100. package/dist/core/dist/utils/math.js +26 -0
  101. package/dist/core/dist/utils/poisoned-data-reporter.js +15 -0
  102. package/dist/core/dist/utils/time.js +41 -0
  103. package/dist/index.d.ts +834 -63
  104. package/dist/index.js +142 -8025
  105. package/dist/ui/Crosshair.vue.js +53 -0
  106. package/dist/ui/Crosshair.vue2.js +4 -0
  107. package/dist/ui/InfoBar.vue.js +143 -0
  108. package/dist/ui/InfoBar.vue2.js +4 -0
  109. package/dist/ui/Legend.vue.js +212 -0
  110. package/dist/ui/Legend.vue2.js +4 -0
  111. package/dist/ui/Marker.vue.js +47 -0
  112. package/dist/ui/Marker.vue2.js +4 -0
  113. package/dist/ui/Navigator.vue.js +58 -0
  114. package/dist/ui/Navigator.vue2.js +4 -0
  115. package/dist/ui/NumberFlow.vue.js +69 -0
  116. package/dist/ui/NumberFlow.vue2.js +4 -0
  117. package/dist/ui/PieLegend.vue.js +132 -0
  118. package/dist/ui/PieLegend.vue2.js +4 -0
  119. package/dist/ui/PieTooltip.vue.js +135 -0
  120. package/dist/ui/PieTooltip.vue2.js +4 -0
  121. package/dist/ui/ReferenceLine.vue.js +44 -0
  122. package/dist/ui/ReferenceLine.vue2.js +4 -0
  123. package/dist/ui/TimeAxis.vue.js +43 -0
  124. package/dist/ui/TimeAxis.vue2.js +4 -0
  125. package/dist/ui/TimeRegion.vue.js +41 -0
  126. package/dist/ui/TimeRegion.vue2.js +4 -0
  127. package/dist/ui/Title.vue.js +54 -0
  128. package/dist/ui/Title.vue2.js +4 -0
  129. package/dist/ui/Tooltip.vue.js +195 -0
  130. package/dist/ui/Tooltip.vue2.js +4 -0
  131. package/dist/ui/YAxis.vue.js +42 -0
  132. package/dist/ui/YAxis.vue2.js +4 -0
  133. package/dist/ui/YLabel.vue.js +105 -0
  134. package/dist/ui/YLabel.vue2.js +4 -0
  135. package/package.json +2 -2
  136. package/src/BarSeries.vue +12 -13
  137. package/src/CandlestickSeries.vue +17 -6
  138. package/src/LineSeries.vue +12 -13
  139. package/src/PieSeries.vue +2 -1
  140. package/src/index.ts +23 -0
  141. package/src/ui/Legend.vue +1 -2
  142. package/src/ui/Marker.vue +62 -0
  143. package/src/ui/ReferenceLine.vue +58 -0
  144. package/src/ui/TimeRegion.vue +54 -0
@@ -0,0 +1,4 @@
1
+ import f from "./Tooltip.vue.js";
2
+ export {
3
+ f as default
4
+ };
@@ -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,4 @@
1
+ import f from "./YAxis.vue.js";
2
+ export {
3
+ f as default
4
+ };
@@ -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
+ };
@@ -0,0 +1,4 @@
1
+ import f from "./YLabel.vue.js";
2
+ export {
3
+ f as default
4
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wick-charts/vue",
3
- "version": "0.4.2",
3
+ "version": "0.5.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.4.2"
48
+ "@wick-charts/core": "^0.5.1"
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, SeriesSyncState, TimePoint } from '@wick-charts/core';
3
- import { EMPTY_SYNC_STATE, syncSeriesLayer } from '@wick-charts/core';
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
- data: TimePoint[][];
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 snapping Y every tick.
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: TimePoint[][]): void {
22
- chart.batch(() => {
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 id = chart.addSeries('bar', {
28
+ const layerCount = toLayers(props.data).length;
29
+ const id = chart.addSeries(BarSeriesDef, {
31
30
  ...props.options,
32
- layers: props.data.length,
31
+ layers: layerCount,
33
32
  id: props.id,
34
33
  });
35
34
  seriesId.value = id;
36
- prevSync = props.data.map(() => EMPTY_SYNC_STATE);
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
- data: OHLCInput[];
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('candlestick', { ...props.options, id: props.id });
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
- prevSync = syncSeriesLayer({ chart, id, data: props.data, prev: prevSync });
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
- prevSync = syncSeriesLayer({ chart, id, data, prev: prevSync });
52
+ applyData(id, data);
42
53
  },
43
54
  );
44
55
 
@@ -1,12 +1,13 @@
1
1
  <script setup lang="ts">
2
- import type { LineSeriesOptions, SeriesSyncState, TimePoint } from '@wick-charts/core';
3
- import { EMPTY_SYNC_STATE, syncSeriesLayer } from '@wick-charts/core';
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
- data: TimePoint[][];
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 snapping Y every tick.
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: TimePoint[][]): void {
22
- chart.batch(() => {
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 id = chart.addSeries('line', {
28
+ const layerCount = toLayers(props.data).length;
29
+ const id = chart.addSeries(LineSeriesDef, {
31
30
  ...props.options,
32
- layers: props.data.length,
31
+ layers: layerCount,
33
32
  id: props.id,
34
33
  });
35
34
  seriesId.value = id;
36
- prevSync = props.data.map(() => EMPTY_SYNC_STATE);
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('pie', { ...props.options, id: props.id });
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: baseLabel ? `${baseLabel} ${layerIndex + 1}` : `Series ${layerIndex + 1}`,
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>