mirror of
https://github.com/henrygd/beszel.git
synced 2026-09-30 13:27:46 +02:00
fix(site): even y-axis ticks on system charts (#2466)
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
|||||||
ChartLegendContent,
|
ChartLegendContent,
|
||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
|
fixedDomainTicks,
|
||||||
xAxis,
|
xAxis,
|
||||||
} from "@/components/ui/chart"
|
} from "@/components/ui/chart"
|
||||||
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
||||||
@@ -143,6 +144,7 @@ export default function AreaChartDefault({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
domain={domain ?? [0, max ?? "auto"]}
|
domain={domain ?? [0, max ?? "auto"]}
|
||||||
|
ticks={fixedDomainTicks(domain ?? [0, max ?? "auto"])}
|
||||||
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ChartLegendContent,
|
ChartLegendContent,
|
||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
|
fixedDomainTicks,
|
||||||
xAxis,
|
xAxis,
|
||||||
} from "@/components/ui/chart"
|
} from "@/components/ui/chart"
|
||||||
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
import { chartMargin, cn, formatShortDate } from "@/lib/utils"
|
||||||
@@ -186,6 +187,7 @@ export default function LineChartDefault({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
domain={domain ?? [0, max ?? "auto"]}
|
domain={domain ?? [0, max ?? "auto"]}
|
||||||
|
ticks={fixedDomainTicks(domain ?? [0, max ?? "auto"])}
|
||||||
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
tickFormatter={(value, index) => updateYAxisWidth(tickFormatter(value, index))}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
@@ -199,6 +201,7 @@ export default function LineChartDefault({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={rightAxisWidth}
|
width={rightAxisWidth}
|
||||||
domain={domain2 ?? [0, max2 ?? "auto"]}
|
domain={domain2 ?? [0, max2 ?? "auto"]}
|
||||||
|
ticks={fixedDomainTicks(domain2 ?? [0, max2 ?? "auto"])}
|
||||||
tickFormatter={tickFormatter2 ?? tickFormatter}
|
tickFormatter={tickFormatter2 ?? tickFormatter}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useContainerDataPoints } from "@/components/charts/hooks"
|
|||||||
import { decimalString, toFixedFloat } from "@/lib/utils"
|
import { decimalString, toFixedFloat } from "@/lib/utils"
|
||||||
import type { ChartConfig } from "@/components/ui/chart"
|
import type { ChartConfig } from "@/components/ui/chart"
|
||||||
import type { ChartData } from "@/types"
|
import type { ChartData } from "@/types"
|
||||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
|
||||||
import CpuCoresSheet from "../cpu-sheet"
|
import CpuCoresSheet from "../cpu-sheet"
|
||||||
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
||||||
import { dockerOrPodman } from "../chart-data"
|
import { dockerOrPodman } from "../chart-data"
|
||||||
@@ -52,7 +51,6 @@ export function CpuChart({
|
|||||||
]}
|
]}
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
/>
|
/>
|
||||||
</ChartCard>
|
</ChartCard>
|
||||||
)
|
)
|
||||||
@@ -87,7 +85,6 @@ export function ContainerCpuChart({
|
|||||||
dataPoints={dataPoints}
|
dataPoints={dataPoints}
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
showTotal={true}
|
showTotal={true}
|
||||||
reverseStackOrder={true}
|
reverseStackOrder={true}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
|||||||
import type { SystemStatsRecord } from "@/types"
|
import type { SystemStatsRecord } from "@/types"
|
||||||
import { ChartCard, SelectAvgMax } from "../chart-card"
|
import { ChartCard, SelectAvgMax } from "../chart-card"
|
||||||
import { Unit } from "@/lib/enums"
|
import { Unit } from "@/lib/enums"
|
||||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
|
||||||
import DiskIoSheet from "../disk-io-sheet"
|
import DiskIoSheet from "../disk-io-sheet"
|
||||||
import type { SystemData } from "../use-system-data"
|
import type { SystemData } from "../use-system-data"
|
||||||
import { useStore } from "@nanostores/react"
|
import { useStore } from "@nanostores/react"
|
||||||
@@ -194,7 +193,6 @@ export function DiskIOChart({ systemData, extraFsName }: { systemData: SystemDat
|
|||||||
<AreaChartDefault
|
<AreaChartDefault
|
||||||
chartData={chartData}
|
chartData={chartData}
|
||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
// domain={pinnedAxisDomain(true)}
|
|
||||||
showTotal={true}
|
showTotal={true}
|
||||||
dataPoints={[
|
dataPoints={[
|
||||||
{
|
{
|
||||||
@@ -250,7 +248,6 @@ export function DiskUtilizationChart({ systemData, extraFsName }: { systemData:
|
|||||||
>
|
>
|
||||||
<AreaChartDefault
|
<AreaChartDefault
|
||||||
chartData={chartData}
|
chartData={chartData}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import type { ChartData, SystemStatsRecord } from "@/types"
|
|||||||
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
import { ChartCard, FilterBar, SelectAvgMax } from "../chart-card"
|
||||||
import { dockerOrPodman } from "../chart-data"
|
import { dockerOrPodman } from "../chart-data"
|
||||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
|
||||||
|
|
||||||
export function MemoryChart({
|
export function MemoryChart({
|
||||||
chartData,
|
chartData,
|
||||||
@@ -114,7 +113,6 @@ export function ContainerMemoryChart({
|
|||||||
const { value, unit } = formatBytes(item.value, false, Unit.Bytes, true)
|
const { value, unit } = formatBytes(item.value, false, Unit.Bytes, true)
|
||||||
return `${decimalString(value)} ${unit}`
|
return `${decimalString(value)} ${unit}`
|
||||||
}}
|
}}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
showTotal={true}
|
showTotal={true}
|
||||||
reverseStackOrder={true}
|
reverseStackOrder={true}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useContainerDataPoints } from "@/components/charts/hooks"
|
|||||||
import { $userSettings } from "@/lib/stores"
|
import { $userSettings } from "@/lib/stores"
|
||||||
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
||||||
import type { ChartConfig } from "@/components/ui/chart"
|
import type { ChartConfig } from "@/components/ui/chart"
|
||||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
|
||||||
import type { ChartData, SystemStatsRecord } from "@/types"
|
import type { ChartData, SystemStatsRecord } from "@/types"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import NetworkSheet from "../network-sheet"
|
import NetworkSheet from "../network-sheet"
|
||||||
@@ -171,7 +170,6 @@ export function ContainerNetworkChart({
|
|||||||
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
|
||||||
}}
|
}}
|
||||||
contentFormatter={contentFormatter}
|
contentFormatter={contentFormatter}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
showTotal={true}
|
showTotal={true}
|
||||||
reverseStackOrder={true}
|
reverseStackOrder={true}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export default memo(function CpuCoresSheet({
|
|||||||
opacity: 0.35,
|
opacity: 0.35,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
tickFormatter={(val) => `${val}%`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||||
contentFormatter={({ value }) => `${value}%`}
|
contentFormatter={({ value }) => `${value}%`}
|
||||||
/>
|
/>
|
||||||
</ChartCard>
|
</ChartCard>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
|
|||||||
import { ChartCard, SelectAvgMax } from "@/components/routes/system/chart-card"
|
import { ChartCard, SelectAvgMax } from "@/components/routes/system/chart-card"
|
||||||
import type { SystemData } from "@/components/routes/system/use-system-data"
|
import type { SystemData } from "@/components/routes/system/use-system-data"
|
||||||
import { diskDataFns, DiskUtilizationChart } from "./charts/disk-charts"
|
import { diskDataFns, DiskUtilizationChart } from "./charts/disk-charts"
|
||||||
import { pinnedAxisDomain } from "@/components/ui/chart"
|
|
||||||
|
|
||||||
export default memo(function DiskIOSheet({
|
export default memo(function DiskIOSheet({
|
||||||
systemData,
|
systemData,
|
||||||
@@ -129,7 +128,6 @@ export default memo(function DiskIOSheet({
|
|||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
chartProps={chartProps}
|
chartProps={chartProps}
|
||||||
showTotal={true}
|
showTotal={true}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
itemSorter={(a, b) => a.order - b.order}
|
itemSorter={(a, b) => a.order - b.order}
|
||||||
reverseStackOrder={true}
|
reverseStackOrder={true}
|
||||||
dataPoints={[
|
dataPoints={[
|
||||||
@@ -176,7 +174,6 @@ export default memo(function DiskIOSheet({
|
|||||||
>
|
>
|
||||||
<AreaChartDefault
|
<AreaChartDefault
|
||||||
chartData={chartData}
|
chartData={chartData}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}%`}
|
||||||
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
contentFormatter={({ value }) => `${decimalString(value)}%`}
|
||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
@@ -216,7 +213,6 @@ export default memo(function DiskIOSheet({
|
|||||||
>
|
>
|
||||||
<AreaChartDefault
|
<AreaChartDefault
|
||||||
chartData={chartData}
|
chartData={chartData}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)}`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)}`}
|
||||||
contentFormatter={({ value }) => decimalString(value, value < 10 ? 3 : 2)}
|
contentFormatter={({ value }) => decimalString(value, value < 10 ? 3 : 2)}
|
||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
@@ -248,7 +244,6 @@ export default memo(function DiskIOSheet({
|
|||||||
>
|
>
|
||||||
<AreaChartDefault
|
<AreaChartDefault
|
||||||
chartData={chartData}
|
chartData={chartData}
|
||||||
domain={pinnedAxisDomain()}
|
|
||||||
tickFormatter={(val) => `${toFixedFloat(val, 2)} ms`}
|
tickFormatter={(val) => `${toFixedFloat(val, 2)} ms`}
|
||||||
contentFormatter={({ value }) => `${decimalString(value)} ms`}
|
contentFormatter={({ value }) => `${decimalString(value)} ms`}
|
||||||
maxToggled={showMax}
|
maxToggled={showMax}
|
||||||
|
|||||||
@@ -474,17 +474,19 @@ export {
|
|||||||
// ChartStyle,
|
// ChartStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pinnedAxisDomain(): AxisDomain {
|
const roundFloat = (value: number) => Number(value.toPrecision(12))
|
||||||
return [
|
|
||||||
0,
|
/**
|
||||||
(dataMax: number) => {
|
* Four equal intervals for a fixed [0, max] domain (e.g. total memory or disk size), with max as the top tick.
|
||||||
if (dataMax > 10) {
|
* Recharts stops one full step before max, which leaves a large gap below the top tick.
|
||||||
return Math.round(dataMax)
|
*/
|
||||||
}
|
export function fixedDomainTicks(domain?: AxisDomain): number[] | undefined {
|
||||||
if (dataMax > 1) {
|
if (!Array.isArray(domain)) {
|
||||||
return Math.round(dataMax / 0.1) * 0.1
|
return undefined
|
||||||
}
|
}
|
||||||
return dataMax
|
const [min, max] = domain
|
||||||
},
|
if (min !== 0 || typeof max !== "number" || !(max > 0) || !Number.isFinite(max)) {
|
||||||
]
|
return undefined
|
||||||
|
}
|
||||||
|
return [0, 1, 2, 3, 4].map((i) => roundFloat((max * i) / 4))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user