This commit is contained in:
syuilo 2023-01-03 14:08:52 +09:00
parent c93f091ba8
commit fb05e86db7
5 changed files with 103 additions and 16 deletions

View file

@ -1,6 +1,7 @@
<template> <template>
<div class="cbbedffa"> <div class="cbbedffa">
<canvas ref="chartEl"></canvas> <canvas ref="chartEl"></canvas>
<MkChartLegend ref="legendEl" style="margin-top: 8px;"/>
<div v-if="fetching" class="fetching"> <div v-if="fetching" class="fetching">
<MkLoading/> <MkLoading/>
</div> </div>
@ -24,6 +25,8 @@ import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import date from '@/filters/date'; import date from '@/filters/date';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
import { chartLegend } from '@/scripts/chart-legend';
import MkChartLegend from '@/components/MkChartLegend.vue';
initChart(); initChart();
@ -67,6 +70,8 @@ const props = defineProps({
}, },
}); });
let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>();
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
const negate = arr => arr.map(x => -x); const negate = arr => arr.map(x => -x);
@ -220,11 +225,7 @@ const render = () => {
}, },
plugins: { plugins: {
legend: { legend: {
display: props.detailed, display: false,
position: 'bottom',
labels: {
boxWidth: 16,
},
}, },
tooltip: { tooltip: {
enabled: false, enabled: false,
@ -264,7 +265,7 @@ const render = () => {
gradient, gradient,
}, },
}, },
plugins: [chartVLine(vLineColor)], plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl)] : [])],
}); });
}; };

View file

@ -0,0 +1,75 @@
<template>
<div :class="$style.root">
<button v-for="item in items" class="_button item" :class="{ disabled: item.hidden }" @click="onClick(item)">
<span class="box" :style="{ background: chart.config.type === 'line' ? item.strokeStyle?.toString() : item.fillStyle?.toString() }"></span>
{{ item.text }}
</button>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue';
import { Chart, LegendItem } from 'chart.js';
const props = defineProps({
});
let chart = $shallowRef<Chart>();
let items = $shallowRef<LegendItem[]>([]);
function update(_chart: Chart, _items: LegendItem[]) {
chart = _chart,
items = _items;
}
function onClick(item: LegendItem) {
if (chart == null) return;
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
chart.toggleDataVisibility(item.index);
} else {
chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
}
chart.update();
}
defineExpose({
update,
});
</script>
<style lang="scss" module>
.root {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
&:global {
> .item {
font-size: 85%;
padding: 4px 12px 4px 8px;
border: solid 1px var(--divider);
border-radius: 999px;
&:hover {
border-color: var(--inputBorderHover);
}
&.disabled {
text-decoration: line-through;
opacity: 0.6;
}
> .box {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 100%;
vertical-align: -10%;
}
}
}
}
</style>

View file

@ -3,6 +3,7 @@
<MkLoading v-if="fetching"/> <MkLoading v-if="fetching"/>
<div v-show="!fetching" :class="$style.root" class="_panel"> <div v-show="!fetching" :class="$style.root" class="_panel">
<canvas ref="chartEl"></canvas> <canvas ref="chartEl"></canvas>
<MkChartLegend ref="legendEl" style="margin-top: 8px;"/>
</div> </div>
</div> </div>
</template> </template>
@ -20,6 +21,8 @@ import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { chartVLine } from '@/scripts/chart-vline'; import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color'; import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart'; import { initChart } from '@/scripts/init-chart';
import { chartLegend } from '@/scripts/chart-legend';
import MkChartLegend from '@/components/MkChartLegend.vue';
initChart(); initChart();
@ -28,6 +31,7 @@ const props = defineProps<{
}>(); }>();
const chartEl = $shallowRef<HTMLCanvasElement>(null); const chartEl = $shallowRef<HTMLCanvasElement>(null);
let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>();
const now = new Date(); const now = new Date();
let chartInstance: Chart = null; let chartInstance: Chart = null;
const chartLimit = 30; const chartLimit = 30;
@ -153,14 +157,7 @@ async function renderChart() {
}, },
}, },
legend: { legend: {
display: true, display: false,
position: 'bottom',
padding: {
left: 0,
right: 0,
top: 8,
bottom: 0,
},
}, },
tooltip: { tooltip: {
enabled: false, enabled: false,
@ -173,7 +170,7 @@ async function renderChart() {
gradient, gradient,
}, },
}, },
plugins: [chartVLine(vLineColor)], plugins: [chartVLine(vLineColor), chartLegend(legendEl)],
}); });
fetching = false; fetching = false;

View file

@ -0,0 +1,12 @@
import { Plugin } from 'chart.js';
import MkChartLegend from '@/components/MkChartLegend.vue';
export const chartLegend = (legend: InstanceType<typeof MkChartLegend>) => ({
id: 'htmlLegend',
afterUpdate(chart, args, options) {
// Reuse the built-in legendItems generator
const items = chart.options.plugins.legend.labels.generateLabels(chart);
legend.update(chart, items);
},
}) as Plugin;

View file

@ -1,3 +1,5 @@
import { Plugin } from 'chart.js';
export const chartVLine = (vLineColor: string) => ({ export const chartVLine = (vLineColor: string) => ({
id: 'vLine', id: 'vLine',
beforeDraw(chart, args, options) { beforeDraw(chart, args, options) {
@ -18,4 +20,4 @@ export const chartVLine = (vLineColor: string) => ({
ctx.restore(); ctx.restore();
} }
}, },
}); }) as Plugin;