diff --git a/components/chart/chart.js b/components/chart/chart.js
index 449a120..9393407 100644
--- a/components/chart/chart.js
+++ b/components/chart/chart.js
@@ -1,17 +1,29 @@
import React, { Component } from 'react'
-import { Text, View, FlatList, ScrollView } from 'react-native'
+import { View, FlatList } from 'react-native'
import range from 'date-range'
import { LocalDate } from 'js-joda'
-import Icon from 'react-native-vector-icons/Entypo'
-import { getCycleDay, getOrCreateCycleDay, cycleDaysSortedByDate } from '../../db'
-import cycleModule from '../../lib/cycle'
+import { yAxis, normalizeToScale } from './y-axis'
+import DayColumn from './day-column'
+import { getCycleDay, cycleDaysSortedByDate } from '../../db'
import styles from './styles'
import config from './config'
-import { getCycleStatusForDay } from '../../lib/sympto-adapter'
-const getCycleDayNumber = cycleModule().getCycleDayNumber
+const yAxisView = {yAxis.labels}
-const yAxis = makeYAxis(config)
+function getInfoForNeighborColumns(index, cols) {
+ const ret = {}
+ const right = index > 0 ? cols[index - 1] : undefined
+ const left = index < cols.length - 1 ? cols[index + 1] : undefined
+ if (right && right.y) {
+ ret.rightY = right.y
+ ret.rightTemperatureExclude = right.temperatureExclude
+ }
+ if (left && left.y) {
+ ret.leftY = left.y
+ ret.leftTemperatureExclude = left.temperatureExclude
+ }
+ return ret
+}
export default class CycleChart extends Component {
constructor(props) {
@@ -19,6 +31,16 @@ export default class CycleChart extends Component {
this.state = {
columns: makeColumnInfo(config.xAxisRangeInDays)
}
+ this.renderColumn = ({item, index}) => {
+ return (
+
+ )
+ }
this.reCalculateChartInfo = (function(Chart) {
return function() {
@@ -33,186 +55,22 @@ export default class CycleChart extends Component {
cycleDaysSortedByDate.removeListener(this.reCalculateChartInfo)
}
- passDateToDayView(dateString) {
- const cycleDay = getOrCreateCycleDay(dateString)
- this.props.navigation.navigate('cycleDay', { cycleDay })
- }
-
- placeHorizontalGrid() {
- }
-
- makeDayColumn({ dateString, cycleDay, y }, index) {
- const cycleDayNumber = getCycleDayNumber(dateString)
- const label = styles.column.label
- const dateText = dateString.split('-').slice(1).join('-')
- const getFhmAndLtlInfo = setUpFertilityStatusFunc()
- const nfpLineInfo = getFhmAndLtlInfo(dateString, cycleDay)
-
- const horizontalGrid = yAxis.labels.map((_, i) => {
- return React.createElement(
- View,
- {
- style: Object.assign(
- {},
- styles.horizontalGrid,
- { marginTop: yAxis.tickDistance }
- ),
- key: i.toString()
- }
- )
- })
- //TODO move these so they are visible
- const cycleDayLabel = (
-
- {cycleDayNumber}
- )
- const dateLabel = (
-
- {dateText}
-
- )
- const columnElements = []
- if (cycleDay && cycleDay.bleeding) {
- console.log('ever?')
- columnElements.push(
-
- )
- }
- columnElements.push(...[horizontalGrid, cycleDayLabel, dateLabel])
- // {nfpLineInfo.drawFhmLine ?
- // : null}
- // />)
-
- // onPress: () => this.passDateToDayView(dateString),
-
- //
- // : null}
-
- // {nfpLineInfo.drawLtlAt ?
- // : null}
-
- if (y) {
- columnElements.push(this.drawDotAndLines(y, cycleDay.temperature.exclude, index))
- }
- // {cycleDay && cycleDay.mucus ?
- // : null}
-
- // {y ?
- // this.drawDotAndLines(y, cycleDay.temperature.exclude, index)
- // : null} */}
-
- return React.createElement(
- View,
- {
- style: styles.column.rect,
- key: index.toString()
- },
- columnElements
- )
- }
-
- drawDotAndLines(currY, exclude, index) {
- /*
- ) */
- let lineToRight
- let lineToLeft
- const cols = this.state.columns
-
- function makeLine(otherColY, x, excludeLine) {
- const middleY = ((otherColY - currY) / 2) + currY
- const target = [x, middleY]
- const lineStyle = excludeLine ? styles.curveExcluded : styles.curve
-
- return
- }
-
- const thereIsADotToTheRight = index > 0 && cols[index - 1].y
- const thereIsADotToTheLeft = index < cols.length - 1 && cols[index + 1].y
-
- /* if (thereIsADotToTheRight) {
- const otherDot = cols[index - 1]
- const excludedLine = otherDot.cycleDay.temperature.exclude || exclude
- lineToRight = makeLine(otherDot.y, config.columnWidth, excludedLine)
- }
- if (thereIsADotToTheLeft) {
- const otherDot = cols[index + 1]
- const excludedLine = otherDot.cycleDay.temperature.exclude || exclude
- lineToLeft = makeLine(otherDot.y, 0, excludedLine)
- } */
-
- const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots
- return [
- /* {lineToRight}
- {lineToLeft} */
-
- ]
- }
-
render() {
return (
-
- {yAxis.labels}
+
+ {yAxisView}
{
- return this.makeDayColumn(item, index)
- }}
+ renderItem={this.renderColumn}
keyExtractor={item => item.dateString}
- initialNumToRender={20}
- />
-
+ initialNumToRender={15}
+ maxToRenderPerBatch={5}
+ >
+
+
)
}
}
@@ -228,11 +86,16 @@ function makeColumnInfo(n) {
return xAxisDates.map(dateString => {
const cycleDay = getCycleDay(dateString)
- const temp = cycleDay && cycleDay.temperature && cycleDay.temperature.value
+ 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,
- cycleDay,
- y: temp ? normalizeToScale(temp) : null
+ y: symptoms.temperature ? normalizeToScale(symptoms.temperature) : null,
+ ...symptoms
}
})
}
@@ -246,114 +109,4 @@ function getPreviousDays(n) {
const earlierDate = new Date(today - (range.DAY * n))
return range(earlierDate, today).reverse()
-}
-
-function normalizeToScale(temp) {
- const scale = config.temperatureScale
- const valueRelativeToScale = (scale.high - temp) / (scale.high - scale.low)
- const scaleHeight = config.chartHeight
- return scaleHeight * valueRelativeToScale
-}
-
-function makeYAxis() {
- const scaleMin = config.temperatureScale.low
- const scaleMax = config.temperatureScale.high
- const numberOfTicks = (scaleMax - scaleMin) * 2
- const tickDistance = config.chartHeight / numberOfTicks
-
- const labels = []
- // for style reasons, we don't want the first and last tick
- for (let i = 1; i < numberOfTicks - 1; i++) {
- const y = tickDistance * i
- const style = styles.yAxisLabel
- // 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
- labels.push(
-
- {scaleMax - i * 0.5}
-
- )
- }
-
- return {labels, tickDistance}
-}
-
-function setUpFertilityStatusFunc() {
- let cycleStatus
- let cycleStartDate
- let noMoreCycles = false
-
- function updateCurrentCycle(dateString) {
- cycleStatus = getCycleStatusForDay(dateString)
- if(!cycleStatus) {
- noMoreCycles = true
- return
- }
- if (cycleStatus.phases.preOvulatory) {
- cycleStartDate = cycleStatus.phases.preOvulatory.start.date
- } else {
- cycleStartDate = cycleStatus.phases.periOvulatory.start.date
- }
- }
-
- function dateIsInPeriOrPostPhase(dateString) {
- return (
- dateString >= cycleStatus.phases.periOvulatory.start.date
- )
- }
-
- function precededByAnotherTempValue(dateString) {
- return (
- // we are only interested in days that have a preceding
- // temp
- Object.keys(cycleStatus.phases).some(phaseName => {
- return cycleStatus.phases[phaseName].cycleDays.some(day => {
- return day.temperature && day.date < dateString
- })
- })
- // and also a following temp, so we don't draw the line
- // longer than necessary
- &&
- cycleStatus.phases.postOvulatory.cycleDays.some(day => {
- return day.temperature && day.date > dateString
- })
- )
- }
-
- function isInTempMeasuringPhase(cycleDay, dateString) {
- return (
- cycleDay && cycleDay.temperature
- || precededByAnotherTempValue(dateString)
- )
- }
-
- return function(dateString, cycleDay) {
- const ret = {}
- if (!cycleStatus && !noMoreCycles) updateCurrentCycle(dateString)
- if (noMoreCycles) return ret
-
- if (dateString < cycleStartDate) updateCurrentCycle(dateString)
- if (noMoreCycles) return ret
-
- const tempShift = cycleStatus.temperatureShift
-
- if (tempShift) {
- if (tempShift.firstHighMeasurementDay.date === dateString) {
- ret.drawFhmLine = true
- }
-
- if (
- dateIsInPeriOrPostPhase(dateString) &&
- isInTempMeasuringPhase(cycleDay, dateString)
- ) {
- ret.drawLtlAt = normalizeToScale(tempShift.ltl)
- }
- }
-
- return ret
- }
}
\ No newline at end of file
diff --git a/components/chart/config.js b/components/chart/config.js
index d36413a..e9d5f95 100644
--- a/components/chart/config.js
+++ b/components/chart/config.js
@@ -2,10 +2,10 @@ const config = {
chartHeight: 350,
columnWidth: 30,
temperatureScale: {
- low: 33,
+ low: 35,
high: 40
},
- xAxisRangeInDays: 30
+ xAxisRangeInDays: 50
}
const margin = 3
diff --git a/components/chart/day-column.js b/components/chart/day-column.js
new file mode 100644
index 0000000..cdcb015
--- /dev/null
+++ b/components/chart/day-column.js
@@ -0,0 +1,175 @@
+import React, { Component } from 'react'
+import {
+ Text, View
+} from 'react-native'
+import Icon from 'react-native-vector-icons/Entypo'
+import styles from './styles'
+import config from './config'
+import { getOrCreateCycleDay } from '../../db'
+import cycleModule from '../../lib/cycle'
+import setUpFertilityStatusFunc from './nfp-lines'
+import { horizontalGrid } from './y-axis'
+import slowlog from 'react-native-slowlog'
+
+const getCycleDayNumber = cycleModule().getCycleDayNumber
+const label = styles.column.label
+const getFhmAndLtlInfo = setUpFertilityStatusFunc()
+
+export default class DayColumn extends Component {
+ constructor(props) {
+ super(props)
+ slowlog(this, /.*/, {threshold: 30})
+ }
+ makeDayColumn(data, index) {
+ const {
+ dateString,
+ y,
+ temperature,
+ temperatureExclude,
+ bleeding,
+ mucus
+ } = data
+ const cycleDayNumber = getCycleDayNumber(dateString)
+ const shortDate = dateString.split('-').slice(1).join('-')
+ const nfpLineInfo = getFhmAndLtlInfo(dateString, temperature)
+
+ //TODO move these so they are visible
+ const cycleDayLabel = (
+
+ {cycleDayNumber}
+ )
+ const dateLabel = (
+
+ {shortDate}
+
+ )
+ const columnElements = []
+ if (bleeding) {
+ columnElements.push(
+
+ )
+ }
+ columnElements.push(...[horizontalGrid, cycleDayLabel, dateLabel])
+ // {nfpLineInfo.drawFhmLine ?
+ // : null}
+ // />)
+
+ // onPress: () => this.passDateToDayView(dateString),
+
+ //
+ // : null}
+
+ // {nfpLineInfo.drawLtlAt ?
+ // : null}
+
+ if (y) {
+ columnElements.push(this.drawDotAndLines(y, temperatureExclude, index))
+ }
+ // {cycleDay && cycleDay.mucus ?
+ // : null}
+
+ // {y ?
+ // this.drawDotAndLines(y, cycleDay.temperature.exclude, index)
+ // : null} */}
+
+ return React.createElement(
+ View,
+ {
+ style: styles.column.rect,
+ key: index.toString()
+ },
+ columnElements
+ )
+ }
+
+ drawDotAndLines(currY, exclude) {
+ /*
+ ) */
+ let lineToRight
+ let lineToLeft
+
+ /* function makeLine(otherColY, x, excludeLine) {
+ const middleY = ((otherColY - currY) / 2) + currY
+ const target = [x, middleY]
+ const lineStyle = excludeLine ? styles.curveExcluded : styles.curve
+
+ return
+ } */
+
+ /* if (this.props.rightY) {
+ const excludedLine = this.props.rightTemperatureExclude || exclude
+ lineToRight = makeLine(this.props.rightY, config.columnWidth, excludedLine)
+ }
+ if (this.props.leftY) {
+ const excludedLine = this.props.leftTemperatureExclude || exclude
+ lineToLeft = makeLine(this.props.leftY, 0, excludedLine)
+ } */
+
+ const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots
+/* return (
+ {lineToRight}
+ {lineToLeft}
+
+ ) */
+ }
+
+ passDateToDayView(dateString) {
+ const cycleDay = getOrCreateCycleDay(dateString)
+ this.props.navigate('cycleDay', { cycleDay })
+ }
+
+ shouldComponentUpdate(newProps) {
+ return Object.keys(newProps).some(key => newProps[key] != this.props[key])
+ }
+
+ render() {
+ return this.makeDayColumn(this.props.item, this.props.index)
+ }
+}
\ No newline at end of file
diff --git a/components/chart/nfp-lines.js b/components/chart/nfp-lines.js
new file mode 100644
index 0000000..e5265ac
--- /dev/null
+++ b/components/chart/nfp-lines.js
@@ -0,0 +1,77 @@
+import { getCycleStatusForDay } from '../../lib/sympto-adapter'
+import { normalizeToScale } from './y-axis'
+
+export default function () {
+ const cycle = {
+ status: null
+ }
+
+ function updateCurrentCycle(dateString) {
+ cycle.status = getCycleStatusForDay(dateString)
+ if(!cycle.status) {
+ cycle.noMoreCycles = true
+ return
+ }
+ if (cycle.status.phases.preOvulatory) {
+ cycle.startDate = cycle.status.phases.preOvulatory.start.date
+ } else {
+ cycle.startDate = cycle.status.phases.periOvulatory.start.date
+ }
+ }
+
+ function dateIsInPeriOrPostPhase(dateString) {
+ return (
+ dateString >= cycle.status.phases.periOvulatory.start.date
+ )
+ }
+
+ function precededByAnotherTempValue(dateString) {
+ return (
+ // we are only interested in days that have a preceding
+ // temp
+ Object.keys(cycle.status.phases).some(phaseName => {
+ return cycle.status.phases[phaseName].cycleDays.some(day => {
+ return day.temperature && day.date < dateString
+ })
+ })
+ // and also a following temp, so we don't draw the line
+ // longer than necessary
+ &&
+ cycle.status.phases.postOvulatory.cycleDays.some(day => {
+ return day.temperature && day.date > dateString
+ })
+ )
+ }
+
+ function isInTempMeasuringPhase(temperature, dateString) {
+ return (
+ temperature || precededByAnotherTempValue(dateString)
+ )
+ }
+
+ return function(dateString, temperature) {
+ const ret = {}
+ if (!cycle.status && !cycle.noMoreCycles) updateCurrentCycle(dateString)
+ if (cycle.noMoreCycles) return ret
+
+ if (dateString < cycle.startDate) updateCurrentCycle(dateString)
+ if (cycle.noMoreCycles) return ret
+
+ const tempShift = cycle.status.temperatureShift
+
+ if (tempShift) {
+ if (tempShift.firstHighMeasurementDay.date === dateString) {
+ ret.drawFhmLine = true
+ }
+
+ if (
+ dateIsInPeriOrPostPhase(dateString) &&
+ isInTempMeasuringPhase(temperature, dateString)
+ ) {
+ ret.drawLtlAt = normalizeToScale(tempShift.ltl)
+ }
+ }
+
+ return ret
+ }
+}
\ No newline at end of file
diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js
new file mode 100644
index 0000000..e90dcac
--- /dev/null
+++ b/components/chart/y-axis.js
@@ -0,0 +1,54 @@
+import React from 'react'
+import { Text, View } from 'react-native'
+import config from './config'
+import styles from './styles'
+
+function makeYAxis() {
+ const scaleMin = config.temperatureScale.low
+ const scaleMax = config.temperatureScale.high
+ const numberOfTicks = (scaleMax - scaleMin) * 2
+ const tickDistance = config.chartHeight / numberOfTicks
+
+ const tickPositions = []
+ const labels = []
+ // for style reasons, we don't want the first and last tick
+ for (let i = 1; i < numberOfTicks - 1; i++) {
+ const y = tickDistance * i
+ const style = styles.yAxisLabel
+ // 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
+ labels.push(
+
+ {scaleMax - i * 0.5}
+
+ )
+ tickPositions.push(y)
+ }
+
+ return {labels, tickPositions}
+}
+
+export const yAxis = makeYAxis()
+
+export const horizontalGrid = yAxis.tickPositions.map(tick => {
+ return (
+
+ )
+})
+
+export function normalizeToScale(temp) {
+ const scale = config.temperatureScale
+ const valueRelativeToScale = (scale.high - temp) / (scale.high - scale.low)
+ const scaleHeight = config.chartHeight
+ return scaleHeight * valueRelativeToScale
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 86dcf00..b0cdbd3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6426,6 +6426,11 @@
"resolved": "https://registry.npmjs.org/react-native-simple-radio-button/-/react-native-simple-radio-button-2.7.2.tgz",
"integrity": "sha512-BdlllHsC/gYJtxPJ2tshDWN8CzmlGg1G9uB+Lu4FRGvGkwhvMtJ/uNShMbvxu134xosH/feri6HQgLGlIT202Q=="
},
+ "react-native-slowlog": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/react-native-slowlog/-/react-native-slowlog-1.0.2.tgz",
+ "integrity": "sha1-VSCXnj751Sc0ldQx/zvjTwLjXIk="
+ },
"react-native-tab-view": {
"version": "0.0.77",
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz",
diff --git a/package.json b/package.json
index 58f2638..cf36e50 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"react-native-share": "^1.1.0",
"react-native-simple-radio-button": "^2.7.1",
"react-native-vector-icons": "^5.0.0",
+ "react-native-slowlog": "^1.0.2",
"react-navigation": "^2.0.4",
"realm": "^2.7.1",
"uuid": "^3.2.1"