@opengeoweb/time-series 15.2.0 → 15.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.esm.js CHANGED
@@ -3,7 +3,7 @@ import React, { useCallback, useState, useMemo, useEffect, memo } from 'react';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
4
  import { CustomIconButton, dateUtils, TooltipSelect, CustomAccordion, CustomTooltip, CustomToggleButton, ToolContainerDraggable, ToggleMenu, CustomDialog, SearchField, SearchHighlight, AlertBanner, useConfirmationDialog, SwitchButton, useResizeObserver } from '@opengeoweb/shared';
5
5
  import { snackbarActions, snackbarTypes, snackbarListener, snackbarReducer } from '@opengeoweb/snackbar';
6
- import { mapUtils, selectorMemoizationOptions, genericSelectors, uiSelectors, uiTypes, uiActions, useSetupDialog, mapSelectors, mapListener, serviceListener, layersListener, syncGroupsListener, genericListener, openlayersListener, uiReducer, syncGroupsReducer, layerReducer, serviceReducer, mapReducer, loadingIndicatorActions, syncGroupsActions, genericActions, mapActions, layerActions } from '@opengeoweb/store';
6
+ import { mapUtils, selectorMemoizationOptions, genericSelectors, uiSelectors, uiTypes, uiActions, useSetupDialog, mapSelectors, mapListener, serviceListener, layersListener, syncGroupsListener, genericListener, openlayersListener, uiReducer, syncGroupsReducer, layerReducer, serviceReducer, mapReducer, loadingIndicatorActions, syncGroupsActions, genericActions, useSyncgroupTimeState, mapActions, layerActions } from '@opengeoweb/store';
7
7
  import { useTheme, MenuItem, LinearProgress, Grid, Box, Typography, ClickAwayListener, Input, Collapse, Button, List, ListItem, ListItemText, InputAdornment, ListItemButton, styled, Card, Stack, Tooltip, ListItemIcon, Checkbox } from '@mui/material';
8
8
  import { isString, trim, trimStart, compact, chain, groupBy, countBy, sortBy, uniqBy, isEqual } from 'lodash';
9
9
  import { ReactSortable } from 'react-sortablejs';
@@ -1120,9 +1120,15 @@ date) {
1120
1120
  };
1121
1121
  // 1 day to past, 10 days to future
1122
1122
  var clipInterval = [1 * 24, 10 * 24];
1123
- var constructTimeInterval = function constructTimeInterval(collection, instance, parameter) {
1123
+ var constructTimeInterval = function constructTimeInterval(collection, instance, syncgroupTimeState) {
1124
1124
  var _instance$extent$temp, _instance$extent2, _collection$extent4;
1125
1125
  var interval = (_instance$extent$temp = (_instance$extent2 = instance.extent) == null || (_instance$extent2 = _instance$extent2.temporal) == null ? void 0 : _instance$extent2.interval[0]) != null ? _instance$extent$temp : collection == null || (_collection$extent4 = collection.extent) == null || (_collection$extent4 = _collection$extent4.temporal) == null ? void 0 : _collection$extent4.interval[0];
1126
+ // If syncgroupTimeState is set, use this instead of the fixed timerange.
1127
+ if ((syncgroupTimeState == null ? void 0 : syncgroupTimeState.start) !== undefined && (syncgroupTimeState == null ? void 0 : syncgroupTimeState.end) !== undefined) {
1128
+ var timeRangeStartIso = dateUtils.dateToString(dateUtils.fromUnix(syncgroupTimeState.start));
1129
+ var timeRangeEndIso = dateUtils.dateToString(dateUtils.fromUnix(syncgroupTimeState.end));
1130
+ return timeRangeStartIso + "/" + timeRangeEndIso;
1131
+ }
1126
1132
  var _clipEdrInterval = clipEdrInterval(interval, clipInterval[0], clipInterval[1]),
1127
1133
  start = _clipEdrInterval[0],
1128
1134
  end = _clipEdrInterval[1];
@@ -3248,7 +3254,7 @@ var useGetCollectionsAndInstanceDetails = function useGetCollectionsAndInstanceD
3248
3254
  }
3249
3255
  });
3250
3256
  };
3251
- var useGetPlotsWithData = function useGetPlotsWithData(plotsWithoutData, selectedLocation, services, splitGeoJsonByCollection, t) {
3257
+ var useGetPlotsWithData = function useGetPlotsWithData(plotsWithoutData, selectedLocation, services, splitGeoJsonByCollection, t, syncgroupTimeState) {
3252
3258
  var _useState = useState([]),
3253
3259
  plotsWithData = _useState[0],
3254
3260
  setPlotsWithData = _useState[1];
@@ -3281,7 +3287,7 @@ var useGetPlotsWithData = function useGetPlotsWithData(plotsWithoutData, selecte
3281
3287
  };
3282
3288
  // Construct timeinterval that needs to be fetched
3283
3289
  // Create here so if new data is advertised by the collection/instance a new request is made
3284
- var intervalParam = constructTimeInterval(collection, instanceInfo);
3290
+ var intervalParam = constructTimeInterval(collection, instanceInfo, syncgroupTimeState);
3285
3291
  return {
3286
3292
  queryKey: generateTimeSeriesQueryKeys(['get-parameter-data', parameter.propertyName, parameter.serviceId, parameter.collectionId, parameter.instanceId || 'undefined', ((_parameter$dimension = parameter.dimension) == null ? void 0 : _parameter$dimension.value) || 'undefined', intervalParam, selectedLocation.lat.toString() || 'undefined', selectedLocation.lon.toString() || 'undefined']),
3287
3293
  queryFn: function () {
@@ -3320,7 +3326,7 @@ var useGetPlotsWithData = function useGetPlotsWithData(plotsWithoutData, selecte
3320
3326
  retry: false
3321
3327
  };
3322
3328
  });
3323
- }, [collectionDetails, geojsonMap, plotsWithoutData.parameters, selectedLocation, collectionsList, isDetailsFetching]);
3329
+ }, [plotsWithoutData.parameters, collectionsList, collectionDetails, syncgroupTimeState, selectedLocation, isDetailsFetching, geojsonMap]);
3324
3330
  var results = useQueries({
3325
3331
  queries: queries,
3326
3332
  combine: function combine(results) {
@@ -7660,6 +7666,34 @@ var useChartHeight = function useChartHeight(_ref) {
7660
7666
  updateHeight: updateHeight
7661
7667
  };
7662
7668
  };
7669
+ var applyDataZoomState = function applyDataZoomState(option, dataZoomState) {
7670
+ if (!dataZoomState || !(option != null && option.dataZoom) || !Array.isArray(option.dataZoom)) {
7671
+ return option;
7672
+ }
7673
+ return Object.assign({}, option, {
7674
+ dataZoom: option.dataZoom.map(function (dz) {
7675
+ return Object.assign({}, dz, {
7676
+ start: dataZoomState.start,
7677
+ end: dataZoomState.end
7678
+ });
7679
+ })
7680
+ });
7681
+ };
7682
+ var extractDataZoomState = function extractDataZoomState(params) {
7683
+ if (params.batch && params.batch.length > 0) {
7684
+ return {
7685
+ start: params.batch[0].start,
7686
+ end: params.batch[0].end
7687
+ };
7688
+ }
7689
+ if (params.start !== undefined && params.end !== undefined) {
7690
+ return {
7691
+ start: params.start,
7692
+ end: params.end
7693
+ };
7694
+ }
7695
+ return null;
7696
+ };
7663
7697
  var TimeSeriesChart = function TimeSeriesChart(_ref2) {
7664
7698
  var plotsWithData = _ref2.plotsWithData,
7665
7699
  _ref2$animation = _ref2.animation,
@@ -7670,14 +7704,18 @@ var TimeSeriesChart = function TimeSeriesChart(_ref2) {
7670
7704
  var _useThemeContext = useThemeContext(),
7671
7705
  namedTheme = _useThemeContext.namedTheme;
7672
7706
  var isDark = (namedTheme == null ? void 0 : namedTheme.theme.palette.mode) === 'dark';
7707
+ var dataZoomStateRef = React.useRef(null);
7673
7708
  var enabledPlots = plotsWithData.filter(function (plot) {
7674
7709
  return plot.enabled === undefined || plot.enabled;
7675
7710
  });
7676
7711
  var option = getOption(enabledPlots);
7712
+ var optionWithZoom = React.useMemo(function () {
7713
+ return applyDataZoomState(option, dataZoomStateRef.current);
7714
+ }, [option]);
7677
7715
  var _useChartHeight = useChartHeight({
7678
7716
  plotsWithData: enabledPlots,
7679
7717
  shouldShowLegend: shouldShowLegend,
7680
- option: option
7718
+ option: optionWithZoom
7681
7719
  }),
7682
7720
  chartHeight = _useChartHeight.chartHeight,
7683
7721
  chartRef = _useChartHeight.chartRef,
@@ -7690,6 +7728,12 @@ var TimeSeriesChart = function TimeSeriesChart(_ref2) {
7690
7728
  // noop, prevent flickering when toggling legend
7691
7729
  onEvents: {
7692
7730
  finished: function finished() {},
7731
+ datazoom: function datazoom(params) {
7732
+ var newState = extractDataZoomState(params);
7733
+ if (newState) {
7734
+ dataZoomStateRef.current = newState;
7735
+ }
7736
+ },
7693
7737
  legendselectchanged: function legendselectchanged(params) {
7694
7738
  if (!option.legend) {
7695
7739
  return;
@@ -7702,7 +7746,7 @@ var TimeSeriesChart = function TimeSeriesChart(_ref2) {
7702
7746
  }
7703
7747
  }
7704
7748
  },
7705
- option: Object.assign({}, option, {
7749
+ option: Object.assign({}, optionWithZoom, {
7706
7750
  animation: animation
7707
7751
  }),
7708
7752
  ref: chartRef,
@@ -7724,10 +7768,11 @@ var TimeSeriesView = /*#__PURE__*/React.memo(function (_ref) {
7724
7768
  isLoading = _ref.isLoading,
7725
7769
  _ref$shouldShowLegend = _ref.shouldShowLegend,
7726
7770
  shouldShowLegend = _ref$shouldShowLegend === void 0 ? true : _ref$shouldShowLegend,
7727
- onToggleLegendParam = _ref.onToggleLegendParam;
7771
+ onToggleLegendParam = _ref.onToggleLegendParam,
7772
+ syncgroupTimeState = _ref.syncgroupTimeState;
7728
7773
  var _useTimeseriesTransla = useTimeseriesTranslation(),
7729
7774
  t = _useTimeseriesTransla.t;
7730
- var _useGetPlotsWithData = useGetPlotsWithData(plotPreset, selectedLocation, services, splitGeoJsonByCollection, t),
7775
+ var _useGetPlotsWithData = useGetPlotsWithData(plotPreset, selectedLocation, services, splitGeoJsonByCollection, t, syncgroupTimeState),
7731
7776
  plotsWithData = _useGetPlotsWithData.data,
7732
7777
  isFetchingPlots = _useGetPlotsWithData.isFetching,
7733
7778
  error = _useGetPlotsWithData.error;
@@ -7754,11 +7799,13 @@ var TimeSeriesView = /*#__PURE__*/React.memo(function (_ref) {
7754
7799
  })]
7755
7800
  });
7756
7801
  }, function (previousProps, nextProps) {
7802
+ var _previousProps$syncgr, _nextProps$syncgroupT, _previousProps$syncgr2, _nextProps$syncgroupT2;
7757
7803
  var samePreset = previousProps.plotPreset === nextProps.plotPreset;
7758
7804
  var sameLocation = isEqual(previousProps.selectedLocation, nextProps.selectedLocation);
7759
7805
  var sameGeoJson = isEqual(previousProps.splitGeoJsonByCollection, nextProps.splitGeoJsonByCollection);
7760
7806
  var sameLegend = previousProps.shouldShowLegend === nextProps.shouldShowLegend;
7761
- return samePreset && sameLocation && sameGeoJson && sameLegend;
7807
+ var sameTime = ((_previousProps$syncgr = previousProps.syncgroupTimeState) == null ? void 0 : _previousProps$syncgr.start) === ((_nextProps$syncgroupT = nextProps.syncgroupTimeState) == null ? void 0 : _nextProps$syncgroupT.start) && ((_previousProps$syncgr2 = previousProps.syncgroupTimeState) == null ? void 0 : _previousProps$syncgr2.end) === ((_nextProps$syncgroupT2 = nextProps.syncgroupTimeState) == null ? void 0 : _nextProps$syncgroupT2.end);
7808
+ return samePreset && sameLocation && sameGeoJson && sameLegend && sameTime;
7762
7809
  });
7763
7810
 
7764
7811
  var TOOLTIP_TITLE = 'Timeseries Manager';
@@ -8089,6 +8136,7 @@ var TimeSeriesConnect = function TimeSeriesConnect(_ref3) {
8089
8136
  panelId: panelId
8090
8137
  }));
8091
8138
  };
8139
+ var syncgroupTimeState = useSyncgroupTimeState(panelId, 1000);
8092
8140
  return jsxs(Stack, {
8093
8141
  "data-testid": "TimeSeriesConnect",
8094
8142
  sx: {
@@ -8152,7 +8200,8 @@ var TimeSeriesConnect = function TimeSeriesConnect(_ref3) {
8152
8200
  selectedLocation: timeSeriesLocation,
8153
8201
  services: services,
8154
8202
  shouldShowLegend: shouldShowLegend,
8155
- splitGeoJsonByCollection: geoJSONWithService || []
8203
+ splitGeoJsonByCollection: geoJSONWithService || [],
8204
+ syncgroupTimeState: syncgroupTimeState
8156
8205
  })
8157
8206
  })]
8158
8207
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/time-series",
3
- "version": "15.2.0",
3
+ "version": "15.3.0",
4
4
  "description": "GeoWeb time-series library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -9,25 +9,25 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "immer": "^10.0.3",
12
- "@opengeoweb/shared": "15.2.0",
12
+ "@opengeoweb/shared": "15.3.0",
13
13
  "@reduxjs/toolkit": "^2.6.1",
14
14
  "react-redux": "^9.2.0",
15
- "@opengeoweb/webmap": "15.2.0",
16
- "@opengeoweb/webmap-react": "15.2.0",
15
+ "@opengeoweb/webmap": "15.3.0",
16
+ "@opengeoweb/webmap-react": "15.3.0",
17
17
  "lodash": "^4.17.21",
18
- "@opengeoweb/api": "15.2.0",
19
- "@opengeoweb/theme": "15.2.0",
20
- "@opengeoweb/store": "15.2.0",
18
+ "@opengeoweb/api": "15.3.0",
19
+ "@opengeoweb/theme": "15.3.0",
20
+ "@opengeoweb/store": "15.3.0",
21
21
  "echarts-for-react": "^3.0.2",
22
22
  "echarts": "^5.4.3",
23
23
  "react-sortablejs": "^6.1.4",
24
- "@opengeoweb/snackbar": "15.2.0",
24
+ "@opengeoweb/snackbar": "15.3.0",
25
25
  "react-window": "^2.2.6",
26
26
  "msw": "^2.7.3",
27
27
  "i18next": "^25.0.1",
28
28
  "react-i18next": "^15.1.1",
29
- "@opengeoweb/core": "15.2.0",
30
- "@opengeoweb/form-fields": "15.2.0",
29
+ "@opengeoweb/core": "15.3.0",
30
+ "@opengeoweb/form-fields": "15.3.0",
31
31
  "@mui/material": "^7.0.1",
32
32
  "react-hook-form": "^7.61.1",
33
33
  "uuid": "^10.0.0",
@@ -35,6 +35,7 @@ export declare const TimeSeriesEDRNetherlandsObsDemo: {
35
35
  }[];
36
36
  };
