@cfasim-ui/docs 0.4.0 → 0.4.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.
- package/charts/BarChart/BarChart.md +8 -1
- package/charts/BarChart/BarChart.vue +18 -3
- package/charts/ChartMenu/ChartMenu.vue +11 -4
- package/charts/ChoroplethMap/ChoroplethMap.md +42 -0
- package/charts/ChoroplethMap/ChoroplethMap.vue +22 -2
- package/charts/DataTable/DataTable.md +39 -9
- package/charts/DataTable/DataTable.vue +45 -59
- package/charts/LineChart/LineChart.md +3 -2
- package/charts/LineChart/LineChart.vue +18 -3
- package/index.json +1 -1
- package/package.json +1 -1
|
@@ -130,13 +130,17 @@ menu, and CSV export wiring with [`LineChart`](./line-chart).
|
|
|
130
130
|
|
|
131
131
|
### Custom value tick format
|
|
132
132
|
|
|
133
|
+
Use `value-tick-format` to format the value-axis labels. `tooltip-value-format` controls the tooltip values independently; if omitted, the tooltip uses `value-tick-format`.
|
|
134
|
+
|
|
133
135
|
<ComponentDemo>
|
|
134
136
|
<BarChart
|
|
135
137
|
:data="[0.12, 0.34, 0.56, 0.78]"
|
|
136
138
|
:categories="['A', 'B', 'C', 'D']"
|
|
137
139
|
:value-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
|
|
140
|
+
:tooltip-value-format="(v) => `${(v * 100).toFixed(1)}%`"
|
|
138
141
|
:height="220"
|
|
139
142
|
y-label="Coverage"
|
|
143
|
+
tooltip-trigger="hover"
|
|
140
144
|
/>
|
|
141
145
|
|
|
142
146
|
<template #code>
|
|
@@ -146,8 +150,10 @@ menu, and CSV export wiring with [`LineChart`](./line-chart).
|
|
|
146
150
|
:data="[0.12, 0.34, 0.56, 0.78]"
|
|
147
151
|
:categories="['A', 'B', 'C', 'D']"
|
|
148
152
|
:value-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
|
|
153
|
+
:tooltip-value-format="(v) => `${(v * 100).toFixed(1)}%`"
|
|
149
154
|
:height="220"
|
|
150
155
|
y-label="Coverage"
|
|
156
|
+
tooltip-trigger="hover"
|
|
151
157
|
/>
|
|
152
158
|
```
|
|
153
159
|
|
|
@@ -174,13 +180,14 @@ menu, and CSV export wiring with [`LineChart`](./line-chart).
|
|
|
174
180
|
| `valueMin` | `number` | No | `0` |
|
|
175
181
|
| `valueTicks` | `number \| number[]` | No | — |
|
|
176
182
|
| `valueTickFormat` | `(value: number) => string` | No | — |
|
|
183
|
+
| `tooltipValueFormat` | `(value: number) => string` | No | — |
|
|
177
184
|
| `categoryFormat` | `(label: string, index: number) => string` | No | — |
|
|
178
185
|
| `barPadding` | `number` | No | `0.2` |
|
|
179
186
|
| `groupGap` | `number` | No | `1` |
|
|
180
187
|
| `debounce` | `number` | No | — |
|
|
181
188
|
| `menu` | `boolean \| string` | No | `true` |
|
|
182
189
|
| `valueGrid` | `boolean` | No | `true` |
|
|
183
|
-
| `tooltipData` | `unknown
|
|
190
|
+
| `tooltipData` | `ArrayLike<unknown>` | No | — |
|
|
184
191
|
| `tooltipTrigger` | `"hover" \| "click"` | No | — |
|
|
185
192
|
| `tooltipClamp` | `"none" \| "chart" \| "window"` | No | `"chart"` |
|
|
186
193
|
| `csv` | `string \| (() => string)` | No | — |
|
|
@@ -57,6 +57,11 @@ const props = withDefaults(
|
|
|
57
57
|
valueTicks?: number | number[];
|
|
58
58
|
/** Formatter for value-axis tick labels. */
|
|
59
59
|
valueTickFormat?: (value: number) => string;
|
|
60
|
+
/**
|
|
61
|
+
* Formatter for numeric values shown in the default tooltip. Receives
|
|
62
|
+
* the raw value. Defaults to the same tick formatter used for axes.
|
|
63
|
+
*/
|
|
64
|
+
tooltipValueFormat?: (value: number) => string;
|
|
60
65
|
/** Formatter for category-axis labels. Receives the resolved category string. */
|
|
61
66
|
categoryFormat?: (label: string, index: number) => string;
|
|
62
67
|
/**
|
|
@@ -72,8 +77,12 @@ const props = withDefaults(
|
|
|
72
77
|
debounce?: number;
|
|
73
78
|
menu?: boolean | string;
|
|
74
79
|
valueGrid?: boolean;
|
|
75
|
-
/**
|
|
76
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Custom per-index data passed to the tooltip slot. Accepts a plain
|
|
82
|
+
* array or any `ArrayLike` (e.g. a typed array column from a
|
|
83
|
+
* `ModelOutput`).
|
|
84
|
+
*/
|
|
85
|
+
tooltipData?: ArrayLike<unknown>;
|
|
77
86
|
/** Tooltip activation mode. */
|
|
78
87
|
tooltipTrigger?: "hover" | "click";
|
|
79
88
|
/** Boundary for tooltip flip/clamp. Default "chart". */
|
|
@@ -399,6 +408,12 @@ function defaultColor(i: number): string {
|
|
|
399
408
|
return DEFAULT_COLORS[i % DEFAULT_COLORS.length];
|
|
400
409
|
}
|
|
401
410
|
|
|
411
|
+
function formatTooltipValue(v: number): string {
|
|
412
|
+
if (props.tooltipValueFormat) return props.tooltipValueFormat(v);
|
|
413
|
+
if (props.valueTickFormat) return props.valueTickFormat(v);
|
|
414
|
+
return formatTick(v);
|
|
415
|
+
}
|
|
416
|
+
|
|
402
417
|
const valueTickItems = computed(() => {
|
|
403
418
|
const { min, max } = valueExtent.value;
|
|
404
419
|
const fmt = (v: number) =>
|
|
@@ -775,7 +790,7 @@ const hoverBand = computed(() => {
|
|
|
775
790
|
class="bar-chart-tooltip-swatch"
|
|
776
791
|
:style="{ background: v.color }"
|
|
777
792
|
/>
|
|
778
|
-
{{ isFinite(v.value) ?
|
|
793
|
+
{{ isFinite(v.value) ? formatTooltipValue(v.value) : "—" }}
|
|
779
794
|
</div>
|
|
780
795
|
</div>
|
|
781
796
|
</slot>
|
|
@@ -12,16 +12,23 @@ export interface ChartMenuItem {
|
|
|
12
12
|
action: () => void;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const props = withDefaults(
|
|
16
|
+
defineProps<{
|
|
17
|
+
items: ChartMenuItem[];
|
|
18
|
+
/** Force the dropdown style even when only one item is provided. */
|
|
19
|
+
forceDropdown?: boolean;
|
|
20
|
+
}>(),
|
|
21
|
+
{ forceDropdown: false },
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const useDropdown = () => props.forceDropdown || props.items.length > 1;
|
|
18
25
|
</script>
|
|
19
26
|
|
|
20
27
|
<template>
|
|
21
28
|
<div class="chart-menu-trigger-area">
|
|
22
29
|
<!-- Single item: plain button -->
|
|
23
30
|
<button
|
|
24
|
-
v-if="
|
|
31
|
+
v-if="!useDropdown()"
|
|
25
32
|
class="chart-menu-button chart-menu-single"
|
|
26
33
|
:aria-label="items[0].label"
|
|
27
34
|
@click="items[0].action"
|
|
@@ -322,6 +322,47 @@ Set `geoType="hsas"` to render Health Service Area boundaries. HSAs are dissolve
|
|
|
322
322
|
</template>
|
|
323
323
|
</ComponentDemo>
|
|
324
324
|
|
|
325
|
+
### Custom tooltip number format
|
|
326
|
+
|
|
327
|
+
Pass `tooltip-value-format` to format numeric values shown in the tooltip
|
|
328
|
+
(both the native SVG `<title>` and the interactive HTML tooltip when
|
|
329
|
+
`tooltip-trigger` is set). Use `tooltip-format` instead if you want full
|
|
330
|
+
control over the tooltip's HTML.
|
|
331
|
+
|
|
332
|
+
<ComponentDemo>
|
|
333
|
+
<ChoroplethMap
|
|
334
|
+
:topology="statesTopo"
|
|
335
|
+
:data="[
|
|
336
|
+
{ id: '06', value: 39538223 },
|
|
337
|
+
{ id: '48', value: 29145505 },
|
|
338
|
+
{ id: '12', value: 21538187 },
|
|
339
|
+
{ id: '36', value: 20201249 },
|
|
340
|
+
]"
|
|
341
|
+
:tooltip-value-format="(v) => v.toLocaleString('en-US')"
|
|
342
|
+
title="US population (2020)"
|
|
343
|
+
:height="300"
|
|
344
|
+
/>
|
|
345
|
+
|
|
346
|
+
<template #code>
|
|
347
|
+
|
|
348
|
+
```vue
|
|
349
|
+
<ChoroplethMap
|
|
350
|
+
:topology="statesTopo"
|
|
351
|
+
:data="[
|
|
352
|
+
{ id: '06', value: 39538223 },
|
|
353
|
+
{ id: '48', value: 29145505 },
|
|
354
|
+
{ id: '12', value: 21538187 },
|
|
355
|
+
{ id: '36', value: 20201249 },
|
|
356
|
+
]"
|
|
357
|
+
:tooltip-value-format="(v) => v.toLocaleString('en-US')"
|
|
358
|
+
title="US population (2020)"
|
|
359
|
+
:height="300"
|
|
360
|
+
/>
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
</template>
|
|
364
|
+
</ComponentDemo>
|
|
365
|
+
|
|
325
366
|
## Props
|
|
326
367
|
|
|
327
368
|
| Prop | Type | Required | Default |
|
|
@@ -346,6 +387,7 @@ Set `geoType="hsas"` to render Health Service Area boundaries. HSAs are dissolve
|
|
|
346
387
|
id: string` | No | — |
|
|
347
388
|
| `name` | `string` | Yes | — |
|
|
348
389
|
| `value` | `number \| string` | No | — |
|
|
390
|
+
| `tooltipValueFormat` | `(value: number) => string` | No | — |
|
|
349
391
|
| `tooltipClamp` | `"none" \| "chart" \| "window"` | No | `"chart"` |
|
|
350
392
|
|
|
351
393
|
|
|
@@ -82,6 +82,12 @@ const props = withDefaults(
|
|
|
82
82
|
name: string;
|
|
83
83
|
value?: number | string;
|
|
84
84
|
}) => string;
|
|
85
|
+
/**
|
|
86
|
+
* Formatter for numeric values shown in the default tooltip. Receives
|
|
87
|
+
* the raw value. Ignored when `tooltipFormat` is provided (the caller
|
|
88
|
+
* controls the entire tooltip in that case).
|
|
89
|
+
*/
|
|
90
|
+
tooltipValueFormat?: (value: number) => string;
|
|
85
91
|
/**
|
|
86
92
|
* Boundary for tooltip flip/clamp. `"none"` always places to the right of
|
|
87
93
|
* the pointer with no clamping. `"chart"` (default) uses the map
|
|
@@ -392,6 +398,14 @@ function stateValue(
|
|
|
392
398
|
return dataMap.value.get(String(feat.id));
|
|
393
399
|
}
|
|
394
400
|
|
|
401
|
+
function formatTooltipValue(value: number | string | undefined): string {
|
|
402
|
+
if (value == null) return "";
|
|
403
|
+
if (typeof value === "number" && props.tooltipValueFormat) {
|
|
404
|
+
return props.tooltipValueFormat(value);
|
|
405
|
+
}
|
|
406
|
+
return String(value);
|
|
407
|
+
}
|
|
408
|
+
|
|
395
409
|
const featMap = computed(() => {
|
|
396
410
|
const m = new Map<string, (typeof featuresGeo.value.features)[number]>();
|
|
397
411
|
for (const f of featuresGeo.value.features) m.set(String(f.id), f);
|
|
@@ -429,8 +443,10 @@ function showTooltip(
|
|
|
429
443
|
const data = { id: String(feat.id), name, value };
|
|
430
444
|
if (props.tooltipFormat) {
|
|
431
445
|
tooltipEl.innerHTML = props.tooltipFormat(data);
|
|
446
|
+
} else if (value == null) {
|
|
447
|
+
tooltipEl.textContent = name;
|
|
432
448
|
} else {
|
|
433
|
-
tooltipEl.textContent =
|
|
449
|
+
tooltipEl.textContent = `${name}: ${formatTooltipValue(value)}`;
|
|
434
450
|
}
|
|
435
451
|
const chartRect = containerRef.value?.getBoundingClientRect();
|
|
436
452
|
const { left, top } = placeTooltip(
|
|
@@ -643,7 +659,11 @@ const menuItems = computed<ChartMenuItem[]>(() => {
|
|
|
643
659
|
>
|
|
644
660
|
<title v-if="!tooltipTrigger">
|
|
645
661
|
{{ stateName(feat)
|
|
646
|
-
}}{{
|
|
662
|
+
}}{{
|
|
663
|
+
stateValue(feat) != null
|
|
664
|
+
? `: ${formatTooltipValue(stateValue(feat))}`
|
|
665
|
+
: ""
|
|
666
|
+
}}
|
|
647
667
|
</title>
|
|
648
668
|
</path>
|
|
649
669
|
<path
|
|
@@ -87,19 +87,48 @@ A table for displaying columnar data. Accepts a plain record of arrays or a `Mod
|
|
|
87
87
|
</template>
|
|
88
88
|
</ComponentDemo>
|
|
89
89
|
|
|
90
|
-
###
|
|
90
|
+
### Full width
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
By default the table sizes to its content (columns default to a fixed
|
|
93
|
+
medium width, so they're evenly spaced). Pass `full-width` to stretch the
|
|
94
|
+
table to fill its container; columns without an explicit width will share
|
|
95
|
+
the available space equally.
|
|
96
|
+
|
|
97
|
+
<ComponentDemo>
|
|
98
|
+
<DataTable
|
|
99
|
+
:data="{ day: [0, 1, 2, 3, 4], susceptible: [1000, 980, 945, 900, 860], infected: [1, 21, 56, 101, 141] }"
|
|
100
|
+
full-width
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
<template #code>
|
|
104
|
+
|
|
105
|
+
```vue
|
|
106
|
+
<DataTable
|
|
107
|
+
:data="{
|
|
108
|
+
day: [0, 1, 2, 3, 4],
|
|
109
|
+
susceptible: [1000, 980, 945, 900, 860],
|
|
110
|
+
infected: [1, 21, 56, 101, 141],
|
|
111
|
+
}"
|
|
112
|
+
full-width
|
|
113
|
+
/>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
</template>
|
|
117
|
+
</ComponentDemo>
|
|
118
|
+
|
|
119
|
+
### Download menu
|
|
120
|
+
|
|
121
|
+
A `⋯` menu appears in the top-right corner of every table with a
|
|
122
|
+
**Download** item that exports the data as CSV. Use `download-menu-link`
|
|
123
|
+
to customize the menu item label, `filename` to control the downloaded
|
|
124
|
+
filename, and `csv` to supply custom CSV content. Pass `:menu="false"`
|
|
125
|
+
to hide the menu entirely.
|
|
97
126
|
|
|
98
127
|
<ComponentDemo>
|
|
99
128
|
<DataTable
|
|
100
129
|
:data="{ day: [0, 1, 2, 3, 4], cases: [1, 21, 56, 101, 141] }"
|
|
101
130
|
filename="sir-cases"
|
|
102
|
-
download-link="Download cases (CSV)"
|
|
131
|
+
download-menu-link="Download cases (CSV)"
|
|
103
132
|
/>
|
|
104
133
|
|
|
105
134
|
<template #code>
|
|
@@ -111,7 +140,7 @@ custom CSV content.
|
|
|
111
140
|
cases: [1, 21, 56, 101, 141],
|
|
112
141
|
}"
|
|
113
142
|
filename="sir-cases"
|
|
114
|
-
download-link="Download cases (CSV)"
|
|
143
|
+
download-menu-link="Download cases (CSV)"
|
|
115
144
|
/>
|
|
116
145
|
```
|
|
117
146
|
|
|
@@ -128,7 +157,8 @@ custom CSV content.
|
|
|
128
157
|
| `menu` | `boolean \| string` | No | `true` |
|
|
129
158
|
| `csv` | `string \| (() => string)` | No | — |
|
|
130
159
|
| `filename` | `string` | No | — |
|
|
131
|
-
| `
|
|
160
|
+
| `downloadMenuLink` | `string` | No | `"Download"` |
|
|
161
|
+
| `fullWidth` | `boolean` | No | `false` |
|
|
132
162
|
|
|
133
163
|
|
|
134
164
|
### ColumnConfig
|
|
@@ -31,22 +31,22 @@ const props = withDefaults(
|
|
|
31
31
|
columnConfig?: Record<string, ColumnConfig>;
|
|
32
32
|
menu?: boolean | string;
|
|
33
33
|
/**
|
|
34
|
-
* Custom CSV content for the Download
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* Custom CSV content for the Download menu item. Can be a raw CSV string
|
|
35
|
+
* or a function returning one. When omitted, CSV is generated from the
|
|
36
|
+
* table data.
|
|
37
37
|
*/
|
|
38
38
|
csv?: string | (() => string);
|
|
39
39
|
/** Filename (without extension) for downloaded CSV files. */
|
|
40
40
|
filename?: string;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* to customize the link text. When set, the Download CSV menu item is
|
|
45
|
-
* hidden.
|
|
42
|
+
* Label for the Download item in the table's top-right menu.
|
|
43
|
+
* Defaults to "Download".
|
|
46
44
|
*/
|
|
47
|
-
|
|
45
|
+
downloadMenuLink?: string;
|
|
46
|
+
/** Stretch the table to fill its container's width. */
|
|
47
|
+
fullWidth?: boolean;
|
|
48
48
|
}>(),
|
|
49
|
-
{ menu: true },
|
|
49
|
+
{ menu: true, fullWidth: false, downloadMenuLink: "Download" },
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
function columnLabel(name: string): string {
|
|
@@ -55,7 +55,10 @@ function columnLabel(name: string): string {
|
|
|
55
55
|
|
|
56
56
|
function columnStyle(name: string): Record<string, string> | undefined {
|
|
57
57
|
const w = props.columnConfig?.[name]?.width;
|
|
58
|
-
if (w == null)
|
|
58
|
+
if (w == null) {
|
|
59
|
+
if (props.fullWidth) return undefined;
|
|
60
|
+
return { width: COLUMN_WIDTHS.medium, minWidth: COLUMN_WIDTHS.medium };
|
|
61
|
+
}
|
|
59
62
|
const value = typeof w === "number" ? `${w}px` : COLUMN_WIDTHS[w];
|
|
60
63
|
return { width: value, minWidth: value };
|
|
61
64
|
}
|
|
@@ -135,36 +138,24 @@ function toCsv(): string {
|
|
|
135
138
|
return lines.join("\n");
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
const menuItems = computed<ChartMenuItem[]>(() =>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
];
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const downloadLinkText = computed(() => {
|
|
149
|
-
if (!props.downloadLink) return null;
|
|
150
|
-
return typeof props.downloadLink === "string"
|
|
151
|
-
? props.downloadLink
|
|
152
|
-
: "Download data (CSV)";
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
const csvHref = computed(() => {
|
|
156
|
-
if (!props.downloadLink) return null;
|
|
157
|
-
return `data:text/csv;charset=utf-8,${encodeURIComponent(toCsv())}`;
|
|
158
|
-
});
|
|
141
|
+
const menuItems = computed<ChartMenuItem[]>(() => [
|
|
142
|
+
{
|
|
143
|
+
label: props.downloadMenuLink,
|
|
144
|
+
action: () => downloadCsv(toCsv(), menuFilename()),
|
|
145
|
+
},
|
|
146
|
+
]);
|
|
159
147
|
|
|
160
|
-
const showMenu = computed(() => props.menu
|
|
148
|
+
const showMenu = computed(() => Boolean(props.menu));
|
|
161
149
|
</script>
|
|
162
150
|
|
|
163
151
|
<template>
|
|
164
|
-
<div
|
|
165
|
-
|
|
152
|
+
<div
|
|
153
|
+
class="TableOuter"
|
|
154
|
+
:class="{ 'full-width': fullWidth, 'has-menu': showMenu }"
|
|
155
|
+
>
|
|
156
|
+
<ChartMenu v-if="showMenu" :items="menuItems" force-dropdown />
|
|
166
157
|
<div class="TableWrapper">
|
|
167
|
-
<table class="Table">
|
|
158
|
+
<table class="Table" :class="{ 'full-width': fullWidth }">
|
|
168
159
|
<colgroup>
|
|
169
160
|
<col
|
|
170
161
|
v-for="col in columns"
|
|
@@ -197,14 +188,6 @@ const showMenu = computed(() => props.menu && menuItems.value.length > 0);
|
|
|
197
188
|
</tbody>
|
|
198
189
|
</table>
|
|
199
190
|
</div>
|
|
200
|
-
<a
|
|
201
|
-
v-if="downloadLinkText"
|
|
202
|
-
class="data-table-download-link"
|
|
203
|
-
:href="csvHref!"
|
|
204
|
-
:download="`${menuFilename()}.csv`"
|
|
205
|
-
>
|
|
206
|
-
{{ downloadLinkText }}
|
|
207
|
-
</a>
|
|
208
191
|
</div>
|
|
209
192
|
</template>
|
|
210
193
|
|
|
@@ -214,17 +197,8 @@ const showMenu = computed(() => props.menu && menuItems.value.length > 0);
|
|
|
214
197
|
display: inline-block;
|
|
215
198
|
}
|
|
216
199
|
|
|
217
|
-
.TableOuter.
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.TableOuter :deep(.chart-menu-trigger-area) {
|
|
222
|
-
top: -32px;
|
|
223
|
-
right: 0;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.TableOuter:hover :deep(.chart-menu-button) {
|
|
227
|
-
opacity: 1;
|
|
200
|
+
.TableOuter.full-width {
|
|
201
|
+
display: block;
|
|
228
202
|
}
|
|
229
203
|
|
|
230
204
|
.TableWrapper {
|
|
@@ -238,6 +212,11 @@ const showMenu = computed(() => props.menu && menuItems.value.length > 0);
|
|
|
238
212
|
border-collapse: collapse;
|
|
239
213
|
font-variant-numeric: tabular-nums;
|
|
240
214
|
border: 1px solid var(--color-border);
|
|
215
|
+
table-layout: fixed;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.Table.full-width {
|
|
219
|
+
width: 100%;
|
|
241
220
|
}
|
|
242
221
|
|
|
243
222
|
.Table tr,
|
|
@@ -251,6 +230,7 @@ const showMenu = computed(() => props.menu && menuItems.value.length > 0);
|
|
|
251
230
|
.Table td {
|
|
252
231
|
padding: 0.75em 1.25em;
|
|
253
232
|
white-space: nowrap;
|
|
233
|
+
text-align: left;
|
|
254
234
|
}
|
|
255
235
|
|
|
256
236
|
.Table th {
|
|
@@ -268,10 +248,16 @@ const showMenu = computed(() => props.menu && menuItems.value.length > 0);
|
|
|
268
248
|
border-bottom: none;
|
|
269
249
|
}
|
|
270
250
|
|
|
271
|
-
.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
251
|
+
.TableOuter :deep(.chart-menu-trigger-area) {
|
|
252
|
+
top: 4px;
|
|
253
|
+
right: 4px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.TableOuter :deep(.chart-menu-button) {
|
|
257
|
+
opacity: 1;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.TableOuter.has-menu .Table thead th:last-child {
|
|
261
|
+
padding-right: 2.5em;
|
|
276
262
|
}
|
|
277
263
|
</style>
|
|
@@ -100,7 +100,7 @@ When `x` is omitted, `y`/`data` values are plotted at indices 0, 1, 2, etc.
|
|
|
100
100
|
|
|
101
101
|
### Tooltip
|
|
102
102
|
|
|
103
|
-
Hover over the chart to see a tooltip with values at each data point. Set `tooltip-trigger="hover"` to enable the built-in tooltip with crosshair and highlight dots. Use the `#tooltip` slot for custom content.
|
|
103
|
+
Hover over the chart to see a tooltip with values at each data point. Set `tooltip-trigger="hover"` to enable the built-in tooltip with crosshair and highlight dots. Use the `#tooltip` slot for custom content. Pass `tooltip-value-format` to control how numeric values render (e.g. percentages, currency); it falls back to `y-tick-format` when omitted.
|
|
104
104
|
|
|
105
105
|
<ComponentDemo>
|
|
106
106
|
<LineChart
|
|
@@ -462,12 +462,13 @@ until the user clicks Download:
|
|
|
462
462
|
| `yTicks` | `number \| number[]` | No | — |
|
|
463
463
|
| `xTickFormat` | `(value: number, index: number) => string` | No | — |
|
|
464
464
|
| `yTickFormat` | `(value: number) => string` | No | — |
|
|
465
|
+
| `tooltipValueFormat` | `(value: number) => string` | No | — |
|
|
465
466
|
| `xLabels` | `string[]` | No | — |
|
|
466
467
|
| `debounce` | `number` | No | — |
|
|
467
468
|
| `menu` | `boolean \| string` | No | `true` |
|
|
468
469
|
| `xGrid` | `boolean` | No | — |
|
|
469
470
|
| `yGrid` | `boolean` | No | — |
|
|
470
|
-
| `tooltipData` | `unknown
|
|
471
|
+
| `tooltipData` | `ArrayLike<unknown>` | No | — |
|
|
471
472
|
| `tooltipTrigger` | `"hover" \| "click"` | No | — |
|
|
472
473
|
| `tooltipClamp` | `"none" \| "chart" \| "window"` | No | `"chart"` |
|
|
473
474
|
| `csv` | `string \| (() => string)` | No | — |
|
|
@@ -128,6 +128,11 @@ const props = withDefaults(
|
|
|
128
128
|
xTickFormat?: (value: number, index: number) => string;
|
|
129
129
|
/** Formatter for y-axis tick labels. Receives the raw numeric value. */
|
|
130
130
|
yTickFormat?: (value: number) => string;
|
|
131
|
+
/**
|
|
132
|
+
* Formatter for numeric values shown in the default tooltip. Receives
|
|
133
|
+
* the raw value. Defaults to the same tick formatter used for axes.
|
|
134
|
+
*/
|
|
135
|
+
tooltipValueFormat?: (value: number) => string;
|
|
131
136
|
/**
|
|
132
137
|
* @deprecated Use `xTickFormat` (e.g. `(_, i) => labels[i]`) together
|
|
133
138
|
* with `xTicks` for explicit control. Still honored for tooltip x-labels
|
|
@@ -138,8 +143,12 @@ const props = withDefaults(
|
|
|
138
143
|
menu?: boolean | string;
|
|
139
144
|
xGrid?: boolean;
|
|
140
145
|
yGrid?: boolean;
|
|
141
|
-
/**
|
|
142
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Custom per-index data passed to the tooltip slot. Accepts a plain
|
|
148
|
+
* array or any `ArrayLike` (e.g. a typed array column from a
|
|
149
|
+
* `ModelOutput`).
|
|
150
|
+
*/
|
|
151
|
+
tooltipData?: ArrayLike<unknown>;
|
|
143
152
|
/** Tooltip activation mode. Default: 'hover' */
|
|
144
153
|
tooltipTrigger?: "hover" | "click";
|
|
145
154
|
/**
|
|
@@ -216,6 +225,12 @@ function resolveSeries(s: Series): ResolvedSeries {
|
|
|
216
225
|
return { ...s, data: s.y ?? s.data ?? EMPTY_DATA };
|
|
217
226
|
}
|
|
218
227
|
|
|
228
|
+
function formatTooltipValue(v: number): string {
|
|
229
|
+
if (props.tooltipValueFormat) return props.tooltipValueFormat(v);
|
|
230
|
+
if (props.yTickFormat) return props.yTickFormat(v);
|
|
231
|
+
return formatTick(v);
|
|
232
|
+
}
|
|
233
|
+
|
|
219
234
|
const allSeries = computed<ResolvedSeries[]>(() => {
|
|
220
235
|
if (props.series && props.series.length > 0)
|
|
221
236
|
return props.series.map(resolveSeries);
|
|
@@ -1122,7 +1137,7 @@ const {
|
|
|
1122
1137
|
class="line-chart-tooltip-swatch"
|
|
1123
1138
|
:style="{ background: v.color }"
|
|
1124
1139
|
/>
|
|
1125
|
-
{{ isFinite(v.value) ?
|
|
1140
|
+
{{ isFinite(v.value) ? formatTooltipValue(v.value) : "—" }}
|
|
1126
1141
|
</div>
|
|
1127
1142
|
</div>
|
|
1128
1143
|
</slot>
|
package/index.json
CHANGED