diff --git a/src/lib/charts/timeSeriesDisplayToChartConfig.ts b/src/lib/charts/timeSeriesDisplayToChartConfig.ts index 8ccf88d78..f00cebdd7 100644 --- a/src/lib/charts/timeSeriesDisplayToChartConfig.ts +++ b/src/lib/charts/timeSeriesDisplayToChartConfig.ts @@ -1,6 +1,7 @@ import type { ChartConfig } from './types/ChartConfig.js' import type { ChartSeries } from './types/ChartSeries.js' import type { + ActionPeriod, TimeSeriesDisplayPlotItemXAxis, TimeSeriesDisplaySubplot, TimeSeriesDisplaySubplotItem, @@ -16,14 +17,34 @@ import { AxisPosition, AxisType, } from '@deltares/fews-web-oc-charts' +import { convertFewsPiDateTimeToJsDate } from '@/lib/date/index.js' export function timeSeriesDisplayToChartConfig( subplot: TimeSeriesDisplaySubplot, title: string, + period?: ActionPeriod, ): ChartConfig { + const xAxis = subplot.xAxis ? xAxisFromPlotItemXAxis(subplot.xAxis) : [] + if (period) { + // The period is always specified in UTC. + const timeZoneOffsetString = 'Z' + const domain: [Date, Date] = [ + convertFewsPiDateTimeToJsDate(period.startDate, timeZoneOffsetString), + convertFewsPiDateTimeToJsDate(period.endDate, timeZoneOffsetString), + ] + // Set the domain of the x-axis to be equal to the period, even if there are + // no data points in parts of the period. + if (xAxis.length === 0) { + xAxis.push({ domain }) + } else { + // Time series charts always have just a single x-axis. + xAxis[0].domain = domain + } + } + const config: ChartConfig = { title: title, - xAxis: subplot.xAxis ? xAxisFromPlotItemXAxis(subplot.xAxis) : [], + xAxis, yAxis: yAxisFromSubplot(subplot), series: [], } diff --git a/src/lib/date/convertFewsPiDateTimeToJsDate.test.ts b/src/lib/date/convertFewsPiDateTimeToJsDate.test.ts new file mode 100644 index 000000000..0a3627c0f --- /dev/null +++ b/src/lib/date/convertFewsPiDateTimeToJsDate.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from 'vitest' + +import { convertFewsPiDateTimeToJsDate } from '.' + +test('parses a FEWS PI date/time object to a Date object without timezone offset', () => { + const fewsDatetime = { date: '2021-07-01', time: '12:00:00' } + const result = convertFewsPiDateTimeToJsDate(fewsDatetime, 'Z') + expect(result).toEqual(new Date('2021-07-01T12:00:00Z')) +}) + +test('parses a FEWS PI date/time object to a Date object with a timezone offset', () => { + const fewsDatetime = { date: '2021-07-01', time: '12:00:00' } + const result = convertFewsPiDateTimeToJsDate(fewsDatetime, '+02:00') + expect(result).toEqual(new Date('2021-07-01T12:00:00+02:00')) +}) diff --git a/src/lib/date/index.ts b/src/lib/date/index.ts index 71d89be30..96cf4988b 100644 --- a/src/lib/date/index.ts +++ b/src/lib/date/index.ts @@ -36,3 +36,20 @@ export function getDateWithMinutesOffset(date: Date, minutesOffset: number) { result.setMinutes(result.getMinutes() + minutesOffset) return result } + +/** + * Converts a FEWS PI date/time object to a Date object. + * + * @param fewsDatetime - The FEWS date/time object to convert. + * @param timeZoneOffsetString - Timezone offset string to apply to the date. + * E.g., '+02:00' or 'Z'. + * @returns The date/time as a Date object. + */ +export function convertFewsPiDateTimeToJsDate( + fewsDatetime: { date: string; time: string }, + timeZoneOffsetString: string, +): Date { + return new Date( + `${fewsDatetime.date}T${fewsDatetime.time}${timeZoneOffsetString}`, + ) +} diff --git a/src/services/useDisplayConfig/index.ts b/src/services/useDisplayConfig/index.ts index b65369f58..f8b088131 100644 --- a/src/services/useDisplayConfig/index.ts +++ b/src/services/useDisplayConfig/index.ts @@ -8,7 +8,6 @@ import { ref, toValue, watchEffect } from 'vue' import type { MaybeRefOrGetter, Ref } from 'vue' import { DisplayConfig } from '../../lib/display/DisplayConfig.js' import { timeSeriesDisplayToChartConfig } from '../../lib/charts/timeSeriesDisplayToChartConfig.js' -import { ChartConfig } from '../../lib/charts/types/ChartConfig.js' import { createTransformRequestFn } from '@/lib/requests/transformRequest.js' import { MD5 } from 'crypto-js' @@ -47,14 +46,12 @@ function actionsResponseToDisplayConfig( for (const result of actionsResponse.results) { if (result.config === undefined) continue const title = result.config.timeSeriesDisplay.title ?? '' - const timeSeriesDisplayIndex: number | undefined = - result.config.timeSeriesDisplay.index ?? undefined - let subplots: ChartConfig[] = [] - if (result.config.timeSeriesDisplay.subplots) { - subplots = result.config.timeSeriesDisplay.subplots?.map((subPlot) => { - return timeSeriesDisplayToChartConfig(subPlot, title) - }) - } + const timeSeriesDisplayIndex = result.config.timeSeriesDisplay.index + const period = result.config.timeSeriesDisplay.period + const subplots = + result.config.timeSeriesDisplay.subplots?.map((subPlot) => { + return timeSeriesDisplayToChartConfig(subPlot, title, period) + }) ?? [] const display: DisplayConfig = { id: title, title, diff --git a/src/services/useTimeSeries/index.ts b/src/services/useTimeSeries/index.ts index d9aa7fa8e..cd9565b10 100644 --- a/src/services/useTimeSeries/index.ts +++ b/src/services/useTimeSeries/index.ts @@ -14,6 +14,7 @@ import { SeriesUrlRequest } from '../../lib/timeseries/timeSeriesResource' import { createTransformRequestFn } from '@/lib/requests/transformRequest' import { difference } from 'lodash-es' import { SeriesData } from '@/lib/timeseries/types/SeriesData' +import { convertFewsPiDateTimeToJsDate } from '@/lib/date' export interface UseTimeSeriesReturn { error: Ref @@ -38,13 +39,6 @@ function timeZoneOffsetString(offset: number): string { .padStart(2, '0')}` } -function parsePiDateTime( - event: { date: string; time: string }, - timeZone: string, -) { - return `${event.date}T${event.time}${timeZone}` -} - /** * Reactive async state. Will not block your setup function and will trigger changes once * the promise is ready. @@ -152,14 +146,18 @@ export function useTimeSeries( _series.header.parameter = header.parameterId _series.header.location = header.stationName _series.header.source = header.moduleInstanceId - _series.start = new Date( - parsePiDateTime(header.startDate, timeZone), + _series.start = convertFewsPiDateTimeToJsDate( + header.startDate, + timeZone, + ) + _series.end = convertFewsPiDateTimeToJsDate( + header.endDate, + timeZone, ) - _series.end = new Date(parsePiDateTime(header.endDate, timeZone)) if (timeSeries.events) { _series.data = timeSeries.events.map((event) => { return { - x: new Date(parsePiDateTime(event, timeZone)), + x: convertFewsPiDateTimeToJsDate(event, timeZone), y: event.value === _series.missingValue ? null @@ -264,7 +262,7 @@ function fillSeriesForElevation( if (time === undefined || date === undefined) { return false } - const eventDate = new Date(parsePiDateTime({ date, time }, timeZone)) + const eventDate = convertFewsPiDateTimeToJsDate({ date, time }, timeZone) return eventDate.getTime() === currentDate.getTime() })