diff --git a/CHANGELOG.md b/CHANGELOG.md index e9dcac4..4247800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ Todas as alterações notáveis neste projeto serão documentadas neste arquivo. O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.0.0/), e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/spec/v2.0.0.html). +## [0.9.0] - 2023-10-24 + +### Adicionado + +- Controle da janela de tempo para o experimento. Agora são exportadas apenas as medidas mais recentes, na janela de tempo definida. O intervalo de medidas exibidas segue o tamanho da janela até um limite máximo para evitar lentidão na renderização. + ## [0.8.1] - 2023-10-03 ### Alterado diff --git a/package.json b/package.json index c6d661f..41e9221 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ftrlab", "productName": "FTRLab", - "version": "0.8.1", + "version": "0.9.0", "description": "Uma aplicação desktop para um sistema de aquisição de dados em física experimental", "main": "./out/main/index.js", "author": { diff --git a/src/main/ipc/handlers/configure.ts b/src/main/ipc/handlers/configure.ts index 34dfb34..26ef237 100644 --- a/src/main/ipc/handlers/configure.ts +++ b/src/main/ipc/handlers/configure.ts @@ -161,23 +161,30 @@ export function configureIpcHandlers(devicesController: DevicesController) { const sensor: Sensor = (await SensorModel.findByPk(request.sensorId)) ?.dataValues + const maxTimestamp: number = await MeasurementModel.max('timestamp', { + where: { + sensorId: sensor.id, + }, + }) + const measurements: Measurement[] = ( await MeasurementModel.findAll({ where: { - sensorId: request.sensorId, + sensorId: sensor.id, + timestamp: { + [Op.gte]: maxTimestamp - request.timeRange, + }, }, + order: [['timestamp', 'ASC']], }) - ).map((model) => model.dataValues) + ).map((measurementM) => transformToRelativeTime(measurementM.dataValues)) const fileHeader = `t, ${sensor.quantity}` const fileBody = measurements - .sort((a, b) => a.timestamp - b.timestamp) .map( (measurement) => - `${(measurement.timestamp - startTime).toFixed(6)}, ${ - measurement.value - }`, + `${measurement.timestamp.toFixed(6)}, ${measurement.value}`, ) .join('\n') diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index ec731f1..34f96e0 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -1,16 +1,20 @@ import './styles/global.css' +import { useState } from 'react' + import { Header } from './components/Header' import { ReactQueryProvider } from './components/providers/ReactQueryProvider' import { ThemeProvider } from './components/providers/ThemeProvider' import { Sidebar } from './components/Sidebar' import { useDevices } from './features/devices/hooks/useDevices' import { ChartsArea } from './features/measurements/components/ChartsArea' +import { maxDisplayedTimeRange } from './features/measurements/constants/maxDisplayedTimeRange' import { useMeasurements } from './features/measurements/hooks/useMeasurements' export function App() { + const [timeRange, setTimeRange] = useState(maxDisplayedTimeRange) const devices = useDevices() - const { sensorMeasurements, clearMeasurements } = useMeasurements() + const { sensorMeasurements, clearMeasurements } = useMeasurements(timeRange) return ( @@ -24,10 +28,15 @@ export function App() { }} >
- + diff --git a/src/renderer/src/components/Sidebar.tsx b/src/renderer/src/components/Sidebar.tsx index 586b2e5..985161c 100644 --- a/src/renderer/src/components/Sidebar.tsx +++ b/src/renderer/src/components/Sidebar.tsx @@ -1,10 +1,14 @@ +import { Dispatch, SetStateAction } from 'react' + +import { DeviceCard } from '@renderer/features/devices/components/DeviceCard' import { devicePriorityCompare } from '@renderer/features/devices/utils/deviceOrderingPriority' +import { ControlCard } from '@renderer/features/measurements/components/ControlCard' import { Device } from '@shared/types/Device' -import { DeviceCard } from '../features/devices/components/DeviceCard' - interface SidebarProps { devices: Array + timeRange: number + setTimeRange: Dispatch> } export function Sidebar(props: SidebarProps) { @@ -15,8 +19,13 @@ export function Sidebar(props: SidebarProps) { gridArea: 'aside', }} > - {props.devices.sort(devicePriorityCompare).map((device, index) => ( - + + + {props.devices.sort(devicePriorityCompare).map((device) => ( + ))} ) diff --git a/src/renderer/src/features/measurements/components/Chart.tsx b/src/renderer/src/features/measurements/components/Chart.tsx index 4d76aea..2d35332 100644 --- a/src/renderer/src/features/measurements/components/Chart.tsx +++ b/src/renderer/src/features/measurements/components/Chart.tsx @@ -26,6 +26,7 @@ interface ChartProps { YAxis: { key: string; name: string } data: Object[] sensor: Sensor + timeRange: number } export function Chart(props: ChartProps) { @@ -116,6 +117,7 @@ export function Chart(props: ChartProps) { onClick={() => { window.api.measurements.export({ sensorId: props.sensor.id, + timeRange: props.timeRange, }) }} > diff --git a/src/renderer/src/features/measurements/components/ChartContainer.tsx b/src/renderer/src/features/measurements/components/ChartContainer.tsx index 07fa7ab..e9d90ad 100644 --- a/src/renderer/src/features/measurements/components/ChartContainer.tsx +++ b/src/renderer/src/features/measurements/components/ChartContainer.tsx @@ -7,6 +7,7 @@ import { Chart } from './Chart' interface ChartContainerProps { sensor: Sensor measurements: Measurement[] + timeRange: number } export function ChartContainer(props: ChartContainerProps) { @@ -32,6 +33,7 @@ export function ChartContainer(props: ChartContainerProps) { YAxis={serie.YAxis} data={serie.data} sensor={props.sensor} + timeRange={props.timeRange} > ) } diff --git a/src/renderer/src/features/measurements/components/ChartsArea.tsx b/src/renderer/src/features/measurements/components/ChartsArea.tsx index 9d4ee42..ba818f3 100644 --- a/src/renderer/src/features/measurements/components/ChartsArea.tsx +++ b/src/renderer/src/features/measurements/components/ChartsArea.tsx @@ -6,6 +6,7 @@ import { ChartContainer } from './ChartContainer' interface ChartsAreaProps { devices: Device[] sensorMeasurements: MeasurementsBySensor + timeRange: number } export function ChartsArea(props: ChartsAreaProps) { @@ -28,6 +29,7 @@ export function ChartsArea(props: ChartsAreaProps) { sensor={sensor} measurements={props.sensorMeasurements[sensor.id]!} key={sensor.id} + timeRange={props.timeRange} > ))} diff --git a/src/renderer/src/features/measurements/components/ControlCard.tsx b/src/renderer/src/features/measurements/components/ControlCard.tsx new file mode 100644 index 0000000..7d3f2cf --- /dev/null +++ b/src/renderer/src/features/measurements/components/ControlCard.tsx @@ -0,0 +1,35 @@ +import { Dispatch, SetStateAction } from 'react' + +import { Slider } from '@mui/material' + +import { maxDisplayedTimeRange } from '../constants/maxDisplayedTimeRange' +import { formatTime } from '../utils/formatTime' + +interface ControlCardProps { + timeRange: number + setTimeRange: Dispatch> +} + +export function ControlCard(props: ControlCardProps) { + return ( +
+

+ Janela de tempo:{' '} + {formatTime(props.timeRange)} +

+ `${value} s`} + valueLabelDisplay="auto" + scale={(value) => Math.floor(2 ** value)} + value={Math.log2(props.timeRange)} + onChange={(event, value) => { + props.setTimeRange(2 ** (value as number)) + }} + /> +
+ ) +} diff --git a/src/renderer/src/features/measurements/constants/defaultDisplayedTimeRange.ts b/src/renderer/src/features/measurements/constants/defaultDisplayedTimeRange.ts deleted file mode 100644 index 21cfcf1..0000000 --- a/src/renderer/src/features/measurements/constants/defaultDisplayedTimeRange.ts +++ /dev/null @@ -1 +0,0 @@ -export const defaultDisplayedTimeRange = 8 diff --git a/src/renderer/src/features/measurements/constants/maxDisplayedTimeRange.ts b/src/renderer/src/features/measurements/constants/maxDisplayedTimeRange.ts new file mode 100644 index 0000000..8c3b86a --- /dev/null +++ b/src/renderer/src/features/measurements/constants/maxDisplayedTimeRange.ts @@ -0,0 +1 @@ +export const maxDisplayedTimeRange = 8 diff --git a/src/renderer/src/features/measurements/hooks/useMeasurements.ts b/src/renderer/src/features/measurements/hooks/useMeasurements.ts index 1bf6dbb..523f1f4 100644 --- a/src/renderer/src/features/measurements/hooks/useMeasurements.ts +++ b/src/renderer/src/features/measurements/hooks/useMeasurements.ts @@ -1,17 +1,21 @@ import { useEffect, useState } from 'react' -import { defaultDisplayedTimeRange } from '@renderer/features/measurements/constants/defaultDisplayedTimeRange' +import { maxDisplayedTimeRange } from '@renderer/features/measurements/constants/maxDisplayedTimeRange' import { Measurement, MeasurementsBySensor } from '@shared/types/Measurement' import { transformToRelativeTime } from '../../devices/utils/transformToRelativeTime' -export function useMeasurements() { +export function useMeasurements(timeRange: number) { const [sensorMeasurements, setSensorMeasurements] = useState({}) useEffect(() => { + const displayedTimeRange = + timeRange <= maxDisplayedTimeRange ? timeRange : maxDisplayedTimeRange window.api.measurements - .findLastByDevice({ timeRange: defaultDisplayedTimeRange }) + .findLastByDevice({ + timeRange: displayedTimeRange, + }) .then(({ measurementsBySensor }) => { setSensorMeasurements(measurementsBySensor) }) @@ -40,7 +44,7 @@ export function useMeasurements() { // Filtra para manter apenas as medições mais recentes const thresholdTimestamp = Math.floor( - newSensorState.at(-1)!.timestamp - defaultDisplayedTimeRange, + newSensorState.at(-1)!.timestamp - displayedTimeRange, ) const startIndex = newSensorState.findIndex( (measurement) => measurement.timestamp > thresholdTimestamp, @@ -57,7 +61,7 @@ export function useMeasurements() { ) return removeListener - }, []) + }, [timeRange]) const clearMeasurements = async () => { await window.api.measurements.deleteAll() diff --git a/src/renderer/src/features/measurements/utils/formatTime.ts b/src/renderer/src/features/measurements/utils/formatTime.ts new file mode 100644 index 0000000..a39670a --- /dev/null +++ b/src/renderer/src/features/measurements/utils/formatTime.ts @@ -0,0 +1,13 @@ +export function formatTime(t: number) { + const hours = Math.floor(t / 3600) + const minutes = Math.floor((t - 3600 * hours) / 60) + const seconds = Math.floor((t - 3600 * hours - 60 * minutes) % 60) + + if (hours > 0) { + return `${hours}h ${minutes}min` + } else if (minutes > 0) { + return `${minutes}min ${seconds}s` + } else { + return `${seconds}s` + } +} diff --git a/src/shared/types/ipc.ts b/src/shared/types/ipc.ts index 971d058..a28f494 100644 --- a/src/shared/types/ipc.ts +++ b/src/shared/types/ipc.ts @@ -51,4 +51,5 @@ export interface UpdateDeviceSettingsRequest { export interface ExportMeasurementsRequest { sensorId: SensorId + timeRange: number }