@wick-charts/vue 0.5.0 → 0.6.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.
Files changed (80) hide show
  1. package/README.md +18 -3
  2. package/dist/BarSeries.vue.js +26 -20
  3. package/dist/CandlestickSeries.vue.js +30 -24
  4. package/dist/ChartContainer.vue.js +88 -65
  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/y-target.js +13 -12
  18. package/dist/core/dist/chart.js +908 -626
  19. package/dist/core/dist/components/annotation-chip.js +28 -0
  20. package/dist/core/dist/components/edge-indicator.js +58 -26
  21. package/dist/core/dist/components/loading-indicator.js +46 -0
  22. package/dist/core/dist/components/marker.js +49 -31
  23. package/dist/core/dist/components/reference-line.js +27 -36
  24. package/dist/core/dist/components/time-region.js +30 -28
  25. package/dist/core/dist/data/store.js +38 -19
  26. package/dist/core/dist/data/sync.js +60 -38
  27. package/dist/core/dist/heatmap-tooltip.js +16 -0
  28. package/dist/core/dist/interactions/handler.js +67 -43
  29. package/dist/core/dist/perf/perf-hud.js +2 -2
  30. package/dist/core/dist/scales/x-scale.js +85 -37
  31. package/dist/core/dist/scales/y-scale.js +38 -27
  32. package/dist/core/dist/series/bar-intro.js +18 -0
  33. package/dist/core/dist/series/bar.js +337 -205
  34. package/dist/core/dist/series/base-multi-layer.js +224 -96
  35. package/dist/core/dist/series/candlestick-intro.js +57 -0
  36. package/dist/core/dist/series/candlestick.js +454 -276
  37. package/dist/core/dist/series/heatmap.js +387 -0
  38. package/dist/core/dist/series/line-intro.js +85 -0
  39. package/dist/core/dist/series/line.js +590 -282
  40. package/dist/core/dist/series/painters/builtins.js +2 -2
  41. package/dist/core/dist/series/pie.js +396 -259
  42. package/dist/core/dist/series/register-builtins.js +8 -7
  43. package/dist/core/dist/series/types.js +6 -0
  44. package/dist/core/dist/series/wave-intro.js +26 -0
  45. package/dist/core/dist/theme/create.js +69 -63
  46. package/dist/core/dist/theme/themes/mint-breeze.js +2 -2
  47. package/dist/core/dist/theme/themes/sand-dune.js +2 -2
  48. package/dist/core/dist/utils/color.js +109 -34
  49. package/dist/core/dist/utils/deep-equal.js +18 -0
  50. package/dist/core/dist/utils/time.js +25 -19
  51. package/dist/index.d.ts +1411 -122
  52. package/dist/index.js +177 -130
  53. package/dist/ui/Crosshair.vue.js +20 -21
  54. package/dist/ui/HeatmapTooltip.vue.js +96 -0
  55. package/dist/ui/HeatmapTooltip.vue2.js +4 -0
  56. package/dist/ui/InfoBar.vue.js +46 -47
  57. package/dist/ui/Legend.vue.js +80 -79
  58. package/dist/ui/PieLegend.vue.js +5 -5
  59. package/dist/ui/PieTooltip.vue.js +77 -67
  60. package/dist/ui/Tooltip.vue.js +60 -60
  61. package/dist/ui/YAxis.vue.js +2 -2
  62. package/dist/ui/YLabel.vue.js +94 -61
  63. package/package.json +2 -2
  64. package/src/BarSeries.vue +23 -7
  65. package/src/CandlestickSeries.vue +23 -7
  66. package/src/ChartContainer.vue +134 -12
  67. package/src/HeatmapSeries.vue +69 -0
  68. package/src/LineSeries.vue +23 -7
  69. package/src/PieSeries.vue +22 -6
  70. package/src/index.ts +84 -3
  71. package/src/ui/Crosshair.vue +1 -2
  72. package/src/ui/HeatmapTooltip.vue +144 -0
  73. package/src/ui/InfoBar.vue +1 -2
  74. package/src/ui/Legend.vue +13 -0
  75. package/src/ui/Marker.vue +1 -1
  76. package/src/ui/PieTooltip.vue +10 -0
  77. package/src/ui/ReferenceLine.vue +2 -2
  78. package/src/ui/TimeRegion.vue +2 -2
  79. package/src/ui/Tooltip.vue +2 -2
  80. package/src/ui/YLabel.vue +123 -8
