Feature: Combine dynamic month label with moving month label in x axis
Co-authored-by: @livgm
This commit is contained in:
@@ -1,21 +1,23 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
import AppText from '../common/app-text'
|
import AppText from '../common/app-text'
|
||||||
|
|
||||||
import { Sizes, Typography } from '../../styles'
|
import { Sizes, Typography } from '../../styles'
|
||||||
import { CHART_YAXIS_WIDTH } from '../../config'
|
import { CHART_YAXIS_WIDTH } from '../../config'
|
||||||
import { shared as labels } from '../../i18n/en/labels'
|
|
||||||
|
|
||||||
const ChartLegend = ({ height }) => {
|
const ChartLegend = ({ height, currentDate }) => {
|
||||||
|
const displayedMonth = moment(currentDate).format('MMM')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, { height }]}>
|
<View style={[styles.container, { height }]}>
|
||||||
<View style={[styles.singleLabelContainer, { height: height / 2 }]}>
|
<View style={[styles.singleLabelContainer, { height: height / 2 }]}>
|
||||||
<AppText style={styles.textBold}>#</AppText>
|
<AppText style={styles.textBold}>#</AppText>
|
||||||
</View>
|
</View>
|
||||||
<View style={[styles.singleLabelContainer, { height: height / 2 }]}>
|
<View style={[styles.singleLabelContainer, { height: height / 2 }]}>
|
||||||
<AppText style={styles.text}>{labels.date}</AppText>
|
<AppText style={styles.text}>{displayedMonth}</AppText>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
@@ -23,6 +25,7 @@ const ChartLegend = ({ height }) => {
|
|||||||
|
|
||||||
ChartLegend.propTypes = {
|
ChartLegend.propTypes = {
|
||||||
height: PropTypes.number.isRequired,
|
height: PropTypes.number.isRequired,
|
||||||
|
currentDate: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
CHART_GRID_LINE_HORIZONTAL_WIDTH,
|
CHART_GRID_LINE_HORIZONTAL_WIDTH,
|
||||||
CHART_SYMPTOM_HEIGHT_RATIO,
|
CHART_SYMPTOM_HEIGHT_RATIO,
|
||||||
CHART_XAXIS_HEIGHT_RATIO,
|
CHART_XAXIS_HEIGHT_RATIO,
|
||||||
|
CHART_YAXIS_WIDTH,
|
||||||
SYMPTOMS,
|
SYMPTOMS,
|
||||||
} from '../../config'
|
} from '../../config'
|
||||||
import { Spacing } from '../../styles'
|
import { Spacing } from '../../styles'
|
||||||
@@ -97,8 +98,7 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
const shouldShowNoDataWarning =
|
const shouldShowNoDataWarning =
|
||||||
isTemperatureEnabled && chartSymptoms.indexOf('temperature') <= -1
|
isTemperatureEnabled && chartSymptoms.indexOf('temperature') <= -1
|
||||||
|
|
||||||
const { width, height } = Dimensions.get('window')
|
const { height } = Dimensions.get('window')
|
||||||
const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
|
|
||||||
|
|
||||||
const xAxisHeight = height * 0.7 * CHART_XAXIS_HEIGHT_RATIO
|
const xAxisHeight = height * 0.7 * CHART_XAXIS_HEIGHT_RATIO
|
||||||
const remainingHeight = height * 0.7 - xAxisHeight
|
const remainingHeight = height * 0.7 - xAxisHeight
|
||||||
@@ -117,6 +117,29 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
|
|
||||||
const columns = makeColumnInfo()
|
const columns = makeColumnInfo()
|
||||||
|
|
||||||
|
// Monitor scrolling to show proper month abbreviation in symptom chart
|
||||||
|
|
||||||
|
const [currentScrollPosition, setCurrentScrollPosition] = useState(0)
|
||||||
|
|
||||||
|
const handleScroll = (event) => {
|
||||||
|
const currentPosition = event.nativeEvent.contentOffset.x
|
||||||
|
setCurrentScrollPosition(currentPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [numberOfColumnsToRender, setNumberOfColumnsToRender] = useState(0)
|
||||||
|
const onLayout = (event) => {
|
||||||
|
const { width } = event.nativeEvent.layout
|
||||||
|
setNumberOfColumnsToRender(
|
||||||
|
Math.round((width - CHART_YAXIS_WIDTH) / CHART_COLUMN_WIDTH)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getcomputedDateInView = () => {
|
||||||
|
const columnIndex = Math.floor(currentScrollPosition / CHART_COLUMN_WIDTH)
|
||||||
|
// detect oldest visible day to render its month dynamically
|
||||||
|
return columns[columnIndex + numberOfColumnsToRender]
|
||||||
|
}
|
||||||
|
|
||||||
const renderColumn = ({ item }) => {
|
const renderColumn = ({ item }) => {
|
||||||
return (
|
return (
|
||||||
<DayColumn
|
<DayColumn
|
||||||
@@ -144,7 +167,7 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
contentContainerStyle={styles.pageContainer}
|
contentContainerStyle={styles.pageContainer}
|
||||||
scrollViewStyle={styles.page}
|
scrollViewStyle={styles.page}
|
||||||
>
|
>
|
||||||
<View style={styles.chartContainer}>
|
<View style={styles.chartContainer} onLayout={onLayout}>
|
||||||
{shouldShowHint && <Tutorial onClose={hideHint} />}
|
{shouldShowHint && <Tutorial onClose={hideHint} />}
|
||||||
{shouldShowNoDataWarning && <NoTemperature />}
|
{shouldShowNoDataWarning && <NoTemperature />}
|
||||||
<View style={styles.chartArea}>
|
<View style={styles.chartArea}>
|
||||||
@@ -154,12 +177,15 @@ const CycleChart = ({ navigate, setDate }) => {
|
|||||||
symptomsSectionHeight={symptomRowHeight}
|
symptomsSectionHeight={symptomRowHeight}
|
||||||
shouldShowTemperatureColumn={shouldShowTemperatureColumn}
|
shouldShowTemperatureColumn={shouldShowTemperatureColumn}
|
||||||
xAxisHeight={xAxisHeight}
|
xAxisHeight={xAxisHeight}
|
||||||
|
computedDate={getcomputedDateInView()}
|
||||||
/>
|
/>
|
||||||
<MainGrid
|
<MainGrid
|
||||||
data={columns}
|
data={columns}
|
||||||
renderItem={renderColumn}
|
renderItem={renderColumn}
|
||||||
initialNumToRender={numberOfColumnsToRender}
|
initialNumToRender={numberOfColumnsToRender}
|
||||||
contentContainerStyle={{ height: chartHeight }}
|
contentContainerStyle={{ height: chartHeight }}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
scrollEventThrottle={16} // Detects scroll events at roughly 60fps
|
||||||
/>
|
/>
|
||||||
{shouldShowTemperatureColumn && (
|
{shouldShowTemperatureColumn && (
|
||||||
<HorizontalGrid height={columnHeight} />
|
<HorizontalGrid height={columnHeight} />
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ const YAxis = ({
|
|||||||
symptomsSectionHeight,
|
symptomsSectionHeight,
|
||||||
shouldShowTemperatureColumn,
|
shouldShowTemperatureColumn,
|
||||||
xAxisHeight,
|
xAxisHeight,
|
||||||
|
computedDate,
|
||||||
}) => {
|
}) => {
|
||||||
const symptomIconHeight = symptomsSectionHeight / symptomsToDisplay.length
|
const symptomIconHeight = symptomsSectionHeight / symptomsToDisplay.length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{shouldShowTemperatureColumn && <TickList height={height} />}
|
{shouldShowTemperatureColumn && <TickList height={height} />}
|
||||||
<ChartLegend height={xAxisHeight} />
|
<ChartLegend height={xAxisHeight} currentDate={computedDate} />
|
||||||
<View style={[styles.yAxis, { height: symptomsSectionHeight }]}>
|
<View style={[styles.yAxis, { height: symptomsSectionHeight }]}>
|
||||||
{symptomsToDisplay.map((symptom) => (
|
{symptomsToDisplay.map((symptom) => (
|
||||||
<SymptomIcon
|
<SymptomIcon
|
||||||
@@ -40,6 +41,7 @@ YAxis.propTypes = {
|
|||||||
symptomsSectionHeight: PropTypes.number,
|
symptomsSectionHeight: PropTypes.number,
|
||||||
shouldShowTemperatureColumn: PropTypes.bool,
|
shouldShowTemperatureColumn: PropTypes.bool,
|
||||||
xAxisHeight: PropTypes.number.isRequired,
|
xAxisHeight: PropTypes.number.isRequired,
|
||||||
|
computedDate: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
Reference in New Issue
Block a user