diff --git a/.eslintrc b/.eslintrc index fb7b9841bb670442504403efe5a08fea2c28bd5b..028ba73c90d0499ada5fdb8333828bb1dd55e9ac 100644 --- a/.eslintrc +++ b/.eslintrc @@ -49,6 +49,13 @@ "prefer-const": "error", "no-trailing-spaces": "error", "react/prop-types": 0, - "max-len": [1, {"ignoreStrings": true}] + "max-len": [ + 1, + { + "ignoreStrings": true, + "ignoreComments": true, + "ignoreTemplateLiterals": true + } + ] } } \ No newline at end of file diff --git a/components/chart/chart.js b/components/chart/chart.js index 09bcf44978b77fcfd608b0d2acce2c7e9fff191b..d8a971340eaeda4c18b301bf4f05ffd9819f9f97 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -1,9 +1,9 @@ import React, { Component } from 'react' -import { View, FlatList, ScrollView } from 'react-native' +import { View, FlatList, Text } from 'react-native' import range from 'date-range' import { LocalDate } from 'js-joda' import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis' -import setUpFertilityStatusFunc from './nfp-lines' +import nfpLines from './nfp-lines' import DayColumn from './day-column' import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db' import styles from './styles' @@ -12,24 +12,27 @@ import { scaleObservable } from '../../local-storage' export default class CycleChart extends Component { constructor(props) { super(props) - this.state = { - columns: makeColumnInfo(setUpFertilityStatusFunc()), - } + this.state = {} this.renderColumn = ({item, index}) => { return ( <DayColumn {...item} index={index} navigate={this.props.navigate} + chartHeight={this.state.chartHeight} /> ) } + } - this.reCalculateChartInfo = (function(Chart) { - return function() { - Chart.setState({columns: makeColumnInfo(setUpFertilityStatusFunc())}) - } - })(this) + onLayout = ({ nativeEvent }) => { + if (this.state.chartHeight) return + + const height = nativeEvent.layout.height + this.setState({ chartHeight: height }) + this.reCalculateChartInfo = () => { + this.setState({ columns: this.makeColumnInfo(nfpLines(height)) }) + } cycleDaysSortedByDate.addListener(this.reCalculateChartInfo) this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false) @@ -40,13 +43,65 @@ export default class CycleChart extends Component { this.removeObvListener() } + makeColumnInfo(getFhmAndLtlInfo) { + let amountOfCycleDays = getAmountOfCycleDays() + // if there's not much data yet, we want to show at least 30 days on the chart + if (amountOfCycleDays < 30) { + amountOfCycleDays = 30 + } else { + // we don't want the chart to end abruptly before the first data day + amountOfCycleDays += 5 + } + const jsDates = getTodayAndPreviousDays(amountOfCycleDays) + const xAxisDates = jsDates.map(jsDate => { + return LocalDate.of( + jsDate.getFullYear(), + jsDate.getMonth() + 1, + jsDate.getDate() + ).toString() + }) + + const columns = xAxisDates.map(dateString => { + const cycleDay = getCycleDay(dateString) + const symptoms = ['temperature', 'mucus', 'bleeding'].reduce((acc, symptom) => { + acc[symptom] = cycleDay && cycleDay[symptom] && cycleDay[symptom].value + acc[`${symptom}Exclude`] = cycleDay && cycleDay[symptom] && cycleDay[symptom].exclude + return acc + }, {}) + + const temp = symptoms.temperature + return { + dateString, + y: temp ? normalizeToScale(temp, this.state.chartHeight) : null, + ...symptoms, + ...getFhmAndLtlInfo(dateString, temp) + } + }) + + return columns.map((col, i) => { + const info = getInfoForNeighborColumns(i, columns) + return Object.assign(col, info) + }) + } + render() { return ( - <ScrollView> - <View style={{ flexDirection: 'row', marginTop: 50 }}> - <View {...styles.yAxis}>{makeYAxisLabels()}</View> - {makeHorizontalGrid()} - {<FlatList + <View + onLayout={this.onLayout} + style={{ flexDirection: 'row', flex: 1 }} + > + {!this.state.chartHeight && <Text>Loading...</Text>} + {this.state.chartHeight && + <View + style={[styles.yAxis, {height: this.state.chartHeight}]} + > + {makeYAxisLabels(this.state.chartHeight)} + </View>} + + {this.state.chartHeight && makeHorizontalGrid(this.state.chartHeight)} + + {this.state.chartHeight && + <FlatList horizontal={true} inverted={true} showsHorizontalScrollIndicator={false} @@ -56,51 +111,13 @@ export default class CycleChart extends Component { initialNumToRender={15} maxToRenderPerBatch={5} > - </FlatList>} - </View> - </ScrollView> + </FlatList> + } + </View> ) } } -function makeColumnInfo(getFhmAndLtlInfo) { - let amountOfCycleDays = getAmountOfCycleDays() - // if there's not much data yet, we want to show at least 30 days on the chart - if (amountOfCycleDays < 30) { - amountOfCycleDays = 30 - } else { - // we don't want the chart to end abruptly before the first data day - amountOfCycleDays += 5 - } - const xAxisDates = getTodayAndPreviousDays(amountOfCycleDays).map(jsDate => { - return LocalDate.of( - jsDate.getFullYear(), - jsDate.getMonth() + 1, - jsDate.getDate() - ).toString() - }) - - const columns = xAxisDates.map(dateString => { - const cycleDay = getCycleDay(dateString) - const symptoms = ['temperature', 'mucus', 'bleeding'].reduce((acc, symptom) => { - acc[symptom] = cycleDay && cycleDay[symptom] && cycleDay[symptom].value - acc[`${symptom}Exclude`] = cycleDay && cycleDay[symptom] && cycleDay[symptom].exclude - return acc - }, {}) - - return { - dateString, - y: symptoms.temperature ? normalizeToScale(symptoms.temperature) : null, - ...symptoms, - ...getFhmAndLtlInfo(dateString, symptoms.temperature) - } - }) - - return columns.map((col, i) => { - const info = getInfoForNeighborColumns(i, columns) - return Object.assign(col, info) - }) -} function getTodayAndPreviousDays(n) { const today = new Date() diff --git a/components/chart/day-column.js b/components/chart/day-column.js index 1b61a7aec5014f8bf025b34cbd543be0aaa10e6d..b6bf2d53f7328942c913d55d1a14b272398e8030 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -105,25 +105,22 @@ export default class DayColumn extends Component { const cycleDayNumber = getCycleDayNumber(dateString) const shortDate = dateString.split('-').slice(1).join('-') const cycleDayLabel = ( - <Text style={label.number} y={config.cycleDayNumberRowY}> + <Text style={label.number}> {cycleDayNumber} </Text>) const dateLabel = ( - <Text style = {label.date} y={config.dateRowY}> + <Text style = {label.date}> {shortDate} </Text> ) - columnElements.push( - <View position='absolute' bottom={0} key='date'> - {cycleDayLabel} - {dateLabel} - </View> - ) - return React.createElement( + const columnHeight = this.props.chartHeight * config.columnHeightPercentage + const xAxisHeight = this.props.chartHeight * config.xAxisHeightPercentage + + const column = React.createElement( TouchableOpacity, { - style: styles.column.rect, + style: [styles.column.rect, {height: columnHeight}], key: this.props.index.toString(), onPress: () => { this.passDateToDayView(dateString) @@ -132,5 +129,15 @@ export default class DayColumn extends Component { }, columnElements ) + + return ( + <View> + {column} + <View style={{height: xAxisHeight}}> + {cycleDayLabel} + {dateLabel} + </View> + </View> + ) } } \ No newline at end of file diff --git a/components/chart/nfp-lines.js b/components/chart/nfp-lines.js index d9f4507f67ea6583762646588f7e4013f46ef192..ded95e8197e1e28cba34a8fa05b3383a1a2412eb 100644 --- a/components/chart/nfp-lines.js +++ b/components/chart/nfp-lines.js @@ -1,7 +1,7 @@ import { getCycleStatusForDay } from '../../lib/sympto-adapter' import { normalizeToScale } from './y-axis' -export default function () { +export default function (chartHeight) { const cycle = { status: null } @@ -71,7 +71,7 @@ export default function () { dateIsInPeriOrPostPhase(dateString) && isInTempMeasuringPhase(temperature, dateString) ) { - ret.drawLtlAt = normalizeToScale(tempShift.ltl) + ret.drawLtlAt = normalizeToScale(tempShift.ltl, chartHeight) } } diff --git a/components/chart/styles.js b/components/chart/styles.js index 8ee5a30e9e7e316c17c56cfba472aca3d2b3486d..d60e1a0c5eff1eafffaeb9cd060cc804e4944fc9 100644 --- a/components/chart/styles.js +++ b/components/chart/styles.js @@ -38,10 +38,10 @@ const styles = { }, rect: { width: config.columnWidth, - height: config.chartHeight, borderStyle: 'solid', borderColor: 'grey', - borderWidth: 0.5 + borderLeftWidth: 0.5, + borderRightWidth: 0.5, } }, bleedingIcon: { @@ -63,7 +63,6 @@ const styles = { '#993299' ], yAxis: { - height: config.chartHeight, width: config.columnWidth, borderRightWidth: 0.5, borderColor: 'lightgrey', diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index 5b78b3683f6ce216b83af173630980810a09f4d4..e65449b97d4711f8890f2b36d1123f5f96daa0db 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -4,19 +4,18 @@ import config from '../../config' import styles from './styles' import { scaleObservable } from '../../local-storage' -export function makeYAxisLabels() { +export function makeYAxisLabels(chartHeight) { const units = config.temperatureScale.units const scaleMax = scaleObservable.value.max + const style = styles.yAxisLabel - return getTickPositions().map((y, i) => { - const style = styles.yAxisLabel + return getTickPositions(chartHeight).map((y, i) => { // this eyeballing is sadly necessary because RN does not // support percentage values for transforms, which we'd need // to reliably place the label vertically centered to the grid - style.top = y - 8 return ( <Text - style={{ ...style }} + style={[style, {top: y - 8}]} key={i}> {scaleMax - i * units} </Text> @@ -24,8 +23,8 @@ export function makeYAxisLabels() { }) } -export function makeHorizontalGrid() { - return getTickPositions().map(tick => { +export function makeHorizontalGrid(chartHeight) { + return getTickPositions(chartHeight).map(tick => { return ( <View top={tick} @@ -36,24 +35,25 @@ export function makeHorizontalGrid() { }) } -function getTickPositions() { +function getTickPositions(chartHeight) { const units = config.temperatureScale.units const scaleMin = scaleObservable.value.min const scaleMax = scaleObservable.value.max - const numberOfTicks = (scaleMax - scaleMin) * (1 / units) - const tickDistance = config.chartHeight / numberOfTicks + const numberOfTicks = (scaleMax - scaleMin) * (1 / units) + 1 + const columnHeight = chartHeight * config.columnHeightPercentage + const tickDistance = columnHeight / numberOfTicks const tickPositions = [] - // for style reasons, we don't want the first and last tick - for (let i = 1; i < numberOfTicks - 1; i++) { - tickPositions.push(tickDistance * i) + const margin = tickDistance / 2 + for (let i = 0; i < numberOfTicks; i++) { + tickPositions.push(tickDistance * i + margin) } return tickPositions } -export function normalizeToScale(temp) { +export function normalizeToScale(temp, chartHeight) { const scale = scaleObservable.value const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min) - const scaleHeight = config.chartHeight + const scaleHeight = chartHeight * config.columnHeightPercentage return scaleHeight * valueRelativeToScale } \ No newline at end of file diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index fd3f905e04216184f7f661834377c6e9678dc322..fda52006729b9225d16ed2ec9dca7aa32e54c0fa 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -42,7 +42,6 @@ export default class Temp extends Component { } } else { const prevTemp = getPreviousTemperature(this.cycleDay) - console.log(prevTemp) if (prevTemp) { this.state.temperature = prevTemp.toString() this.state.isSuggestion = true @@ -122,7 +121,6 @@ export default class Temp extends Component { class TempInput extends Component { checkRange = () => { const value = Number(this.props.value) - console.log(value) if (isNaN(value)) return const scale = scaleObservable.value if (value < scale.min || value > scale.max) { diff --git a/config.js b/config.js index d44ba54ce32195ce7f2dedc0e3a76c9c1e485422..ffb8f6041a48c25379df2d8217e345458672571b 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,7 @@ const config = { - chartHeight: 350, columnWidth: 25, + columnHeightPercentage: 0.92, + xAxisHeightPercentage: 0.08, temperatureScale: { defaultLow: 35, defaultHigh: 38, @@ -10,9 +11,6 @@ const config = { } } -const margin = 3 -config.columnMiddle = config.columnWidth / 2, -config.dateRowY = config.chartHeight - 15 - margin -config.cycleDayNumberRowY = config.chartHeight - margin +config.columnMiddle = config.columnWidth / 2 export default config \ No newline at end of file diff --git a/styles/index.js b/styles/index.js index 43a55996d0c501ca2b510644302fd010cd1091fc..406de7abddc38fd42041dfcf537bc973a0d3a165 100644 --- a/styles/index.js +++ b/styles/index.js @@ -92,16 +92,17 @@ export default StyleSheet.create({ }, header: { backgroundColor: primaryColor, - paddingVertical: 18, paddingHorizontal: 15, alignItems: 'center', - justifyContent: 'center' + justifyContent: 'center', + height: '10%' }, menu: { backgroundColor: primaryColor, alignItems: 'center', justifyContent: 'space-between', - flexDirection: 'row' + flexDirection: 'row', + height: '12%' }, menuItem: { alignItems: 'center', @@ -116,7 +117,8 @@ export default StyleSheet.create({ }, headerCycleDay: { flexDirection: 'row', - justifyContent: 'space-between' + justifyContent: 'space-between', + height: '15%' }, navigationArrow: { fontSize: 60,