TransitionDirector.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: Storytelling
  5. * (C) Copyright IBM Corp. 2017, 2018
  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/Class', '../../util/AnimationHelper'], function (Class, AnimationHelper) {
  9. var TransitionDirector = Class.extend({
  10. layoutConfiguration: {
  11. 'widget': {
  12. hasOpacity: true,
  13. hideIfNotLinked: true
  14. },
  15. 'group': {
  16. hasOpacity: false,
  17. hideIfNotLinked: false
  18. }
  19. },
  20. init: function init(options) {
  21. TransitionDirector.inherited('init', this, arguments);
  22. this.rootLayout = options.rootLayout;
  23. },
  24. /*
  25. * returns a reduce callback suitable for layout view reduction.
  26. * The accumulator will be an array of promises that will be resolved once all the transitions have been completed.
  27. */
  28. getOnTransitionCallback: function getOnTransitionCallback(event) {
  29. return this._onTransitionCallback.bind(this, event);
  30. },
  31. /*
  32. * returns a reduce callback suitable for layout view reduction.
  33. * The accumulator will be an array of promises that will be resolved once all the transitions have been completed.
  34. */
  35. getAfterTransitionCallback: function getAfterTransitionCallback(event) {
  36. return this._afterTransitionCallback.bind(this, event);
  37. },
  38. _onTransitionCallback: function _onTransitionCallback(event, layoutView, promises) {
  39. promises = promises || [];
  40. if (event.to) {
  41. promises.push(this._animateToNext(event.linkIdMap, layoutView));
  42. } else if (event.from) {
  43. promises.push(this._animateFromPrevious(event.linkIdMap, layoutView));
  44. }
  45. return promises;
  46. },
  47. /*
  48. * Here we animate the current widget to the style of the widget/group in the next scene.
  49. */
  50. _animateToNext: function _animateToNext(linkIdMap, layoutView) {
  51. var config = this.layoutConfiguration[layoutView.model.type];
  52. var $node = layoutView.$el;
  53. var widgetInNextView = linkIdMap.forward[layoutView.id];
  54. if (!widgetInNextView) {
  55. // models not linked... hide the node if we are configured to do so for this type
  56. if (config && config.hideIfNotLinked) {
  57. $node.hide();
  58. }
  59. return Promise.resolve();
  60. }
  61. $node.show();
  62. var toWidget = this.rootLayout.findModel(widgetInNextView);
  63. var fromWidget = layoutView.model;
  64. var scaleX = parseFloat(toWidget.style.width, 10) / parseFloat(fromWidget.style.width, 10);
  65. var scaleY = parseFloat(toWidget.style.height, 10) / parseFloat(fromWidget.style.height, 10);
  66. var deltaXpercent = (parseFloat(toWidget.style.left, 10) - parseFloat(fromWidget.style.left, 10)) / 100;
  67. var deltaYpercent = (parseFloat(toWidget.style.top, 10) - parseFloat(fromWidget.style.top, 10)) / 100;
  68. var deltaXpx = $node.parent().width() * deltaXpercent;
  69. var deltaYpx = $node.parent().height() * deltaYpercent;
  70. // Make sure all widgets will start with a transform applied
  71. $node.css({
  72. transform: 'scale(1)'
  73. });
  74. var toWidgetTransform = this._getLayoutNodeTransform(toWidget);
  75. var cssProperties = {
  76. transition: 'transform 0.9s',
  77. transform: ' translate(' + deltaXpx + 'px, ' + deltaYpx + 'px) ' + toWidgetTransform + 'translate(-50%,-50%) scale(' + scaleX + ',' + scaleY + ') translate(50%,50%)'
  78. };
  79. if (config && config.hasOpacity) {
  80. cssProperties.transition += ', opacity 0.9s ease-in';
  81. cssProperties.opacity = '0';
  82. }
  83. return AnimationHelper.Animate($node, cssProperties);
  84. },
  85. /*
  86. * Here we animate the current widget to the style of the widget/group in the previous scene.
  87. */
  88. _animateFromPrevious: function _animateFromPrevious(linkIdMap, layoutView) {
  89. var config = this.layoutConfiguration[layoutView.model.type];
  90. var $node = layoutView.$el;
  91. var widgetInPreviousView = linkIdMap.backward[layoutView.id];
  92. if (!widgetInPreviousView) {
  93. return Promise.resolve();
  94. }
  95. var fromWidget = this.rootLayout.findModel(widgetInPreviousView);
  96. var toWidget = layoutView.model;
  97. var scaleX = parseFloat(toWidget.style.width, 10) / parseFloat(fromWidget.style.width, 10);
  98. var scaleY = parseFloat(toWidget.style.height, 10) / parseFloat(fromWidget.style.height, 10);
  99. var deltaXpercent = (parseFloat(toWidget.style.left, 10) - parseFloat(fromWidget.style.left, 10)) / 100;
  100. var deltaYpercent = (parseFloat(toWidget.style.top, 10) - parseFloat(fromWidget.style.top, 10)) / 100;
  101. var deltaXpx = $node.parent().width() * deltaXpercent;
  102. var deltaYpx = $node.parent().height() * deltaYpercent;
  103. var toWidgetTransform = this._getLayoutNodeTransform(toWidget);
  104. var fromWidgetTransform = this._getLayoutNodeTransform(fromWidget);
  105. var toCss = {
  106. transform: 'translate(' + -1 * deltaXpx + 'px, ' + -1 * deltaYpx + 'px)' + fromWidgetTransform + ' translate(-50%,-50%) scale(' + 1 / scaleX + ',' + 1 / scaleY + ') translate(50%,50%)'
  107. };
  108. if (config && config.hasOpacity) {
  109. toCss.opacity = '0';
  110. }
  111. $node.css(toCss);
  112. toCss = {
  113. transition: 'transform 0.9s',
  114. transform: 'translate(0px, 0px) ' + toWidgetTransform + 'translate(-50%,-50%) scale(1, 1) translate(50%,50%)'
  115. };
  116. if (config && config.hasOpacity) {
  117. toCss.transition += ', opacity 0.9s ease-out';
  118. toCss.opacity = 1;
  119. if (toWidget.style.opacity || toWidget.style.opacity === 0) {
  120. toCss.opacity = toWidget.style.opacity;
  121. }
  122. }
  123. return AnimationHelper.Animate($node, toCss);
  124. },
  125. /*
  126. * The styles on linked widgets modified in _animateFromPrevious and _animateToNext need to be restored
  127. * Widgets not in the next view hidden in _animateToNext need to be shown
  128. */
  129. _afterTransitionCallback: function _afterTransitionCallback(event, layoutView, promises) {
  130. promises = promises || [];
  131. var config = this.layoutConfiguration[layoutView.model.type];
  132. var $node = layoutView.$el;
  133. var model = layoutView.model;
  134. var transform = this._getLayoutNodeTransform(model);
  135. var css = {
  136. transition: 'none',
  137. transform: transform
  138. };
  139. if (config && config.hasOpacity) {
  140. css.opacity = 1;
  141. if (model.style.opacity || model.style.opacity === 0) {
  142. css.opacity = model.style.opacity;
  143. }
  144. }
  145. var widgetInPreviousView = event.linkIdMap.backward[layoutView.id];
  146. var widgetInNextView = event.linkIdMap.forward[layoutView.id];
  147. if (widgetInPreviousView || widgetInNextView) {
  148. $node.css(css);
  149. }
  150. if (!widgetInNextView) {
  151. $node.show();
  152. }
  153. promises.push(Promise.resolve());
  154. return promises;
  155. },
  156. _getLayoutNodeTransform: function _getLayoutNodeTransform(model) {
  157. var style = model.style;
  158. var transform;
  159. if (style && style.transform) {
  160. transform = style.transform;
  161. }
  162. if (!transform || transform === 'none' || transform === 'matrix(0, 0, 0, 0, 0, 0)') {
  163. transform = '';
  164. }
  165. return transform;
  166. }
  167. });
  168. return TransitionDirector;
  169. });
  170. //# sourceMappingURL=TransitionDirector.js.map