mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-10-31 05:24:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			165 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <!--
 | |
| SPDX-FileCopyrightText: syuilo and misskey-project
 | |
| SPDX-License-Identifier: AGPL-3.0-only
 | |
| -->
 | |
| 
 | |
| <template>
 | |
| <div>
 | |
| 	<MkLoading v-if="fetching"/>
 | |
| 	<div v-show="!fetching" :class="$style.root">
 | |
| 		<canvas ref="chartEl"></canvas>
 | |
| 	</div>
 | |
| </div>
 | |
| </template>
 | |
| 
 | |
| <script lang="ts" setup>
 | |
| import { onMounted, shallowRef, ref, nextTick } from 'vue';
 | |
| import { Chart } from 'chart.js';
 | |
| import gradient from 'chartjs-plugin-gradient';
 | |
| import tinycolor from 'tinycolor2';
 | |
| import { misskeyApi } from '@/scripts/misskey-api.js';
 | |
| import { defaultStore } from '@/store.js';
 | |
| import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
 | |
| import { chartVLine } from '@/scripts/chart-vline.js';
 | |
| import { initChart } from '@/scripts/init-chart.js';
 | |
| 
 | |
| initChart();
 | |
| 
 | |
| const chartEl = shallowRef<HTMLCanvasElement | null>(null);
 | |
| const now = new Date();
 | |
| let chartInstance: Chart | null = null;
 | |
| const chartLimit = 30;
 | |
| const 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 misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
 | |
| 
 | |
| 	fetching.value = false;
 | |
| 
 | |
| 	await nextTick();
 | |
| 
 | |
| 	const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
 | |
| 
 | |
| 	const computedStyle = getComputedStyle(document.documentElement);
 | |
| 	const accent = tinycolor(computedStyle.getPropertyValue('--accent')).toHexString();
 | |
| 
 | |
| 	const colorRead = accent;
 | |
| 	const colorWrite = '#2ecc71';
 | |
| 
 | |
| 	const max = Math.max(...raw.read);
 | |
| 
 | |
| 	if (chartEl.value == null) return;
 | |
| 
 | |
| 	chartInstance = new Chart(chartEl.value, {
 | |
| 		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.5,
 | |
| 				categoryPercentage: 1,
 | |
| 				fill: true,
 | |
| 			}],
 | |
| 		},
 | |
| 		options: {
 | |
| 			aspectRatio: 2.5,
 | |
| 			layout: {
 | |
| 				padding: {
 | |
| 					left: 0,
 | |
| 					right: 8,
 | |
| 					top: 0,
 | |
| 					bottom: 0,
 | |
| 				},
 | |
| 			},
 | |
| 			scales: {
 | |
| 				x: {
 | |
| 					type: 'time',
 | |
| 					offset: true,
 | |
| 					time: {
 | |
| 						unit: 'day',
 | |
| 						displayFormats: {
 | |
| 							day: 'M/d',
 | |
| 							month: 'Y/M',
 | |
| 						},
 | |
| 					},
 | |
| 					grid: {
 | |
| 						display: false,
 | |
| 					},
 | |
| 					ticks: {
 | |
| 						stepSize: 1,
 | |
| 						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,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		plugins: [chartVLine(vLineColor)],
 | |
| 	});
 | |
| }
 | |
| 
 | |
| onMounted(async () => {
 | |
| 	renderChart();
 | |
| });
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" module>
 | |
| .root {
 | |
| 	padding: 20px;
 | |
| }
 | |
| </style>
 |