diff --git a/src/atom/chart.ts b/src/atom/chart.ts new file mode 100644 index 0000000..6b2128f --- /dev/null +++ b/src/atom/chart.ts @@ -0,0 +1,5 @@ +import { atom } from "jotai"; + +export const cpuUsageHistoryAtom = atom([]); +export const memoryUsageHistoryAtom = atom([]); +export const graphicUsageHistoryAtom = atom([]); diff --git a/src/atom/main.ts b/src/atom/main.ts index db44c5e..a7ef9c5 100644 --- a/src/atom/main.ts +++ b/src/atom/main.ts @@ -1,4 +1,8 @@ import type { Settings } from "@/types/settingsType"; import { atom } from "jotai"; -export const settingsAtom = atom(null); +export const settingsAtom = atom({ + language: "en", + theme: "light", + display_targets: [], +}); diff --git a/src/consts/chart.ts b/src/consts/chart.ts new file mode 100644 index 0000000..bd3d409 --- /dev/null +++ b/src/consts/chart.ts @@ -0,0 +1,6 @@ +export const chartConfig = { + /** + * グラフの履歴の長さ(秒) + */ + historyLengthSec: 60, +} as const; diff --git a/src/hooks/useHardwareData.ts b/src/hooks/useHardwareData.ts new file mode 100644 index 0000000..066515f --- /dev/null +++ b/src/hooks/useHardwareData.ts @@ -0,0 +1,61 @@ +import { + cpuUsageHistoryAtom, + graphicUsageHistoryAtom, + memoryUsageHistoryAtom, +} from "@/atom/chart"; +import { chartConfig } from "@/consts/chart"; +import { + getCpuUsage, + getGpuUsage, + getMemoryUsage, +} from "@/services/hardwareService"; +import type { ChartDataType } from "@/types/chartType"; +import { type PrimitiveAtom, useSetAtom } from "jotai"; +import { useEffect } from "react"; + +type AtomActionMapping = { + atom: PrimitiveAtom; + action: () => Promise; +}; + +/** + * ハードウェア使用率の履歴を更新する + */ +export const useUsageUpdater = (dataType: ChartDataType) => { + const mapping: Record = { + cpu: { + atom: cpuUsageHistoryAtom, + action: getCpuUsage, + }, + memory: { + atom: memoryUsageHistoryAtom, + action: getMemoryUsage, + }, + gpu: { + atom: graphicUsageHistoryAtom, + action: getGpuUsage, + }, + }; + + const setHistory = useSetAtom(mapping[dataType].atom); + const getUsage = mapping[dataType].action; + + useEffect(() => { + const intervalId = setInterval(async () => { + const usage = await getUsage(); + setHistory((prev) => { + const newHistory = [...prev, usage]; + + // 履歴保持数に満たない場合は0で埋める + const paddedHistory = Array( + Math.max(chartConfig.historyLengthSec - newHistory.length, 0), + ) + .fill(null) + .concat(newHistory); + return paddedHistory.slice(-chartConfig.historyLengthSec); + }); + }, 1000); + + return () => clearInterval(intervalId); + }, [setHistory, getUsage]); +}; diff --git a/src/template/Chart.tsx b/src/template/Chart.tsx index f704487..8c731b5 100644 --- a/src/template/Chart.tsx +++ b/src/template/Chart.tsx @@ -1,76 +1,61 @@ +import { + cpuUsageHistoryAtom, + graphicUsageHistoryAtom, + memoryUsageHistoryAtom, +} from "@/atom/chart"; import { settingsAtom } from "@/atom/main"; import LineChart from "@/components/LineChart"; -import { - getCpuMemoryHistory, - getCpuUsageHistory, - getGpuUsageHistory, -} from "@/services/hardwareService"; +import { chartConfig } from "@/consts/chart"; +import { useUsageUpdater } from "@/hooks/useHardwareData"; + import { useAtom } from "jotai"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useMemo } from "react"; -const ChartTemplate = () => { - const [cpuData, setCpuData] = useState([]); - const [memoryData, setMemoryData] = useState([]); - const [gpuData, setGpuData] = useState([]); - const [labels, setLabels] = useState([]); +const labels = Array(chartConfig.historyLengthSec).fill(""); - const [settings] = useAtom(settingsAtom); +const CpuUsageChart = () => { + const [cpuUsageHistory] = useAtom(cpuUsageHistoryAtom); + useUsageUpdater("cpu"); - const fetchData = useCallback(async () => { - const seconds = 60; + return ( + + ); +}; - const newCpuDataPromise = settings?.display_targets.includes("cpu") - ? getCpuUsageHistory(seconds) - : Promise.resolve([]); - const newMemoryDataPromise = settings?.display_targets.includes("memory") - ? getCpuMemoryHistory(seconds) - : Promise.resolve([]); - const newGpuDataPromise = settings?.display_targets.includes("gpu") - ? getGpuUsageHistory(seconds) - : Promise.resolve([]); +const MemoryUsageChart = () => { + const [memoryUsageHistory] = useAtom(memoryUsageHistoryAtom); + useUsageUpdater("memory"); + + return ( + + ); +}; - const [newCpuData, newMemoryData, newGpuData] = await Promise.all([ - newCpuDataPromise, - newMemoryDataPromise, - newGpuDataPromise, - ]); +const GpuUsageChart = () => { + const [graphicUsageHistory] = useAtom(graphicUsageHistoryAtom); + useUsageUpdater("gpu"); - if (cpuData.length < seconds) { - setCpuData([...cpuData, newCpuData[newCpuData.length - 1]]); - setMemoryData([...memoryData, newMemoryData[newMemoryData.length - 1]]); - setGpuData([...gpuData, newGpuData[newGpuData.length - 1]]); - setLabels([...labels, ""]); - } else { - setCpuData([...cpuData.slice(1), newCpuData[newCpuData.length - 1]]); - setMemoryData([ - ...memoryData.slice(1), - newMemoryData[newMemoryData.length - 1], - ]); - setGpuData([...gpuData.slice(1), newGpuData[newGpuData.length - 1]]); - setLabels([...labels.slice(1), ""]); - } - }, [settings, cpuData, memoryData, gpuData, labels]); + return ( + + ); +}; - useEffect(() => { - const interval = setInterval(fetchData, 1000); - return () => clearInterval(interval); - }, [fetchData]); +const ChartTemplate = () => { + const [settings] = useAtom(settingsAtom); const renderedCharts = useMemo(() => { return ( <> - {settings?.display_targets.includes("cpu") && ( - - )} - {settings?.display_targets.includes("memory") && ( - - )} - {settings?.display_targets.includes("gpu") && ( - - )} + {settings?.display_targets.includes("cpu") && } + {settings?.display_targets.includes("memory") && } + {settings?.display_targets.includes("gpu") && } ); - }, [labels, cpuData, memoryData, gpuData, settings]); + }, [settings]); return
{renderedCharts}
; }; diff --git a/src/types/settingsType.ts b/src/types/settingsType.ts index 7296922..b618b03 100644 --- a/src/types/settingsType.ts +++ b/src/types/settingsType.ts @@ -1,5 +1,7 @@ +import type { ChartDataType } from "./chartType"; + export type Settings = { language: string; theme: "light" | "dark"; - display_targets: "cpu" | "memory" | "gpu"; + display_targets: Array; };