Private
Public Access
1
0

Replace built-in chart legend with custom legend for reliable hover sync

ApexCharts legendMouseOver event is unreliable for donut charts. Use custom
HTML legend items with direct mouseenter/mouseleave handlers that sync
highlighting between legend, chart slices, and the category table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-15 21:30:22 -05:00
parent 1df5283188
commit 7a333a1705
+26 -8
View File
@@ -86,6 +86,19 @@
:options="spendingChartOptions"
:series="spendingChartSeries"
/>
<div v-if="spending.categories.length > 0" class="d-flex flex-wrap justify-center ga-2 mt-2">
<div
v-for="(cat, idx) in spending.categories"
:key="cat.categoryName"
class="d-flex align-center ga-1 px-2 py-1 rounded cursor-pointer legend-item"
:class="{ 'spending-row-highlight': highlightedCategory === cat.categoryName }"
@mouseenter="highlightCategory(cat.categoryName)"
@mouseleave="unhighlightCategory()"
>
<span class="legend-dot" :style="{ backgroundColor: chartColors[idx % chartColors.length] }" />
<span class="text-caption">{{ cat.categoryName }}</span>
</div>
</div>
<div v-else class="text-center pa-8 text-medium-emphasis">No spending data for this period</div>
</v-col>
<v-col cols="12" md="7">
@@ -347,6 +360,8 @@ function setChartHighlight(categoryName: string | null) {
}
}
const chartColors = ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0', '#546E7A', '#26a69a', '#D10CE8', '#2E93fA', '#FF9800']
const spendingChartOptions = computed(() => ({
chart: {
type: 'donut' as const,
@@ -358,17 +373,11 @@ const spendingChartOptions = computed(() => ({
dataPointMouseLeave: () => {
setChartHighlight(null)
},
legendMouseOver: (_ctx: any, config: any) => {
const labels = spending.value?.categories.map(c => c.categoryName) ?? []
setChartHighlight(labels[config.seriesIndex] ?? null)
},
legendMouseOut: () => {
setChartHighlight(null)
},
},
},
colors: chartColors,
labels: spending.value?.categories.map(c => c.categoryName) ?? [],
legend: { position: 'bottom' as const, labels: { colors: labelColor.value } },
legend: { show: false },
dataLabels: { style: { colors: ['#FFFFFF'] }, dropShadow: { enabled: true, top: 1, left: 1, blur: 2, opacity: 0.5 } },
tooltip: {
y: {
@@ -589,4 +598,13 @@ onMounted(async () => {
background-color: rgba(var(--v-theme-primary), 0.15);
transition: background-color 0.15s;
}
.legend-dot {
width: 10px;
height: 10px;
border-radius: 50%;
flex-shrink: 0;
}
.legend-item {
transition: background-color 0.15s;
}
</style>