diff --git a/components/Graph.js b/components/Graph.js index cdbfc31..e24487b 100644 --- a/components/Graph.js +++ b/components/Graph.js @@ -1,71 +1,101 @@ import React from 'react'; import { View, StyleSheet } from 'react-native'; +import { useWindowDimensions } from 'react-native'; //import Svg, {Polyline, Polygon, Rect, G} from 'react-native-svg-web'; -import Svg, { Polyline, Polygon, Rect, G, Text } from 'react-native-svg'; +import Svg, { Polyline, Polygon, Rect, G, Text, Circle } from 'react-native-svg'; import { connect } from 'react-redux'; -function computeTickMark(largest, mostTicks) { +function computeTickMarks(largest, mostTicks) { const minimum = largest / mostTicks const magnitude = 10 ** Math.floor(Math.log10(minimum)) const residual = minimum / magnitude + let tickInterval = 0; if (residual > 5) - return 10 * magnitude + tickInterval = 10 * magnitude; else if (residual > 2) - return 5 * magnitude + tickInterval = 5 * magnitude; else if (residual > 1) - return 2 * magnitude + tickInterval = 2 * magnitude; else - return magnitude + tickInterval = magnitude; + + let result = []; + let nextTick = tickInterval; + while (nextTick < largest) { + result.push(nextTick); + nextTick += tickInterval; + } + return result; } +let isFirstRender = true; + const Graph = props => { const graphHeight = 100; + const numPoints = 300; + const yLabelSpace = 40; + const graphWidth = numPoints + yLabelSpace; + const minKgScale = 3; // scale such that upper graph value is n kg - const data = props.data.slice(-300); - const maxElement = data.reduce((running, x) => Math.max(x, running), 2 / props.kgFactor); + const data = props.data.slice(-numPoints); + const maxValueDeviceCoord = data.reduce((running, x) => Math.max(x, running), minKgScale / props.kgFactor); + const maxValueKg = Math.max(maxValueDeviceCoord * props.kgFactor, minKgScale); - const coordStr = data.map((element, i) => `${i}, ${100 - (element * 100 / maxElement)}`); + const dataInDeviceCoordToSvgCoordX = x => yLabelSpace + x; + const dataInDeviceCoordToSvgCoordY = y => graphHeight - (y * 100 / maxValueDeviceCoord); + const dataInKgToSvgCoordX = dataInDeviceCoordToSvgCoordX; + const dataInKgToSvgCoordY = y => dataInDeviceCoordToSvgCoordY(y / props.kgFactor); - const tick = computeTickMark(maxElement * props.kgFactor * 0.6, 4); - let ticks = []; - let nextTick = tick; - while (nextTick < maxElement * props.kgFactor) { - ticks.push(nextTick); - nextTick += tick; - } + const coordStr = data.map((element, i) => `${dataInDeviceCoordToSvgCoordX(i)}, ${dataInDeviceCoordToSvgCoordY(element)}`).join(" "); + const ticks = computeTickMarks(maxValueKg * 0.9, 4); + let viewBox = `0 0 ${graphWidth} ${graphHeight}`; + + const cutOffIndex = Math.max(0, props.data.size - numPoints); + const peaksToDisplay = props.peaks.filter(p => p > cutOffIndex) + const peaksXCoords = peaksToDisplay.map(p => dataInDeviceCoordToSvgCoordX(p - cutOffIndex)); + const peaksYCoords = peaksToDisplay.map(p => dataInDeviceCoordToSvgCoordY(props.data.get(p))); return ( - - - - {ticks.map(tick => ( - - - + + + {ticks.map(tick => ( + + + {tick} kg - - ) - )} + + ) + )} + {peaksXCoords.zip(peaksYCoords).map(peak => ( + + ))} ); @@ -75,9 +105,9 @@ const Graph = props => { const mapStateToProps = (state) => { return { data: state.deviceState.measurements, - kgFactor: state.settings.analysis.kgFactor + kgFactor: state.settings.analysis.kgFactor, + peaks: state.deviceState.analysis.peaks, }; }; - export default connect(mapStateToProps)(Graph); diff --git a/components/IconCard.js b/components/IconCard.js index 4f58635..dcae824 100644 --- a/components/IconCard.js +++ b/components/IconCard.js @@ -30,7 +30,7 @@ const styles = StyleSheet.create({ }); IconCard.defaultProps = { - fontSize: 85, + fontSize: 65, flex: 1 }; diff --git a/components/LiveTrainingView.js b/components/LiveTrainingView.js index cde8a66..d4b1cac 100644 --- a/components/LiveTrainingView.js +++ b/components/LiveTrainingView.js @@ -16,7 +16,7 @@ function LiveTrainingView(props) { props.navigation.navigate('Home'); }; const laps = (analysis.peaks.size / props.peaksPerLap).toFixed(1); - const totalMomentum = Math.trunc(analysis.totalMomentum / 10000); + const totalMomentum = Math.trunc(analysis.totalMomentum * props.kgFactor / 10 / 60); useKeepAwake(); @@ -70,6 +70,7 @@ const mapStateToProps = (state) => { session: state.deviceState, peaksPerLap: state.settings.analysis.peaksPerLap, theme: state.settings.theme, + kgFactor: state.settings.analysis.kgFactor, }; }; diff --git a/data_processing/DataAnalysis.js b/data_processing/DataAnalysis.js index dc8fd79..5b9e608 100644 --- a/data_processing/DataAnalysis.js +++ b/data_processing/DataAnalysis.js @@ -22,10 +22,11 @@ export default class DataAnalysis { else { this._resetCache(analysisParameters, sessionId); newData = allMeasurements; + console.log("cache reset"); } // peaks - const newPeaks = this.peakDetectorSimple.addVector(newData); + const newPeaks = this.peakDetectorSimple.addVector(newData.toArray()); this.allPeaks = this.allPeaks.concat(List(newPeaks)); // aggregated sum/max @@ -43,7 +44,7 @@ export default class DataAnalysis { peaks: this.allPeaks, totalTime: allMeasurements / analysisParameters.numMeasurementsPerSec, - totalMomentum: this.aggregatedMomentum / allMeasurements.size, + totalMomentum: this.aggregatedMomentum, peakMax: this.peakMax, momentumWindow: momentumWindow, diff --git a/data_processing/PeakDetection.js b/data_processing/PeakDetection.js index d331036..713fadb 100644 --- a/data_processing/PeakDetection.js +++ b/data_processing/PeakDetection.js @@ -21,6 +21,7 @@ class PeakDetectorSimple { addVector(vec) { let result = []; + for (let i = 0; i < vec.length; ++i) { const res = this.add(vec[i]); if(res !== null) diff --git a/state/DeviceReduxCoupling.js b/state/DeviceReduxCoupling.js index c62cadf..027da32 100644 --- a/state/DeviceReduxCoupling.js +++ b/state/DeviceReduxCoupling.js @@ -126,10 +126,8 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => { case DEVICE_DISCONNECT: return { ...INITIAL_DEVICE_STATE, connState: ConnState.DISCONNECTED }; case SESSION_STARTED: - console.log("session started"); return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_RUNNING, sessionId: action.sessionId }; case SESSION_STOPPED: - console.log("session stopped"); return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED }; case START_SESSION: if(state.connState === ConnState.SESSION_STARTED) diff --git a/state/Reducer.js b/state/Reducer.js index f0cbd06..c784ed9 100644 --- a/state/Reducer.js +++ b/state/Reducer.js @@ -34,10 +34,10 @@ const INITIAL_SETTINGS = { windowSizeInSecs: 5, numMeasurementsPerSec: 10, - kgFactor: 1.0 / 1100.0, + kgFactor: 1.0 / 700.0, peakDetector: 'SIMPLE', // either 'SIMPLE' or 'ZSCORE' - peakDetectorSimpleThreshold: 2500, + peakDetectorSimpleThreshold: 2000, peakDetectorZScoreLag: 8, // peak detector z-score values peakDetectorZScoreThreshold: 2,