iceshrimp-legacy/packages/client/src/pages/admin/overview.active-users.vue
2023-04-07 17:01:42 -07:00

182 lines
3.3 KiB
Vue

<template>
<div>
<MkLoading v-if="fetching" />
<div v-show="!fetching" :class="$style.root" class="_panel">
<canvas ref="chartEl"></canvas>
</div>
</div>
</template>
<script lang="ts" setup>
import {
markRaw,
version as vueVersion,
onMounted,
onBeforeUnmount,
nextTick,
} from "vue";
import { Chart } from "chart.js";
import tinycolor from "tinycolor2";
import gradient from "chartjs-plugin-gradient";
import * as os from "@/os";
import { defaultStore } from "@/store";
import { useChartTooltip } from "@/scripts/use-chart-tooltip";
import { chartVLine } from "@/scripts/chart-vline";
import { alpha } from "@/scripts/color";
import { initChart } from "@/scripts/init-chart";
initChart();
const chartEl = $shallowRef<HTMLCanvasElement>(null);
const now = new Date();
let chartInstance: Chart = null;
const chartLimit = 7;
let fetching = $ref(true);
const { handler: externalTooltipHandler } = useChartTooltip();
async function renderChart() {
if (chartInstance) {
chartInstance.destroy();
}
const getDate = (ago: number) => {
const y = now.getFullYear();
const m = now.getMonth();
const d = now.getDate();
return new Date(y, m, d - ago);
};
const format = (arr) => {
return arr.map((v, i) => ({
x: getDate(i).getTime(),
y: v,
}));
};
const raw = await os.api("charts/active-users", {
limit: chartLimit,
span: "day",
});
const vLineColor = defaultStore.state.darkMode
? "rgba(255, 255, 255, 0.2)"
: "rgba(0, 0, 0, 0.2)";
const colorRead = "#eb6f92";
const colorWrite = "#f6c177";
const max = Math.max(...raw.read);
chartInstance = new Chart(chartEl, {
type: "bar",
data: {
datasets: [
{
parsing: false,
label: "Read",
data: format(raw.read).slice().reverse(),
pointRadius: 0,
borderWidth: 0,
borderJoinStyle: "round",
borderRadius: 4,
backgroundColor: colorRead,
barPercentage: 0.7,
categoryPercentage: 0.5,
fill: true,
},
{
parsing: false,
label: "Write",
data: format(raw.write).slice().reverse(),
pointRadius: 0,
borderWidth: 0,
borderJoinStyle: "round",
borderRadius: 4,
backgroundColor: colorWrite,
barPercentage: 0.7,
categoryPercentage: 0.5,
fill: true,
},
],
},
options: {
aspectRatio: 2.5,
layout: {
padding: {
left: 0,
right: 8,
top: 0,
bottom: 0,
},
},
scales: {
x: {
type: "time",
offset: true,
time: {
stepSize: 1,
unit: "day",
displayFormats: {
day: "M/d",
month: "Y/M",
},
},
grid: {
display: false,
},
ticks: {
display: true,
maxRotation: 0,
autoSkipPadding: 8,
},
},
y: {
position: "left",
suggestedMax: 10,
grid: {
display: true,
},
ticks: {
display: true,
//mirror: true,
},
},
},
interaction: {
intersect: false,
mode: "index",
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
mode: "index",
animation: {
duration: 0,
},
external: externalTooltipHandler,
},
gradient,
},
},
plugins: [chartVLine(vLineColor)],
});
fetching = false;
}
onMounted(async () => {
renderChart();
});
</script>
<style lang="scss" module>
.root {
padding: 20px;
}
</style>