diff --git a/src/app/donut/page.tsx b/src/app/donut/page.tsx new file mode 100644 index 0000000..afb1a60 --- /dev/null +++ b/src/app/donut/page.tsx @@ -0,0 +1,29 @@ +import './styles.css'; +import {Donut} from "@/components/Donut"; + +const data = [ + { + label: "One", + colour: "#ce4b99", + value: 35, + }, + { + label: "Two", + colour: "#b1c94e", + value: 15, + }, + { + label: "Three", + colour: "#377bbc", + value: 50, + }, + { + label: "Four", + colour: "#f49f35", + value: 100, + } +] + +export default function App() { + return +} diff --git a/src/app/donut/styles.css b/src/app/donut/styles.css new file mode 100644 index 0000000..4423406 --- /dev/null +++ b/src/app/donut/styles.css @@ -0,0 +1,19 @@ +.chart-text { + font: 16px/1.4em "Montserrat", Arial, sans-serif; + fill: #000; + transform: translateY(0.25em); +} + +.chart-number { + font-size: 0.6em; + line-height: 1; + text-anchor: middle; + transform: translateY(-0.25em); +} + +.chart-label { + font-size: 0.2em; + text-transform: uppercase; + text-anchor: middle; + transform: translateY(0.7em); +} diff --git a/src/components/Donut.tsx b/src/components/Donut.tsx new file mode 100644 index 0000000..c5ddd77 --- /dev/null +++ b/src/components/Donut.tsx @@ -0,0 +1,90 @@ +import * as R from "ramda"; +import DonutTooltip from "@/components/DonutTooltip"; +import './donut-styles.css' + +export type DonutChartData = { + label: string; + colour: string; + value: number; +}[]; + +export function Donut({data, centerLabel, formatter, hoverSuffix}: { + data: DonutChartData, + formatter: (value: number) => string, + centerLabel: string, + hoverSuffix: string, +}) { + const radius = 100 / (2 * Math.PI); + const backgroundColour = "#d2d3d4"; + + const preppedData = R.sortBy(R.compose(R.negate, R.prop('value')), data); + const total = R.sum(R.pluck('value', preppedData)); + const normalisingFactor = 100 / total; + + return ( + <> + + + {/* The hole in the middle of the donut */} + + + {/* The ring in the background of the donut, if it was not 100% full */} + + + { + preppedData.map((segment, index, array) => { + const { + label, + colour, + value + } = segment; + const precedingSegments = array.slice(0, index); + const offset = precedingSegments.reduce((acc, segment) => acc + segment.value, 0); + + return ( + + ) + }) + } + + + + {formatter(total)} + + + {centerLabel} + + + + + ); +} diff --git a/src/components/DonutTooltip.tsx b/src/components/DonutTooltip.tsx new file mode 100644 index 0000000..0c5f8f9 --- /dev/null +++ b/src/components/DonutTooltip.tsx @@ -0,0 +1,7 @@ +'use client'; + +import {Tooltip} from "react-tooltip"; + +export default function DonutTooltip() { + return +} diff --git a/src/components/OverviewPage.tsx b/src/components/OverviewPage.tsx index ee20d8d..2b9f45e 100644 --- a/src/components/OverviewPage.tsx +++ b/src/components/OverviewPage.tsx @@ -34,7 +34,7 @@ export default function OverviewPage({

{config.title}

-
+
{config.subjects.map((subject) => ( { const project = data.projects.find(p => p.projectId === entries[0].projectId)!; + const totalDuration = (entries).map((entry) => entry.duration).reduce((a, b) => a + b, 0); return ({ - name: project.name, - value: (entries).map((entry) => entry.duration).reduce((a, b) => a + b, 0), + label: project.name, + value: (totalDuration / (60 * 60)), colour: project.color, }); }) @@ -30,20 +26,15 @@ export function SubjectComparisonCard({ data: Data, }) { const breakdownData = useBreakdownData(data); - const colours = breakdownData.map((entry) => entry.colour); - - const valueFormatter = (number: number) => `${(number / (60 * 60)).toFixed(2)} hours`; return ( Relative Breakdown - v.toFixed(2)} + centerLabel={"hours"} + hoverSuffix={"h"} /> ) diff --git a/src/components/donut-styles.css b/src/components/donut-styles.css new file mode 100644 index 0000000..4423406 --- /dev/null +++ b/src/components/donut-styles.css @@ -0,0 +1,19 @@ +.chart-text { + font: 16px/1.4em "Montserrat", Arial, sans-serif; + fill: #000; + transform: translateY(0.25em); +} + +.chart-number { + font-size: 0.6em; + line-height: 1; + text-anchor: middle; + transform: translateY(-0.25em); +} + +.chart-label { + font-size: 0.2em; + text-transform: uppercase; + text-anchor: middle; + transform: translateY(0.7em); +}