Skip to content

Commit

Permalink
Fix geosolutions-it#9208 Timeline map sync does not update for time r…
Browse files Browse the repository at this point in the history
…anges visualization
  • Loading branch information
allyoucanmap committed Jun 1, 2023
1 parent 153554e commit 205bc6c
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 12 deletions.
23 changes: 22 additions & 1 deletion web/client/epics/__tests__/timeline-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ import {
SET_SNAP_RADIO_BUTTON_ENABLED,
AUTOSELECT,
SELECT_TIME,
SET_TIME_LAYERS
SET_TIME_LAYERS,
setMapSync
} from '../../actions/timeline';
import { changeLayerProperties, removeNode } from '../../actions/layers';
import { SET_CURRENT_TIME, SET_OFFSET_TIME, updateLayerDimensionData } from '../../actions/dimension';
Expand Down Expand Up @@ -1123,6 +1124,26 @@ describe('timeline Epics', () => {
done();
}, MAPSYNC_OFF_STATE);
});
it('mapSync off via action should trigger update range', done => {
// tests with mapsync on take around 400 ms to run, so this have to be set with a bigger time
// TODO: use mock-axios or other tools to speed up these tests
testEpic(addTimeoutEpic(updateRangeDataOnRangeChange, 500), 4, setMapSync(false), ([action1, action2, action3, action4]) => {
const { type: startType } = action1;
const { type: range1Type, range } = action2;
const { type: range2Type } = action3;
const { type: endType } = action4;
// first action moves the current timeline view to center the current time
expect(startType).toBe(LOADING);
expect(endType).toBe(LOADING);
// in this case loading fixed file of domain values causes double trigger of range data loaded with domain
// in real world the 2nd response is histogram. TODO: test also histogram
expect(range1Type).toBe(RANGE_DATA_LOADED);
expect(range2Type).toBe(RANGE_DATA_LOADED);
expect(range.start).toBe("2000-01-01T00:00:00.000Z");
expect(range.end).toBe("2001-12-31T00:00:00.000Z");
done();
}, MAPSYNC_OFF_STATE);
});
describe('fixed domain values', () => {
const MAPSYNC_ON_DOMAIN_VALUES_STATE = set('dimension.data.time.TEST_LAYER.domain',
"2000-03-01T00:00:00.000Z,2000-06-08T00:00:00.000Z"
Expand Down
10 changes: 5 additions & 5 deletions web/client/epics/dimension.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import { layersWithTimeDataSelector, offsetTimeSelector, currentTimeSelector } f
import { describeDomains, getMultidimURL } from '../api/MultiDim';
import { domainsToDimensionsObject } from '../utils/TimeUtils';
import { pick, find, get, flatten } from 'lodash';

import { expandLimitSelector } from '../selectors/timeline';

const DESCRIBE_DOMAIN_OPTIONS = {
expandLimit: 10 // TODO: increase this limit to max client allowed
expandLimit: 10
};


Expand All @@ -50,7 +50,7 @@ export const updateLayerDimensionOnCurrentTimeSelection = (action$, { getState =
* Check the presence of Multidimensional API extension, then setup layers properly.
* Updates also current dimension state
*/
export const queryMultidimensionalAPIExtensionOnAddLayer = (action$) =>
export const queryMultidimensionalAPIExtensionOnAddLayer = (action$, {getState = () => {}} = {}) =>
action$
.ofType(ADD_LAYER)
.filter(
Expand All @@ -61,7 +61,7 @@ export const queryMultidimensionalAPIExtensionOnAddLayer = (action$) =>
.map(({ layer = {} } = {}) => ({ layer, multidimURL: getMultidimURL(layer)}))
// every add layer has it's own flow, this is why it uses
.flatMap(({ layer = {}, multidimURL } = {}) =>
describeDomains(multidimURL, layer.name, undefined, DESCRIBE_DOMAIN_OPTIONS)
describeDomains(multidimURL, layer.name, undefined, { expandLimit: expandLimitSelector(getState()) || DESCRIBE_DOMAIN_OPTIONS.expandLimit })
.switchMap( domains => {
const dimensions = domainsToDimensionsObject(domains, multidimURL) || [];
if (dimensions && dimensions.length > 0) {
Expand Down Expand Up @@ -106,7 +106,7 @@ export const updateLayerDimensionDataOnMapLoad = (action$, {getState = () => {}}
.concat(Observable.from(layersWithMultidim)
// one flow for each dimension
.mergeMap(l =>
describeDomains(getTimeMultidimURL(l), l.name, undefined, DESCRIBE_DOMAIN_OPTIONS)
describeDomains(getTimeMultidimURL(l), l.name, undefined, { expandLimit: expandLimitSelector(getState()) || DESCRIBE_DOMAIN_OPTIONS.expandLimit })
.switchMap( domains =>
Observable.from(flatten(domainsToDimensionsObject(domains, getTimeMultidimURL(l))
.map(d => [
Expand Down
6 changes: 4 additions & 2 deletions web/client/epics/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,13 @@ export const updateRangeDataOnRangeChange = (action$, { getState = () => { } } =
)
.debounceTime(400)
.merge(action$.ofType(UPDATE_LAYER_DIMENSION_DATA).debounceTime(50))
.switchMap( () => {
.switchMap( (action) => {
// we should force the range data update when we turn off the map sync
const resetMapSync = action.mapSync === false;
const timeData = timeDataSelector(getState()) || {};
const layerIds = Object.keys(timeData).filter(id => timeData[id] && timeData[id].domain
// when data is already fully downloaded, no need to refresh, except if the mapSync is active
&& (isTimeDomainInterval(timeData[id].domain)) || isMapSync(getState()));
&& (isTimeDomainInterval(timeData[id].domain)) || isMapSync(getState()) || resetMapSync);
// update range data for every layer that need to sync with histogram/domain
return Rx.Observable.merge(
...layerIds.map(id =>
Expand Down
38 changes: 36 additions & 2 deletions web/client/selectors/__tests__/timeline-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
multidimOptionsSelectorCreator,
timelineLayersSelector,
timelineLayersSetting,
timelineLayersParsedSettings
timelineLayersParsedSettings,
getTimeItems
} from '../timeline';

import { set, compose } from '../../utils/ImmutableUtils';
Expand Down Expand Up @@ -169,7 +170,40 @@ describe('timeline selector', () => {
expect(timelayer[0].id).toEqual(TEST_LAYER_ID);
expect(timelayer[0].hideInTimeline).toEqual(true);
});

it('getTimeItems should give priority to rangeData', () => {
const data = {
source: {
type: 'multidim-extension',
version: '1.2',
url: '/geoserver/gwc/service/wmts'
},
name: 'time',
domain: '2022-06-01T00:00:00.000Z/2023-06-01T00:00:00.000Z,2023-01-01T00:00:00.000Z/2023-06-01T00:00:00.000Z,2023-01-01T00:00:00.000Z/2023-12-31T00:00:00.000Z'
};
const range = {
start: '2022-06-01T00:00:00.000Z',
end: '2024-01-09T11:07:53.218Z'
};
let timeItems = getTimeItems(data, range);
expect(timeItems.length).toBe(3);
const rangeData = {
range: {
start: '2022-06-01T00:00:00.000Z',
end: '2024-01-09T11:07:53.218Z'
},
histogram: {
values: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
domain: '2022-06-01T00:00:00.000Z/2023-06-01T00:00:00.000Z/PT704H'
},
domain: {
values: [
'2022-06-01T00:00:00.000Z/2023-06-01T00:00:00.000Z'
]
}
};
timeItems = getTimeItems(data, range, rangeData);
expect(timeItems.length).toBe(1);
});
it('itemsSelector', () => {
const histogramItems = itemsSelector(SAMPLE_STATE_HISTOGRAM);
expect(histogramItems.length).toBe(31);
Expand Down
8 changes: 6 additions & 2 deletions web/client/selectors/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,14 @@ export const rangeDataToItems = (rangeData = {}, range) => {
* @param {object} rangeData object that contains domain or histogram
*/
export const getTimeItems = (data = {}, range, rangeData) => {
// rangeData populates when some changes ara applied with map sync
// we should use this when available
// because represent the latest updated value
if (rangeData?.domain || rangeData?.histogram) {
return rangeDataToItems(rangeData, range);
}
if (data && data.values || data && data.domain && !isTimeDomainInterval(data.domain)) {
return valuesToItems(data.values || data.domain.split(','), range);
} else if (rangeData && rangeData.histogram) {
return rangeDataToItems(rangeData, range);
}
return [];
};
Expand Down

0 comments on commit 205bc6c

Please sign in to comment.