@wick-charts/vue 0.8.1 → 0.8.2

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 (38) hide show
  1. package/dist/BandSeries.vue.js +25 -24
  2. package/dist/BarSeries.vue.js +27 -26
  3. package/dist/CandlestickSeries.vue.js +25 -24
  4. package/dist/HeatmapSeries.vue.js +21 -20
  5. package/dist/LineSeries.vue.js +24 -23
  6. package/dist/PieSeries.vue.js +25 -24
  7. package/dist/composables.js +63 -36
  8. package/dist/core/dist/axis/dom-labels.js +64 -53
  9. package/dist/core/dist/chart/options.js +1 -1
  10. package/dist/core/dist/chart/y-target.js +38 -32
  11. package/dist/core/dist/chart.js +475 -439
  12. package/dist/core/dist/data/decimation.js +52 -51
  13. package/dist/core/dist/data/store.js +38 -20
  14. package/dist/core/dist/data/sync.js +80 -69
  15. package/dist/core/dist/perf/perf-hud.js +3 -3
  16. package/dist/core/dist/scales/tick-tracker.js +2 -1
  17. package/dist/core/dist/series/band.js +1 -1
  18. package/dist/core/dist/series/bar.js +240 -211
  19. package/dist/core/dist/series/base-multi-layer.js +267 -249
  20. package/dist/core/dist/series/candlestick.js +116 -116
  21. package/dist/core/dist/series/line.js +540 -455
  22. package/dist/core/dist/snapshots.js +96 -77
  23. package/dist/index.d.ts +22 -4
  24. package/dist/ui/InfoBar.vue.js +68 -68
  25. package/dist/ui/NumberFlow.vue.js +36 -27
  26. package/dist/ui/Tooltip.vue.js +127 -130
  27. package/package.json +2 -2
  28. package/src/BandSeries.vue +5 -3
  29. package/src/BarSeries.vue +5 -3
  30. package/src/CandlestickSeries.vue +5 -4
  31. package/src/ChartContainer.vue +1 -1
  32. package/src/HeatmapSeries.vue +5 -4
  33. package/src/LineSeries.vue +5 -3
  34. package/src/PieSeries.vue +6 -5
  35. package/src/composables.ts +64 -1
  36. package/src/ui/InfoBar.vue +11 -3
  37. package/src/ui/NumberFlow.vue +17 -3
  38. package/src/ui/Tooltip.vue +23 -12
@@ -4,13 +4,13 @@ import {
4
4
  type OHLCData,
5
5
  type SeriesSnapshot,
6
6
  type SnapshotSort,
7
- type TimePoint,
8
7
  type TooltipFormatter,
9
8
  buildHoverSnapshots,
10
9
  buildLastSnapshots,
11
10
  formatCompact,
12
11
  formatHeaderX,
13
12
  formatPriceAdaptive,
13
+ formatRowValue,
14
14
  resolveCandlestickBodyColor,
15
15
  } from '@wick-charts/core';
16
16
  import { computed, inject, onMounted, onUnmounted, ref, useSlots } from 'vue';
@@ -56,12 +56,15 @@ const onOverlayChange = () => {
56
56
  };
57
57
  onMounted(() => {
58
58
  chart.on('overlayChange', onOverlayChange);
59
+ // Rows read animated values (smoothing, fades, percent shares).
60
+ chart.on('seriesFrame', onOverlayChange);
59
61
  // Catch-up: a sibling series' mount effect may have registered data in the
60
62
  // same synchronous flush, so poke the computed now.
61
63
  if (chart.getSeriesIds().length > 0) bump.value++;
62
64
  });
63
65
  onUnmounted(() => {
64
66
  chart.off('overlayChange', onOverlayChange);
67
+ chart.off('seriesFrame', onOverlayChange);
65
68
  });
66
69
 
67
70
  // Hover-over-the-y-axis gap: the overlay canvas includes the y-axis strip,
@@ -89,7 +92,12 @@ const snapshots = computed<readonly SeriesSnapshot[]>(() =>
89
92
  isHover.value ? (hoverSnapshots.value as readonly SeriesSnapshot[]) : lastSnapshots.value,
90
93
  );
91
94
 
