-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DistanceUnitFormatter and DurationUnitFormatter, two react compon…
…ents to automatically choose the best unit for a value They also allow clicking on the values to cycle between the different possible units. Example usage is shown in transit routing output for the walking mode. Fixes #775
- Loading branch information
1 parent
726c117
commit 83c3a2c
Showing
7 changed files
with
189 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
packages/chaire-lib-frontend/src/components/pageParts/DistanceUnitFormatter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright 2023, Polytechnique Montreal and contributors | ||
* | ||
* This file is licensed under the MIT License. | ||
* License text available at https://opensource.org/licenses/MIT | ||
*/ | ||
import React, { useState, useEffect } from 'react'; | ||
import { withTranslation, WithTranslation } from 'react-i18next'; | ||
import { roundToDecimals } from 'chaire-lib-common/lib/utils/MathUtils'; | ||
import { metersToMiles, metersToFeet } from 'chaire-lib-common/lib/utils/PhysicsUtils'; | ||
|
||
const destinationUnitOptions = ['kilometers', 'meters', 'miles', 'feet'] as const; | ||
type destinationUnitOptionsType = typeof destinationUnitOptions[number]; | ||
|
||
export interface DistanceUnitFormatterProps extends WithTranslation { | ||
value: number; | ||
sourceUnit: 'kilometers' | 'meters'; | ||
destinationUnit?: destinationUnitOptionsType; | ||
} | ||
|
||
const DistanceUnitFormatter: React.FunctionComponent<DistanceUnitFormatterProps> = ( | ||
props: DistanceUnitFormatterProps | ||
) => { | ||
const [destinationUnit, setDestinationUnit] = useState<string | undefined>(props.destinationUnit); | ||
|
||
const valueInMeters = props.sourceUnit === 'meters' ? props.value : props.value / 1000; | ||
|
||
useEffect(() => { | ||
// If the destination unit was not specified, we choose the best one based on the magnitude of the value. | ||
if (destinationUnit === undefined) { | ||
if (valueInMeters < 1000) { | ||
setDestinationUnit('meters'); | ||
} else { | ||
setDestinationUnit('kilometers'); | ||
} | ||
} | ||
}, [valueInMeters]); | ||
|
||
const unitFormatters: Record<destinationUnitOptionsType, (value: number) => string> = { | ||
meters: (value) => `${roundToDecimals(value, 0)} ${props.t('main:meterAbbr')}`, | ||
kilometers: (value) => `${roundToDecimals(value / 1000, 2)} ${props.t('main:kilometerAbbr')}`, | ||
miles: (value) => `${roundToDecimals(metersToMiles(value), 2)} ${props.t('main:mileAbbr')}`, | ||
feet: (value) => `${roundToDecimals(metersToFeet(value), 0)} ${props.t('main:feetAbbr')}` | ||
}; | ||
|
||
const formattedValue = destinationUnit ? unitFormatters[destinationUnit](valueInMeters) : ''; | ||
|
||
const cycleThroughDestinationUnits = () => { | ||
// Infer the next unit based on the currently displayed unit. | ||
setDestinationUnit((prevUnit) => { | ||
return destinationUnitOptions[ | ||
(destinationUnitOptions.indexOf(prevUnit as destinationUnitOptionsType) + 1) % | ||
destinationUnitOptions.length | ||
]; | ||
}); | ||
}; | ||
|
||
return <span onClick={cycleThroughDestinationUnits}>{formattedValue}</span>; | ||
}; | ||
|
||
export default withTranslation([])(DistanceUnitFormatter); |
66 changes: 66 additions & 0 deletions
66
packages/chaire-lib-frontend/src/components/pageParts/DurationUnitFormatter.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright 2023, Polytechnique Montreal and contributors | ||
* | ||
* This file is licensed under the MIT License. | ||
* License text available at https://opensource.org/licenses/MIT | ||
*/ | ||
import React, { useState, useEffect } from 'react'; | ||
import { withTranslation, WithTranslation } from 'react-i18next'; | ||
import { toXXhrYYminZZsec } from 'chaire-lib-common/lib/utils/DateTimeUtils'; | ||
import { roundToDecimals } from 'chaire-lib-common/lib/utils/MathUtils'; | ||
|
||
const destinationUnitOptions = ['hrMinSec', 'seconds', 'minutes', 'hours'] as const; | ||
type destinationUnitOptionsType = typeof destinationUnitOptions[number]; | ||
|
||
export interface DurationUnitFormatterProps extends WithTranslation { | ||
value: number; | ||
sourceUnit: 'seconds' | 'minutes' | 'hours'; | ||
destinationUnit?: destinationUnitOptionsType; | ||
} | ||
|
||
const DurationUnitFormatter: React.FunctionComponent<DurationUnitFormatterProps> = ( | ||
props: DurationUnitFormatterProps | ||
) => { | ||
const [destinationUnit, setDestinationUnit] = useState<string | undefined>(props.destinationUnit); | ||
|
||
const valueInSeconds = | ||
props.sourceUnit === 'seconds' | ||
? props.value | ||
: props.sourceUnit === 'minutes' | ||
? props.value * 60 | ||
: props.sourceUnit === 'hours' | ||
? props.value * 60 * 60 | ||
: props.value; | ||
|
||
useEffect(() => { | ||
// If the destination unit was not specified, we choose a default. | ||
if (destinationUnit === undefined) { | ||
setDestinationUnit('hrMinSec'); | ||
} | ||
}, [valueInSeconds]); | ||
|
||
const unitFormatters: Record<destinationUnitOptionsType, (value: number) => string> = { | ||
hrMinSec: (value) => | ||
toXXhrYYminZZsec(value, props.t('main:hourAbbr'), props.t('main:minuteAbbr'), props.t('main:secondAbbr')) || | ||
`${value.toString()} ${props.t('main:secondAbbr')}`, | ||
seconds: (value) => `${roundToDecimals(value, 2)} ${props.t('main:secondAbbr')}`, | ||
minutes: (value) => `${roundToDecimals(value / 60, 2)} ${props.t('main:minuteAbbr')}`, | ||
hours: (value) => `${roundToDecimals(value / 3600, 2)} ${props.t('main:hourAbbr')}` | ||
}; | ||
|
||
const formattedValue = destinationUnit ? unitFormatters[destinationUnit](valueInSeconds) : ''; | ||
|
||
const cycleThroughDestinationUnits = () => { | ||
// Infer the next unit based on the currently displayed unit. | ||
setDestinationUnit((prevUnit) => { | ||
return destinationUnitOptions[ | ||
(destinationUnitOptions.indexOf(prevUnit as destinationUnitOptionsType) + 1) % | ||
destinationUnitOptions.length | ||
]; | ||
}); | ||
}; | ||
|
||
return <span onClick={cycleThroughDestinationUnits}>{formattedValue}</span>; | ||
}; | ||
|
||
export default withTranslation([])(DurationUnitFormatter); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters