@opengeoweb/time-series 20.2.0-nightly-20261029 → 21.0.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/dist/index.esm.js CHANGED
@@ -7950,6 +7950,177 @@ function getPlotCharts(plotsWithData) {
7950
7950
  return plotCharts;
7951
7951
  }
7952
7952
 
7953
+ /** One clock per view; standalone charts can use their own clock. Times are milliseconds. */
7954
+ var useCurrentTime = function useCurrentTime(enabled) {
7955
+ if (enabled === void 0) {
7956
+ enabled = true;
7957
+ }
7958
+ var _React$useState = React.useState(Date.now),
7959
+ now = _React$useState[0],
7960
+ setNow = _React$useState[1];
7961
+ React.useEffect(function () {
7962
+ if (!enabled) {
7963
+ return undefined;
7964
+ }
7965
+ var update = function update() {
7966
+ return setNow(Date.now());
7967
+ };
7968
+ update();
7969
+ var timer = window.setInterval(update, 60000);
7970
+ return function () {
7971
+ return window.clearInterval(timer);
7972
+ };
7973
+ }, [enabled]);
7974
+ return now;
7975
+ };
7976
+ /** Fractional category index, preserving the spacing of the chart's time axis. */
7977
+ var getCurrentTimeIndex = function getCurrentTimeIndex(timestamps, currentTime) {
7978
+ if (!Number.isFinite(currentTime) || !timestamps.length || currentTime < timestamps[0] || currentTime > timestamps[timestamps.length - 1]) {
7979
+ return undefined;
7980
+ }
7981
+ var next = timestamps.findIndex(function (time) {
7982
+ return time >= currentTime;
7983
+ });
7984
+ if (next < 0) {
7985
+ return undefined;
7986
+ }
7987
+ if (next === 0 || timestamps[next] === currentTime) {
7988
+ return next;
7989
+ }
7990
+ return next - 1 + (currentTime - timestamps[next - 1]) / (timestamps[next] - timestamps[next - 1]);
7991
+ };
7992
+ var getCurrentTimeLines = function getCurrentTimeLines(instance, currentTime, showPlots, showZoom) {
7993
+ if (instance.isDisposed()) {
7994
+ return [];
7995
+ }
7996
+ var api = instance;
7997
+ var model = api.getModel();
7998
+ if (!model) {
7999
+ return [];
8000
+ }
8001
+ var lines = [];
8002
+ model.eachComponent('xAxis', function (axis) {
8003
+ var timestamps = axis.getCategories().map(function (time) {
8004
+ return Date.parse(time);
8005
+ });
8006
+ var index = getCurrentTimeIndex(timestamps, currentTime);
8007
+ if (index === undefined) {
8008
+ return;
8009
+ }
8010
+ var _axis$axis$scale$getE = axis.axis.scale.getExtent(),
8011
+ min = _axis$axis$scale$getE[0],
8012
+ max = _axis$axis$scale$getE[1];
8013
+ if (showPlots && index >= min && index <= max) {
8014
+ var _model$getComponent;
8015
+ var rect = (_model$getComponent = model.getComponent('grid', axis.get('gridIndex'))) == null || (_model$getComponent = _model$getComponent.coordinateSystem) == null ? void 0 : _model$getComponent.getRect();
8016
+ var lower = Math.floor(index);
8017
+ var upper = Math.ceil(index);
8018
+ var left = instance.convertToPixel({
8019
+ xAxisIndex: axis.componentIndex
8020
+ }, lower);
8021
+ var right = instance.convertToPixel({
8022
+ xAxisIndex: axis.componentIndex
8023
+ }, upper);
8024
+ var x = left + (right - left) * (index - lower);
8025
+ if (rect && Number.isFinite(x) && x >= rect.x && x <= rect.x + rect.width) {
8026
+ lines.push({
8027
+ id: "plot-" + axis.componentIndex,
8028
+ x: x,
8029
+ y: rect.y,
8030
+ height: rect.height
8031
+ });
8032
+ }
8033
+ }
8034
+ if (showZoom && axis.componentIndex === 0) {
8035
+ var _displayables$sliderG;
8036
+ var zoom = model.getComponent('dataZoom', 0);
8037
+ var view = zoom && zoom.get('show') && api.getViewOfComponentModel(zoom);
8038
+ var _ref = view || {},
8039
+ displayables = _ref._displayables;
8040
+ var background = displayables == null || (_displayables$sliderG = displayables.sliderGroup) == null ? void 0 : _displayables$sliderG.childAt(0);
8041
+ if (background) {
8042
+ background.getComputedTransform();
8043
+ var start = background.transformCoordToGlobal(0, 0);
8044
+ var end = background.transformCoordToGlobal(background.shape.width, background.shape.height);
8045
+ var fraction = timestamps.length === 1 ? 0.5 : index / (timestamps.length - 1);
8046
+ lines.push({
8047
+ id: 'zoom',
8048
+ x: start[0] + fraction * (end[0] - start[0]),
8049
+ y: Math.min(start[1], end[1]),
8050
+ height: Math.abs(end[1] - start[1])
8051
+ });
8052
+ }
8053
+ }
8054
+ });
8055
+ return lines;
8056
+ };
8057
+ var CurrentTime = function CurrentTime(_ref2) {
8058
+ var instance = _ref2.instance,
8059
+ currentTime = _ref2.currentTime,
8060
+ showPlots = _ref2.showPlots,
8061
+ showZoom = _ref2.showZoom;
8062
+ var theme = useTheme();
8063
+ var _React$useState2 = React.useState([]),
8064
+ lines = _React$useState2[0],
8065
+ setLines = _React$useState2[1];
8066
+ React.useEffect(function () {
8067
+ if (!instance) {
8068
+ return undefined;
8069
+ }
8070
+ var update = function update() {
8071
+ var next = getCurrentTimeLines(instance, currentTime, showPlots, showZoom);
8072
+ setLines(function (previous) {
8073
+ return JSON.stringify(previous) === JSON.stringify(next) ? previous : next;
8074
+ });
8075
+ };
8076
+ update();
8077
+ instance.on('rendered', update);
8078
+ return function () {
8079
+ if (!instance.isDisposed()) {
8080
+ instance.off('rendered', update);
8081
+ }
8082
+ };
8083
+ }, [instance, currentTime, showPlots, showZoom]);
8084
+ var _theme$palette$geoweb = theme.palette.geowebColors.timeSlider,
8085
+ playerNeedleTime = _theme$palette$geoweb.playerNeedleTime,
8086
+ playerNeedleTimeTop = _theme$palette$geoweb.playerNeedleTimeTop;
8087
+ return jsx("svg", {
8088
+ "aria-hidden": "true",
8089
+ "data-testid": "CurrentTime",
8090
+ style: {
8091
+ position: 'absolute',
8092
+ inset: 0,
8093
+ width: '100%',
8094
+ height: '100%',
8095
+ pointerEvents: 'none',
8096
+ overflow: 'hidden'
8097
+ },
8098
+ children: lines.map(function (_ref3) {
8099
+ var id = _ref3.id,
8100
+ x = _ref3.x,
8101
+ y = _ref3.y,
8102
+ height = _ref3.height;
8103
+ return jsxs("g", {
8104
+ children: [jsx("line", {
8105
+ stroke: playerNeedleTime.rgba,
8106
+ strokeWidth: 7,
8107
+ x1: x,
8108
+ x2: x,
8109
+ y1: y,
8110
+ y2: y + height
8111
+ }), jsx("line", {
8112
+ stroke: playerNeedleTimeTop.rgba,
8113
+ strokeWidth: 2,
8114
+ x1: x,
8115
+ x2: x,
8116
+ y1: y,
8117
+ y2: y + height
8118
+ })]
8119
+ }, id);
8120
+ })
8121
+ });
8122
+ };
8123
+
7953
8124
  // Guard: mocked ReactECharts (forwardRef) has no real prototype chain.
7954
8125
  var reactEChartsProto = ReactECharts.prototype;
7955
8126
  var echartsReactCoreProto = reactEChartsProto ? Object.getPrototypeOf(reactEChartsProto) : null;
@@ -8194,7 +8365,12 @@ var TimeSeriesChart = function TimeSeriesChart(_ref3) {
8194
8365
  shouldShowZoom = _ref3$shouldShowZoom === void 0 ? true : _ref3$shouldShowZoom,
8195
8366
  controlsOnly = _ref3.controlsOnly,
8196
8367
  synchronization = _ref3.synchronization,
8197
- sharedTimesteps = _ref3.sharedTimesteps;
8368
+ sharedTimesteps = _ref3.sharedTimesteps,
8369
+ currentTime = _ref3.currentTime;
8370
+ var now = useCurrentTime(currentTime === undefined && controlsOnly !== 'legend');
8371
+ var _React$useState2 = React.useState(null),
8372
+ indicatorInstance = _React$useState2[0],
8373
+ setIndicatorInstance = _React$useState2[1];
8198
8374
  var theme = useTheme();
8199
8375
  var isDark = theme.palette.mode === 'dark';
8200
8376
  var containerRef = React.useRef(null);
@@ -8315,18 +8491,21 @@ var TimeSeriesChart = function TimeSeriesChart(_ref3) {
8315
8491
  return observer.disconnect();
8316
8492
  };
8317
8493
  }, [observesContainer, updateHeight]);
8318
- return option ? jsx("div", {
8494
+ return option ? jsxs("div", {
8319
8495
  "data-testid": controlsOnly ? {
8320
8496
  legend: 'TimeSeriesLegend',
8321
8497
  zoom: 'TimeSeriesZoom'
8322
8498
  }[controlsOnly] : 'TimeSeriesChart',
8323
8499
  ref: containerRef,
8324
8500
  style: fitToContainer ? {
8501
+ position: 'relative',
8325
8502
  height: '100%',
8326
8503
  width: '100%',
8327
8504
  minHeight: 0
8328
- } : undefined,
8329
- children: jsx(ReactECharts, {
8505
+ } : {
8506
+ position: 'relative'
8507
+ },
8508
+ children: [jsx(ReactECharts, {
8330
8509
  autoResize: !observesContainer,
8331
8510
  notMerge: true,
8332
8511
  onChartReady: function onChartReady(instance) {
@@ -8338,6 +8517,7 @@ var TimeSeriesChart = function TimeSeriesChart(_ref3) {
8338
8517
  synchronization == null || synchronization.register(instance, controlsOnly !== 'zoom');
8339
8518
  }
8340
8519
  updateHeight(instance);
8520
+ setIndicatorInstance(instance);
8341
8521
  },
8342
8522
  // noop, prevent flickering when toggling legend
8343
8523
  onEvents: {
@@ -8385,7 +8565,12 @@ var TimeSeriesChart = function TimeSeriesChart(_ref3) {
8385
8565
  minWidth: fitToContainer ? 0 : MIN_GRAPH_WIDTH
8386
8566
  },
8387
8567
  theme: isDark ? EChartsDarkTheme : EChartsLightTheme
8388
- })
8568
+ }), controlsOnly !== 'legend' && jsx(CurrentTime, {
8569
+ currentTime: currentTime != null ? currentTime : now,
8570
+ instance: indicatorInstance,
8571
+ showPlots: !controlsOnly,
8572
+ showZoom: controlsOnly === 'zoom' || shouldShowZoom
8573
+ })]
8389
8574
  }) : null;
8390
8575
  };
8391
8576
 
@@ -8538,7 +8723,8 @@ var TimeSeriesPlot = function TimeSeriesPlot(_ref) {
8538
8723
  var plot = _ref.plot,
8539
8724
  parametersFailingInAllPlots = _ref.parametersFailingInAllPlots,
8540
8725
  synchronization = _ref.synchronization,
8541
- sharedTimesteps = _ref.sharedTimesteps;
8726
+ sharedTimesteps = _ref.sharedTimesteps,
8727
+ currentTime = _ref.currentTime;
8542
8728
  var _useTimeseriesTransla = useTimeseriesTranslation(),
8543
8729
  t = _useTimeseriesTransla.t;
8544
8730
  var commonKeys = new Set(parametersFailingInAllPlots.map(getParameterKey));
@@ -8566,6 +8752,7 @@ var TimeSeriesPlot = function TimeSeriesPlot(_ref) {
8566
8752
  minHeight: 0
8567
8753
  },
8568
8754
  children: jsx(TimeSeriesChart, {
8755
+ currentTime: currentTime,
8569
8756
  fitToContainer: true,
8570
8757
  plotsWithData: [plot],
8571
8758
  sharedTimesteps: sharedTimesteps,
@@ -8590,6 +8777,7 @@ var TimeSeriesView = /*#__PURE__*/React.memo(function (_ref2) {
8590
8777
  var _useTimeseriesTransla2 = useTimeseriesTranslation(),
8591
8778
  t = _useTimeseriesTransla2.t;
8592
8779
  var synchronization = useChartSynchronization();
8780
+ var currentTime = useCurrentTime();
8593
8781
  var _useGetPlotsWithData = useGetPlotsWithData(plotPreset, selectedLocation, services, splitGeoJsonByCollection, t, syncgroupTimeState),
8594
8782
  plotsWithData = _useGetPlotsWithData.data,
8595
8783
  isFetchingPlots = _useGetPlotsWithData.isFetching;
@@ -8652,6 +8840,7 @@ var TimeSeriesView = /*#__PURE__*/React.memo(function (_ref2) {
8652
8840
  return item.plotId === plotId;
8653
8841
  });
8654
8842
  return plot ? jsx(TimeSeriesPlot, {
8843
+ currentTime: currentTime,
8655
8844
  parametersFailingInAllPlots: parametersFailingInAllPlots,
8656
8845
  plot: plot,
8657
8846
  sharedTimesteps: sharedTimesteps,
@@ -8710,6 +8899,7 @@ var TimeSeriesView = /*#__PURE__*/React.memo(function (_ref2) {
8710
8899
  },
8711
8900
  children: jsx(TimeSeriesChart, {
8712
8901
  controlsOnly: "zoom",
8902
+ currentTime: currentTime,
8713
8903
  plotsWithData: plotsWithData,
8714
8904
  sharedTimesteps: sharedTimesteps,
8715
8905
  shouldShowLegend: false,
@@ -0,0 +1,20 @@
1
+ import type { EChartsInstance } from 'echarts-for-react';
2
+ import React from 'react';
3
+ /** One clock per view; standalone charts can use their own clock. Times are milliseconds. */
4
+ export declare const useCurrentTime: (enabled?: boolean) => number;
5
+ /** Fractional category index, preserving the spacing of the chart's time axis. */
6
+ export declare const getCurrentTimeIndex: (timestamps: number[], currentTime: number) => number | undefined;
7
+ interface IndicatorLine {
8
+ id: string;
9
+ x: number;
10
+ y: number;
11
+ height: number;
12
+ }
13
+ export declare const getCurrentTimeLines: (instance: EChartsInstance, currentTime: number, showPlots: boolean, showZoom: boolean) => IndicatorLine[];
14
+ export declare const CurrentTime: React.FC<{
15
+ instance: EChartsInstance | null;
16
+ currentTime: number;
17
+ showPlots: boolean;
18
+ showZoom: boolean;
19
+ }>;
20
+ export {};
@@ -0,0 +1 @@
1
+ export * from './CurrentTime';
@@ -52,5 +52,6 @@ export declare const TimeSeriesChart: React.FC<{
52
52
  controlsOnly?: 'legend' | 'zoom';
53
53
  synchronization?: ReturnType<typeof useChartSynchronization>;
54
54
  sharedTimesteps?: Date[];
55
+ currentTime?: number;
55
56
  }>;
56
57
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/time-series",
3
- "version": "20.2.0-nightly-20261029",
3
+ "version": "21.0.0",
4
4
  "description": "GeoWeb time-series library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -21,26 +21,26 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "immer": "^10.0.3",
24
- "@opengeoweb/shared": "20.2.0-nightly-20261029",
24
+ "@opengeoweb/shared": "21.0.0",
25
25
  "@reduxjs/toolkit": "^2.6.1",
26
26
  "react-redux": "^9.2.0",
27
- "@opengeoweb/webmap": "20.2.0-nightly-20261029",
28
- "@opengeoweb/webmap-react": "20.2.0-nightly-20261029",
27
+ "@opengeoweb/webmap": "21.0.0",
28
+ "@opengeoweb/webmap-react": "21.0.0",
29
29
  "lodash": "^4.18.1",
30
- "@opengeoweb/api": "20.2.0-nightly-20261029",
31
- "@opengeoweb/authentication": "20.2.0-nightly-20261029",
32
- "@opengeoweb/theme": "20.2.0-nightly-20261029",
33
- "@opengeoweb/store": "20.2.0-nightly-20261029",
30
+ "@opengeoweb/api": "21.0.0",
31
+ "@opengeoweb/authentication": "21.0.0",
32
+ "@opengeoweb/theme": "21.0.0",
33
+ "@opengeoweb/store": "21.0.0",
34
34
  "echarts-for-react": "^3.0.6",
35
35
  "echarts": "^6.1.0",
36
36
  "react-sortablejs": "^6.1.4",
37
- "@opengeoweb/snackbar": "20.2.0-nightly-20261029",
37
+ "@opengeoweb/snackbar": "21.0.0",
38
38
  "react-window": "^2.2.6",
39
39
  "msw": "^2.7.3",
40
40
  "i18next": "^25.0.1",
41
41
  "react-i18next": "^15.1.1",
42
- "@opengeoweb/core": "20.2.0-nightly-20261029",
43
- "@opengeoweb/form-fields": "20.2.0-nightly-20261029",
42
+ "@opengeoweb/core": "21.0.0",
43
+ "@opengeoweb/form-fields": "21.0.0",
44
44
  "@mui/material": "^9.0.1",
45
45
  "react-hook-form": "^7.61.1",
46
46
  "uuid": "^11.1.1",