Graph & android fixes
This commit is contained in:
parent
fa1518546b
commit
a870a0af85
3
App.js
3
App.js
|
@ -13,7 +13,7 @@ import ThemedStackNavigation from './components/ThemedStackNavigation';
|
||||||
|
|
||||||
|
|
||||||
const store = createStore(swimtrackerReducer);
|
const store = createStore(swimtrackerReducer);
|
||||||
const deviceReduxCoupling = new DeviceReduxCoupling(store);
|
//const deviceReduxCoupling = new DeviceReduxCoupling(store);
|
||||||
|
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
|
@ -31,6 +31,7 @@ export default class App extends React.Component {
|
||||||
...Ionicons.font,
|
...Ionicons.font,
|
||||||
});
|
});
|
||||||
this.setState({ isReady: true });
|
this.setState({ isReady: true });
|
||||||
|
this.device = new DeviceReduxCoupling(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,34 +1,83 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {View, StyleSheet, Text} from 'react-native';
|
import { View, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
//import Svg, {Polyline, Polygon, Rect, G} from 'react-native-svg-web';
|
//import Svg, {Polyline, Polygon, Rect, G} from 'react-native-svg-web';
|
||||||
import Svg, {Polyline, Polygon, Rect, G} from 'react-native-svg';
|
import Svg, { Polyline, Polygon, Rect, G, Text } from 'react-native-svg';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
|
||||||
|
function computeTickMark(largest, mostTicks) {
|
||||||
|
const minimum = largest / mostTicks
|
||||||
|
const magnitude = 10 ** Math.floor(Math.log10(minimum))
|
||||||
|
const residual = minimum / magnitude
|
||||||
|
if (residual > 5)
|
||||||
|
return 10 * magnitude
|
||||||
|
else if (residual > 2)
|
||||||
|
return 5 * magnitude
|
||||||
|
else if (residual > 1)
|
||||||
|
return 2 * magnitude
|
||||||
|
else
|
||||||
|
return magnitude
|
||||||
|
}
|
||||||
|
|
||||||
const Graph = props => {
|
const Graph = props => {
|
||||||
const graphHeight = 100;
|
const graphHeight = 100;
|
||||||
|
|
||||||
const data = props.data.slice(-600);
|
const data = props.data.slice(-300);
|
||||||
|
const maxElement = data.reduce((running, x) => Math.max(x, running), 2 / props.kgFactor);
|
||||||
const coordStr = data.map((element, i) => `${i}, ${element / 2}`);
|
|
||||||
|
const coordStr = data.map((element, i) => `${i}, ${100 - (element * 100 / maxElement)}`);
|
||||||
|
|
||||||
|
const tick = computeTickMark(maxElement * props.kgFactor * 0.6, 4);
|
||||||
|
let ticks = [];
|
||||||
|
let nextTick = tick;
|
||||||
|
while (nextTick < maxElement * props.kgFactor) {
|
||||||
|
ticks.push(nextTick);
|
||||||
|
nextTick += tick;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{justifyContent: 'center', alignItems: 'center'}}>
|
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
|
||||||
<Svg height={graphHeight} width="80%" viewbox="0 0 100 100">
|
<Svg height={graphHeight} width="80%" viewbox="0 0 300 100">
|
||||||
<G transform={"translate(0," + graphHeight.toString() + ") scale(1, -1)"}>
|
|
||||||
<Polyline
|
<Polyline
|
||||||
points={coordStr.join(" ")}
|
points={coordStr.join(" ")}
|
||||||
stroke="black"
|
stroke="black"
|
||||||
strokeWidth="3"
|
strokeWidth="3"
|
||||||
strokeOpacity="0.5"
|
strokeOpacity="0.5"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
fill="none"
|
fill="none"
|
||||||
/>
|
/>
|
||||||
</G>
|
{ticks.map(tick => (
|
||||||
|
<React.Fragment>
|
||||||
|
<Polyline
|
||||||
|
points={`40, ${100 - (tick / props.kgFactor * 100 / maxElement)} 300, ${100 - (tick / props.kgFactor * 100 / maxElement)}`}
|
||||||
|
stroke="black"
|
||||||
|
strokeWidth="1"
|
||||||
|
strokeDasharray="5,5"
|
||||||
|
strokeOpacity="0.5"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
<Text x="5" y={`${100 - (tick / props.kgFactor * 100 / maxElement - 4) }`}
|
||||||
|
alignmentBaseline="center"
|
||||||
|
strokeOpacity="0.5"
|
||||||
|
fillOpacity="0.5"
|
||||||
|
fontSize="9pt">{tick} kg </Text>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</Svg>
|
</Svg>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default Graph;
|
const mapStateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
data: state.deviceState.measurements,
|
||||||
|
kgFactor: state.settings.analysis.kgFactor
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(Graph);
|
||||||
|
|
|
@ -50,7 +50,7 @@ function HomeView(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
return { running: state.deviceState.connState == ConnState.CONNECTED_STARTING };
|
return { running: state.deviceState.connState === ConnState.CONNECTED_RUNNING };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps)(HomeView);
|
export default connect(mapStateToProps)(HomeView);
|
||||||
|
|
|
@ -31,6 +31,7 @@ function LiveTrainingView(props) {
|
||||||
<IconCard label="BAHNEN" value={laps} iconName="retweet" iconType="AntDesign" />
|
<IconCard label="BAHNEN" value={laps} iconName="retweet" iconType="AntDesign" />
|
||||||
<IconCard label="ZÜGE" value={analysis.peaks.size} iconName="dashboard" iconType="AntDesign" />
|
<IconCard label="ZÜGE" value={analysis.peaks.size} iconName="dashboard" iconType="AntDesign" />
|
||||||
<IconCard label="KRAFT" value={totalMomentum} iconName="ruler" iconType="Entypo" />
|
<IconCard label="KRAFT" value={totalMomentum} iconName="ruler" iconType="Entypo" />
|
||||||
|
<Graph></Graph>
|
||||||
{/*
|
{/*
|
||||||
<IconCard label="ZÜGE" value={this.state.numPeaks} iconName="dashboard" iconType="AntDesign" />
|
<IconCard label="ZÜGE" value={this.state.numPeaks} iconName="dashboard" iconType="AntDesign" />
|
||||||
<IconCard label="BAHNEN" value={this.state.numLaps} iconName="retweet" iconType="AntDesign" />
|
<IconCard label="BAHNEN" value={this.state.numLaps} iconName="retweet" iconType="AntDesign" />
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
export const CHANGE_USER_NAME = "SET_USERNAME";
|
|
||||||
export const CHANGE_THEME = "CHANGE_THEME";
|
|
||||||
export const RESET_DEVICE_DATA = "RESET_DEVICE_DATA";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const changeUsername = newUsername => ({
|
|
||||||
type: CHANGE_USER_NAME,
|
|
||||||
newUserName: newUsername,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const changeTheme = newThemeName => ({
|
|
||||||
type: CHANGE_THEME,
|
|
||||||
newThemeName: newThemeName
|
|
||||||
});
|
|
||||||
|
|
||||||
export const startSession = () => ({
|
|
||||||
type: START_SESSION
|
|
||||||
});
|
|
||||||
|
|
||||||
export const stopSession = () => ({
|
|
||||||
type: STOP_SESSION
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------
|
|
||||||
|
|
||||||
|
|
|
@ -126,12 +126,18 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
|
||||||
case DEVICE_DISCONNECT:
|
case DEVICE_DISCONNECT:
|
||||||
return { ...INITIAL_DEVICE_STATE, connState: ConnState.DISCONNECTED };
|
return { ...INITIAL_DEVICE_STATE, connState: ConnState.DISCONNECTED };
|
||||||
case SESSION_STARTED:
|
case SESSION_STARTED:
|
||||||
|
console.log("session started");
|
||||||
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_RUNNING, sessionId: action.sessionId };
|
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_RUNNING, sessionId: action.sessionId };
|
||||||
case SESSION_STOPPED:
|
case SESSION_STOPPED:
|
||||||
|
console.log("session stopped");
|
||||||
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED };
|
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPED };
|
||||||
case START_SESSION:
|
case START_SESSION:
|
||||||
|
if(state.connState === ConnState.SESSION_STARTED)
|
||||||
|
return state;
|
||||||
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING };
|
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STARTING };
|
||||||
case STOP_SESSION:
|
case STOP_SESSION:
|
||||||
|
if(state.connState === ConnState.SESSION_STOPPED)
|
||||||
|
return state;
|
||||||
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING };
|
return { ...INITIAL_DEVICE_STATE, connState: ConnState.CONNECTED_STOPPING };
|
||||||
default:
|
default:
|
||||||
console.log("Unhandled state in deviceStateReducer", action.type);
|
console.log("Unhandled state in deviceStateReducer", action.type);
|
||||||
|
@ -140,4 +146,4 @@ export const deviceStateReducer = (state = INITIAL_DEVICE_STATE, action) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,29 @@
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import { CHANGE_THEME, CHANGE_USER_NAME, NEW_DEVICE_DATA, START_SESSION, STOP_SESSION, RESET_DEVICE_DATA } from './ActionCreators';
|
|
||||||
import { deviceStateReducer } from "./DeviceReduxCoupling";
|
import { deviceStateReducer } from "./DeviceReduxCoupling";
|
||||||
|
|
||||||
|
export const CHANGE_USER_NAME = "SET_USERNAME";
|
||||||
|
export const CHANGE_THEME = "CHANGE_THEME";
|
||||||
|
export const RESET_DEVICE_DATA = "RESET_DEVICE_DATA";
|
||||||
|
|
||||||
|
|
||||||
|
export const changeUsername = newUsername => ({
|
||||||
|
type: CHANGE_USER_NAME,
|
||||||
|
newUserName: newUsername,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const changeTheme = newThemeName => ({
|
||||||
|
type: CHANGE_THEME,
|
||||||
|
newThemeName: newThemeName
|
||||||
|
});
|
||||||
|
|
||||||
|
export const startSession = () => ({
|
||||||
|
type: START_SESSION
|
||||||
|
});
|
||||||
|
|
||||||
|
export const stopSession = () => ({
|
||||||
|
type: STOP_SESSION
|
||||||
|
});
|
||||||
|
|
||||||
const INITIAL_SETTINGS = {
|
const INITIAL_SETTINGS = {
|
||||||
theme: "hot",
|
theme: "hot",
|
||||||
username: "",
|
username: "",
|
||||||
|
@ -12,6 +34,8 @@ const INITIAL_SETTINGS = {
|
||||||
windowSizeInSecs: 5,
|
windowSizeInSecs: 5,
|
||||||
numMeasurementsPerSec: 10,
|
numMeasurementsPerSec: 10,
|
||||||
|
|
||||||
|
kgFactor: 1.0 / 1100.0,
|
||||||
|
|
||||||
peakDetector: 'SIMPLE', // either 'SIMPLE' or 'ZSCORE'
|
peakDetector: 'SIMPLE', // either 'SIMPLE' or 'ZSCORE'
|
||||||
peakDetectorSimpleThreshold: 2500,
|
peakDetectorSimpleThreshold: 2500,
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue