@@ -6,14 +6,21 @@ import tidePredictor, {
66} from '@neaps/tide-predictor'
77import type { GeolibInputCoordinates } from 'geolib/es/types'
88
9- type DatumOption = {
9+ type Units = 'meters' | 'feet'
10+ type PredictionOptions = {
1011 /** Datum to return predictions in. Defaults to 'MLLW' if available for the nearest station. */
1112 datum ?: string
13+
14+ /** Units for returned water levels. Defaults to 'meters'. */
15+ units ?: Units
1216}
1317
14- export type ExtremesOptions = ExtremesInput & DatumOption
15- export type TimelineOptions = TimeSpan & DatumOption
16- export type WaterLevelOptions = { time : Date } & DatumOption
18+ export type ExtremesOptions = ExtremesInput & PredictionOptions
19+ export type TimelineOptions = TimeSpan & PredictionOptions
20+ export type WaterLevelOptions = { time : Date } & PredictionOptions
21+
22+ const feetPerMeter = 3.2808399
23+ const defaultUnits : Units = 'meters'
1724
1825/**
1926 * Get extremes prediction using the nearest station to the given position.
@@ -105,7 +112,7 @@ export function useStation(station: Station, distance?: number) {
105112 // Use MLLW as the default datum if available
106113 const defaultDatum = 'MLLW' in datums ? 'MLLW' : undefined
107114
108- function getPredictor ( { datum = defaultDatum } : DatumOption = { } ) {
115+ function getPredictor ( { datum = defaultDatum } : PredictionOptions = { } ) {
109116 let offset = 0
110117
111118 if ( datum ) {
@@ -139,47 +146,62 @@ export function useStation(station: Station, distance?: number) {
139146 datums,
140147 harmonic_constituents,
141148 defaultDatum,
142- getExtremesPrediction ( { datum = defaultDatum , ... input } : ExtremesOptions ) {
143- return {
144- datum ,
145- distance ,
146- station ,
147- extremes : getPredictor ( { datum } ) . getExtremesPrediction ( {
148- ...input ,
149- offsets : station . offsets
150- } )
151- }
149+ getExtremesPrediction ( {
150+ datum = defaultDatum ,
151+ units = defaultUnits ,
152+ ... options
153+ } : ExtremesOptions ) {
154+ const extremes = getPredictor ( { datum } )
155+ . getExtremesPrediction ( { ...options , offsets : station . offsets } )
156+ . map ( ( e ) => toPreferredUnits ( e , units ) )
157+
158+ return { datum , units , station , distance , extremes }
152159 } ,
153160
154161 getTimelinePrediction ( {
155162 datum = defaultDatum ,
156- ...params
163+ units = defaultUnits ,
164+ ...options
157165 } : TimelineOptions ) {
158166 if ( station . type === 'subordinate' ) {
159167 throw new Error (
160168 `Timeline predictions are not supported for subordinate stations.`
161169 )
162170 }
171+ const timeline = getPredictor ( { datum } )
172+ . getTimelinePrediction ( options )
173+ . map ( ( e ) => toPreferredUnits ( e , units ) )
163174
164- return {
165- datum,
166- station,
167- timeline : getPredictor ( { datum } ) . getTimelinePrediction ( params )
168- }
175+ return { datum, units, station, distance, timeline }
169176 } ,
170177
171- getWaterLevelAtTime ( { time, datum = defaultDatum } : WaterLevelOptions ) {
178+ getWaterLevelAtTime ( {
179+ time,
180+ datum = defaultDatum ,
181+ units = defaultUnits
182+ } : WaterLevelOptions ) {
172183 if ( station . type === 'subordinate' ) {
173184 throw new Error (
174185 `Water level predictions are not supported for subordinate stations.`
175186 )
176187 }
177188
178- return {
179- datum,
180- station,
181- ...getPredictor ( { datum } ) . getWaterLevelAtTime ( { time } )
182- }
189+ const prediction = toPreferredUnits (
190+ getPredictor ( { datum } ) . getWaterLevelAtTime ( { time } ) ,
191+ units
192+ )
193+
194+ return { datum, units, station, distance, ...prediction }
183195 }
184196 }
185197}
198+
199+ function toPreferredUnits < T extends { level : number } > (
200+ prediction : T ,
201+ units : Units
202+ ) : T {
203+ let { level } = prediction
204+ if ( units === 'feet' ) level *= feetPerMeter
205+ else if ( units !== 'meters' ) throw new Error ( `Unsupported units: ${ units } ` )
206+ return { ...prediction , level }
207+ }
0 commit comments