From 8a5a4bc0674f0b1e55ecba37a6b6a4567bdbf1f2 Mon Sep 17 00:00:00 2001 From: Brandon McFarlin <6525520+Brandawg93@users.noreply.github.com> Date: Sun, 29 Dec 2024 22:56:36 -0500 Subject: [PATCH] mui charts --- __tests__/unit/app/page.test.tsx | 5 - .../unit/client/components/gauge.test.tsx | 4 - .../client/components/line-chart.test.tsx | 4 - .../client/components/watts-chart.test.tsx | 4 - package.json | 3 - pnpm-lock.yaml | 42 ------ src/client/components/charts-container.tsx | 5 - src/client/components/line-chart.tsx | 120 ++++++++---------- src/client/components/watts-chart.tsx | 106 +++++++--------- 9 files changed, 105 insertions(+), 188 deletions(-) diff --git a/__tests__/unit/app/page.test.tsx b/__tests__/unit/app/page.test.tsx index c01473a..fe695bb 100644 --- a/__tests__/unit/app/page.test.tsx +++ b/__tests__/unit/app/page.test.tsx @@ -23,11 +23,6 @@ jest.mock('@tanstack/react-query', () => { } }) -jest.mock('react-chartjs-2', () => ({ - Line: () => null, - Doughnut: () => null, -})) - jest.mock('../../../src/app/actions', () => ({ getDevices: jest.fn(), checkSettings: jest.fn(), diff --git a/__tests__/unit/client/components/gauge.test.tsx b/__tests__/unit/client/components/gauge.test.tsx index 5f0fe15..e25579a 100644 --- a/__tests__/unit/client/components/gauge.test.tsx +++ b/__tests__/unit/client/components/gauge.test.tsx @@ -2,10 +2,6 @@ import React from 'react' import { render, fireEvent } from '@testing-library/react' import Gauge from '@/client/components/gauge' -jest.mock('react-chartjs-2', () => ({ - Doughnut: () => null, -})) - describe('Gauge', () => { it('renders', () => { const { getByTestId } = render() diff --git a/__tests__/unit/client/components/line-chart.test.tsx b/__tests__/unit/client/components/line-chart.test.tsx index bf9c246..b64759d 100644 --- a/__tests__/unit/client/components/line-chart.test.tsx +++ b/__tests__/unit/client/components/line-chart.test.tsx @@ -3,10 +3,6 @@ import { render } from '@testing-library/react' import LineChart from '@/client/components/line-chart' import { DEVICE } from '@/common/types' -jest.mock('react-chartjs-2', () => ({ - Line: () => null, -})) - const device: DEVICE = { vars: { 'input.voltage': { diff --git a/__tests__/unit/client/components/watts-chart.test.tsx b/__tests__/unit/client/components/watts-chart.test.tsx index 066d2f4..98db941 100644 --- a/__tests__/unit/client/components/watts-chart.test.tsx +++ b/__tests__/unit/client/components/watts-chart.test.tsx @@ -3,10 +3,6 @@ import { render } from '@testing-library/react' import WattsChart from '@/client/components/watts-chart' import { DEVICE } from '@/common/types' -jest.mock('react-chartjs-2', () => ({ - Line: () => null, -})) - const device: DEVICE = { vars: { 'ups.realpower': { diff --git a/package.json b/package.json index 1f507c5..2e3ef04 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,6 @@ "@mui/x-charts": "^7.23.2", "@tanstack/react-query": "^5.62.8", "@tanstack/react-table": "^8.20.6", - "chart.js": "^4.4.7", - "chartjs-plugin-annotation": "^3.1.0", "i18next": "^24.1.2", "i18next-browser-languagedetector": "^8.0.2", "i18next-resources-to-backend": "^1.2.1", @@ -48,7 +46,6 @@ "next": "^15.1.1", "next-i18next": "^15.4.1", "react": "^19.0.0", - "react-chartjs-2": "^5.2.0", "react-dom": "^19.0.0", "react-i18next": "^15.2.0", "react-icons": "^5.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6aa70e8..df2df46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,12 +41,6 @@ importers: '@tanstack/react-table': specifier: ^8.20.6 version: 8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - chart.js: - specifier: ^4.4.7 - version: 4.4.7 - chartjs-plugin-annotation: - specifier: ^3.1.0 - version: 3.1.0(chart.js@4.4.7) i18next: specifier: ^24.1.2 version: 24.1.2(typescript@5.7.2) @@ -71,9 +65,6 @@ importers: react: specifier: ^19.0.0 version: 19.0.0 - react-chartjs-2: - specifier: ^5.2.0 - version: 5.2.0(chart.js@4.4.7)(react@19.0.0) react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) @@ -845,9 +836,6 @@ packages: '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} - '@kurkle/color@0.3.2': - resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} - '@material-tailwind/react@2.1.10': resolution: {integrity: sha512-xGU/mLDKDBp/qZ8Dp2XR7fKcTpDuFeZEBqoL9Bk/29kakKxNxjUGYSRHEFLsyOFf4VIhU6WGHdIS7tOA3QGJHA==} peerDependencies: @@ -1787,15 +1775,6 @@ packages: character-reference-invalid@1.1.4: resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} - chart.js@4.4.7: - resolution: {integrity: sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==} - engines: {pnpm: '>=8'} - - chartjs-plugin-annotation@3.1.0: - resolution: {integrity: sha512-EkAed6/ycXD/7n0ShrlT1T2Hm3acnbFhgkIEJLa0X+M6S16x0zwj1Fv4suv/2bwayCT3jGPdAtI9uLcAMToaQQ==} - peerDependencies: - chart.js: '>=4.0.0' - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -3778,12 +3757,6 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-chartjs-2@5.2.0: - resolution: {integrity: sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==} - peerDependencies: - chart.js: ^4.1.1 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-copy-to-clipboard@5.1.0: resolution: {integrity: sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==} peerDependencies: @@ -5455,8 +5428,6 @@ snapshots: '@jsdevtools/ono@7.1.3': {} - '@kurkle/color@0.3.2': {} - '@material-tailwind/react@2.1.10(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@floating-ui/react': 0.19.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -6771,14 +6742,6 @@ snapshots: character-reference-invalid@1.1.4: {} - chart.js@4.4.7: - dependencies: - '@kurkle/color': 0.3.2 - - chartjs-plugin-annotation@3.1.0(chart.js@4.4.7): - dependencies: - chart.js: 4.4.7 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -9001,11 +8964,6 @@ snapshots: strip-json-comments: 2.0.1 optional: true - react-chartjs-2@5.2.0(chart.js@4.4.7)(react@19.0.0): - dependencies: - chart.js: 4.4.7 - react: 19.0.0 - react-copy-to-clipboard@5.1.0(react@19.0.0): dependencies: copy-to-clipboard: 3.3.3 diff --git a/src/client/components/charts-container.tsx b/src/client/components/charts-container.tsx index e477d47..907625b 100644 --- a/src/client/components/charts-container.tsx +++ b/src/client/components/charts-container.tsx @@ -1,15 +1,10 @@ 'use client' -import 'chart.js/auto' import React from 'react' -import { Chart } from 'chart.js' -import annotationPlugin from 'chartjs-plugin-annotation' import { VARS, DeviceData } from '@/common/types' import LineChart from '@/client/components/line-chart' import WattsChart from '@/client/components/watts-chart' -Chart.register(annotationPlugin) - type Props = { vars: VARS data: DeviceData diff --git a/src/client/components/line-chart.tsx b/src/client/components/line-chart.tsx index 2d6345c..03037d6 100644 --- a/src/client/components/line-chart.tsx +++ b/src/client/components/line-chart.tsx @@ -1,9 +1,17 @@ import React, { useEffect, useState, useRef, useContext } from 'react' -import { Line } from 'react-chartjs-2' import { Card } from '@material-tailwind/react' - +import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer' +import { ChartsLegend } from '@mui/x-charts/ChartsLegend' +import { ChartsGrid } from '@mui/x-charts/ChartsGrid' +import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine' +import { LinePlot, MarkPlot } from '@mui/x-charts/LineChart' +import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis' +import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis' +import { ThemeProvider, createTheme } from '@mui/material/styles' +import CssBaseline from '@mui/material/CssBaseline' import { useTranslation } from 'react-i18next' import { LanguageContext } from '@/client/context/language' +import { ThemeContext } from '../context/theme' type Props = { id: string @@ -16,6 +24,12 @@ type Props = { export default function LineChart(props: Props) { const { id, inputVoltage, inputVoltageNominal, outputVoltage, updated } = props const lng = useContext(LanguageContext) + const { theme } = useContext(ThemeContext) + const darkTheme = createTheme({ + palette: { + mode: theme, + }, + }) const { t } = useTranslation(lng) const [inputVoltageData, setInputVoltageData] = useState>([]) const [outputVoltageData, setOutputVoltageData] = useState>([]) @@ -35,69 +49,47 @@ export default function LineChart(props: Props) { }, [id, inputVoltage, outputVoltage, updated]) return ( - - ''), - datasets: [ - { - label: t('lineChart.inputVoltage'), - data: inputVoltageData, - fill: false, - borderColor: 'rgb(8, 143, 143)', - tension: 0.1, - }, + + + + index) }]} + yAxis={[ { - label: t('lineChart.outputVoltage'), - data: outputVoltageData, - fill: false, - borderColor: 'rgb(255, 83, 73)', - tension: 0.1, - }, - { - label: t('lineChart.nominalInputVoltage'), - data: [], - borderColor: 'black', - borderDash: [6, 6], - borderDashOffset: 0, - borderWidth: 3, - backgroundColor: 'rgb(0, 0, 0, 0)', - }, - ], - }} - options={{ - animation: { - duration: window.matchMedia('(prefers-reduced-motion: no-preference)').matches ? 1000 : 0, - }, - scales: { - y: { - ticks: { - callback: (tickValue: string | number) => `${tickValue}V`, - }, - }, - }, - maintainAspectRatio: false, - plugins: { - annotation: { - annotations: { - nominal: { - type: 'line', - borderColor: 'black', - borderDash: [6, 6], - borderDashOffset: 0, - borderWidth: 3, - scaleID: 'y', - value: inputVoltageNominal, - }, - }, + scaleType: 'linear', + valueFormatter: (value: number) => `${value}V`, + min: inputVoltageNominal + ? Math.min(...inputVoltageData, ...outputVoltageData, inputVoltageNominal) + : Math.min(...inputVoltageData, ...outputVoltageData), + max: inputVoltageNominal + ? Math.max(...inputVoltageData, ...outputVoltageData, inputVoltageNominal) + : Math.max(...inputVoltageData, ...outputVoltageData), }, - }, - }} - /> - + ]} + > + + + {inputVoltageNominal && ( + + )} + + + + + + + ) } diff --git a/src/client/components/watts-chart.tsx b/src/client/components/watts-chart.tsx index e94c732..24b6ba5 100644 --- a/src/client/components/watts-chart.tsx +++ b/src/client/components/watts-chart.tsx @@ -1,9 +1,17 @@ import React, { useEffect, useState, useRef, useContext } from 'react' -import { Line } from 'react-chartjs-2' import { Card } from '@material-tailwind/react' +import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer' +import { ChartsLegend } from '@mui/x-charts/ChartsLegend' +import { ChartsGrid } from '@mui/x-charts/ChartsGrid' +import { ChartsReferenceLine } from '@mui/x-charts/ChartsReferenceLine' +import { LinePlot, MarkPlot } from '@mui/x-charts/LineChart' +import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis' +import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis' +import { ThemeProvider, createTheme } from '@mui/material/styles' +import CssBaseline from '@mui/material/CssBaseline' import { useTranslation } from 'react-i18next' - import { LanguageContext } from '@/client/context/language' +import { ThemeContext } from '../context/theme' type Props = { id: string @@ -17,6 +25,12 @@ export default function WattsChart(props: Props) { const [dataPoints, setDataPoints] = useState>([]) const prevDataRef = useRef(id) const lng = useContext(LanguageContext) + const { theme } = useContext(ThemeContext) + const darkTheme = createTheme({ + palette: { + mode: theme, + }, + }) const { t } = useTranslation(lng) useEffect(() => { @@ -30,62 +44,40 @@ export default function WattsChart(props: Props) { }, [id, realpower, updated]) return ( - - ''), - datasets: [ - { - label: t('wattsChart.realpower'), - data: dataPoints, - fill: false, - borderColor: 'rgb(8, 143, 143)', - tension: 0.1, - }, + + + + index) }]} + yAxis={[ { - label: t('wattsChart.nominalRealpower'), - data: [], - borderColor: 'black', - borderDash: [6, 6], - borderDashOffset: 0, - borderWidth: 3, - backgroundColor: 'rgb(0, 0, 0, 0)', - }, - ], - }} - options={{ - animation: { - duration: window.matchMedia('(prefers-reduced-motion: no-preference)').matches ? 1000 : 0, - }, - scales: { - y: { - ticks: { - callback: (tickValue: string | number) => `${tickValue}W`, - }, - }, - }, - maintainAspectRatio: false, - plugins: { - annotation: { - annotations: { - nominal: { - type: 'line', - borderColor: 'black', - borderDash: [6, 6], - borderDashOffset: 0, - borderWidth: 3, - scaleID: 'y', - value: realpowerNominal, - }, - }, + scaleType: 'linear', + valueFormatter: (value: number) => `${value}V`, + min: realpowerNominal ? Math.min(...dataPoints, realpowerNominal) : Math.min(...dataPoints), + max: realpowerNominal ? Math.max(...dataPoints, realpowerNominal) : Math.max(...dataPoints), }, - }, - }} - /> - + ]} + > + + + {realpowerNominal && ( + + )} + + + + + + + ) }