Determine chart height dynamically and fill the window
This commit is contained in:
@@ -49,6 +49,13 @@
|
|||||||
"prefer-const": "error",
|
"prefer-const": "error",
|
||||||
"no-trailing-spaces": "error",
|
"no-trailing-spaces": "error",
|
||||||
"react/prop-types": 0,
|
"react/prop-types": 0,
|
||||||
"max-len": [1, {"ignoreStrings": true}]
|
"max-len": [
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
"ignoreStrings": true,
|
||||||
|
"ignoreComments": true,
|
||||||
|
"ignoreTemplateLiterals": true
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+54
-37
@@ -1,9 +1,9 @@
|
|||||||
import React, { Component } from 'react'
|
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 range from 'date-range'
|
||||||
import { LocalDate } from 'js-joda'
|
import { LocalDate } from 'js-joda'
|
||||||
import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis'
|
import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis'
|
||||||
import setUpFertilityStatusFunc from './nfp-lines'
|
import nfpLines from './nfp-lines'
|
||||||
import DayColumn from './day-column'
|
import DayColumn from './day-column'
|
||||||
import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db'
|
import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db'
|
||||||
import styles from './styles'
|
import styles from './styles'
|
||||||
@@ -12,24 +12,27 @@ import { scaleObservable } from '../../local-storage'
|
|||||||
export default class CycleChart extends Component {
|
export default class CycleChart extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {}
|
||||||
columns: makeColumnInfo(setUpFertilityStatusFunc()),
|
|
||||||
}
|
|
||||||
this.renderColumn = ({item, index}) => {
|
this.renderColumn = ({item, index}) => {
|
||||||
return (
|
return (
|
||||||
<DayColumn
|
<DayColumn
|
||||||
{...item}
|
{...item}
|
||||||
index={index}
|
index={index}
|
||||||
navigate={this.props.navigate}
|
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)
|
cycleDaysSortedByDate.addListener(this.reCalculateChartInfo)
|
||||||
this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false)
|
this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false)
|
||||||
@@ -40,30 +43,7 @@ export default class CycleChart extends Component {
|
|||||||
this.removeObvListener()
|
this.removeObvListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
makeColumnInfo(getFhmAndLtlInfo) {
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<View style={{ flexDirection: 'row', marginTop: 50 }}>
|
|
||||||
<View {...styles.yAxis}>{makeYAxisLabels()}</View>
|
|
||||||
{makeHorizontalGrid()}
|
|
||||||
{<FlatList
|
|
||||||
horizontal={true}
|
|
||||||
inverted={true}
|
|
||||||
showsHorizontalScrollIndicator={false}
|
|
||||||
data={this.state.columns}
|
|
||||||
renderItem={this.renderColumn}
|
|
||||||
keyExtractor={item => item.dateString}
|
|
||||||
initialNumToRender={15}
|
|
||||||
maxToRenderPerBatch={5}
|
|
||||||
>
|
|
||||||
</FlatList>}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeColumnInfo(getFhmAndLtlInfo) {
|
|
||||||
let amountOfCycleDays = getAmountOfCycleDays()
|
let amountOfCycleDays = getAmountOfCycleDays()
|
||||||
// if there's not much data yet, we want to show at least 30 days on the chart
|
// if there's not much data yet, we want to show at least 30 days on the chart
|
||||||
if (amountOfCycleDays < 30) {
|
if (amountOfCycleDays < 30) {
|
||||||
@@ -72,7 +52,8 @@ function makeColumnInfo(getFhmAndLtlInfo) {
|
|||||||
// we don't want the chart to end abruptly before the first data day
|
// we don't want the chart to end abruptly before the first data day
|
||||||
amountOfCycleDays += 5
|
amountOfCycleDays += 5
|
||||||
}
|
}
|
||||||
const xAxisDates = getTodayAndPreviousDays(amountOfCycleDays).map(jsDate => {
|
const jsDates = getTodayAndPreviousDays(amountOfCycleDays)
|
||||||
|
const xAxisDates = jsDates.map(jsDate => {
|
||||||
return LocalDate.of(
|
return LocalDate.of(
|
||||||
jsDate.getFullYear(),
|
jsDate.getFullYear(),
|
||||||
jsDate.getMonth() + 1,
|
jsDate.getMonth() + 1,
|
||||||
@@ -88,11 +69,12 @@ function makeColumnInfo(getFhmAndLtlInfo) {
|
|||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
|
const temp = symptoms.temperature
|
||||||
return {
|
return {
|
||||||
dateString,
|
dateString,
|
||||||
y: symptoms.temperature ? normalizeToScale(symptoms.temperature) : null,
|
y: temp ? normalizeToScale(temp, this.state.chartHeight) : null,
|
||||||
...symptoms,
|
...symptoms,
|
||||||
...getFhmAndLtlInfo(dateString, symptoms.temperature)
|
...getFhmAndLtlInfo(dateString, temp)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -100,8 +82,43 @@ function makeColumnInfo(getFhmAndLtlInfo) {
|
|||||||
const info = getInfoForNeighborColumns(i, columns)
|
const info = getInfoForNeighborColumns(i, columns)
|
||||||
return Object.assign(col, info)
|
return Object.assign(col, info)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<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}
|
||||||
|
data={this.state.columns}
|
||||||
|
renderItem={this.renderColumn}
|
||||||
|
keyExtractor={item => item.dateString}
|
||||||
|
initialNumToRender={15}
|
||||||
|
maxToRenderPerBatch={5}
|
||||||
|
>
|
||||||
|
</FlatList>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getTodayAndPreviousDays(n) {
|
function getTodayAndPreviousDays(n) {
|
||||||
const today = new Date()
|
const today = new Date()
|
||||||
today.setHours(0)
|
today.setHours(0)
|
||||||
|
|||||||
@@ -105,25 +105,22 @@ export default class DayColumn extends Component {
|
|||||||
const cycleDayNumber = getCycleDayNumber(dateString)
|
const cycleDayNumber = getCycleDayNumber(dateString)
|
||||||
const shortDate = dateString.split('-').slice(1).join('-')
|
const shortDate = dateString.split('-').slice(1).join('-')
|
||||||
const cycleDayLabel = (
|
const cycleDayLabel = (
|
||||||
<Text style={label.number} y={config.cycleDayNumberRowY}>
|
<Text style={label.number}>
|
||||||
{cycleDayNumber}
|
{cycleDayNumber}
|
||||||
</Text>)
|
</Text>)
|
||||||
const dateLabel = (
|
const dateLabel = (
|
||||||
<Text style = {label.date} y={config.dateRowY}>
|
<Text style = {label.date}>
|
||||||
{shortDate}
|
{shortDate}
|
||||||
</Text>
|
</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,
|
TouchableOpacity,
|
||||||
{
|
{
|
||||||
style: styles.column.rect,
|
style: [styles.column.rect, {height: columnHeight}],
|
||||||
key: this.props.index.toString(),
|
key: this.props.index.toString(),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
this.passDateToDayView(dateString)
|
this.passDateToDayView(dateString)
|
||||||
@@ -132,5 +129,15 @@ export default class DayColumn extends Component {
|
|||||||
},
|
},
|
||||||
columnElements
|
columnElements
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{column}
|
||||||
|
<View style={{height: xAxisHeight}}>
|
||||||
|
{cycleDayLabel}
|
||||||
|
{dateLabel}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
||||||
import { normalizeToScale } from './y-axis'
|
import { normalizeToScale } from './y-axis'
|
||||||
|
|
||||||
export default function () {
|
export default function (chartHeight) {
|
||||||
const cycle = {
|
const cycle = {
|
||||||
status: null
|
status: null
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ export default function () {
|
|||||||
dateIsInPeriOrPostPhase(dateString) &&
|
dateIsInPeriOrPostPhase(dateString) &&
|
||||||
isInTempMeasuringPhase(temperature, dateString)
|
isInTempMeasuringPhase(temperature, dateString)
|
||||||
) {
|
) {
|
||||||
ret.drawLtlAt = normalizeToScale(tempShift.ltl)
|
ret.drawLtlAt = normalizeToScale(tempShift.ltl, chartHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ const styles = {
|
|||||||
},
|
},
|
||||||
rect: {
|
rect: {
|
||||||
width: config.columnWidth,
|
width: config.columnWidth,
|
||||||
height: config.chartHeight,
|
|
||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
borderColor: 'grey',
|
borderColor: 'grey',
|
||||||
borderWidth: 0.5
|
borderLeftWidth: 0.5,
|
||||||
|
borderRightWidth: 0.5,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
bleedingIcon: {
|
bleedingIcon: {
|
||||||
@@ -63,7 +63,6 @@ const styles = {
|
|||||||
'#993299'
|
'#993299'
|
||||||
],
|
],
|
||||||
yAxis: {
|
yAxis: {
|
||||||
height: config.chartHeight,
|
|
||||||
width: config.columnWidth,
|
width: config.columnWidth,
|
||||||
borderRightWidth: 0.5,
|
borderRightWidth: 0.5,
|
||||||
borderColor: 'lightgrey',
|
borderColor: 'lightgrey',
|
||||||
|
|||||||
+15
-15
@@ -4,19 +4,18 @@ import config from '../../config'
|
|||||||
import styles from './styles'
|
import styles from './styles'
|
||||||
import { scaleObservable } from '../../local-storage'
|
import { scaleObservable } from '../../local-storage'
|
||||||
|
|
||||||
export function makeYAxisLabels() {
|
export function makeYAxisLabels(chartHeight) {
|
||||||
const units = config.temperatureScale.units
|
const units = config.temperatureScale.units
|
||||||
const scaleMax = scaleObservable.value.max
|
const scaleMax = scaleObservable.value.max
|
||||||
|
|
||||||
return getTickPositions().map((y, i) => {
|
|
||||||
const style = styles.yAxisLabel
|
const style = styles.yAxisLabel
|
||||||
|
|
||||||
|
return getTickPositions(chartHeight).map((y, i) => {
|
||||||
// this eyeballing is sadly necessary because RN does not
|
// this eyeballing is sadly necessary because RN does not
|
||||||
// support percentage values for transforms, which we'd need
|
// support percentage values for transforms, which we'd need
|
||||||
// to reliably place the label vertically centered to the grid
|
// to reliably place the label vertically centered to the grid
|
||||||
style.top = y - 8
|
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
style={{ ...style }}
|
style={[style, {top: y - 8}]}
|
||||||
key={i}>
|
key={i}>
|
||||||
{scaleMax - i * units}
|
{scaleMax - i * units}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -24,8 +23,8 @@ export function makeYAxisLabels() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeHorizontalGrid() {
|
export function makeHorizontalGrid(chartHeight) {
|
||||||
return getTickPositions().map(tick => {
|
return getTickPositions(chartHeight).map(tick => {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
top={tick}
|
top={tick}
|
||||||
@@ -36,24 +35,25 @@ export function makeHorizontalGrid() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTickPositions() {
|
function getTickPositions(chartHeight) {
|
||||||
const units = config.temperatureScale.units
|
const units = config.temperatureScale.units
|
||||||
const scaleMin = scaleObservable.value.min
|
const scaleMin = scaleObservable.value.min
|
||||||
const scaleMax = scaleObservable.value.max
|
const scaleMax = scaleObservable.value.max
|
||||||
const numberOfTicks = (scaleMax - scaleMin) * (1 / units)
|
const numberOfTicks = (scaleMax - scaleMin) * (1 / units) + 1
|
||||||
const tickDistance = config.chartHeight / numberOfTicks
|
const columnHeight = chartHeight * config.columnHeightPercentage
|
||||||
|
const tickDistance = columnHeight / numberOfTicks
|
||||||
|
|
||||||
const tickPositions = []
|
const tickPositions = []
|
||||||
// for style reasons, we don't want the first and last tick
|
const margin = tickDistance / 2
|
||||||
for (let i = 1; i < numberOfTicks - 1; i++) {
|
for (let i = 0; i < numberOfTicks; i++) {
|
||||||
tickPositions.push(tickDistance * i)
|
tickPositions.push(tickDistance * i + margin)
|
||||||
}
|
}
|
||||||
return tickPositions
|
return tickPositions
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeToScale(temp) {
|
export function normalizeToScale(temp, chartHeight) {
|
||||||
const scale = scaleObservable.value
|
const scale = scaleObservable.value
|
||||||
const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min)
|
const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min)
|
||||||
const scaleHeight = config.chartHeight
|
const scaleHeight = chartHeight * config.columnHeightPercentage
|
||||||
return scaleHeight * valueRelativeToScale
|
return scaleHeight * valueRelativeToScale
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,6 @@ export default class Temp extends Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const prevTemp = getPreviousTemperature(this.cycleDay)
|
const prevTemp = getPreviousTemperature(this.cycleDay)
|
||||||
console.log(prevTemp)
|
|
||||||
if (prevTemp) {
|
if (prevTemp) {
|
||||||
this.state.temperature = prevTemp.toString()
|
this.state.temperature = prevTemp.toString()
|
||||||
this.state.isSuggestion = true
|
this.state.isSuggestion = true
|
||||||
@@ -122,7 +121,6 @@ export default class Temp extends Component {
|
|||||||
class TempInput extends Component {
|
class TempInput extends Component {
|
||||||
checkRange = () => {
|
checkRange = () => {
|
||||||
const value = Number(this.props.value)
|
const value = Number(this.props.value)
|
||||||
console.log(value)
|
|
||||||
if (isNaN(value)) return
|
if (isNaN(value)) return
|
||||||
const scale = scaleObservable.value
|
const scale = scaleObservable.value
|
||||||
if (value < scale.min || value > scale.max) {
|
if (value < scale.min || value > scale.max) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const config = {
|
const config = {
|
||||||
chartHeight: 350,
|
|
||||||
columnWidth: 25,
|
columnWidth: 25,
|
||||||
|
columnHeightPercentage: 0.92,
|
||||||
|
xAxisHeightPercentage: 0.08,
|
||||||
temperatureScale: {
|
temperatureScale: {
|
||||||
defaultLow: 35,
|
defaultLow: 35,
|
||||||
defaultHigh: 38,
|
defaultHigh: 38,
|
||||||
@@ -10,9 +11,6 @@ const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const margin = 3
|
config.columnMiddle = config.columnWidth / 2
|
||||||
config.columnMiddle = config.columnWidth / 2,
|
|
||||||
config.dateRowY = config.chartHeight - 15 - margin
|
|
||||||
config.cycleDayNumberRowY = config.chartHeight - margin
|
|
||||||
|
|
||||||
export default config
|
export default config
|
||||||
+6
-4
@@ -92,16 +92,17 @@ export default StyleSheet.create({
|
|||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: primaryColor,
|
||||||
paddingVertical: 18,
|
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: 15,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center'
|
justifyContent: 'center',
|
||||||
|
height: '10%'
|
||||||
},
|
},
|
||||||
menu: {
|
menu: {
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: primaryColor,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
flexDirection: 'row'
|
flexDirection: 'row',
|
||||||
|
height: '12%'
|
||||||
},
|
},
|
||||||
menuItem: {
|
menuItem: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -116,7 +117,8 @@ export default StyleSheet.create({
|
|||||||
},
|
},
|
||||||
headerCycleDay: {
|
headerCycleDay: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between'
|
justifyContent: 'space-between',
|
||||||
|
height: '15%'
|
||||||
},
|
},
|
||||||
navigationArrow: {
|
navigationArrow: {
|
||||||
fontSize: 60,
|
fontSize: 60,
|
||||||
|
|||||||
Reference in New Issue
Block a user