fix wrapping of y axis chart labels

This commit is contained in:
Henry Dollman
2024-09-16 13:14:23 -04:00
parent c46879694d
commit e03e2b8d67
15 changed files with 117 additions and 143 deletions

View File

@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react'
export default function BandwidthChart({ export default function BandwidthChart({
ticks, ticks,
@@ -22,19 +21,16 @@ export default function BandwidthChart({
ticks: number[] ticks: number[]
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -52,10 +48,13 @@ export default function BandwidthChart({
className="tracking-tighter" className="tracking-tighter"
width={yAxisWidth} width={yAxisWidth}
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]} // domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)} tickFormatter={(value) => {
const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
return updateYAxisWidth(val)
}}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' MB/s'} // unit={' MB/s'}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -5,8 +5,8 @@ import {
ChartTooltip, ChartTooltip,
ChartTooltipContent, ChartTooltipContent,
} from '@/components/ui/chart' } from '@/components/ui/chart'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils' import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime, $containerFilter } from '@/lib/stores' import { $chartTime, $containerFilter } from '@/lib/stores'
@@ -18,12 +18,9 @@ export default function ContainerCpuChart({
chartData: Record<string, number | string>[] chartData: Record<string, number | string>[]
ticks: number[] ticks: number[]
}) { }) {
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const filter = useStore($containerFilter) const filter = useStore($containerFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const chartConfig = useMemo(() => { const chartConfig = useMemo(() => {
let config = {} as Record< let config = {} as Record<
@@ -65,12 +62,12 @@ export default function ContainerCpuChart({
// } // }
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -89,8 +86,10 @@ export default function ContainerCpuChart({
width={yAxisWidth} width={yAxisWidth}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={'%'} tickFormatter={(x) => {
tickFormatter={(x) => (x % 1 === 0 ? x : x.toFixed(1))} const val = (x % 1 === 0 ? x : x.toFixed(1)) + '%'
return updateYAxisWidth(val)
}}
/> />
<XAxis <XAxis
dataKey="time" dataKey="time"

View File

@@ -5,14 +5,14 @@ import {
ChartTooltip, ChartTooltip,
ChartTooltipContent, ChartTooltipContent,
} from '@/components/ui/chart' } from '@/components/ui/chart'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
@@ -26,11 +26,8 @@ export default function ContainerMemChart({
ticks: number[] ticks: number[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const filter = useStore($containerFilter) const filter = useStore($containerFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const chartConfig = useMemo(() => { const chartConfig = useMemo(() => {
let config = {} as Record< let config = {} as Record<
@@ -72,12 +69,12 @@ export default function ContainerMemChart({
// } // }
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -94,9 +91,11 @@ export default function ContainerMemChart({
// domain={[0, (max: number) => Math.ceil(max)]} // domain={[0, (max: number) => Math.ceil(max)]}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' GB'}
width={yAxisWidth} width={yAxisWidth}
tickFormatter={(value) => toFixedWithoutTrailingZeros(value / 1024, 2)} tickFormatter={(value) => {
const val = toFixedWithoutTrailingZeros(value / 1024, 2) + ' GB'
return updateYAxisWidth(val)
}}
/> />
<XAxis <XAxis
dataKey="time" dataKey="time"

View File

@@ -5,14 +5,14 @@ import {
ChartTooltip, ChartTooltip,
ChartTooltipContent, ChartTooltipContent,
} from '@/components/ui/chart' } from '@/components/ui/chart'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
@@ -27,11 +27,8 @@ export default function ContainerCpuChart({
ticks: number[] ticks: number[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const filter = useStore($containerFilter) const filter = useStore($containerFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const chartConfig = useMemo(() => { const chartConfig = useMemo(() => {
let config = {} as Record< let config = {} as Record<
@@ -72,12 +69,12 @@ export default function ContainerCpuChart({
// } // }
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -95,8 +92,10 @@ export default function ContainerCpuChart({
width={yAxisWidth} width={yAxisWidth}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' MB/s'} tickFormatter={(value) => {
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)} const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
return updateYAxisWidth(val)
}}
/> />
<XAxis <XAxis
dataKey="time" dataKey="time"

View File

@@ -1,12 +1,11 @@
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils' import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react'
export default function CpuChart({ export default function CpuChart({
ticks, ticks,
@@ -16,17 +15,14 @@ export default function CpuChart({
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
return ( return (
<div ref={chartRef}> <div>
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -42,7 +38,7 @@ export default function CpuChart({
width={yAxisWidth} width={yAxisWidth}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={'%'} tickFormatter={(value) => updateYAxisWidth(value + '%')}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -1,8 +1,8 @@
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils' import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
@@ -16,22 +16,19 @@ export default function DiskChart({
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const diskSize = useMemo(() => { const diskSize = useMemo(() => {
return Math.round(systemData.at(-1)?.stats.d ?? NaN) return Math.round(systemData.at(-1)?.stats.d ?? NaN)
}, [systemData]) }, [systemData])
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -53,7 +50,7 @@ export default function DiskChart({
minTickGap={6} minTickGap={6}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' GB'} tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react'
export default function DiskIoChart({ export default function DiskIoChart({
ticks, ticks,
@@ -23,22 +22,15 @@ export default function DiskIoChart({
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
// if (!systemData.length || !ticks.length) {
// return <Spinner />
// }
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -56,10 +48,12 @@ export default function DiskIoChart({
className="tracking-tighter" className="tracking-tighter"
width={yAxisWidth} width={yAxisWidth}
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]} // domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)} tickFormatter={(value) => {
const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
return updateYAxisWidth(val)
}}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' MB/s'}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -1,8 +1,8 @@
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils' import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
@@ -18,10 +18,7 @@ export default function ExFsDiskChart({
fs: string fs: string
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const diskSize = useMemo(() => { const diskSize = useMemo(() => {
const size = systemData.at(-1)?.stats.efs?.[fs].d ?? 0 const size = systemData.at(-1)?.stats.efs?.[fs].d ?? 0
@@ -29,11 +26,11 @@ export default function ExFsDiskChart({
}, [systemData]) }, [systemData])
return ( return (
<div ref={chartRef}> <div>
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -52,7 +49,7 @@ export default function ExFsDiskChart({
minTickGap={6} minTickGap={6}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' GB'} tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react'
export default function ExFsDiskIoChart({ export default function ExFsDiskIoChart({
ticks, ticks,
@@ -25,22 +24,15 @@ export default function ExFsDiskIoChart({
fs: string fs: string
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
// if (!systemData.length || !ticks.length) {
// return <Spinner />
// }
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -58,10 +50,12 @@ export default function ExFsDiskIoChart({
className="tracking-tighter" className="tracking-tighter"
width={yAxisWidth} width={yAxisWidth}
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]} // domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)} tickFormatter={(value) => {
const val = toFixedWithoutTrailingZeros(value, 2)
return updateYAxisWidth(val + ' MB/s')
}}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' MB/s'}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -2,14 +2,14 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedFloat, toFixedFloat,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
@@ -22,23 +22,20 @@ export default function MemChart({
ticks: number[] ticks: number[]
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
const totalMem = useMemo(() => { const totalMem = useMemo(() => {
return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1) return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1)
}, [systemData]) }, [systemData])
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart <AreaChart
@@ -58,7 +55,10 @@ export default function MemChart({
width={yAxisWidth} width={yAxisWidth}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' GB'} tickFormatter={(value) => {
const val = toFixedFloat(value, 1)
return updateYAxisWidth(val + ' GB')
}}
/> />
)} )}
<XAxis <XAxis

View File

@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
// import Spinner from '../spinner' // import Spinner from '../spinner'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react'
export default function SwapChart({ export default function SwapChart({
ticks, ticks,
@@ -23,17 +22,14 @@ export default function SwapChart({
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const chartRef = useRef<HTMLDivElement>(null) const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
const yAxisWidth = useYaxisWidth(chartRef)
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
return ( return (
<div ref={chartRef}> <div>
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<AreaChart accessibilityLayer data={systemData} margin={{ top: 10 }}> <AreaChart accessibilityLayer data={systemData} margin={{ top: 10 }}>
@@ -44,7 +40,7 @@ export default function SwapChart({
width={yAxisWidth} width={yAxisWidth}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' GB'} tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -8,17 +8,17 @@ import {
ChartTooltipContent, ChartTooltipContent,
} from '@/components/ui/chart' } from '@/components/ui/chart'
import { import {
useYAxisWidth,
chartTimeData, chartTimeData,
cn, cn,
formatShortDate, formatShortDate,
toFixedWithoutTrailingZeros, toFixedWithoutTrailingZeros,
twoDecimalString, twoDecimalString,
useYaxisWidth,
} from '@/lib/utils' } from '@/lib/utils'
import { useStore } from '@nanostores/react' import { useStore } from '@nanostores/react'
import { $chartTime } from '@/lib/stores' import { $chartTime } from '@/lib/stores'
import { SystemStatsRecord } from '@/types' import { SystemStatsRecord } from '@/types'
import { useMemo, useRef } from 'react' import { useMemo } from 'react'
export default function TemperatureChart({ export default function TemperatureChart({
ticks, ticks,
@@ -27,9 +27,8 @@ export default function TemperatureChart({
ticks: number[] ticks: number[]
systemData: SystemStatsRecord[] systemData: SystemStatsRecord[]
}) { }) {
const chartRef = useRef<HTMLDivElement>(null)
const yAxisWidth = useYaxisWidth(chartRef)
const chartTime = useStore($chartTime) const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
/** Format temperature data for chart and assign colors */ /** Format temperature data for chart and assign colors */
const newChartData = useMemo(() => { const newChartData = useMemo(() => {
@@ -55,15 +54,13 @@ export default function TemperatureChart({
return chartData return chartData
}, [systemData]) }, [systemData])
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
return ( return (
<div ref={chartRef}> <div>
{/* {!yAxisSet && <Spinner />} */} {/* {!yAxisSet && <Spinner />} */}
<ChartContainer <ChartContainer
config={{}} config={{}}
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', { className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
'opacity-100': yAxisSet, 'opacity-100': yAxisWidth,
})} })}
> >
<LineChart <LineChart
@@ -80,10 +77,12 @@ export default function TemperatureChart({
<YAxis <YAxis
className="tracking-tighter" className="tracking-tighter"
width={yAxisWidth} width={yAxisWidth}
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)} tickFormatter={(value) => {
const val = toFixedWithoutTrailingZeros(value, 2)
return updateYAxisWidth(val + ' °C')
}}
tickLine={false} tickLine={false}
axisLine={false} axisLine={false}
unit={' °C'}
/> />
<XAxis <XAxis
dataKey="created" dataKey="created"

View File

@@ -88,5 +88,5 @@
} }
.recharts-yAxis { .recharts-yAxis {
font-variant-numeric: tabular-nums; @apply tabular-nums;
} }

View File

@@ -195,22 +195,27 @@ export const chartTimeData: ChartTimeData = {
}, },
} }
/** Hacky solution to set the correct width of the yAxis in recharts */ /** Sets the correct width of the y axis in recharts based on the longest label */
export function useYaxisWidth(chartRef: React.RefObject<HTMLDivElement>) { export function useYAxisWidth() {
const [yAxisWidth, setYAxisWidth] = useState(180) const [yAxisWidth, setYAxisWidth] = useState(0)
useEffect(() => { let maxChars = 0
let interval = setInterval(() => { let timeout: Timer
// console.log('chartRef', chartRef.current) function updateYAxisWidth(str: string) {
const yAxisElement = chartRef?.current?.querySelector('.yAxis') if (str.length > maxChars) {
if (yAxisElement) { maxChars = str.length
// console.log('yAxisElement', yAxisElement) const div = document.createElement('div')
clearInterval(interval) div.className = 'text-xs tabular-nums tracking-tighter table sr-only'
setYAxisWidth(yAxisElement.getBoundingClientRect().width + 24) div.innerHTML = str
clearTimeout(timeout)
timeout = setTimeout(() => {
document.body.appendChild(div)
setYAxisWidth(div.offsetWidth + 24)
document.body.removeChild(div)
})
} }
}, 16) return str
return () => clearInterval(interval) }
}, []) return { yAxisWidth, updateYAxisWidth }
return yAxisWidth
} }
export function useClampedIsInViewport(options: HookOptions): [boolean | null, CallbackRef] { export function useClampedIsInViewport(options: HookOptions): [boolean | null, CallbackRef] {

View File

@@ -1,5 +1,5 @@
import './index.css' import './index.css'
import { Suspense, lazy, useEffect } from 'react' import { Suspense, lazy, useEffect, StrictMode } from 'react'
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import Home from './components/routes/home.tsx' import Home from './components/routes/home.tsx'
import { ThemeProvider } from './components/theme-provider.tsx' import { ThemeProvider } from './components/theme-provider.tsx'
@@ -218,10 +218,10 @@ const Layout = () => {
ReactDOM.createRoot(document.getElementById('app')!).render( ReactDOM.createRoot(document.getElementById('app')!).render(
// strict mode in dev mounts / unmounts components twice // strict mode in dev mounts / unmounts components twice
// and breaks the clipboard dialog // and breaks the clipboard dialog
//<React.StrictMode> //<StrictMode>
<ThemeProvider> <ThemeProvider>
<Layout /> <Layout />
<Toaster /> <Toaster />
</ThemeProvider> </ThemeProvider>
//</React.StrictMode> //</StrictMode>
) )