TimelineView.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: Storytelling
  5. * (C) Copyright IBM Corp. 2014, 2020
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. define(['baglass/core-client/js/core-client/ui/core/View', 'jquery', 'underscore', 'text!./templates/TimelineView.html', './TimelineRulerView', './TimelineTimeIndicatorView', './TimelineSliderView', './SnapIndicatorView', 'storytelling-ui/storytelling-ui.min', 'react', 'react-dom', '../ScaleManager', 'baglass/core-client/js/core-client/utils/Utils', '../lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/zoom-in_16', '../lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/zoom-out_16', '../lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/zoom-fit_16', '../lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/minimize_16'], function (View, $, _, Template, TimelineRulerView, TimelineTimeIndicatorView, TimelineSliderView, SnapIndicatorView, StorytellingUI, React, ReactDOM, ScaleManager, Utils, zoonInIcon, zoomOutIcon, zoomFitIcon, minimizeIcon) {
  9. var TimelineView = View.extend({
  10. templateString: Template,
  11. events: {
  12. 'primaryaction .zoomIn': 'onZoomInClick',
  13. 'primaryaction .zoomOut': 'onZoomOutClick',
  14. 'primaryaction .zoomFit': 'onZoomToFitClick',
  15. 'primaryaction .timelineRuler': 'onTimelineRulerClick'
  16. },
  17. init: function init(options) {
  18. TimelineView.inherited('init', this, arguments);
  19. this.storyController = options.storyController;
  20. this.controller = options.controller;
  21. this.dashboardApi = options.dashboardApi;
  22. this.dndManager = options.dndManager;
  23. this.glassContext = options.glassContext;
  24. this.services = options.services;
  25. this.stringResources = this.dashboardApi.getDashboardCoreSvc('.StringResources');
  26. this.zoom = 1;
  27. this.rangeSliders = null;
  28. this.rangeSlidersMap = null;
  29. this.scaleManager = new ScaleManager();
  30. },
  31. render: function render() {
  32. this.controller.on('duration:changed', this.onDurationChanged, this);
  33. this.controller.on('modelEpisode:added', this.onWidgetAdded, this);
  34. this.controller.on('modelEpisode:removed', this.onWidgetRemoved, this);
  35. this.controller.on('modelEpisode:changed', this.onModelEpisodeChanged, this);
  36. this.controller.on('modelEpisodes:reorder', this.onModelEpisodesReorder, this);
  37. this.controller.on('slider:change', this.onSliderTitleChange, this);
  38. this.controller.on('timeline:change', this.onSliderChange, this);
  39. this.controller.on('timeline:willChange', this.onSliderWillChange, this);
  40. this.controller.on('timeline:select', this.onSliderSelect, this);
  41. this.controller.on('timeline:movingUp', this.onSliderMoveUp, this);
  42. this.controller.on('timeline:movingDown', this.onSliderMoveDown, this);
  43. this.controller.on('timeline:doneMoving', this.onSliderDrop, this);
  44. this.controller.on('timeline:sliderDragStarted', this.onDragStarted, this);
  45. this.controller.on('timeline:highlightIndicatorDragStarted', this.highlightIndicatorDragStarted, this);
  46. this.controller.on('timeline:highlightIndicatorDragEnded', this.highlightIndicatorDragEnded, this);
  47. this.scaleManager.on('scale:change', this.onScaleChanged, this);
  48. $(window).on('resize.privateViewEvents' + this.viewId, this.onResize.bind(this));
  49. var sHtml = this.dotTemplate({
  50. timelineRightContainerLabel: this.stringResources.get('timelineRightContainerLabel'),
  51. collapseScene: this.stringResources.get('close'),
  52. zoomToFit: this.stringResources.get('timelineZoomFit'),
  53. zoomIn: this.stringResources.get('timelineZoomIn'),
  54. zoomOut: this.stringResources.get('timelineZoomOut')
  55. });
  56. this.$el.addClass('timeline').attr('role', 'region').attr('aria-label', this.stringResources.get('timelineViewLabel')).html(sHtml);
  57. this.$scrollContainer = this.$('.timelineContent');
  58. this.$timelineSliders = this.$scrollContainer.find('.timelineSliders');
  59. this.$blanket = this.$el.find('.timelineBlanket');
  60. this.$leftContainer = this.$el.find('.leftContainer');
  61. var $rightContainer = this.$el.find('.rightContainer');
  62. this.$zoomOutButton = $rightContainer.find('.zoomOut');
  63. this.$zoomInButton = $rightContainer.find('.zoomIn');
  64. this.$zoomFitButton = $rightContainer.find('.zoomFit');
  65. this.$collapseButton = $rightContainer.find('.collapseScene');
  66. Utils.setIcon(this.$zoomInButton, zoonInIcon.default.id);
  67. Utils.setIcon(this.$zoomOutButton, zoomOutIcon.default.id);
  68. Utils.setIcon(this.$zoomFitButton, zoomFitIcon.default.id);
  69. Utils.setIcon(this.$collapseButton, minimizeIcon.default.id);
  70. this.renderTimelineRowTracks();
  71. this.renderTimelines();
  72. this.renderRulerView();
  73. this.scaleToFit();
  74. this.registerHandlers();
  75. this._updateSelectedSliders();
  76. this.setFocus();
  77. },
  78. /**
  79. * @param Object fadeInOptions an equivalent object to jquery fadeIn options
  80. * @param Function fadeInOptions.complete see jquery fadeIn
  81. * @param Number fadeInOptions.duration see jquery fadeIn
  82. */
  83. renderFadeIn: function renderFadeIn(fadeInOptions) {
  84. this.render();
  85. this.hide();
  86. this.$el.fadeIn(fadeInOptions);
  87. },
  88. /**
  89. * @param Object fadeOutOptions an equivalent object to jquery fadeOut options
  90. * @param Function fadeOutOptions.complete see jquery fadeOut
  91. * @param Number fadeOptionOptions.duration see jquery fadeOut
  92. */
  93. fadeOut: function fadeOut(fadeOutOptions) {
  94. this.$el.fadeOut(fadeOutOptions);
  95. },
  96. renderRulerView: function renderRulerView() {
  97. this.timeRulerView = new TimelineRulerView({
  98. el: this.$el.find('.timelineRuler'),
  99. controller: this.controller,
  100. scaleManager: this.scaleManager
  101. });
  102. this.timeRulerView.render();
  103. this.timeIndicatorView = new TimelineTimeIndicatorView({
  104. el: this.$el.find('.timelinePosition'),
  105. controller: this.controller,
  106. scaleManager: this.scaleManager,
  107. services: this.services
  108. });
  109. this.timeIndicatorView.render();
  110. // Fix the ruler position.
  111. this._fixRulerPosition();
  112. },
  113. renderSnapIndicatorView: function renderSnapIndicatorView() {
  114. this.snapIndicatorView = new SnapIndicatorView({
  115. $slidersHolder: this.$el.find('.timelineSliders'),
  116. controller: this.controller,
  117. scaleManager: this.scaleManager
  118. });
  119. this.snapIndicatorView.render();
  120. },
  121. registerHandlers: function registerHandlers() {
  122. this.$collapseButton.on('primaryaction', this.storyController.collapseScene.bind(this.storyController));
  123. this.$scrollContainer.on('scroll', this.onScroll.bind(this));
  124. },
  125. onSliderTitleChange: function onSliderTitleChange() /*event*/{
  126. if (this.rangeSlidersMap) {
  127. _.each(this.rangeSlidersMap, function (view) {
  128. var label = this._getWidgetTitle(view.id);
  129. if (label !== view.getLabel()) {
  130. view.setLabel(label);
  131. }
  132. }.bind(this));
  133. }
  134. },
  135. renderTimelineRowTracks: function renderTimelineRowTracks() {
  136. var marginTop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  137. var timelineRowTrack = React.createElement(StorytellingUI.RowTrackView, {
  138. timelineEpisodes: this.controller.getTimelineEpisodes(),
  139. marginTop: marginTop
  140. });
  141. ReactDOM.render(timelineRowTrack, this.$leftContainer[0]);
  142. },
  143. renderTimelines: function renderTimelines() {
  144. // Reset the slider list.
  145. this.rangeSlidersId = [];
  146. if (this.rangeSlidersMap) {
  147. _.each(this.rangeSlidersMap, function (view) {
  148. view.remove();
  149. });
  150. }
  151. this.rangeSlidersMap = {};
  152. // Use an object in order to treat it as a hashset (rather than an array, which allows duplicates)
  153. var timelineInfos = this._createTimelineInfos();
  154. _.each(timelineInfos, function (info) {
  155. this.renderTimeline(info);
  156. }.bind(this));
  157. },
  158. renderTimeline: function renderTimeline(info) {
  159. var el = $('<div/>').appendTo(this.$timelineSliders);
  160. var view = new TimelineSliderView({
  161. el: el,
  162. id: info.id,
  163. model: info.model,
  164. label: this._getWidgetTitle(info.id),
  165. scaleManager: this.scaleManager,
  166. timelineController: this.controller,
  167. glassContext: this.glassContext,
  168. dndManager: this.dndManager,
  169. services: this.services,
  170. dashboardApi: this.dashboardApi
  171. });
  172. view.render();
  173. this.rangeSlidersId.push(info.id);
  174. this.rangeSlidersMap[info.id] = view;
  175. },
  176. setFocus: function setFocus() {
  177. this.$el.find('.timelinePosition .handle').focus();
  178. },
  179. remove: function remove() {
  180. $(window).off('resize.privateViewEvents' + this.viewId);
  181. this.controller.off('duration:changed', this.onDurationChanged, this);
  182. this.controller.off('modelEpisode:added', this.onWidgetAdded, this);
  183. this.controller.off('modelEpisode:removed', this.onWidgetRemoved, this);
  184. this.controller.off('modelEpisode:changed', this.onModelEpisodeChanged, this);
  185. this.controller.off('modelEpisodes:reorder', this.onModelEpisodesReorder, this);
  186. this.controller.off('slider:change', this.onSliderTitleChange, this);
  187. this.controller.off('timeline:change', this.onSliderChange, this);
  188. this.controller.off('timeline:willChange', this.onSliderWillChange, this);
  189. this.controller.off('timeline:select', this.onSliderSelect, this);
  190. this.controller.off('timeline:movingUp', this.onSliderMoveUp, this);
  191. this.controller.off('timeline:movingDown', this.onSliderMoveDown, this);
  192. this.controller.off('timeline:doneMoving', this.onSliderDrop, this);
  193. this.controller.off('timeline:sliderDragStarted', this.onDragStarted, this);
  194. this.controller.off('timeline:highlightIndicatorDragStarted', this.highlightIndicatorDragStarted, this);
  195. this.controller.off('timeline:highlightIndicatorDragEnded', this.highlightIndicatorDragEnded, this);
  196. this.scaleManager.off('scale:change', this.onScaleChanged, this);
  197. this.timeRulerView = null;
  198. if (this.timeIndicatorView) {
  199. this.timeIndicatorView.remove();
  200. this.timeIndicatorView = null;
  201. }
  202. if (this.$leftContainer && this.$leftContainer.length) {
  203. ReactDOM.unmountComponentAtNode(this.$leftContainer[0]);
  204. }
  205. this.rangeSlidersId = null;
  206. if (this.rangeSlidersMap) {
  207. _.each(this.rangeSlidersMap, function (view) {
  208. view.remove();
  209. });
  210. }
  211. this.rangeSlidersMap = null;
  212. TimelineView.inherited('remove', this, arguments);
  213. },
  214. scaleToFit: function scaleToFit() {
  215. var duration = this.controller.getDuration();
  216. if (duration === 0) {
  217. duration = this.controller.getDefaultWidgetDuration();
  218. }
  219. this.scaleManager.updateDuration(duration, this.$scrollContainer.outerWidth(false));
  220. this.scaleManager.scaleToFit();
  221. },
  222. /* View events.*/
  223. onResize: function onResize() {
  224. if (this.$el.is(':visible')) {
  225. // We only resize if the view is visible.
  226. this.scaleToFit();
  227. this.scaleManager.stepScale(this.zoom);
  228. this._updateTimelineWidth();
  229. }
  230. },
  231. onScroll: function onScroll() {
  232. this._fixRulerPosition();
  233. this._updateSelectedSliders();
  234. },
  235. onZoomInClick: function onZoomInClick() {
  236. var step = 2;
  237. this.scaleManager.stepScale(step);
  238. this.zoom = this.zoom * step;
  239. this._updateZoomButtons();
  240. },
  241. onZoomOutClick: function onZoomOutClick() {
  242. var step = 0.5;
  243. this.scaleManager.stepScale(step);
  244. this.zoom = this.zoom * step;
  245. this._updateZoomButtons();
  246. },
  247. onZoomToFitClick: function onZoomToFitClick() {
  248. this.scaleToFit();
  249. this.zoom = 1;
  250. this._updateZoomButtons();
  251. },
  252. onTimelineRulerClick: function onTimelineRulerClick() {
  253. this.timeIndicatorView.setFocus();
  254. },
  255. onSliderWillChange: function onSliderWillChange(event) {
  256. if (this.controller.isPlaying()) {
  257. this.controller.pause();
  258. }
  259. if (event.getDragValue) {
  260. this.controller.updateLastEstablishedEventQueue();
  261. if (!this.snapIndicatorView) {
  262. this.renderSnapIndicatorView();
  263. }
  264. this.snapIndicatorView.showIndicator(event.getDragValue, event.getDraggingElement);
  265. }
  266. },
  267. onSliderChange: function onSliderChange() {
  268. // Update the scale since the width might have changed.
  269. this._updateTimelineWidth();
  270. if (this.lastStatePlaying && this.controller.getCursorTime() < this.controller.getDuration()) {
  271. this.controller.play();
  272. }
  273. if (this.snapIndicatorView) {
  274. this.snapIndicatorView.removeIndicator();
  275. }
  276. },
  277. onSliderSelect: function onSliderSelect() {
  278. this.lastStatePlaying = this.controller.isPlaying();
  279. },
  280. _closeFlyouts: function _closeFlyouts(widgetId) {
  281. this.controller.trigger('slider:closeFlyouts', { widgetId: widgetId });
  282. },
  283. /* Controller events.*/
  284. onScaleChanged: function onScaleChanged(event) {
  285. this._updateTimelinesScale(event.scale, event.previousScale);
  286. this._updateZoomButtons();
  287. },
  288. onDurationChanged: function onDurationChanged() {
  289. this._updateBlanket();
  290. },
  291. onWidgetAdded: function onWidgetAdded(id) {
  292. // Get the newly added widget timeline.
  293. var episode = this.controller.getTimelineEpisodeById(id);
  294. if (episode) {
  295. var info = this._createTimelineInfo(episode);
  296. // Render the timeline.
  297. this.renderTimeline(info);
  298. this._onWidgetAddRemove();
  299. }
  300. },
  301. onWidgetRemoved: function onWidgetRemoved(id) {
  302. this._closeFlyouts(id);
  303. var slider = this._getSliderByModelId(id);
  304. if (slider) {
  305. slider.remove();
  306. // Remove the reference to the range slider.
  307. var index = _.indexOf(this.rangeSlidersId, id);
  308. if (index >= 0) {
  309. this.rangeSlidersId.splice(index, 1);
  310. this.rangeSlidersMap[id].remove();
  311. delete this.rangeSlidersMap[id];
  312. }
  313. this._onWidgetAddRemove();
  314. }
  315. },
  316. _getWidgetTitle: function _getWidgetTitle(id) {
  317. var content = this.dashboardApi.getCanvas().getContent(id);
  318. var spec = content.getFeature('Serializer').toJSON();
  319. var hasGraphic = !!content.getPropertyValue('value.graphic.content');
  320. var contentData = Object.assign({}, spec.features.Models_internal, { hasGraphic: hasGraphic });
  321. return this.dashboardApi.getFeature('.SmartNamingSvc').getWidgetName(contentData);
  322. },
  323. onModelEpisodeChanged: function onModelEpisodeChanged(options) {
  324. if (this.rangeSlidersMap) {
  325. var slider = this.rangeSlidersMap[options.id];
  326. if (slider) {
  327. var newValue = this._createTimelineValue(options.value);
  328. slider.setValue(newValue, true);
  329. }
  330. }
  331. },
  332. onModelEpisodesReorder: function onModelEpisodesReorder() {
  333. var $previousFocus = $(document.activeElement);
  334. var timelineInfos = this._createTimelineInfos();
  335. this.rangeSlidersId = [];
  336. // this code assumes that the existing timeline entries were reordered
  337. // I.e no new timeline entries where added.
  338. var $previous = null;
  339. _.each(timelineInfos, function (info) {
  340. this.rangeSlidersId.push(info.id);
  341. var $slider = this._getSliderByModelId(info.id);
  342. if (!$previous) {
  343. this.$timelineSliders.prepend($slider);
  344. } else {
  345. $previous.after($slider);
  346. }
  347. $previous = $slider;
  348. }.bind(this));
  349. $previousFocus.focus();
  350. },
  351. onShowSliderSelection: function onShowSliderSelection(evt) {
  352. var selectedSlider = this.rangeSlidersMap[evt.widgetId];
  353. //when you select widget outside of focused scene, don't select timeline
  354. if (selectedSlider) {
  355. selectedSlider.toggleSelected(true);
  356. this._updateSelectedSlider(evt.widgetId);
  357. }
  358. },
  359. onSliderDrop: function onSliderDrop(event) {
  360. var index = _.indexOf(this.rangeSlidersId, event.id);
  361. this.controller.moveEpisodeBefore(event.id, this.rangeSlidersId[index + 1], { payloadData: event.payloadData });
  362. },
  363. onDragStarted: function onDragStarted(id) {
  364. this._closeFlyouts(id);
  365. },
  366. highlightIndicatorDragStarted: function highlightIndicatorDragStarted() {
  367. // Disable timeline scrolling when a highlight is dragged
  368. this.$scrollContainer.css({ overflow: 'hidden' });
  369. },
  370. highlightIndicatorDragEnded: function highlightIndicatorDragEnded() {
  371. // Re-enable timeline scrolling when highlight dragging stops
  372. this.$scrollContainer.css({ overflow: 'auto' });
  373. },
  374. onSliderMoveUp: function onSliderMoveUp(event) {
  375. var $previousFocus = $(document.activeElement);
  376. var index = _.indexOf(this.rangeSlidersId, event.id);
  377. var toIndex = event.to ? _.indexOf(this.rangeSlidersId, event.to) : index - 1;
  378. if (index === -1 || toIndex < 0) {
  379. return;
  380. }
  381. //move the slider up until we get to where we should be.
  382. while (index > toIndex) {
  383. var $slider = this._getSliderByModelId(this.rangeSlidersId[index]);
  384. var $previousSlider = this._getSliderByModelId(this.rangeSlidersId[index - 1]);
  385. $slider.insertBefore($previousSlider);
  386. var t = this.rangeSlidersId[index - 1];
  387. this.rangeSlidersId[index - 1] = this.rangeSlidersId[index];
  388. this.rangeSlidersId[index] = t;
  389. index--;
  390. }
  391. // fix ie 11 svg icons disappear problem
  392. // no need to check browser as embedSVGIcon does the check in the Utils
  393. Utils.embedSVGIcon(this.$el);
  394. $previousFocus.focus();
  395. },
  396. onSliderMoveDown: function onSliderMoveDown(event) {
  397. var $previousFocus = $(document.activeElement);
  398. var index = _.indexOf(this.rangeSlidersId, event.id);
  399. var toIndex = event.to ? _.indexOf(this.rangeSlidersId, event.to) : index + 1;
  400. if (index === -1 || toIndex === -1 || toIndex >= this.rangeSlidersId.length) {
  401. return;
  402. }
  403. //move the slider down until we get to where we should be.
  404. while (index < toIndex) {
  405. var $slider = this._getSliderByModelId(this.rangeSlidersId[index]);
  406. var $nextSlider = this._getSliderByModelId(this.rangeSlidersId[index + 1]);
  407. $slider.insertAfter($nextSlider);
  408. var t = this.rangeSlidersId[index + 1];
  409. this.rangeSlidersId[index + 1] = this.rangeSlidersId[index];
  410. this.rangeSlidersId[index] = t;
  411. index++;
  412. }
  413. // fix ie 11 svg icons disappear problem
  414. Utils.embedSVGIcon(this.$el);
  415. $previousFocus.focus();
  416. },
  417. _getSliderByModelId: function _getSliderByModelId(widgetId) {
  418. return this.$timelineSliders.find('#timelineWidgetSlider' + widgetId);
  419. },
  420. _updateBlanket: function _updateBlanket() {
  421. this.$blanket.css('left', this.scaleManager.convertTimeToPosition(this.controller.getDuration()) + 'px');
  422. },
  423. _updateSelectedSliders: function _updateSelectedSliders() {
  424. var map = this.controller.getSelectedWidgetMap();
  425. _.each(Object.keys(map), function (key) {
  426. if (map[key]) {
  427. this.onShowSliderSelection({ widgetId: key });
  428. // Close any flyouts on container scrolling
  429. this._closeFlyouts(key);
  430. }
  431. }.bind(this));
  432. },
  433. _updateSelectedSlider: function _updateSelectedSlider(id) {
  434. this.rangeSlidersMap[id].$el.toggleClass('bringToFront', this.$scrollContainer.scrollTop() === 0);
  435. },
  436. _clearHoverTimeout: function _clearHoverTimeout() {
  437. if (this.hoverTimeout) {
  438. clearTimeout(this.hoverTimeout);
  439. this.hoverTimeout = null;
  440. }
  441. },
  442. _onWidgetAddRemove: function _onWidgetAddRemove() {
  443. // Update the timeline scales.
  444. this._updateTimelineWidth();
  445. // Ensure the indicator is updated.
  446. this.timeIndicatorView.refresh();
  447. // Re-render the timeline row track and blanket position
  448. this._fixRulerPosition();
  449. },
  450. _updateTimelineWidth: function _updateTimelineWidth() {
  451. var durationWidth = 500 + this.scaleManager.convertTimeToPosition(this.controller.getDuration());
  452. var pageWidth = this.$scrollContainer.outerWidth(false);
  453. var width = Math.max(durationWidth, pageWidth);
  454. this.$timelineSliders.css('width', width + 'px');
  455. this.$blanket.css('width', width - parseInt(this.$blanket.css('left'), 10));
  456. this.timeRulerView.refresh();
  457. },
  458. _updateTimelinesScale: function _updateTimelinesScale(scale) {
  459. this._updateBlanket();
  460. this._updateTimelineWidth();
  461. var map = this.rangeSlidersMap;
  462. _.each(this.rangeSlidersId, function (id) {
  463. var item = map[id];
  464. item.setScale(scale);
  465. });
  466. },
  467. _createTimelineValue: function _createTimelineValue(value) {
  468. var defaultPixelsPerSecond = this.scaleManager.getScaleToPixelRatio();
  469. return [value[0] / 1000 * defaultPixelsPerSecond, value[1] / 1000 * defaultPixelsPerSecond];
  470. },
  471. _createTimelineInfo: function _createTimelineInfo(episode) {
  472. var start = episode.getEntranceAct().timer;
  473. var end = episode.getExitAct().timer;
  474. var timeValue = this._createTimelineValue([start, end]);
  475. return {
  476. model: {
  477. value: timeValue,
  478. scale: this.scaleManager.getScale()
  479. },
  480. id: episode.id
  481. };
  482. },
  483. _createTimelineInfos: function _createTimelineInfos() {
  484. // Create a timeline info object for each timeline.
  485. return _.map(this.controller.getTimelineEpisodes(), function (timeline) {
  486. return this._createTimelineInfo(timeline);
  487. }.bind(this));
  488. },
  489. _fixRulerPosition: function _fixRulerPosition() {
  490. // Ensure the ruler stays at the top when the timeline is scrolled vertically.
  491. var scrollTop = this.$scrollContainer.scrollTop();
  492. var scrollLeft = this.$scrollContainer.scrollLeft();
  493. this.$blanket.css('top', scrollTop + 'px');
  494. this.timeIndicatorView.onScroll({
  495. scrollTop: scrollTop,
  496. scrollLeft: scrollLeft
  497. });
  498. this.timeRulerView.setOffsetLeft(scrollLeft);
  499. this.renderTimelineRowTracks(-scrollTop);
  500. },
  501. _updateZoomButtons: function _updateZoomButtons() {
  502. var scale = this.scaleManager.getScale();
  503. var canZoomIn = scale < this.scaleManager.getMaxScale();
  504. var canZoomOut = scale > this.scaleManager.getMinScale();
  505. this.$zoomOutButton.toggleClass('disabled', !canZoomOut);
  506. this.$zoomInButton.toggleClass('disabled', !canZoomIn);
  507. this.$zoomInButton.attr('aria-disabled', !canZoomIn);
  508. this.$zoomOutButton.attr('aria-disabled', !canZoomOut);
  509. }
  510. });
  511. return TimelineView;
  512. });
  513. //# sourceMappingURL=TimelineView.js.map