125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
'use client';
|
|
// greets https://github.com/wa0x6e/cal-heatmap-react-starter/blob/main/src/components/cal-heatmap.tsx
|
|
|
|
import CalHeatmap from 'cal-heatmap';
|
|
// @ts-ignore cal-heatmap is jenk
|
|
import Legend from 'cal-heatmap/plugins/Legend';
|
|
// @ts-ignore cal-heatmap is jenk
|
|
import Tooltip from 'cal-heatmap/plugins/Tooltip';
|
|
import { DataRecord } from 'cal-heatmap/src/options/Options';
|
|
import 'cal-heatmap/cal-heatmap.css';
|
|
import dayjs from 'dayjs';
|
|
import { useEffect, useState, useRef } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { getSafeDate } from '@/lib/dates';
|
|
|
|
export interface ICalProps {
|
|
data: DataRecord[];
|
|
slug: string;
|
|
}
|
|
|
|
|
|
export function Cal({ data, slug }: ICalProps) {
|
|
const router = useRouter();
|
|
const [cellSize, setCellSize] = useState(13);
|
|
const [targetElementId, setTargetElementId] = useState('');
|
|
|
|
const generateUniqueId = () => {
|
|
return `cal-${Math.random().toString(36).substring(2, 9)}`;
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
const updateCellSize = () => {
|
|
const windowWidth = window.innerWidth;
|
|
if (windowWidth > 1400) {
|
|
setCellSize(15); // Adjust the cell size for width > 1400px
|
|
} else if (windowWidth > 730) {
|
|
setCellSize(10); // Adjust the cell size for width > 730px
|
|
} else {
|
|
setCellSize(3); // Adjust the cell size for width <= 730px
|
|
}
|
|
}
|
|
updateCellSize();
|
|
// Event listener to update cell size on window resize
|
|
window.addEventListener('resize', updateCellSize);
|
|
|
|
return () => {
|
|
window.removeEventListener('resize', updateCellSize);
|
|
};
|
|
|
|
}, [])
|
|
|
|
|
|
useEffect(() => {
|
|
setTargetElementId(generateUniqueId());
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!targetElementId) return;
|
|
const cal = new CalHeatmap();
|
|
// @ts-ignore
|
|
cal.on('click', (
|
|
event: string,
|
|
timestamp: number,
|
|
value: number
|
|
) => {
|
|
router.push(`/vt/${slug}/stream/${getSafeDate(new Date(timestamp))}`);
|
|
// console.log(`slug=${slug} safeDate=${getSafeDate(new Date(timestamp))}`);
|
|
});
|
|
|
|
cal.paint(
|
|
{
|
|
itemSelector: `#${targetElementId}`,
|
|
scale: {
|
|
color: {
|
|
// @ts-ignore this shit is straight from the example website
|
|
domain: ['missing', 'issue', 'good'],
|
|
type: 'ordinal',
|
|
range: ['red', 'yellow', 'green']
|
|
}
|
|
},
|
|
theme: 'dark',
|
|
verticalOrientation: false,
|
|
data: {
|
|
source: data,
|
|
x: 'date',
|
|
y: 'value',
|
|
// @ts-ignore this shit is straight from the example website
|
|
groupY: d => d[0]
|
|
},
|
|
range: 12,
|
|
date: { start: data[0].date },
|
|
domain: {
|
|
type: 'month',
|
|
gutter: 4,
|
|
label: { text: 'MMM', textAlign: 'start', position: 'top' }
|
|
},
|
|
subDomain: {
|
|
type: 'ghDay',
|
|
radius: 2,
|
|
width: cellSize,
|
|
height: cellSize,
|
|
gutter: 4,
|
|
}
|
|
}, [
|
|
[
|
|
Tooltip,
|
|
{
|
|
text: ((ts: number, value: string, dayjsDate: dayjs.Dayjs) => {
|
|
return `${!!value ? value+' - '+dayjsDate.toString() : dayjsDate.toString() }`;
|
|
})
|
|
}
|
|
]
|
|
]);
|
|
|
|
}, [targetElementId, data, cellSize, router, slug]);
|
|
|
|
|
|
return (
|
|
<>
|
|
<div id={targetElementId}></div>
|
|
</>
|
|
)
|
|
} |