92
- const dataInterval = computed(() => chart.getDataInterval());
95
+ // `chart` is not reactive: `bump` re-reads the interval once data lands after mount.
96
+ const dataInterval = computed(() => {
97
+ void bump.value;
98
+
99
+ return chart.getDataInterval();
100
+ });
93
101
  const displayTime = computed(() => {
94
102
  if (snapshots.value.length === 0) return 0;
95
103
  if (isHover.value && crosshair.value) return crosshair.value.time;
@@ -205,7 +213,7 @@ function isBand(data: SeriesSnapshot['data']): data is BandPoint {
205
213
  }"
206
214
  />
207
215
  <span :style="{ color: s.color, fontWeight: 500 }">
208
- {{ effectiveFormat((s.data as TimePoint).value, 'value') }}
216
+ {{ formatRowValue(s, (v) => effectiveFormat(v, 'value')) }}
209
217
  </span>
210
218
  </span>
211
219
  </template>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted, ref } from 'vue';
2
+ import { computed, onMounted, ref, watch } from 'vue';
3
3
 
4
4
  const props = withDefaults(
5
5
  defineProps<{
@@ -11,6 +11,7 @@ const props = withDefaults(
11
11
  */
12
12
  format?: ((value: number) => string) | Intl.NumberFormatOptions;
13
13
  locale?: string;
14
+ /** Per-digit spin duration in ms. A value that arrives sooner than this after the previous one snaps instead. */
14
15
  spinDuration?: number;
15
16
  }>(),
16
17
  {
@@ -50,6 +51,19 @@ const parts = computed<CharPart[]>(() => {
50
51
  return result;
51
52
  });
52
53
 
54
+ // A spin retargeted mid-turn shows two half digits, so values faster than a spin snap.
55
+ const duration = ref(props.spinDuration);
56
+ let changedAt = Number.NEGATIVE_INFINITY;
57
+ watch(
58
+ () => effectiveFormat.value(props.value),
59
+ () => {
60
+ const now = performance.now();
61
+ const tooFast = now - changedAt < props.spinDuration;
62
+ changedAt = now;
63
+ duration.value = tooFast ? 0 : props.spinDuration;
64
+ },
65
+ );
66
+
53
67
  const digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
54
68
  </script>
55
69
 
@@ -77,8 +91,8 @@ const digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
77
91
  display: 'flex',
78
92
  flexDirection: 'column',
79
93
  transform: 'translateY(' + (-parseInt(part.value) * 1.2) + 'em)',
80
- transition: mounted
81
- ? 'transform ' + spinDuration + 'ms cubic-bezier(0.16, 1, 0.3, 1)'
94
+ transition: mounted && duration > 0
95
+ ? 'transform ' + duration + 'ms cubic-bezier(0.16, 1, 0.3, 1)'
82
96
  : 'none',
83
97
  }"
84
98
  >
@@ -4,14 +4,13 @@ import {
4
4
  type OHLCData,
5
5
  type SeriesSnapshot,
6
6
  type SnapshotSort,
7
- type TimePoint,
8
7
  type TooltipFormatter,
9
8
  buildHoverSnapshots,
10
9
  computeTooltipPosition,
11
10
  formatCompact,
12
- formatDate,
13
- formatHeaderX,
14
11
  formatPriceAdaptive,
12
+ formatRowValue,
13
+ formatTooltipHeader,
15
14
  resolveCandlestickBodyColor,
16
15
  } from '@wick-charts/core';
17
16
  import { computed, onMounted, onUnmounted, ref, useSlots, watchEffect } from 'vue';
@@ -47,14 +46,26 @@ const onOverlayChange = () => {
47
46
  };
48
47
  onMounted(() => {
49
48
  chart.on('overlayChange', onOverlayChange);
49
+ // Rows read animated values (smoothing, fades, percent shares).
50
+ chart.on('seriesFrame', onOverlayChange);
50
51
  if (chart.getSeriesIds().length > 0) bump.value++;
51
52
  });
52
53
  onUnmounted(() => {
53
54
  chart.off('overlayChange', onOverlayChange);
55
+ chart.off('seriesFrame', onOverlayChange);
54
56
  });
55
57
 
56
- const theme = computed(() => chart.getTheme());
57
- const dataInterval = computed(() => chart.getDataInterval());
58
+ const theme = computed(() => {
59
+ void bump.value;
60
+
61
+ return chart.getTheme();
62
+ });
63
+ // `chart` is not reactive: `bump` re-reads the interval once data lands after mount.
64
+ const dataInterval = computed(() => {
65
+ void bump.value;
66
+
67
+ return chart.getDataInterval();
68
+ });
58
69
 
59
70
  const snapshots = computed<readonly SeriesSnapshot[]>(() => {
60
71
  void bump.value;
@@ -127,9 +138,12 @@ const floatingPos = computed<{ left: number; top: number } | null>(() => {
127
138
 
128
139
  const hasOHLC = snapshots.value.some((s) => 'open' in s.data);
129
140
  const lineCount = snapshots.value.filter((s) => !('open' in s.data)).length;
130
- // A band row carries two numbers, so it needs a wider box than a line row.
141
+ // A band row carries two numbers, and a percent-stack row a share and a value, so both need a wider box.
131
142
  const hasBand = snapshots.value.some((s) => 'high' in s.data && !('open' in s.data));
132
- const tooltipWidth = hasBand ? 220 : 160;
143
+ const hasShare = snapshots.value.some((s) => s.share !== undefined);
144
+ let tooltipWidth = 160;
145
+ if (hasBand) tooltipWidth = 220;
146
+ if (hasShare) tooltipWidth = 240;
133
147
  const tooltipHeight = hasOHLC ? 140 : 40 + lineCount * 22;
134
148
 
135
149
  return computeTooltipPosition({
@@ -188,10 +202,7 @@ function isBand(data: SeriesSnapshot['data']): data is BandPoint {
188
202
  letterSpacing: '0.02em',
189
203
  }"
190
204
  >
191
- <template v-if="chart.timeScale.getType() === 'time'">
192
- {{ formatDate(displayTime, { locale: chart.timeScale.getLocale(), timeZone: chart.timeScale.getTimeZone() }) }}
193
- </template>
194
- {{ formatHeaderX(chart, { time: displayTime, snapshots, interval: dataInterval }) }}
205
+ {{ formatTooltipHeader(chart, { time: displayTime, snapshots, interval: dataInterval }) }}
195
206
  </div>
196
207
 
197
208
  <template v-for="s in snapshots" :key="s.id">
@@ -264,7 +275,7 @@ function isBand(data: SeriesSnapshot['data']): data is BandPoint {
264
275
  />
265
276
  <span :style="{ opacity: 0.6, flex: '1' }">{{ s.label ?? 'Value' }}</span>
266
277
  <span :style="{ fontWeight: 600, color: s.color }">
267
- {{ effectiveFormat((s.data as TimePoint).value, 'value') }}
278
+ {{ formatRowValue(s, (v) => effectiveFormat(v, 'value')) }}
268
279
  </span>
269
280
  </div>
270
281
  </template>