@@ -25,6 +25,9 @@ import { getVariableEntryId } from '../../metadata-catalog/utilities.js'
2525 *
2626 * @event terra-date-range-change - Emitted whenever the date range of the date slider is updated
2727 */
28+
29+ type LastChanged = 'variable' | 'location' | undefined
30+
2831export default class TerraDataRods extends TerraElement {
2932 static styles : CSSResultGroup = [ componentStyles , styles ]
3033 static dependencies = {
@@ -90,8 +93,82 @@ export default class TerraDataRods extends TerraElement {
9093
9194 @state ( ) catalogVariable : Variable
9295
96+ /**
97+ * anytime user selects invalid dates
98+ */
99+ @state ( ) private dateErrorMessage ?: string
100+
101+ @state ( ) private lastChanged ?: LastChanged
102+
103+ /**
104+ * add a warning state
105+ */
106+ @state ( ) private spatialWarningMessage ?: string
107+
93108 _fetchVariableTask = getFetchVariableTask ( this )
94109
110+ get variableBoundingBox ( ) {
111+ const variable = this . catalogVariable
112+ if ( ! variable ) return undefined
113+
114+ const {
115+ dataProductWest,
116+ dataProductSouth,
117+ dataProductEast,
118+ dataProductNorth,
119+ } = variable
120+
121+ if (
122+ dataProductWest == null ||
123+ dataProductSouth == null ||
124+ dataProductEast == null ||
125+ dataProductNorth == null
126+ ) {
127+ return undefined
128+ }
129+
130+ return `${ dataProductWest } , ${ dataProductSouth } , ${ dataProductEast } , ${ dataProductNorth } `
131+ }
132+
133+ private compatibilityWarning ( ) {
134+ this . spatialWarningMessage = undefined
135+
136+ if ( ! this . catalogVariable || ! this . location ) return
137+
138+ const {
139+ dataProductWest,
140+ dataProductSouth,
141+ dataProductEast,
142+ dataProductNorth,
143+ } = this . catalogVariable
144+
145+ if (
146+ dataProductWest == null ||
147+ dataProductSouth == null ||
148+ dataProductEast == null ||
149+ dataProductNorth == null
150+ ) {
151+ return
152+ }
153+
154+ const [ latStr , lonStr ] = this . location . split ( ',' )
155+ const lat = Number ( latStr )
156+ const lon = Number ( lonStr )
157+
158+ const inside =
159+ lon >= dataProductWest &&
160+ lon <= dataProductEast &&
161+ lat >= dataProductSouth &&
162+ lat <= dataProductNorth
163+
164+ if ( ! inside ) {
165+ this . spatialWarningMessage =
166+ this . lastChanged === 'variable'
167+ ? 'This variable has no data at the selected location.'
168+ : 'The selected location is outside the coverage of this variable.'
169+ }
170+ }
171+
95172 render ( ) {
96173 const minDate = this . catalogVariable
97174 ? getUTCDate ( this . catalogVariable . dataProductBeginDateTime )
@@ -101,6 +178,9 @@ export default class TerraDataRods extends TerraElement {
101178 : undefined
102179
103180 return html `
181+ ${ this . spatialWarningMessage && this . lastChanged === 'location'
182+ ? html `< div class ="warning "> ⚠️ ${ this . spatialWarningMessage } </ div > `
183+ : null }
104184 < terra-variable-combobox
105185 exportparts ="base:variable-combobox__base, combobox:variable-combobox__combobox, button:variable-combobox__button, listbox:variable-combobox__listbox "
106186 .value =${ getVariableEntryId ( this ) }
@@ -109,8 +189,12 @@ export default class TerraDataRods extends TerraElement {
109189 @terra-combobox-change="${ this . #handleVariableChange} "
110190 > </ terra-variable-combobox >
111191
192+ ${ this . spatialWarningMessage && this . lastChanged === 'variable'
193+ ? html `< div class ="warning "> ⚠️ ${ this . spatialWarningMessage } </ div > `
194+ : null }
112195 < terra-spatial-picker
113196 initial-value =${ this . location }
197+ .spatialConstraints =${ this . variableBoundingBox }
114198 exportparts="map:spatial-picker__map, leaflet-bbox:spatial-picker__leaflet-bbox, leaflet-point:spatial-picker__leaflet-point"
115199 label="Select Point"
116200 @terra-map-change=${ this . #handleMapChange}
@@ -120,12 +204,17 @@ export default class TerraDataRods extends TerraElement {
120204 variable-entry-id =${ getVariableEntryId ( this ) }
121205 start-date =${ this . startDate }
122206 end-date=${ this . endDate }
123- location=${ this . location }
207+ . location=${ this . location ?? undefined }
124208 bearer-token=${ this . bearerToken }
125209 show-citation=${ true }
126210 @terra-date-range-change=${ this . #handleTimeSeriesDateRangeChange}
127211 >
128- < li slot ="help-links "> < a href ="https://disc.gsfc.nasa.gov/information/tools?title=Hydrology%20Time%20Series "> User Guide</ a > </ li >
212+ < li slot ="help-links ">
213+ < a
214+ href ="https://disc.gsfc.nasa.gov/information/tools?title=Hydrology%20Time%20Series "
215+ > User Guide</ a
216+ >
217+ </ li >
129218 </ terra-time-series >
130219
131220 < terra-date-range-slider
@@ -135,7 +224,13 @@ export default class TerraDataRods extends TerraElement {
135224 start-date=${ this . startDate }
136225 end-date=${ this . endDate }
137226 @terra-date-range-change="${ this . #handleDateRangeSliderChangeEvent} "
227+ @terra-date-selection-invalid="${ this . #handleInvalidDateSelection} "
138228 > </ terra-date-range-slider >
229+ ${ this . dateErrorMessage
230+ ? html `< div class ="date-error " style ="color: red; ">
231+ ${ this . dateErrorMessage }
232+ </ div > `
233+ : null }
139234 `
140235 }
141236
@@ -147,14 +242,35 @@ export default class TerraDataRods extends TerraElement {
147242 this . endDate = event . detail . endDate
148243 }
149244
245+ /**
246+ * anytime user selects invalid dates outside variable date range
247+ */
248+ #handleInvalidDateSelection( event : CustomEvent ) {
249+ this . dateErrorMessage = event . detail . message
250+ }
251+
150252 #handleVariableChange( event : TerraComboboxChangeEvent ) {
151- this . variableEntryId = event . detail . entryId
253+ const newEntryId = event . detail . entryId
254+
255+ //Do nothing if this is just initial sync
256+ if ( newEntryId === this . variableEntryId ) {
257+ return
258+ }
259+
260+ this . variableEntryId = newEntryId
261+ this . location = undefined
262+ this . lastChanged = 'variable'
263+
264+ this . compatibilityWarning ( )
152265 }
153266
154267 #handleMapChange( event : TerraMapChangeEvent ) {
155268 if ( event . detail . type === MapEventType . POINT ) {
156269 // TODO: we may want to pick a `toFixed()` length in the spatial picker and stick with it.
157270 this . location = `${ event . detail . latLng . lat . toFixed ( 4 ) } ,${ event . detail . latLng . lng . toFixed ( 4 ) } `
271+ this . lastChanged = 'location'
272+
273+ this . compatibilityWarning ( )
158274 }
159275 }
160276
0 commit comments