@@ -19,12 +19,15 @@ const {
1919 selectLayer,
2020 onRangeChanged
2121} = require ( '../actions/timeline' ) ;
22- const { currentTimeSelector, layersWithTimeDataSelector } = require ( '../selectors/dimension' ) ;
22+
23+ const { error } = require ( '../actions/notifications' ) ;
24+
25+ const { currentTimeSelector, layersWithTimeDataSelector, layerTimeSequenceSelectorCreator } = require ( '../selectors/dimension' ) ;
2326
2427const { LOCATION_CHANGE } = require ( 'react-router-redux' ) ;
2528
2629const { currentFrameSelector, currentFrameValueSelector, lastFrameSelector, playbackRangeSelector, playbackSettingsSelector, frameDurationSelector, statusSelector } = require ( '../selectors/playback' ) ;
27- const { selectedLayerName, selectedLayerUrl, rangeSelector } = require ( '../selectors/timeline' ) ;
30+ const { selectedLayerName, selectedLayerUrl, selectedLayerData , selectedLayerTimeDimensionConfiguration , rangeSelector } = require ( '../selectors/timeline' ) ;
2831
2932const pausable = require ( '../observables/pausable' ) ;
3033const { wrapStartStop } = require ( '../observables/epics' ) ;
@@ -73,8 +76,36 @@ const createAnimationValues = (getState, { fromValue } = {}) => {
7376 return Rx . Observable . of ( values ) ;
7477} ;
7578
79+ /**
80+ * Gets the static list of times to animate
81+ */
82+ const filterAnimationValues = ( values , getState , { fromValue} = { } ) => {
83+ const playbackRange = playbackRangeSelector ( getState ( ) ) || { } ;
84+ const startPlaybackTime = playbackRange . startPlaybackTime ;
85+ const endPlaybackTime = playbackRange . endPlaybackTime ;
86+ return Rx . Observable . of ( values
87+ // remove times before out of playback range
88+ . filter ( v => startPlaybackTime && endPlaybackTime ? moment ( v ) . isSameOrAfter ( startPlaybackTime ) && moment ( v ) . isSameOrBefore ( endPlaybackTime ) : true )
89+ // Remove values before fromValue
90+ . filter ( v => fromValue ? moment ( v ) . isAfter ( fromValue ) : true )
91+ // limit size to BUFFER_SIZE
92+ . slice ( 0 , BUFFER_SIZE ) ) ;
93+ } ;
94+
95+ /**
96+ * Returns an observable that emit an array of time frames, based of the current configuration:
97+ * - If configured as fixed steps, it returns the list of next animation frame calculating them
98+ * - If there is a selected layer and there is the Multidim extension, then use it (in favour of static values configured)
99+ * - If there are values in the dimension configuration, and the Multidim extension is not present, use them to animate
100+ */
76101const getAnimationFrames = ( getState , { fromValue } = { } ) => {
77102 if ( selectedLayerName ( getState ( ) ) ) {
103+ const values = layerTimeSequenceSelectorCreator ( selectedLayerData ( getState ( ) ) ) ( getState ( ) ) ;
104+ const timeDimConfig = selectedLayerTimeDimensionConfiguration ( getState ( ) ) ;
105+ // check if multidim extension is available. It has priority to local values
106+ if ( timeDimConfig && ! timeDimConfig . source && ! ( timeDimConfig . source . type === "multidim-extension" ) && values && values . length > 0 ) {
107+ return filterAnimationValues ( values , getState , { fromValue} ) ;
108+ }
78109 return getDomainValues ( ...domainArgs ( getState , {
79110 fromValue : fromValue
80111 } ) )
@@ -98,7 +129,13 @@ module.exports = {
98129 action$ . ofType ( PLAY ) . exhaustMap ( ( ) =>
99130 getAnimationFrames ( getState )
100131 . map ( ( frames ) => setFrames ( frames ) )
101- . let ( wrapStartStop ( framesLoading ( true ) , framesLoading ( false ) ) )
132+ . let ( wrapStartStop ( framesLoading ( true ) , framesLoading ( false ) ) , ( ) => Rx . Observable . of (
133+ error ( {
134+ title : "There was an error retriving animation" ,
135+ message : "Please contact the administrator"
136+ } ) ,
137+ stop ( )
138+ ) )
102139 . concat (
103140 action$
104141 . ofType ( SET_CURRENT_FRAME )
@@ -118,19 +155,21 @@ module.exports = {
118155 . map ( ( ) => currentFrameValueSelector ( getState ( ) ) )
119156 . map ( t => t ? moveTime ( t ) : stop ( ) ) ,
120157 timeDimensionPlayback : ( action$ , { getState = ( ) => { } } = { } ) =>
121- action$ . ofType ( SET_FRAMES ) . exhaustMap ( ( ) =>
122- Rx . Observable . interval ( frameDurationSelector ( getState ( ) ) * 1000 ) . startWith ( 0 ) // start immediately
123- . let ( pausable (
124- action$
125- . ofType ( PLAY , PAUSE )
126- . map ( a => a . type === PLAY )
127- ) )
128- // pause is with loss, so the count of timer is not correct.
129- // the following scan emit a for every event emitted effectively, with correct count
130- // TODO: in case of loop, we can reset to 0 on load end.
131- . map ( ( ) => setCurrentFrame ( currentFrameSelector ( getState ( ) ) + 1 ) )
132- . concat ( Rx . Observable . of ( stop ( ) ) )
133- . takeUntil ( action$ . ofType ( STOP , LOCATION_CHANGE ) )
158+ action$ . ofType ( SET_FRAMES )
159+ . exhaustMap ( ( ) =>
160+ Rx . Observable . interval ( frameDurationSelector ( getState ( ) ) * 1000 ) . startWith ( 0 ) // start immediately
161+ . let ( pausable (
162+ action$
163+ . ofType ( PLAY , PAUSE )
164+ . map ( a => a . type === PLAY )
165+ ) )
166+ // pause is with loss, so the count of timer is not correct.
167+ // the following scan emit a for every event emitted effectively, with correct count
168+ // TODO: in case of loop, we can reset to 0 on load end.
169+ . map ( ( ) => setCurrentFrame ( currentFrameSelector ( getState ( ) ) + 1 ) )
170+ . concat ( Rx . Observable . of ( stop ( ) ) )
171+ . takeUntil ( action$ . ofType ( STOP , LOCATION_CHANGE ) )
172+
134173 ) ,
135174 /**
136175 * Synchronizes the fixed animation step toggle with guide layer on timeline
0 commit comments