@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.
Files changed (82) hide show
  1. package/README.md +45 -6
  2. package/dist/BarSeries.vue.js +26 -20
  3. package/dist/CandlestickSeries.vue.js +30 -24
  4. package/dist/ChartContainer.vue.js +125 -72
  5. package/dist/HeatmapSeries.vue.js +40 -0
  6. package/dist/HeatmapSeries.vue2.js +4 -0
  7. package/dist/LineSeries.vue.js +26 -20
  8. package/dist/PieSeries.vue.js +24 -18
  9. package/dist/core/dist/animation/animator.js +21 -21
  10. package/dist/core/dist/animation/config.js +114 -87
  11. package/dist/core/dist/animation/easing.js +3 -1
  12. package/dist/core/dist/animation/intro-wave.js +68 -0
  13. package/dist/core/dist/axis/dom-labels.js +13 -14
  14. package/dist/core/dist/chart/badge-animator.js +56 -0
  15. package/dist/core/dist/chart/edge-indicators.js +28 -13
  16. package/dist/core/dist/chart/last-value.js +18 -17
  17. package/dist/core/dist/chart/options.js +27 -16
  18. package/dist/core/dist/chart/y-target.js +13 -12
  19. package/dist/core/dist/chart.js +868 -441
  20. package/dist/core/dist/components/annotation-chip.js +28 -0
  21. package/dist/core/dist/components/crosshair.js +8 -6
  22. package/dist/core/dist/components/edge-indicator.js +58 -26
  23. package/dist/core/dist/components/loading-indicator.js +46 -0
  24. package/dist/core/dist/components/marker.js +49 -31
  25. package/dist/core/dist/components/reference-line.js +27 -36
  26. package/dist/core/dist/components/time-region.js +30 -28
  27. package/dist/core/dist/data/store.js +38 -19
  28. package/dist/core/dist/data/sync.js +60 -38
  29. package/dist/core/dist/heatmap-tooltip.js +16 -0
  30. package/dist/core/dist/interactions/handler.js +86 -46
  31. package/dist/core/dist/perf/perf-hud.js +5 -5
  32. package/dist/core/dist/scales/x-scale.js +85 -37
  33. package/dist/core/dist/scales/y-scale.js +38 -27
  34. package/dist/core/dist/series/bar-intro.js +18 -0
  35. package/dist/core/dist/series/bar.js +337 -205
  36. package/dist/core/dist/series/base-multi-layer.js +224 -96
  37. package/dist/core/dist/series/candlestick-intro.js +57 -0
  38. package/dist/core/dist/series/candlestick.js +454 -276
  39. package/dist/core/dist/series/heatmap.js +387 -0
  40. package/dist/core/dist/series/line-intro.js +85 -0
  41. package/dist/core/dist/series/line.js +590 -282
  42. package/dist/core/dist/series/painters/builtins.js +2 -2
  43. package/dist/core/dist/series/pie.js +396 -259
  44. package/dist/core/dist/series/register-builtins.js +8 -7
  45. package/dist/core/dist/series/types.js +6 -0
  46. package/dist/core/dist/series/wave-intro.js +26 -0
  47. package/dist/core/dist/theme/create.js +69 -63
  48. package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
  49. package/dist/core/dist/theme/themes/sand-dune.js +2 -2
  50. package/dist/core/dist/utils/color.js +109 -34
  51. package/dist/core/dist/utils/deep-equal.js +18 -0
  52. package/dist/core/dist/utils/time.js +25 -19
  53. package/dist/index.d.ts +1494 -122
  54. package/dist/index.js +177 -130
  55. package/dist/ui/Crosshair.vue.js +20 -21
  56. package/dist/ui/HeatmapTooltip.vue.js +96 -0
  57. package/dist/ui/HeatmapTooltip.vue2.js +4 -0
  58. package/dist/ui/InfoBar.vue.js +46 -47
  59. package/dist/ui/Legend.vue.js +80 -79
  60. package/dist/ui/PieLegend.vue.js +5 -5
  61. package/dist/ui/PieTooltip.vue.js +77 -67
  62. package/dist/ui/Tooltip.vue.js +60 -60
  63. package/dist/ui/YAxis.vue.js +2 -2
  64. package/dist/ui/YLabel.vue.js +94 -61
  65. package/package.json +2 -2
  66. package/src/BarSeries.vue +23 -7
  67. package/src/CandlestickSeries.vue +23 -7
  68. package/src/ChartContainer.vue +250 -13
  69. package/src/HeatmapSeries.vue +69 -0
  70. package/src/LineSeries.vue +23 -7
  71. package/src/PieSeries.vue +22 -6
  72. package/src/index.ts +84 -3
  73. package/src/ui/Crosshair.vue +1 -2
  74. package/src/ui/HeatmapTooltip.vue +144 -0
  75. package/src/ui/InfoBar.vue +1 -2
  76. package/src/ui/Legend.vue +13 -0
  77. package/src/ui/Marker.vue +1 -1
  78. package/src/ui/PieTooltip.vue +10 -0
  79. package/src/ui/ReferenceLine.vue +2 -2
  80. package/src/ui/TimeRegion.vue +2 -2
  81. package/src/ui/Tooltip.vue +2 -2
  82. package/src/ui/YLabel.vue +123 -8
