123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- 'use strict';
- define(['baglass/core-client/js/core-client/ui/core/Class', 'underscore'], function (Class, _) {
- var TimeQueue = Class.extend({
-
-
-
-
-
- _endBufferTime: 200,
- animationDuration: 500,
- STATE: {
- PLAYING: 'playing',
- STOPPED: 'stopped',
- PAUSED: 'paused'
- },
-
- _actionToAnimationMap: {
- 'show': { name: 'show', entrance: true, stateGroup: 'visibility' },
- 'slideInLeft': { name: 'slideInLeft', entrance: true, stateGroup: 'visibility' },
- 'slideInRight': { name: 'slideInRight', entrance: true, stateGroup: 'visibility' },
- 'slideInTop': { name: 'slideInTop', entrance: true, stateGroup: 'visibility' },
- 'slideInBottom': { name: 'slideInBottom', entrance: true, stateGroup: 'visibility' },
- 'scaleIn': { name: 'scaleIn', entrance: true, stateGroup: 'visibility' },
- 'shrinkIn': { name: 'shrinkIn', entrance: true, stateGroup: 'visibility' },
- 'pivotIn': { name: 'pivotIn', entrance: true, stateGroup: 'visibility' },
- 'hide': { name: 'hide', entrance: false, stateGroup: 'visibility' },
- 'slideOutLeft': { name: 'slideOutLeft', entrance: false, stateGroup: 'visibility' },
- 'slideOutRight': { name: 'slideOutRight', entrance: false, stateGroup: 'visibility' },
- 'slideOutTop': { name: 'slideOutTop', entrance: false, stateGroup: 'visibility' },
- 'slideOutBottom': { name: 'slideOutBottom', entrance: false, stateGroup: 'visibility' },
- 'scaleOut': { name: 'scaleOut', entrance: false, stateGroup: 'visibility' },
- 'expandOut': { name: 'expandOut', entrance: false, stateGroup: 'visibility' },
- 'pivotOut': { name: 'pivotOut', entrance: false, stateGroup: 'visibility' },
- 'highlight': { name: 'highlight', entrance: false, stateGroup: 'highlight' },
- 'clearHighlight': { name: 'clearHighlight', entrance: false, stateGroup: 'highlight' }
- },
- init: function init(options) {
- TimeQueue.inherited('init', this, arguments);
- this.boardModel = options.boardModel;
- this.eventRouter = options.eventRouter;
- this.currentScene = options.sceneId;
- this.widgetHelper = options.widgetHelper;
- this._eventQueue = {};
- this.currentState = 'stopped';
- this.duration = 0;
- this.current = 0;
- this._tickLength = 50;
-
-
-
- this._timer = null;
- this._startTime = 0;
- this._widgetStateCache = {};
- this.timeQueue = {
- play: this.play.bind(this),
- pause: this.pause.bind(this),
- stop: this.stop.bind(this),
- seek: this.seek.bind(this),
- getState: this.getState.bind(this),
- setTickLength: this.setTickLength.bind(this),
- STATE: this.STATE
- };
- },
- isPlaying: function isPlaying() {
- return this.currentState === this.STATE.PLAYING;
- },
- isStopped: function isStopped() {
- return this.currentState === this.STATE.STOPPED;
- },
- play: function play() {
- if (this._timer) {
- return false;
- }
- return this._playScene();
- },
- isMarker: function isMarker(time) {
- if (this._eventQueue[time]) {
- return this._eventQueue[time].some(function (event) {
- return this._actionToAnimationMap[event.action].entrance || event.action === 'highlight';
- }.bind(this));
- }
- return false;
- },
- isExitAction: function isExitAction(time) {
- if (this._eventQueue[time]) {
- return this._eventQueue[time].some(function (event) {
- var animationInfo = this._actionToAnimationMap[event.action];
- return !animationInfo.entrance && animationInfo.stateGroup === 'visibility';
- }.bind(this));
- }
- return false;
- },
- jumpToNextMarker: function jumpToNextMarker() {
- var nextMarkerTime = this.duration;
- var eventTimes = Object.keys(this._eventQueue);
- var tickPromises = [];
- for (var i = 0; i < eventTimes.length; i++) {
- var candidateTime = parseInt(eventTimes[i], 10);
- if (candidateTime > this.current) {
- if (this.isMarker(candidateTime)) {
- nextMarkerTime = candidateTime;
- break;
- } else if (this.isExitAction(candidateTime)) {
- tickPromises.push(this._executeTick(candidateTime));
- }
- }
- }
- if (this.isPlaying() && nextMarkerTime !== this.duration) {
- this.pause();
- tickPromises.push(this._executeTick(nextMarkerTime).then(this.play.bind(this)));
- } else {
- tickPromises.push(this._executeTick(nextMarkerTime));
- }
- return Promise.all(tickPromises);
- },
- jumpToPreviousMarker: function jumpToPreviousMarker() {
- var previousMarkerTime = 0;
- var eventTimes = Object.keys(this._eventQueue);
- for (var i = 1; i <= eventTimes.length; i++) {
- var candidateTime = parseInt(eventTimes[eventTimes.length - i], 10);
- if (candidateTime < this.current && this.isMarker(candidateTime)) {
- previousMarkerTime = candidateTime;
- break;
- }
- }
- if (this.isPlaying()) {
- this.pause();
- }
- return this.seek(previousMarkerTime);
- },
- _playScene: function _playScene() {
- var ret = false;
- if (this.currentScene) {
- if (this.current >= this.duration) {
- this.current = 0;
- }
- this.seek(this.current);
- this._setState(this.STATE.PLAYING);
- this._startTime = Date.now() - this.current;
- this._timer = setInterval(this._executeTick.bind(this), this._tickLength);
- ret = true;
- }
- return ret;
- },
- _generateEventQueue: function _generateEventQueue() {
- this._eventQueue = {};
- var nMaxTime = 0;
- var widgetIds = this._listWidgetsForCurrentScene();
- _.each(widgetIds, function (widgetId) {
- var episode = this.boardModel.timeline.episodes.get(widgetId);
- if (episode && !episode.acts.isEmpty()) {
- nMaxTime = this._addEpisodeToEventQueue(widgetId, episode, nMaxTime);
- } else {
-
- this._addEventToQueue(widgetId, 0, 'show');
- }
- }.bind(this));
-
- _.each(Object.keys(this._eventQueue), function (key) {
- if (key > nMaxTime - this._endBufferTime) {
- delete this._eventQueue[key];
- }
- }.bind(this));
- return nMaxTime;
- },
- _addEpisodeToEventQueue: function _addEpisodeToEventQueue(widgetId, episode, nMaxTime) {
- episode.acts.each(function (act) {
- if (act.timer || act.timer === 0) {
- var time = this._getEventTickTime(act.timer);
- this._addEventToQueue(widgetId, time, act.action, act.payload);
- nMaxTime = Math.max(nMaxTime, time);
- }
- }.bind(this));
- return nMaxTime;
- },
- _addEventToQueue: function _addEventToQueue(widgetId, time, action, payload) {
- if (!this._eventQueue[time]) {
- this._eventQueue[time] = [];
- }
- this._eventQueue[time].push({
- action: action,
- payload: payload,
- widget: widgetId
- });
- },
- _getEventTickTime: function _getEventTickTime(time) {
- return Math.round(time / this._tickLength) * this._tickLength;
- },
- pause: function pause() {
- if (!this._timer) {
- return false;
- }
- clearInterval(this._timer);
- this._timer = null;
- this._setState(this.STATE.PAUSED);
- return true;
- },
- stop: function stop() {
- if (this._timer) {
- clearInterval(this._timer);
- this._timer = null;
- }
- this._setState(this.STATE.STOPPED);
- return this.seek(0);
- },
- refresh: function refresh() {
-
- this.duration = 0;
- this.seek(this.current);
- },
- reset: function reset() {
-
- this.duration = 0;
- this.current = 0;
- return this.stop();
- },
- seek: function seek(offset) {
- var _this = this;
- if (!this.currentScene) {
- this._triggerUpdateDuration();
- this._triggerTickUpdated();
- return Promise.resolve(false);
- }
- if (this.currentState === this.STATE.PLAYING) {
- this.pause();
- }
- if (!this.duration) {
- this.duration = this._generateEventQueue();
- this._triggerUpdateDuration();
- }
- var nOffset = Math.max(0, Math.min(this.duration, this._getEventTickTime(offset)));
- this.current = nOffset;
- return this._setInitialWidgetState().then(function () {
- var moreToPlay = false;
- if (nOffset < _this.duration) {
- moreToPlay = true;
- }
- _this._triggerTickUpdated();
- return moreToPlay;
- });
- },
- getState: function getState() {
- var oState = {
- currentState: this.currentState,
- currentTime: this.current,
- duration: this.duration,
- sceneId: this.currentScene,
- context: this
- };
- return oState;
- },
- getDuration: function getDuration() {
- return this.duration;
- },
- getMarkers: function getMarkers() {
- var eventTimes = _.map(Object.keys(this._eventQueue), function (timeString) {
- return parseInt(timeString, 10);
- });
- return eventTimes.filter(this.isMarker.bind(this));
- },
- endScene: function endScene() {
- return this.seek(this.duration);
- },
- setTickLength: function setTickLength(tickLength) {
- this.stop();
- this._tickLength = tickLength;
- },
- getTickLength: function getTickLength() {
- return this._tickLength;
- },
- _executeTick: function _executeTick(current) {
- var target = Date.now() - this._startTime;
- var eventPromises = [];
-
- while (target >= this.current + this._tickLength || _.isNumber(current)) {
- if (_.isNumber(current)) {
- this.current = current;
- } else {
- this.current += this._tickLength;
- }
-
- if (this._eventQueue[this.current]) {
- _.each(this._eventQueue[this.current], function (event) {
- eventPromises.push(this._dispatchEvent(event));
- }.bind(this));
- }
- this._triggerTickUpdated();
- if (this.current >= this.duration) {
- this.current = this.duration;
- var endState = this.currentState;
- this._setState(this.STATE.STOPPED);
- clearInterval(this._timer);
- this._timer = null;
- this.eventRouter.trigger('timeline:end', {
- endState: endState
- });
- break;
- }
- if (_.isNumber(current)) {
- break;
- }
- }
- return Promise.all(eventPromises);
- },
- _triggerTickUpdated: function _triggerTickUpdated() {
- this.eventRouter.trigger('timequeue:tick', { currentTime: this.current, sceneId: this.currentScene });
- },
- _setState: function _setState(newState) {
- var sPrevState = this.currentState;
- this.currentState = newState;
- this.eventRouter.trigger('timequeue:stateChanged', {
- currentState: this.currentState,
- prevState: sPrevState,
- currentTime: this.current,
- duration: this.duration,
- sceneId: this.currentScene,
- context: this
- });
- },
- _dispatchEvent: function _dispatchEvent(event, immediate) {
- var nAnimationDuration = immediate ? 0 : this.animationDuration;
- var oAnimation = {
- duration: nAnimationDuration,
- target: event.widget,
- payload: event.payload,
- animation: this._actionToAnimationMap[event.action].name,
- reveal: nAnimationDuration > 0 && this._actionToAnimationMap[event.action].entrance
- };
- if (!oAnimation.animation) {
-
- return Promise.resolve();
- }
- this._updateEventForStateGroup(this._widgetStateCache, event);
- var state = this.widgetHelper.getContentState(oAnimation.target);
- if (state) {
- return state.whenStatusChanges(state.STATUS.RENDERED).then(function () {
- this.eventRouter.trigger('widget:animate', oAnimation);
- }.bind(this));
- }
- return Promise.resolve();
- },
- _setInitialWidgetState: function _setInitialWidgetState() {
- var _this2 = this;
- var stateGroups = {};
- var widgetPromises = [];
- this._hideAllWidgets(stateGroups);
-
- var i = void 0,
- j = void 0;
- for (i = 0; i <= this.current; i += this._tickLength) {
- if (this._eventQueue[i]) {
- for (j = 0; j < this._eventQueue[i].length; j++) {
- this._updateEventForStateGroup(stateGroups, this._eventQueue[i][j]);
- }
- }
- }
- var _isEqual = function _isEqual(a, b) {
- var animationA = _this2._actionToAnimationMap[a.action];
- var animationB = _this2._actionToAnimationMap[b.action];
- return animationA.entrance === animationB.entrance && animationA.stateGroup === 'visibility' && animationB.stateGroup === 'visibility' || _.isEqual(a, b);
- };
-
-
-
- Object.keys(stateGroups).forEach(function (key) {
- var group = stateGroups[key];
- Object.keys(group).forEach(function (widgetId) {
- if (!this._widgetStateCache[key] || !this._widgetStateCache[key][widgetId] || !_isEqual(this._widgetStateCache[key][widgetId], group[widgetId])) {
- widgetPromises.push(this._dispatchEvent(group[widgetId], true));
- }
- }, this);
- }, this);
- return Promise.all(widgetPromises);
- },
- _hideAllWidgets: function _hideAllWidgets(stateGroups) {
- var widgets = this._listWidgetsForCurrentScene() || [];
- widgets.forEach(function (widgetId) {
- this._updateEventForStateGroup(stateGroups, {
- action: 'hide',
- widget: widgetId
- });
- this._updateEventForStateGroup(stateGroups, {
- action: 'clearHighlight',
- widget: widgetId
- });
- }, this);
- },
- _updateEventForStateGroup: function _updateEventForStateGroup(stateGroups, event) {
- var groupName = this._actionToAnimationMap[event.action].stateGroup;
- if (!stateGroups[groupName]) {
- stateGroups[groupName] = {};
- }
- stateGroups[groupName][event.widget] = event;
- },
- _triggerUpdateDuration: function _triggerUpdateDuration() {
- this.eventRouter.trigger('timequeue:durationChanged', { duration: this.duration, sceneId: this.currentScene });
- },
- _listWidgetsForCurrentScene: function _listWidgetsForCurrentScene() {
- if (this.currentScene && this.boardModel) {
- return this.boardModel.layout.listWidgets([this.currentScene]);
- }
- return [];
- }
- });
- return TimeQueue;
- });
|