forked from Testaustime/testaustime-frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDailyCodingTimeChart.tsx
More file actions
124 lines (118 loc) · 3.09 KB
/
DailyCodingTimeChart.tsx
File metadata and controls
124 lines (118 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { addDays, startOfDay, format } from "date-fns";
import { sumBy } from "../../utils/arrayUtils";
import { calculateTickValues } from "../../utils/chartUtils";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
LineElement,
PointElement,
} from "chart.js";
import { prettyDuration, TimeUnit } from "../../utils/dateUtils";
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
PointElement,
LineElement,
);
export interface DailyCodingTimeChartProps {
data: {
date: Date;
duration: number;
}[];
smoothCharts: boolean;
maxTimeUnit: TimeUnit;
}
export const transformData = (
entries: {
duration: number;
dayStart: Date;
}[],
dayCount: number,
) => {
const data = Array(dayCount)
.fill(0)
.map((_, dayIndex) => {
const date = startOfDay(addDays(new Date(), -dayIndex));
const duration = sumBy(
entries.filter(
(entry) => startOfDay(entry.dayStart).getTime() === date.getTime(),
),
(entry) => entry.duration,
);
return { date, duration };
})
.sort((a, b) => a.date.getTime() - b.date.getTime());
return data;
};
export const DailyCodingTimeChart = ({
data: dataRaw,
smoothCharts,
maxTimeUnit,
}: DailyCodingTimeChartProps) => {
const data = [...dataRaw].sort((a, b) => a.date.getTime() - b.date.getTime());
const maxDuration = Math.max(...data.map((d) => d.duration));
const yticks = calculateTickValues(maxDuration);
return (
<Line
options={{
plugins: {
legend: {
display: false,
},
tooltip: {
mode: "index",
intersect: false,
callbacks: {
label: (item) =>
" " + prettyDuration(Number(item.raw), maxTimeUnit),
},
padding: 8,
},
},
scales: {
y: {
min: 0,
max: yticks[yticks.length - 1],
afterBuildTicks: (axis) => {
axis.ticks = yticks.map((tick) => ({ value: tick }));
},
ticks: {
count: yticks.length,
stepSize: yticks[1] - yticks[0],
callback: (_, index) =>
prettyDuration(yticks[index], maxTimeUnit),
},
},
},
}}
data={{
labels: data.map((entry) => format(entry.date, "MMM d")),
datasets: [
{
label: "Daily coding time",
data: data.map((entry) => entry.duration),
borderColor: "#1f78b4",
borderWidth: 4,
// Avoid sharp "miter" spikes at vertices when drawing straight segments.
borderJoinStyle: "round",
borderCapStyle: "round",
pointRadius: 2,
// Avoid "overshoot" where the smoothed curve goes above/below actual points.
cubicInterpolationMode: smoothCharts ? "monotone" : "default",
tension: smoothCharts ? 0.5 : 0,
},
],
}}
/>
);
};