@@ -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<LineSeriesOptions>;
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<LineSeriesOptions>;
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>
package/src/PieSeries.vue CHANGED
@@ -5,12 +5,20 @@ import { onMounted, onUnmounted, ref, watch } from 'vue';
5
5
 
6
6
  import { useChartInstance } from './context';
7
7
 
8
- const props = defineProps<{
9
- data: PieSliceData[];
10
- options?: Partial<PieSeriesOptions>;
11
- /** Stable series ID — same value across remounts. */
12
- id?: string;
13
- }>();
8
+ const props = withDefaults(
9
+ defineProps<{
10
+ data: PieSliceData[];
11
+ options?: Partial<PieSeriesOptions>;
12
+ /** Stable series ID — same value across remounts. */
13
+ id?: string;
14
+ /** Show/hide the series without unmounting it — excludes it from the Y-range fit and tooltip/legend. Default `true`. Live. */
15
+ visible?: boolean;
16
+ }>(),
17
+ // Vue's type-based `defineProps` casts an absent Boolean-typed prop to
18
+ // `false` (not `undefined`) without an explicit default — see the
19
+ // `interactive` fix in ChartContainer.vue for the full explanation.
20
+ { visible: true },
21
+ );
14
22
 
15
23
  const chart = useChartInstance();
16
24
  const seriesId = ref<string | null>(null);
@@ -22,6 +30,7 @@ onMounted(() => {
22
30
  if (props.data.length > 0) {
23
31
  chart.setSeriesData(id, props.data);
24
32
  }
33
+ chart.setSeriesVisible(id, props.visible);
25
34
  });
26
35
 
