@@ -32,7 +32,7 @@ import {
3232 calculateMotorPowerConsumption ,
3333} from "@/lib/telemetry-utils" ;
3434import { useEffect , useState } from "react" ;
35- import { ChevronDownIcon , Download } from "lucide-react" ;
35+ import { Axis3D , ChevronDownIcon , Download } from "lucide-react" ;
3636
3737import { Button } from "@/components/ui/button" ;
3838import { Calendar } from "@/components/ui/calendar" ;
@@ -55,10 +55,31 @@ import {
5555 AlertDialogTrigger ,
5656} from "@/components/ui/alert-dialog" ;
5757import { fetchTelemetryDataInRange } from "@/lib/db-utils" ;
58+ import SimpleCard from "../telemetry/SimpleCard" ;
5859
5960// Configuration constant to enable/disable refresh interval
6061const ENABLE_REFRESH_INTERVAL = false ;
6162
63+ function integrateData ( data : any , dataKey : string ) {
64+ let integral = 0 ;
65+ for ( let i = data . length - 1 ; i > 0 ; i -- ) {
66+ const v0 = data [ i ] [ dataKey ] ;
67+ const v1 = data [ i - 1 ] [ dataKey ] ;
68+
69+ if ( v1 == null || v0 == null ) {
70+ continue ;
71+ }
72+
73+ let midValue = ( v0 + v1 ) / 2 ;
74+ let date1 = new Date ( data [ i - 1 ] . timestamp ) ;
75+ let date2 = new Date ( data [ i ] . timestamp ) ;
76+ let changeX = date2 . getTime ( ) - date1 . getTime ( ) ;
77+
78+ integral += ( midValue * changeX ) / 1000 ;
79+ }
80+ return integral ;
81+ }
82+
6283// Helper function to convert any date to CDT (UTC-5)
6384function toCDT ( date : Date | string ) : Date {
6485 const d = new Date ( date ) ;
@@ -141,6 +162,7 @@ export default function StatsGraphTab() {
141162 const [ selectedDataKeys , setSelectedDataKeys ] = useState < string [ ] > ( [
142163 "battery_main_bat_v" ,
143164 ] ) ;
165+ const [ integrals , setIntegrals ] = useState < any [ ] > ( [ ] ) ;
144166 const [ chartData , setChartData ] = useState < any [ ] > ( [ ] ) ;
145167 const [ startDate , setStartDate ] = useState < Date | undefined > ( ( ) => {
146168 return new Date ( "2025-07-04T01:00:00" ) ;
@@ -281,6 +303,14 @@ export default function StatsGraphTab() {
281303 setSelectedDataKeys ( values . map ( ( v ) => v . replace ( "." , "_" ) ) ) ;
282304 } ;
283305
306+ useEffect ( ( ) => {
307+ let calcIntegrals = [ ] ;
308+ for ( let i = 0 ; i < selectedDataKeys . length ; i ++ ) {
309+ calcIntegrals . push ( integrateData ( chartData , selectedDataKeys [ i ] ) ) ;
310+ }
311+ setIntegrals ( calcIntegrals ) ;
312+ } , [ selectedDataKeys , chartData ] ) ;
313+
284314 useEffect ( ( ) => {
285315 if ( selectedDataKeys . length > 0 && startDate && endDate ) {
286316 // Check if any custom fields are selected
@@ -926,6 +956,26 @@ export default function StatsGraphTab() {
926956 } ) }
927957 </ LineChart >
928958 </ ChartContainer >
959+ < div className = "m-4" > </ div >
960+ < div className = "grid grid-cols-3 md:grid-cols-2 gap-1" >
961+ { selectedDataKeys . map ( ( key , index ) => {
962+ const value = integrals [ index ] ;
963+ const title =
964+ "Integral Value of " +
965+ getLabelFromDataKey ( key ) +
966+ " " +
967+ Number ( value ) . toFixed ( 2 ) ;
968+ return (
969+ < SimpleCard
970+ key = { key }
971+ title = { title }
972+ unit = ""
973+ icon = { Axis3D }
974+ value = { value }
975+ />
976+ ) ;
977+ } ) }
978+ </ div >
929979 </ div >
930980 ) ;
931981}
0 commit comments