37
37
  };
38
+ export declare const TimeSeriesEDRNetherlandsObsDemoWithSyncGroup: () => React.ReactElement;
38
39
  export declare const TimeSeriesUKDemo: () => React.ReactElement;
39
40
  declare const _default: {
40
41
  title: string;
@@ -10,6 +10,19 @@ export declare const useChartHeight: ({ plotsWithData, shouldShowLegend, option,
10
10
  chartRef: React.RefObject<EChartsInstance>;
11
11
  updateHeight: (echartsInstance: EChartsInstance) => void;
12
12
  };
13
+ export interface DataZoomState {
14
+ start: number;
15
+ end: number;
16
+ }
17
+ export declare const applyDataZoomState: (option: EChartsOption, dataZoomState: DataZoomState | null) => EChartsOption;
18
+ export declare const extractDataZoomState: (params: {
19
+ start?: number;
20
+ end?: number;
21
+ batch?: {
22
+ start: number;
23
+ end: number;
24
+ }[];
25
+ }) => DataZoomState | null;
13
26
  export declare const TimeSeriesChart: React.FC<{
14
27
  plotsWithData: PlotWithData[];
15
28
  animation?: boolean;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { PlotPreset, TimeSeriesService } from '@opengeoweb/shared';
3
+ import type { TimeSliderStartEndStep } from '@opengeoweb/store';
3
4
  import type { PointerLocation, GeoJsonWithService } from './types';
4
5
  interface TimeSeriesViewProps {
5
6
  plotPreset: PlotPreset;
@@ -9,6 +10,7 @@ interface TimeSeriesViewProps {
9
10
  isLoading?: (startOrFinish: boolean) => void;
10
11
  shouldShowLegend?: boolean;
11
12
  onToggleLegendParam?: (legendId: string) => void;
13
+ syncgroupTimeState?: TimeSliderStartEndStep;
12
14
  }
13
15
  export declare const TimeSeriesView: React.FC<TimeSeriesViewProps>;
14
16
  export {};
@@ -1,5 +1,6 @@
1
1
  import type { Feature, Geometry, GeometryObject, Position } from 'geojson';
2
- import type { PlotParameter, TimeSeriesService } from '@opengeoweb/shared';
2
+ import type { TimeSeriesService } from '@opengeoweb/shared';
3
+ import type { TimeSliderStartEndStep } from '@opengeoweb/store';
3
4
  import { MapFeatureClass } from '@opengeoweb/webmap-react';
4
5
  import type { EDRCollection, EDRInstance, EDRParameter, Parameter, PointerLocation, SelectParameter } from '../components/TimeSeries/types';
5
6
  import type { TimeseriesCollectionDetail } from '../components/TimeSeriesSelect/utils';
@@ -44,7 +45,7 @@ export declare const getDetailsForCollectionId: (collections: TimeseriesCollecti
44
45
  * @returns Clipped EDR interval, e.g. ["startdate_as_isostring","enddate_as_isostring"]
45
46
  */
46
47
  export declare const clipEdrInterval: (interval: string[] | undefined, maxHoursBefore?: number, maxHoursAfter?: number, date?: number) => [string, string];
47
- export declare const constructTimeInterval: (collection: TimeseriesCollectionDetail | undefined, instance: EDRInstance, parameter: PlotParameter) => string;
48
+ export declare const constructTimeInterval: (collection: TimeseriesCollectionDetail | undefined, instance: EDRInstance, syncgroupTimeState?: TimeSliderStartEndStep) => string;
48
49
  /**
49
50
  * Find nearest point to the target location in timeseries.
50
51
  * Uses equirectangular distance approximation which is not accurate for long
@@ -2,6 +2,7 @@ import type { UseQueryResult } from '@tanstack/react-query';
2
2
  import type { FeatureCollection, Geometry } from 'geojson';
3
3
  import type { TFunction } from 'i18next';
4
4
  import type { PlotPreset, TimeSeriesService } from '@opengeoweb/shared';
5
+ import type { TimeSliderStartEndStep } from '@opengeoweb/store';
5
6
  import type { EDRServiceInformation } from './api';
6
7
  import type { EDRCollection, EDRInstance, GeoJsonWithService, PlotWithData, PointerLocation, UseGetLocationReturnTypeProperties } from '../../components/TimeSeries/types';
7
8
  import type { ParameterCollectionQueryData } from '../../components/TimeSeries/utils';
@@ -51,7 +52,7 @@ export declare const useGetDetailsForCollection: (service: TimeSeriesService, co
51
52
  export declare const useGetInstances: (serviceUrl: string, collectionId: string, supportsInstances?: boolean) => UseQueryResult<EDRInstance[]>;
52
53
  export declare const useGetServiceCollectionDetails: (services: TimeSeriesService[], isOpen: boolean) => CombinedResult<TimeseriesCollectionDetail[]>;
53
54
  export declare const useGetCollectionsAndInstanceDetails: (queryData: Record<string, ParameterCollectionQueryData>) => CombinedResult<TimeseriesCollectionDetail[]>;
54
- export declare const useGetPlotsWithData: (plotsWithoutData: PlotPreset, selectedLocation: PointerLocation, services: TimeSeriesService[], splitGeoJsonByCollection: GeoJsonWithService[], t: TFunction) => {
55
+ export declare const useGetPlotsWithData: (plotsWithoutData: PlotPreset, selectedLocation: PointerLocation, services: TimeSeriesService[], splitGeoJsonByCollection: GeoJsonWithService[], t: TFunction, syncgroupTimeState?: TimeSliderStartEndStep) => {
55
56
  data: PlotWithData[] | undefined;
56
57
  isFetching: boolean;
57
58
  error: Error | null | undefined;