From e03e2b8d67c0a1018457892c8908ec008b719f8e Mon Sep 17 00:00:00 2001 From: Henry Dollman Date: Mon, 16 Sep 2024 13:14:23 -0400 Subject: [PATCH] fix wrapping of y axis chart labels --- .../src/components/charts/bandwidth-chart.tsx | 19 +++++----- .../components/charts/container-cpu-chart.tsx | 19 +++++----- .../components/charts/container-mem-chart.tsx | 19 +++++----- .../components/charts/container-net-chart.tsx | 19 +++++----- .../site/src/components/charts/cpu-chart.tsx | 14 +++---- .../site/src/components/charts/disk-chart.tsx | 15 +++----- .../src/components/charts/disk-io-chart.tsx | 22 ++++------- .../components/charts/extra-fs-disk-chart.tsx | 15 +++----- .../charts/extra-fs-disk-io-chart.tsx | 22 ++++------- .../site/src/components/charts/mem-chart.tsx | 18 ++++----- .../site/src/components/charts/swap-chart.tsx | 14 +++---- .../components/charts/temperature-chart.tsx | 19 +++++----- beszel/site/src/index.css | 2 +- beszel/site/src/lib/utils.ts | 37 +++++++++++-------- beszel/site/src/main.tsx | 6 +-- 15 files changed, 117 insertions(+), 143 deletions(-) diff --git a/beszel/site/src/components/charts/bandwidth-chart.tsx b/beszel/site/src/components/charts/bandwidth-chart.tsx index fa06a85..1a4c6e2 100644 --- a/beszel/site/src/components/charts/bandwidth-chart.tsx +++ b/beszel/site/src/components/charts/bandwidth-chart.tsx @@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { + useYAxisWidth, chartTimeData, cn, formatShortDate, toFixedWithoutTrailingZeros, twoDecimalString, - useYaxisWidth, } from '@/lib/utils' // import Spinner from '../spinner' import { useStore } from '@nanostores/react' import { $chartTime } from '@/lib/stores' import { SystemStatsRecord } from '@/types' -import { useMemo, useRef } from 'react' export default function BandwidthChart({ ticks, @@ -22,19 +21,16 @@ export default function BandwidthChart({ ticks: number[] systemData: SystemStatsRecord[] }) { - const chartRef = useRef(null) - const yAxisWidth = useYaxisWidth(chartRef) const chartTime = useStore($chartTime) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() return ( -
+
{/* {!yAxisSet && } */} (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} axisLine={false} - unit={' MB/s'} + // unit={' MB/s'} /> [] ticks: number[] }) { - const chartRef = useRef(null) - const yAxisWidth = useYaxisWidth(chartRef) const chartTime = useStore($chartTime) const filter = useStore($containerFilter) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const chartConfig = useMemo(() => { let config = {} as Record< @@ -65,12 +62,12 @@ export default function ContainerCpuChart({ // } return ( -
+
{/* {!yAxisSet && } */} (x % 1 === 0 ? x : x.toFixed(1))} + tickFormatter={(x) => { + const val = (x % 1 === 0 ? x : x.toFixed(1)) + '%' + return updateYAxisWidth(val) + }} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) const filter = useStore($containerFilter) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const chartConfig = useMemo(() => { let config = {} as Record< @@ -72,12 +69,12 @@ export default function ContainerMemChart({ // } return ( -
+
{/* {!yAxisSet && } */} Math.ceil(max)]} tickLine={false} axisLine={false} - unit={' GB'} width={yAxisWidth} - tickFormatter={(value) => toFixedWithoutTrailingZeros(value / 1024, 2)} + tickFormatter={(value) => { + const val = toFixedWithoutTrailingZeros(value / 1024, 2) + ' GB' + return updateYAxisWidth(val) + }} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) const filter = useStore($containerFilter) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const chartConfig = useMemo(() => { let config = {} as Record< @@ -72,12 +69,12 @@ export default function ContainerCpuChart({ // } return ( -
+
{/* {!yAxisSet && } */} toFixedWithoutTrailingZeros(value, 2)} + tickFormatter={(value) => { + const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s' + return updateYAxisWidth(val) + }} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() return ( -
+
updateYAxisWidth(value + '%')} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const diskSize = useMemo(() => { return Math.round(systemData.at(-1)?.stats.d ?? NaN) }, [systemData]) return ( -
+
{/* {!yAxisSet && } */} updateYAxisWidth(value + ' GB')} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) - - // if (!systemData.length || !ticks.length) { - // return - // } + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() return ( -
+
{/* {!yAxisSet && } */} (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} axisLine={false} - unit={' MB/s'} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const diskSize = useMemo(() => { const size = systemData.at(-1)?.stats.efs?.[fs].d ?? 0 @@ -29,11 +26,11 @@ export default function ExFsDiskChart({ }, [systemData]) return ( -
+
updateYAxisWidth(value + ' GB')} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) - - // if (!systemData.length || !ticks.length) { - // return - // } + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() return ( -
+
{/* {!yAxisSet && } */} (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} axisLine={false} - unit={' MB/s'} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) const chartTime = useStore($chartTime) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() const totalMem = useMemo(() => { return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1) }, [systemData]) return ( -
+
{/* {!yAxisSet && } */} { + const val = toFixedFloat(value, 1) + return updateYAxisWidth(val + ' GB') + }} /> )} (null) - const yAxisWidth = useYaxisWidth(chartRef) - - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() return ( -
+
@@ -44,7 +40,7 @@ export default function SwapChart({ width={yAxisWidth} tickLine={false} axisLine={false} - unit={' GB'} + tickFormatter={(value) => updateYAxisWidth(value + ' GB')} /> (null) - const yAxisWidth = useYaxisWidth(chartRef) const chartTime = useStore($chartTime) + const { yAxisWidth, updateYAxisWidth } = useYAxisWidth() /** Format temperature data for chart and assign colors */ const newChartData = useMemo(() => { @@ -55,15 +54,13 @@ export default function TemperatureChart({ return chartData }, [systemData]) - const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth]) - return ( -
+
{/* {!yAxisSet && } */} toFixedWithoutTrailingZeros(value, 2)} + tickFormatter={(value) => { + const val = toFixedWithoutTrailingZeros(value, 2) + return updateYAxisWidth(val + ' °C') + }} tickLine={false} axisLine={false} - unit={' °C'} /> ) { - const [yAxisWidth, setYAxisWidth] = useState(180) - useEffect(() => { - let interval = setInterval(() => { - // console.log('chartRef', chartRef.current) - const yAxisElement = chartRef?.current?.querySelector('.yAxis') - if (yAxisElement) { - // console.log('yAxisElement', yAxisElement) - clearInterval(interval) - setYAxisWidth(yAxisElement.getBoundingClientRect().width + 24) - } - }, 16) - return () => clearInterval(interval) - }, []) - return yAxisWidth +/** Sets the correct width of the y axis in recharts based on the longest label */ +export function useYAxisWidth() { + const [yAxisWidth, setYAxisWidth] = useState(0) + let maxChars = 0 + let timeout: Timer + function updateYAxisWidth(str: string) { + if (str.length > maxChars) { + maxChars = str.length + const div = document.createElement('div') + div.className = 'text-xs tabular-nums tracking-tighter table sr-only' + div.innerHTML = str + clearTimeout(timeout) + timeout = setTimeout(() => { + document.body.appendChild(div) + setYAxisWidth(div.offsetWidth + 24) + document.body.removeChild(div) + }) + } + return str + } + return { yAxisWidth, updateYAxisWidth } } export function useClampedIsInViewport(options: HookOptions): [boolean | null, CallbackRef] { diff --git a/beszel/site/src/main.tsx b/beszel/site/src/main.tsx index 60438f9..74762db 100644 --- a/beszel/site/src/main.tsx +++ b/beszel/site/src/main.tsx @@ -1,5 +1,5 @@ import './index.css' -import { Suspense, lazy, useEffect } from 'react' +import { Suspense, lazy, useEffect, StrictMode } from 'react' import ReactDOM from 'react-dom/client' import Home from './components/routes/home.tsx' import { ThemeProvider } from './components/theme-provider.tsx' @@ -218,10 +218,10 @@ const Layout = () => { ReactDOM.createRoot(document.getElementById('app')!).render( // strict mode in dev mounts / unmounts components twice // and breaks the clipboard dialog - // + // - // + // )