@@ -1,105 +1,138 @@
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({
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(S) {
12
- const u = S, e = D(), k = F(), I = n(() => typeof k.default == "function"), r = _(0), i = () => {
13
- r.value++;
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
- 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);
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 w(a, l) {
51
+ function O(t, l) {
21
52
  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;
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(() => (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) {
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 o.value.yLabel.upBackground;
64
+ return r.value.yLabel.upBackground;
34
65
  case "down":
35
- return o.value.yLabel.downBackground;
66
+ return r.value.yLabel.downBackground;
36
67
  default:
37
- return o.value.yLabel.neutralBackground;
68
+ return r.value.yLabel.neutralBackground;
38
69
  }
39
- }), m = n(() => {
40
- r.value;
41
- const a = e.yScale.getRange(), l = a.max - a.min;
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
- }), 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,
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) => a.format(l);
81
+ return (l) => t.format(l);
51
82
  });
52
- return (a, l) => t.value !== null ? (h(), b(x, { key: 0 }, [
53
- I.value ? Y(a.$slots, "default", {
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: 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({
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: E(e).yAxisWidth + "px",
67
- top: c.value + "px",
98
+ right: H(e).yAxisWidth + "px",
99
+ top: x.value + "px",
68
100
  height: "0",
69
- borderTop: "1px dashed " + d.value,
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
- C("div", {
76
- style: L({
107
+ _("div", {
108
+ style: T({
77
109
  position: "absolute",
78
110
  right: "4px",
79
- top: c.value + "px",
111
+ top: x.value + "px",
80
112
  transform: "translateY(-50%)",
113
+ opacity: h.value,
81
114
  pointerEvents: "auto",
82
115
  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,
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
- N(O, {
94
- value: t.value.value,
95
- format: p.value,
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)) : V("", !0);
133
+ ], 64)) : K("", !0);
101
134
  }
102
135
  });
103
136
  export {
104
- A as default
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.5.1",
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.5.1"
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 = defineProps<{
9
- /** Flat `TimePoint[]`, `TimePoint[][]`, or named `{ label, color?, data }` layers. Time accepts ms or `Date`. */
10
- data: MultiLayerData;
11
- options?: Partial<BarSeriesOptions>;
12
- /** Stable series ID — same value across remounts. */
13
- id?: string;
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 = defineProps<{
9
- /** Flat `OHLCInput[]`, or `{ label, data }` to name the stream. */
10
- data: CandlestickData;
11
- options?: Partial<CandlestickSeriesOptions>;
12
- /** Stable series ID — same value across remounts. */
13
- id?: string;
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>