diff --git a/components/chart/chart-line.js b/components/chart/chart-line.js
new file mode 100644
index 0000000..95300ad
--- /dev/null
+++ b/components/chart/chart-line.js
@@ -0,0 +1,28 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import { Shape } from 'react-native/Libraries/ART/ReactNativeART'
+
+import styles from './styles'
+
+const ChartLine = ({ path, isNfpLine = false }) => {
+ const strokeStyle =
+ isNfpLine ? styles.nfpLine.stroke : styles.column.stroke.color
+ const strokeWidth =
+ isNfpLine ? styles.nfpLine.strokeWidth : styles.column.stroke.width
+
+ return (
+
+ )
+}
+
+ChartLine.propTypes = {
+ path: PropTypes.object,
+ isNfpLine: PropTypes.bool,
+}
+
+export default ChartLine
diff --git a/components/chart/chart.js b/components/chart/chart.js
index 8f8a3f5..9598552 100644
--- a/components/chart/chart.js
+++ b/components/chart/chart.js
@@ -1,20 +1,20 @@
import React, { Component } from 'react'
import { View, FlatList, ActivityIndicator } from 'react-native'
-import { LocalDate } from 'js-joda'
+import AppLoadingView from '../app-loading'
import YAxis from './y-axis'
import nfpLines from './nfp-lines'
import DayColumn from './day-column'
import HorizontalGrid from './horizontal-grid'
-import { getCycleDaysSortedByDate, getAmountOfCycleDays } from '../../db'
-import styles from './styles'
+import { getCycleDaysSortedByDate } from '../../db'
+import nothingChanged from '../../db/db-unchanged'
import { scaleObservable } from '../../local-storage'
+import { makeColumnInfo } from '../helpers/chart'
+
import config from '../../config'
-import AppLoadingView from '../app-loading'
-
-import nothingChanged from '../../db/db-unchanged'
+import styles from './styles'
export default class CycleChart extends Component {
constructor(props) {
@@ -32,7 +32,6 @@ export default class CycleChart extends Component {
navigate={this.props.navigate}
symptomHeight={this.symptomHeight}
columnHeight={this.columnHeight}
- chartHeight={this.state.chartHeight}
symptomRowSymptoms={this.symptomRowSymptoms}
chartSymptoms={this.chartSymptoms}
getFhmAndLtlInfo={this.getFhmAndLtlInfo}
@@ -72,7 +71,7 @@ export default class CycleChart extends Component {
this.chartSymptoms.push('temperature')
}
- const columnData = this.makeColumnInfo()
+ const columnData = makeColumnInfo()
this.setState({
columns: columnData,
chartHeight: height
@@ -104,43 +103,29 @@ export default class CycleChart extends Component {
this.removeObvListener()
}
- makeColumnInfo() {
- 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 localDates = getTodayAndPreviousDays(amountOfCycleDays)
- return localDates.map(localDate => localDate.toString())
- }
-
render() {
const { chartHeight, chartLoaded } = this.state
return (
{!chartLoaded && }
{chartHeight && chartLoaded && (
-
+
+
+
+
)}
- {chartHeight && chartLoaded && (
- )
- }
-
{chartHeight &&
)
}
-
-function getTodayAndPreviousDays(n) {
- const today = LocalDate.now()
- const targetDate = today.minusDays(n)
-
- function getDaysInRange(currDate, range) {
- if (currDate.isBefore(targetDate)) {
- return range
- } else {
- range.push(currDate)
- const next = currDate.minusDays(1)
- return getDaysInRange(next, range)
- }
- }
-
- return getDaysInRange(today, [])
-}
diff --git a/components/chart/cycle-day-label.js b/components/chart/cycle-day-label.js
new file mode 100644
index 0000000..38a0d2e
--- /dev/null
+++ b/components/chart/cycle-day-label.js
@@ -0,0 +1,39 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import { Text, View } from 'react-native'
+
+import moment from 'moment'
+import { LocalDate } from 'js-joda'
+
+import styles from './styles'
+import cycleModule from '../../lib/cycle'
+
+const CycleDayLabel = ({ height, date }) => {
+ const { label } = styles.column
+ const dayDate = LocalDate.parse(date)
+ const cycleDayNumber = cycleModule().getCycleDayNumber(date)
+
+ const isFirstDayOfMonth = dayDate.dayOfMonth() === 1
+ const dateFormatting = isFirstDayOfMonth ? 'MMM' : 'Do'
+ const shortDate = moment(date, "YYYY-MM-DD").format(dateFormatting)
+ const boldDateLabel = isFirstDayOfMonth ? {fontWeight: 'bold'} : {}
+
+ return (
+
+
+ {cycleDayNumber ? cycleDayNumber : ' '}
+
+
+ {shortDate}
+
+
+ )
+}
+
+CycleDayLabel.propTypes = {
+ height: PropTypes.number,
+ date: PropTypes.string,
+}
+
+export default CycleDayLabel
diff --git a/components/chart/day-column.js b/components/chart/day-column.js
index 1597697..633f636 100644
--- a/components/chart/day-column.js
+++ b/components/chart/day-column.js
@@ -1,30 +1,20 @@
import React, { Component } from 'react'
-import {
- Text, View, TouchableOpacity
-} from 'react-native'
-import {
- Surface,
- Group as G,
- Path,
- Shape
-} from 'react-native/Libraries/ART/ReactNativeART'
+import { TouchableOpacity } from 'react-native'
import { connect } from 'react-redux'
import { setDate } from '../../slices/date'
-import { LocalDate } from 'js-joda'
-import moment from 'moment'
-import styles from './styles'
-import config from '../../config'
-import cycleModule from '../../lib/cycle'
import { getCycleDay } from '../../db'
-import DotAndLine from './dot-and-line'
import SymptomCell from './symptom-cell'
+import TemperatureColumn from './temperature-column'
+import CycleDayLabel from './cycle-day-label'
-import { normalizeToScale } from '../helpers/chart'
-
-const label = styles.column.label
+import {
+ symptomColorMethods,
+ getTemperatureProps,
+ isSymptomDataComplete
+} from '../helpers/chart'
class DayColumn extends Component {
constructor(props) {
@@ -40,14 +30,13 @@ class DayColumn extends Component {
if (symptomData && symptom === 'temperature') {
symptomDataToDisplay[symptom] =
- this.getTemperatureProps(symptomData, columnHeight, dateString)
+ getTemperatureProps(symptomData, columnHeight, dateString)
} else {
if (symptomData && ! symptomData.exclude) {
// if symptomColorMethods entry doesn't exist for given symptom,
// use 'default'
const getSymptomColorIndex =
- this.symptomColorMethods[symptom] ||
- this.symptomColorMethods['default']
+ symptomColorMethods[symptom] || symptomColorMethods['default']
symptomDataToDisplay[symptom] = getSymptomColorIndex(symptomData)
}
@@ -64,75 +53,6 @@ class DayColumn extends Component {
)
}
- getTemperatureProps = (symptomData, columnHeight, dateString) => {
- const extractedData = {}
- const { value, exclude } = symptomData
- const neighborTemperatureGraphPoints =
- getInfoForNeighborColumns(dateString, columnHeight)
-
- for (const key in neighborTemperatureGraphPoints) {
- extractedData[key] = neighborTemperatureGraphPoints[key]
- }
- return Object.assign({
- value,
- y: normalizeToScale(value, columnHeight),
- temperatureExclude: exclude,
- }, extractedData)
- }
-
- symptomColorMethods = {
- 'mucus': (symptomData) => {
- const { feeling, texture } = symptomData
- const colorIndex = feeling + texture
- return colorIndex
- },
- 'cervix': (symptomData) => {
- const { opening, firmness } = symptomData
- const isDataComplete = opening !== null && firmness !== null
- const isClosedAndHard =
- isDataComplete &&
- (opening === 0 && firmness === 0)
- const colorIndex = isClosedAndHard ? 0 : 2
- return colorIndex
- },
- 'sex': (symptomData) => {
- const { solo, partner } = symptomData
- const colorIndex = (solo !== null && partner !== null) ?
- (solo + 2 * partner - 1) : 0
- return colorIndex
- },
- 'bleeding': (symptomData) => {
- const { value } = symptomData
- const colorIndex = value
- return colorIndex
- },
- 'default': () => { // desire, pain, mood, note
- const colorIndex = 0
- return colorIndex
- }
- }
-
- isSymptomDataComplete = (symptom) => {
- const { dateString } = this.props
- const cycleDayData = getCycleDay(dateString)
- const symptomData = cycleDayData[symptom]
-
- const dataCompletenessCheck = {
- 'cervix': () => {
- const { opening, firmness } = symptomData
- return (opening !== null) && (firmness !== null)
- },
- 'mucus': () => {
- const { feeling, texture } = symptomData
- return (feeling !== null) && (texture !== null)
- },
- 'default': () => {
- return true
- }
- }
- return (dataCompletenessCheck[symptom] || dataCompletenessCheck['default'])()
- }
-
onDaySelect = (date) => {
this.props.setDate(date)
this.props.navigate('CycleDay')
@@ -143,89 +63,11 @@ class DayColumn extends Component {
}
render() {
- const columnElements = []
const { dateString,
symptomRowSymptoms,
- chartHeight,
columnHeight,
xAxisHeight } = this.props
- if(this.fhmAndLtl.drawLtlAt) {
- const ltlLine = ()
- columnElements.push(ltlLine)
- }
-
- if (this.fhmAndLtl.drawFhmLine) {
- const x = styles.nfpLine.strokeWidth / 2
- const fhmLine = ()
- columnElements.push(fhmLine)
- }
-
- if (this.data && this.data.temperature && this.data.temperature.y) {
- const { temperatureExclude,
- y,
- rightY,
- leftY,
- rightTemperatureExclude,
- leftTemperatureExclude
- } = this.data.temperature
-
- columnElements.push(
-
- )
- }
-
- const cycleDayNumber = cycleModule().getCycleDayNumber(dateString)
- const dayDate = LocalDate.parse(dateString)
- const shortDate = dayDate.dayOfMonth() === 1 ?
- moment(dateString, "YYYY-MM-DD").format('MMM')
- :
- moment(dateString, "YYYY-MM-DD").format('Do')
- const boldDateLabel = dayDate.dayOfMonth() === 1 ? {fontWeight: 'bold'} : {}
-
- const cycleDayLabel = (
-
- {cycleDayNumber ? cycleDayNumber : ' '}
- )
- const dateLabel = (
-
- {shortDate}
-
- )
-
- const column = (
-
-
- { columnElements }
-
- )
-
return (
this.onDaySelect(dateString)}
@@ -240,21 +82,25 @@ class DayColumn extends Component {
symptom={symptom}
symptomValue={hasSymptomData && this.data[symptom]}
isSymptomDataComplete={
- hasSymptomData && this.isSymptomDataComplete(symptom)
+ hasSymptomData && isSymptomDataComplete(symptom, dateString)
}
height={this.props.symptomHeight}
/>)
}
)}
-
- {column}
-
+
+
+
-
- {cycleDayLabel}
- {dateLabel}
-
)
}
@@ -270,28 +116,3 @@ export default connect(
null,
mapDispatchToProps,
)(DayColumn)
-
-
-function getInfoForNeighborColumns(dateString, columnHeight) {
- const ret = {
- rightY: null,
- rightTemperatureExclude: null,
- leftY: null,
- leftTemperatureExclude: null
- }
- const target = LocalDate.parse(dateString)
- const dayBefore = target.minusDays(1).toString()
- const dayAfter = target.plusDays(1).toString()
- const cycleDayBefore = getCycleDay(dayBefore)
- const cycleDayAfter = getCycleDay(dayAfter)
- if (cycleDayAfter && cycleDayAfter.temperature) {
- ret.rightY = normalizeToScale(cycleDayAfter.temperature.value, columnHeight)
- ret.rightTemperatureExclude = cycleDayAfter.temperature.exclude
- }
- if (cycleDayBefore && cycleDayBefore.temperature) {
- ret.leftY = normalizeToScale(cycleDayBefore.temperature.value, columnHeight)
- ret.leftTemperatureExclude = cycleDayBefore.temperature.exclude
- }
-
- return ret
-}
diff --git a/components/chart/styles.js b/components/chart/styles.js
index dc3a69b..5580af0 100644
--- a/components/chart/styles.js
+++ b/components/chart/styles.js
@@ -25,6 +25,10 @@ const orangeColor = '#bc6642'
const mintColor = '#6ca299'
const styles = {
+ container: {
+ flexDirection: 'row',
+ flex: 1,
+ },
curve: {
stroke: colorTemperature,
strokeWidth: lineWidth,
diff --git a/components/chart/temperature-column.js b/components/chart/temperature-column.js
new file mode 100644
index 0000000..fab3d97
--- /dev/null
+++ b/components/chart/temperature-column.js
@@ -0,0 +1,64 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+import { Surface , Path } from 'react-native/Libraries/ART/ReactNativeART'
+
+import ChartLine from './chart-line'
+import DotAndLine from './dot-and-line'
+
+import styles from './styles'
+import config from '../../config'
+
+const TemperatureColumn = ({
+ horizontalLinePosition,
+ isVerticalLine,
+ data,
+ columnHeight
+}) => {
+
+ const x = styles.nfpLine.strokeWidth / 2
+
+ return (
+
+
+
+
+ {horizontalLinePosition && }
+
+ {isVerticalLine && }
+
+ {data && data.y && }
+
+
+ )
+}
+
+TemperatureColumn.propTypes = {
+ horizontalLinePosition: PropTypes.number,
+ isVerticalLine: PropTypes.bool,
+ data: PropTypes.object,
+ columnHeight: PropTypes.number,
+}
+
+export default TemperatureColumn
diff --git a/components/helpers/chart.js b/components/helpers/chart.js
index 24a563c..d59a55a 100644
--- a/components/helpers/chart.js
+++ b/components/helpers/chart.js
@@ -1,6 +1,12 @@
+import { LocalDate } from 'js-joda'
+
import { scaleObservable, unitObservable } from '../../local-storage'
+import { getCycleDay, getAmountOfCycleDays } from '../../db'
+
import config from '../../config'
+//YAxis helpers
+
export function normalizeToScale(temp, columnHeight) {
const scale = scaleObservable.value
const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min)
@@ -65,3 +71,130 @@ export function getTickList(columnHeight) {
}
})
}
+
+//DayColumn helpers
+
+export function isSymptomDataComplete(symptom, dateString) {
+ const cycleDayData = getCycleDay(dateString)
+ const symptomData = cycleDayData[symptom]
+
+ const dataCompletenessCheck = {
+ 'cervix': () => {
+ const { opening, firmness } = symptomData
+ return (opening !== null) && (firmness !== null)
+ },
+ 'mucus': () => {
+ const { feeling, texture } = symptomData
+ return (feeling !== null) && (texture !== null)
+ },
+ 'default': () => {
+ return true
+ }
+ }
+ return (dataCompletenessCheck[symptom] || dataCompletenessCheck['default'])()
+}
+
+function getInfoForNeighborColumns(dateString, columnHeight) {
+ const ret = {
+ rightY: null,
+ rightTemperatureExclude: null,
+ leftY: null,
+ leftTemperatureExclude: null
+ }
+ const target = LocalDate.parse(dateString)
+ const dayBefore = target.minusDays(1).toString()
+ const dayAfter = target.plusDays(1).toString()
+ const cycleDayBefore = getCycleDay(dayBefore)
+ const cycleDayAfter = getCycleDay(dayAfter)
+
+ if (cycleDayAfter && cycleDayAfter.temperature) {
+ ret.rightY = normalizeToScale(cycleDayAfter.temperature.value, columnHeight)
+ ret.rightTemperatureExclude = cycleDayAfter.temperature.exclude
+ }
+ if (cycleDayBefore && cycleDayBefore.temperature) {
+ ret.leftY = normalizeToScale(cycleDayBefore.temperature.value, columnHeight)
+ ret.leftTemperatureExclude = cycleDayBefore.temperature.exclude
+ }
+
+ return ret
+}
+
+export function getTemperatureProps(symptomData, columnHeight, dateString) {
+ const extractedData = {}
+ const { value, exclude } = symptomData
+ const neighborTemperatureGraphPoints =
+ getInfoForNeighborColumns(dateString, columnHeight)
+
+ for (const key in neighborTemperatureGraphPoints) {
+ extractedData[key] = neighborTemperatureGraphPoints[key]
+ }
+ return Object.assign({
+ value,
+ y: normalizeToScale(value, columnHeight),
+ temperatureExclude: exclude,
+ }, extractedData)
+}
+
+export const symptomColorMethods = {
+ 'mucus': (symptomData) => {
+ const { feeling, texture } = symptomData
+ const colorIndex = feeling + texture
+ return colorIndex
+ },
+ 'cervix': (symptomData) => {
+ const { opening, firmness } = symptomData
+ const isDataComplete = opening !== null && firmness !== null
+ const isClosedAndHard =
+ isDataComplete &&
+ (opening === 0 && firmness === 0)
+ const colorIndex = isClosedAndHard ? 0 : 2
+ return colorIndex
+ },
+ 'sex': (symptomData) => {
+ const { solo, partner } = symptomData
+ const colorIndex = (solo !== null && partner !== null) ?
+ (solo + 2 * partner - 1) : 0
+ return colorIndex
+ },
+ 'bleeding': (symptomData) => {
+ const { value } = symptomData
+ const colorIndex = value
+ return colorIndex
+ },
+ 'default': () => { // desire, pain, mood, note
+ const colorIndex = 0
+ return colorIndex
+ }
+}
+
+// Chart helpers
+
+export function makeColumnInfo() {
+ 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 localDates = getTodayAndPreviousDays(amountOfCycleDays)
+ return localDates.map(localDate => localDate.toString())
+}
+
+function getTodayAndPreviousDays(n) {
+ const today = LocalDate.now()
+ const targetDate = today.minusDays(n)
+
+ function getDaysInRange(currDate, range) {
+ if (currDate.isBefore(targetDate)) {
+ return range
+ } else {
+ range.push(currDate)
+ const next = currDate.minusDays(1)
+ return getDaysInRange(next, range)
+ }
+ }
+
+ return getDaysInRange(today, [])
+}
\ No newline at end of file