27
36
  onUnmounted(() => {
@@ -46,6 +55,13 @@ watch(
46
55
  },
47
56
  { deep: true },
48
57
  );
58
+
59
+ watch(
60
+ () => props.visible,
61
+ (visible) => {
62
+ if (seriesId.value) chart.setSeriesVisible(seriesId.value, visible);
63
+ },
64
+ );
49
65
  </script>
50
66
 
51
67
  <template><span v-if="false" /></template>
package/src/index.ts CHANGED
@@ -9,16 +9,32 @@
9
9
  */
10
10
 
11
11
  export type {
12
+ AnimationTime,
13
+ AnimationsConfig,
12
14
  AxisBound,
13
15
  AxisConfig,
16
+ BarElementTransform,
17
+ BarEntryAnimation,
18
+ BarIntroDirectives,
19
+ BarIntroElement,
20
+ BarIntroFn,
21
+ BarIntroFrame,
22
+ BarIntroValueArgs,
14
23
  BarPaintArgs,
15
24
  BarPainter,
16
25
  BarSeriesOptions,
17
- /** @deprecated Use {@link StackingMode} instead. */
26
+ BaseSeriesRenderer,
27
+ BitmapCoordinateSpace,
18
28
  BuildHoverSnapshotsArgs,
19
29
  BuildLastSnapshotsArgs,
30
+ CandleElementTransform,
31
+ CandleIntroDirectives,
32
+ CandleIntroElement,
33
+ CandleIntroFn,
34
+ CandleIntroFrame,
20
35
  CandlePaintArgs,
21
36
  CandlePainter,
37
+ CandlestickEntryAnimation,
22
38
  CandlestickSeriesOptions,
23
39
  ChartLayout,
24
40
  ChartOptions,
@@ -26,14 +42,28 @@ export type {
26
42
  CornerMask,
27
43
  CrosshairPosition,
28
44
  CurveKind,
45
+ CustomSpatialSeriesRenderer,
46
+ EdgeReachedInfo,
47
+ EdgeSide,
48
+ EdgeState,
49
+ HeatmapCellData,
50
+ HeatmapCellLabelsOptions,
51
+ HeatmapSeriesOptions,
52
+ HeatmapSeriesRenderer,
29
53
  HoverInfo,
30
54
  LegendItem,
55
+ LineIntroDirectives,
56
+ LineIntroFn,
57
+ LineIntroFrame,
58
+ LineIntroValueArgs,
31
59
  LinePaintArgs,
32
60
  LinePainter,
33
- /** @deprecated Use {@link TimePoint} instead. */
34
61
  LineSeriesOptions,
62
+ LoadingIndicatorArgs,
63
+ LoadingIndicatorFn,
35
64
  MarkerConfig,
36
65
  MarkerShape,
66
+ MultiLayerData,
37
67
  NavigatorCandlePoint,
38
68
  NavigatorControllerParams,
39
69
  NavigatorData,
@@ -42,18 +72,26 @@ export type {
42
72
  NavigatorSeriesType,
43
73
  OHLCData,
44
74
  OHLCInput,
75
+ OverlayRenderContext,
45
76
  PaintEnv,
46
77
  PerfConfig,
47
78
  PerfMonitorOptions,
48
79
  PerfStats,
49
80
  PieSeriesOptions,
81
+ PieSeriesRenderer,
50
82
  PieSliceData,
83
+ PointClickInfo,
51
84
  ReferenceLineConfig,
52
85
  ReferenceLineOrientation,
53
86
  ReferenceLineStyle,
87
+ RenderPadding,
54
88
  RoundedRectArgs,
55
89
  SeriesCreateEnv,
56
90
  SeriesDefinition,
91
+ SeriesHoverInfo,
92
+ SeriesKind,
93
+ SeriesRenderContext,
94
+ SeriesRenderer,
57
95
  SeriesSnapshot,
58
96
  SeriesType,
59
97
  SliceInfo,
@@ -61,19 +99,33 @@ export type {
61
99
  StackingMode,
62
100
  ThemeConfig,
63
101
  ThemePreset,
102
+ TimeFormatOptions,
103
+ TimeFormatter,
64
104
  TimePoint,
65
105
  TimePointInput,
66
106
  TimeRegionConfig,
67
107
  TimeRegionEnd,
108
+ TimeSeriesRenderer,
109
+ TimeTickGenerator,
68
110
  TimeValue,
69
111
  TooltipField,
70
112
  TooltipFormatter,
71
113
  TooltipPosition,
72
114
  TooltipPositionArgs,
73
115
  TracePathArgs,
116
+ Transition,
117
+ TransitionContext,
118
+ TransitionFactory,
74
119
  Typography,
75
120
  ValueFormatter,
121
+ ValueTickGenerator,
76
122
  VisibleRange,
123
+ VisibleRangeSpec,
124
+ WaveIntroDirectives,
125
+ WaveIntroElement,
126
+ WaveIntroFn,
127
+ WaveIntroFrame,
128
+ WaveIntroTransform,
77
129
  XAxisConfig,
78
130
  YAxisConfig,
79
131
  YRange,
@@ -83,56 +135,83 @@ export {
83
135
  BarSeriesDef,
84
136
  CandlestickSeriesDef,
85
137
  ChartInstance,
138
+ HeatmapSeriesDef,
86
139
  LineSeriesDef,
87
140
  NavigatorController,
88
141
  PerfMonitor,
89
142
  PieSeriesDef,
143
+ XScale,
144
+ YScale,
90
145
  andromeda,
91
146
  autoGradient,
92
147
  ayuMirage,
148
+ backfillSweepIntro,
93
149
  buildHoverSnapshots,
94
150
  buildLastSnapshots,
151
+ candleUnfoldIntro,
95
152
  catppuccin,
153
+ centerOutIntro,
96
154
  computeTooltipPosition,
97
155
  createTheme,
156
+ deepEqual,
98
157
  detectInterval,
99
158
  dracula,
159
+ fadeIntro,
100
160
  fillRoundedRect,
101
161
  formatCompact,
102
162
  formatDate,
103
163
  formatPriceAdaptive,
104
164
  formatTime,
105
165
  githubLight,
166
+ growIntro,
106
167
  gruvbox,
107
168
  handwritten,
169
+ hermite,
108
170
  highContrast,
171
+ isDarkBg,
172
+ isTimeSeriesRenderer,
109
173
  lavenderMist,
110
174
  lightPink,
111
175
  materialPalenight,
112
176
  minimalLight,
113
177
  mintBreeze,
178
+ mixColors,
114
179
  monokaiPro,
115
180
  nightOwl,
116
181
  normalizeTime,
117
182
  oneDarkPro,
118
183
  panda,
184
+ parseAnimationTime,
119
185
  peachCream,
120
186
  perfHud,
187
+ plotterIntro,
121
188
  quietLight,
122
189
  registerBuiltinSeries,
123
190
  registerSeriesDefinition,
124
191
  resolveAxisFontSize,
125
192
  resolveAxisTextColor,
126
193
  resolveCandlestickBodyColor,
194
+ riseIntro,
127
195
  rosePineDawn,
128
196
  roundedBarFill,
129
197
  roundedCandleFill,
198
+ sampleRamp,
130
199
  sandDune,
200
+ skeletonLoadingIndicator,
201
+ skeletonMorphIntro,
131
202
  smoothCurve,
203
+ snap,
132
204
  solarizedLight,
205
+ spring,
206
+ springIntro,
133
207
  steppedCurve,
134
208
  straightCurve,
209
+ sweepIntro,
210
+ traceIntro,
135
211
  tracePath,
212
+ unfoldIntro,
213
+ wickBodyIntro,
214
+ wipeIntro,
136
215
  } from '@wick-charts/core';
137
216
 
138
217
  export { default as BarSeries } from './BarSeries.vue';
@@ -142,9 +221,11 @@ export { default as ChartContainer } from './ChartContainer.vue';
142
221
  export { useCrosshairPosition, useLastYValue, usePreviousClose, useVisibleRange, useYRange } from './composables';
143
222
  // Composables and context
144
223
  export { useChartInstance, useTheme } from './context';
224
+ export { default as HeatmapSeries } from './HeatmapSeries.vue';
145
225
  export { default as LineSeries } from './LineSeries.vue';
146
226
  export { default as PieSeries } from './PieSeries.vue';
147
227
  export { default as Crosshair } from './ui/Crosshair.vue';
228
+ export { default as HeatmapTooltip } from './ui/HeatmapTooltip.vue';
148
229
  export { default as InfoBar } from './ui/InfoBar.vue';
149
230
  export { default as Legend } from './ui/Legend.vue';
150
231
  export { default as Marker } from './ui/Marker.vue';
@@ -153,7 +234,7 @@ export { default as NumberFlow } from './ui/NumberFlow.vue';
153
234
  export { default as PieLegend } from './ui/PieLegend.vue';
154
235
  export { default as PieTooltip } from './ui/PieTooltip.vue';
155
236
  export { default as ReferenceLine } from './ui/ReferenceLine.vue';
156
- export { default as TimeAxis } from './ui/TimeAxis.vue';
237
+ export { default as TimeAxis, default as XAxis } from './ui/TimeAxis.vue';
157
238
  export { default as TimeRegion } from './ui/TimeRegion.vue';
158
239
  export { default as Title } from './ui/Title.vue';
159
240
  // UI overlays
@@ -1,5 +1,4 @@
1
1
  <script setup lang="ts">
2
- import { formatTime } from '@wick-charts/core';
3
2
  import { computed, onMounted, onUnmounted, ref } from 'vue';
4
3
 
5
4
  import { useCrosshairPosition } from '../composables';
@@ -79,7 +78,7 @@ const labelStyle = computed(() => ({
79
78
  ...labelStyle,
80
79
  }"
81
80
  >
82
- {{ formatTime(position.time, tickInterval) }}
81
+ {{ chart.timeScale.formatX(position.time, tickInterval) }}
83
82
  </div>
84
83
  </template>
85
84
  </template>
@@ -0,0 +1,144 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ HEATMAP_TOOLTIP_HEIGHT,
4
+ HEATMAP_TOOLTIP_WIDTH,
5
+ type HoverInfo,
6
+ type ValueFormatter,
7
+ computeTooltipPosition,
8
+ defaultHeatmapFormat,
9
+ resolveHeatmapSeriesId,
10
+ } from '@wick-charts/core';
11
+ import { computed, onMounted, onUnmounted, ref } from 'vue';
12
+
13
+ import { useCrosshairPosition } from '../composables';
14
+ import { useChartInstance } from '../context';
15
+
16
+ const props = defineProps<{
17
+ /**
18
+ * Owning series id. **Optional** — when omitted, the first visible heatmap
19
+ * series is picked.
20
+ */
21
+ seriesId?: string;
22
+ /** Custom formatter for the cell value. Default: plain integers, compact decimals. */
23
+ format?: ValueFormatter;
24
+ }>();
25
+
26
+ const effectiveFormat = computed<ValueFormatter>(() => props.format ?? defaultHeatmapFormat);
27
+
28
+ const chart = useChartInstance();
29
+ const crosshair = useCrosshairPosition(chart);
30
+
31
+ const bump = ref(0);
32
+ const handler = () => {
33
+ bump.value++;
34
+ };
35
+ onMounted(() => {
36
+ chart.on('overlayChange', handler);
37
+ });
38
+ onUnmounted(() => {
39
+ chart.off('overlayChange', handler);
40
+ });
41
+
42
+ const theme = computed(() => {
43
+ // `setTheme` fires `overlayChange`; read `bump` so this computed picks up
44
+ // runtime theme swaps instead of freezing on the first-render snapshot.
45
+ void bump.value;
46
+
47
+ return chart.getTheme();
48
+ });
49
+ const resolvedId = computed<string | null>(() => {
50
+ void bump.value;
51
+
52
+ return resolveHeatmapSeriesId(chart, props.seriesId);
53
+ });
54
+
55
+ const info = computed<HoverInfo | null>(() => {
56
+ void crosshair.value;
57
+ void bump.value;
58
+ if (resolvedId.value === null) return null;
59
+
60
+ return chart.getHoverInfo(resolvedId.value);
61
+ });
62
+
63
+ const meterWidth = computed(() => {
64
+ if (!info.value) return 0;
65
+
66
+ return Math.max(2, Math.min(100, info.value.percent));
67
+ });
68
+
69
+ const tooltipPos = computed(() => {
70
+ if (!crosshair.value || !info.value) return null;
71
+ const mediaSize = chart.getMediaSize();
72
+
73
+ return computeTooltipPosition({
74
+ x: crosshair.value.mediaX,
75
+ y: crosshair.value.mediaY,
76
+ chartWidth: mediaSize.width,
77
+ chartHeight: mediaSize.height,
78
+ tooltipWidth: HEATMAP_TOOLTIP_WIDTH,
79
+ tooltipHeight: HEATMAP_TOOLTIP_HEIGHT,
80
+ offsetX: 16,
81
+ offsetY: 16,
82
+ });
83
+ });
84
+ </script>
85
+
86
+ <template>
87
+ <div
88
+ v-if="info && crosshair && tooltipPos"
89
+ :style="{
90
+ position: 'absolute',
91
+ left: tooltipPos.left + 'px',
92
+ top: tooltipPos.top + 'px',
93
+ pointerEvents: 'none',
94
+ background: theme.tooltip.background,
95
+ backdropFilter: 'blur(12px)',
96
+ WebkitBackdropFilter: 'blur(12px)',
97
+ border: '1px solid ' + theme.tooltip.borderColor,
98
+ borderRadius: '8px',
99
+ padding: '10px 14px',
100
+ boxShadow: '0 4px 16px rgba(0,0,0,0.1), 0 1px 4px rgba(0,0,0,0.06)',
101
+ fontSize: theme.typography.fontSize + 'px',
102
+ fontFamily: theme.typography.fontFamily,
103
+ color: theme.tooltip.textColor,
104
+ zIndex: 10,
105
+ display: 'flex',
106
+ flexDirection: 'column',
107
+ gap: '6px',
108
+ minWidth: '120px',
109
+ }"
110
+ >
111
+ <div :style="{ display: 'flex', alignItems: 'center', gap: '8px' }">
112
+ <span
113
+ :style="{
114
+ width: '10px',
115
+ height: '10px',
116
+ borderRadius: '3px',
117
+ background: info.color,
118
+ flexShrink: 0,
119
+ }"
120
+ />
121
+ <span :style="{ fontWeight: 600 }">{{ info.label }}</span>
122
+ <span :style="{ marginLeft: 'auto', fontWeight: 600 }">{{ effectiveFormat(info.value) }}</span>
123
+ </div>
124
+ <div
125
+ :style="{
126
+ position: 'relative',
127
+ height: '4px',
128
+ borderRadius: '2px',
129
+ background: theme.tooltip.borderColor,
130
+ overflow: 'hidden',
131
+ }"
132
+ >
133
+ <div
134
+ :style="{
135
+ position: 'absolute',
136
+ inset: '0',
137
+ width: meterWidth + '%',
138
+ borderRadius: '2px',
139
+ background: info.color,
140
+ }"
141
+ />
142
+ </div>
143
+ </div>
144
+ </template>
@@ -9,7 +9,6 @@ import {
9
9
  buildLastSnapshots,
10
10
  formatCompact,
11
11
  formatPriceAdaptive,
12
- formatTime,
13
12
  resolveCandlestickBodyColor,
14
13
  } from '@wick-charts/core';
15
14
  import { computed, inject, onMounted, onUnmounted, ref, useSlots } from 'vue';
@@ -140,7 +139,7 @@ function isOHLC(data: OHLCData | TimePoint): data is OHLCData {
140
139
  <slot v-if="hasCustomSlot" :snapshots="snapshots" :time="displayTime" :is-hover="isHover" />
141
140
  <template v-else>
142
141
  <span :style="{ color: theme.axis.textColor, marginRight: '2px' }">
143
- {{ formatTime(displayTime, dataInterval) }}
142
+ {{ chart.timeScale.formatX(displayTime, dataInterval) }}
144
143
  </span>
145
144
  <template v-for="s in snapshots" :key="s.id">
146
145
  <span v-if="isOHLC(s.data)" :style="{ display: 'inline-flex', alignItems: 'center', gap: '4px' }">
package/src/ui/Legend.vue CHANGED
@@ -17,12 +17,22 @@ export interface LegendItemOverride {
17
17
 
18
18
  type LegendMode = 'toggle' | 'isolate' | 'solo';
19
19
 
20
+ /** Payload for the `onToggle` prop — one entry per user click, regardless of built-in vs custom rendering. */
21
+ export interface LegendToggleInfo {
22
+ /** The clicked item's id (matches {@link LegendItem.id}). */
23
+ id: string;
24
+ /** Which interaction produced this change. */
25
+ action: 'toggle' | 'isolate' | 'unisolate';
26
+ }
27
+
20
28
  const props = withDefaults(
21
29
  defineProps<{
22
30
  items?: LegendItemOverride[];
23
31
  position?: 'bottom' | 'right';
24
32
  /** `'isolate'` shows only the clicked item; `'solo'` is a @deprecated alias. */
25
33
  mode?: LegendMode;
34
+ /** Fired after a click changes series visibility — via the built-in UI or a custom slot calling `item.toggle()`/`isolate()` directly. */
35
+ onToggle?: (info: LegendToggleInfo) => void;
26
36
  }>(),
27
37
  {
28
38
  position: 'bottom',
@@ -87,6 +97,7 @@ function makeItem(args: MakeItemArgs): LegendItem {
87
97
  } else {
88
98
  chart.setSeriesVisible(seriesId, !chart.isSeriesVisible(seriesId));
89
99
  }
100
+ props.onToggle?.({ id, action: 'toggle' });
90
101
  };
91
102
 
92
103
  const isolate = () => {
@@ -101,6 +112,7 @@ function makeItem(args: MakeItemArgs): LegendItem {
101
112
  }
102
113
  });
103
114
  isolatedId.value = null;
115
+ props.onToggle?.({ id, action: 'unisolate' });
104
116
 
105
117
  return;
106
118
  }
@@ -119,6 +131,7 @@ function makeItem(args: MakeItemArgs): LegendItem {
119
131
  }
120
132
  });
121
133
  isolatedId.value = id;
134
+ props.onToggle?.({ id, action: 'isolate' });
122
135
  };
