🎨
This commit is contained in:
parent
c93f091ba8
commit
fb05e86db7
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<div class="cbbedffa">
|
||||
<canvas ref="chartEl"></canvas>
|
||||
<MkChartLegend ref="legendEl" style="margin-top: 8px;"/>
|
||||
<div v-if="fetching" class="fetching">
|
||||
<MkLoading/>
|
||||
</div>
|
||||
|
@ -24,6 +25,8 @@ import { chartVLine } from '@/scripts/chart-vline';
|
|||
import { alpha } from '@/scripts/color';
|
||||
import date from '@/filters/date';
|
||||
import { initChart } from '@/scripts/init-chart';
|
||||
import { chartLegend } from '@/scripts/chart-legend';
|
||||
import MkChartLegend from '@/components/MkChartLegend.vue';
|
||||
|
||||
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 negate = arr => arr.map(x => -x);
|
||||
|
||||
|
@ -220,11 +225,7 @@ const render = () => {
|
|||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: props.detailed,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
boxWidth: 16,
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
|
@ -264,7 +265,7 @@ const render = () => {
|
|||
gradient,
|
||||
},
|
||||
},
|
||||
plugins: [chartVLine(vLineColor)],
|
||||
plugins: [chartVLine(vLineColor), ...(props.detailed ? [chartLegend(legendEl)] : [])],
|
||||
});
|
||||
};
|
||||
|
||||
|
|
75
packages/frontend/src/components/MkChartLegend.vue
Normal file
75
packages/frontend/src/components/MkChartLegend.vue
Normal 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>
|
|
@ -3,6 +3,7 @@
|
|||
<MkLoading v-if="fetching"/>
|
||||
<div v-show="!fetching" :class="$style.root" class="_panel">
|
||||
<canvas ref="chartEl"></canvas>
|
||||
<MkChartLegend ref="legendEl" style="margin-top: 8px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -20,6 +21,8 @@ import { useChartTooltip } from '@/scripts/use-chart-tooltip';
|
|||
import { chartVLine } from '@/scripts/chart-vline';
|
||||
import { alpha } from '@/scripts/color';
|
||||
import { initChart } from '@/scripts/init-chart';
|
||||
import { chartLegend } from '@/scripts/chart-legend';
|
||||
import MkChartLegend from '@/components/MkChartLegend.vue';
|
||||
|
||||
initChart();
|
||||
|
||||
|
@ -28,6 +31,7 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const chartEl = $shallowRef<HTMLCanvasElement>(null);
|
||||
let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>();
|
||||
const now = new Date();
|
||||
let chartInstance: Chart = null;
|
||||
const chartLimit = 30;
|
||||
|
@ -153,14 +157,7 @@ async function renderChart() {
|
|||
},
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
padding: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 8,
|
||||
bottom: 0,
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
|
@ -173,7 +170,7 @@ async function renderChart() {
|
|||
gradient,
|
||||
},
|
||||
},
|
||||
plugins: [chartVLine(vLineColor)],
|
||||
plugins: [chartVLine(vLineColor), chartLegend(legendEl)],
|
||||
});
|
||||
|
||||
fetching = false;
|
||||
|
|
12
packages/frontend/src/scripts/chart-legend.ts
Normal file
12
packages/frontend/src/scripts/chart-legend.ts
Normal 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;
|
|
@ -1,3 +1,5 @@
|
|||
import { Plugin } from 'chart.js';
|
||||
|
||||
export const chartVLine = (vLineColor: string) => ({
|
||||
id: 'vLine',
|
||||
beforeDraw(chart, args, options) {
|
||||
|
@ -18,4 +20,4 @@ export const chartVLine = (vLineColor: string) => ({
|
|||
ctx.restore();
|
||||
}
|
||||
},
|
||||
});
|
||||
}) as Plugin;
|
||||
|
|
Loading…
Reference in a new issue