123
136
 
124
137
  return { id, seriesId, layerIndex, label, color, isDisabled, toggle, isolate };
package/src/ui/Marker.vue CHANGED
@@ -15,7 +15,7 @@ const props = defineProps<{
15
15
  shape?: MarkerShape;
16
16
  /** Reuse the line pulse halo around the anchor. Default: `false`. */
17
17
  pulse?: boolean;
18
- /** Optional text label drawn in a pill next to the anchor. */
18
+ /** Optional text label drawn as a callout chip whose tail points at the anchor. */
19
19
  label?: string;
20
20
  /** Color override. Falls back to the series color (when `seriesId` is set), then the theme line color. */
21
21
  color?: string;
@@ -188,6 +188,16 @@ const tooltipPos = computed(() => {
188
188
  left: tooltipPos.left + 'px',
189
189
  top: tooltipPos.top + 'px',
190
190
  pointerEvents: 'none',
191
+ background: theme.tooltip.background,
192
+ backdropFilter: 'blur(12px)',
193
+ WebkitBackdropFilter: 'blur(12px)',
194
+ border: '1px solid ' + theme.tooltip.borderColor,
195
+ borderRadius: '8px',
196
+ padding: '10px 14px',
197
+ boxShadow: '0 4px 16px rgba(0,0,0,0.1), 0 1px 4px rgba(0,0,0,0.06)',
198
+ fontFamily: theme.typography.fontFamily,
199
+ fontSize: theme.typography.fontSize + 'px',
200
+ color: theme.tooltip.textColor,
191
201
  zIndex: 10,
192
202
  width: 'max-content',
193
203
  maxWidth: chart.getMediaSize().width + 'px',
@@ -9,9 +9,9 @@ const props = defineProps<{
9
9
  value?: number;
10
10
  /** Vertical line at this `time` (epoch ms or `Date`). Mutually exclusive with `value`. */
11
11
  time?: TimeValue;
12
- /** Line and label-pill color. Default: the theme line color. */
12
+ /** Line and label-chip accent color. Default: the theme line color. */
13
13
  color?: string;
14
- /** Optional text label drawn in a pill at the line's near end. */
14
+ /** Optional text label drawn in an annotation chip at the line's near end. */
15
15
  label?: string;
16
16
  /** Dash style. Default: `'dashed'`. */
17
17
  style?: ReferenceLineStyle;
@@ -11,9 +11,9 @@ const props = defineProps<{
11
11
  to?: TimeRegionEnd;
12
12
  /** Band fill — any CSS color, typically translucent. Default: a faint tint of `color`. */
13
13
  fill?: string;
14
- /** Optional text label drawn in a pill at the top of the band. */
14
+ /** Optional text label drawn in an annotation chip at the top of the band. */
15
15
  label?: string;
16
- /** Edge-line and label-pill accent. Default: the theme's muted axis text color. */
16
+ /** Edge-line and label-chip accent. Default: the theme's muted axis text color. */
17
17
  color?: string;
18
18
  }>();
19
19
 
@@ -10,7 +10,6 @@ import {
10
10
  formatCompact,
11
11
  formatDate,
12
12
  formatPriceAdaptive,
13
- formatTime,
14
13
  resolveCandlestickBodyColor,
15
14
  } from '@wick-charts/core';
16
15
  import { computed, onMounted, onUnmounted, ref, useSlots, watchEffect } from 'vue';
@@ -178,7 +177,8 @@ function isOHLC(data: OHLCData | TimePoint): data is OHLCData {
178
177
  letterSpacing: '0.02em',
179
178
  }"
180
179
  >
181
- {{ formatDate(displayTime) }} {{ formatTime(displayTime, dataInterval) }}
180
+ {{ formatDate(displayTime, { locale: chart.timeScale.getLocale(), timeZone: chart.timeScale.getTimeZone() }) }}
181
+ {{ chart.timeScale.formatX(displayTime, dataInterval) }}
182
182
  </div>
183
183
 
184
184
  <template v-for="s in snapshots" :key="s.id">