animation.js

  1. define(['utils', 'IPlugin', 'errors', 'jquery.easing'], function(Utils, IPlugin, Errors) {
  2. "use strict";
  3. /**
  4. * @class
  5. * Класс анимации переходов в панели
  6. * @param {JQuery} mainDiv - элемент, в котором располагается панель. Должен содержать класс rb-wrapper.
  7. * @param {ElementsPool} elementsPool - хранилище элементов ячеек панели
  8. * @constructor Animation
  9. * @extends IPlugin
  10. */
  11. function Animation(mainDiv, elementsPool) {
  12. this._elementsPool = elementsPool;
  13. if (mainDiv instanceof $) {
  14. this._mainDiv = mainDiv;
  15. } else {
  16. throw new Errors.ArgumentError('mainDiv', mainDiv);
  17. }
  18. }
  19. Utils.inherite(Animation, IPlugin);
  20. /**
  21. * Применить конфигурацию. Учитывает опции wrongTime1, wrongTime2, correctTime, wrongEasing1, wrongEasing2, correctEasing, showAdjacentScreens.
  22. * @param {Moving~config} config - конфигурация
  23. * @memberOf Animation
  24. */
  25. Animation.prototype.configure = function(config) {
  26. function fixTime(argName, time) {
  27. if (typeof time === 'number') {
  28. return time > 0 ? time : 1;
  29. } else {
  30. if (time === undefined) {
  31. return 500;
  32. } else {
  33. throw new Errors.ArgumentError(argName, time);
  34. }
  35. }
  36. }
  37. if (typeof config === 'object') {
  38. if (config.wrongTime1 !== undefined) {
  39. this._wrongTime1 = fixTime('wrongTime1', config.wrongTime1);
  40. }
  41. if (config.wrongTime2 !== undefined) {
  42. this._wrongTime2 = fixTime('wrongTime2', config.wrongTime2);
  43. }
  44. if (config.correctTime !== undefined) {
  45. this._correctTime = fixTime('correctTime', config.correctTime);
  46. }
  47. if (config.wrongEasing1 !== undefined) {
  48. this._wrongEasing1 = config.wrongEasing1;
  49. }
  50. if (config.wrongEasing2 !== undefined) {
  51. this._wrongEasing2 = config.wrongEasing2;
  52. }
  53. if (config.correctEasing !== undefined) {
  54. this._correctEasing = config.correctEasing;
  55. }
  56. if (config.showAdjacentScreens !== undefined) {
  57. this._showAdjacentScreens = config.showAdjacentScreens;
  58. }
  59. }
  60. };
  61. Animation.prototype._animate = function(elem, side, value, easing, time, beforeFn, afterFn) {
  62. beforeFn && beforeFn();
  63. var css = {}, opts;
  64. css[Utils.getStartSide(side)] = value + '%';
  65. opts = {
  66. duration: time,
  67. easing: easing,
  68. queue: false,
  69. done: afterFn
  70. };
  71. elem.animate(css, opts);
  72. };
  73. Animation.prototype._updateState = function(res, elements) {
  74. if (this._isAnimate) {
  75. this._isAnimate = false;
  76. this._new && this._new.stop();
  77. this._old && this._old.stop(false, true);
  78. this._cur && this._cur.stop();
  79. this._prev && this._prev.stop(false, true);
  80. this._next && this._next.stop(false, true);
  81. this._res(false);
  82. }
  83. this._isAnimate = true;
  84. this._old = elements.oldElem;
  85. this._new = elements.newElem;
  86. this._cur = elements.curElem;
  87. this._prev = elements.prevElem;
  88. this._next = elements.nextElem;
  89. this._res = res;
  90. };
  91. /**
  92. * Анимация неудачного перехода
  93. * @param {string} side - сторона перехода
  94. * @memberOf Animation
  95. */
  96. Animation.prototype.goToWrongSide = function(side) {
  97. var self = this,
  98. width = 100,
  99. height = 100,
  100. elem = this._elementsPool.getElementBySide('center'),
  101. nextElem = this._elementsPool.getElementBySide(side),
  102. prevElem = this._elementsPool.getElementBySide(Utils.oppositeSide(side));
  103. return new Promise(function(res, rej) {
  104. function wrongAnimate(elem, startLeft, startTop, beforeFn, afterFn) {
  105. self._animate(elem, side, '+=' + value, self._wrongEasing1, self._isAnimate ? self._wrongTime1 : 10, function() {
  106. startLeft -= 100;
  107. startTop -= 100;
  108. elem.css({'left': startLeft + '%', 'top': startTop + '%'});
  109. beforeFn && beforeFn();
  110. }, function() {
  111. self._animate(elem, side, '-=' + value, self._wrongEasing2, self._isAnimate ? self._wrongTime2 : 10, undefined, function() {
  112. afterFn && afterFn();
  113. });
  114. });
  115. }
  116. self._updateState(res, {
  117. curElem: elem,
  118. prevElem: prevElem,
  119. nextElem: nextElem
  120. });
  121. var dw = width/10, dh = height/10, value = 0, relValWidth = 0, relValHeight = 0;
  122. if (side === 'left') {
  123. relValWidth = -width;
  124. value = - dw;
  125. }
  126. else if (side === 'right') {
  127. relValWidth = width;
  128. value = dw;
  129. }
  130. else if (side === 'top') {
  131. relValHeight = -height;
  132. value = - dh;
  133. }
  134. else if (side === 'bottom') {
  135. relValHeight = height;
  136. value = dh;
  137. }
  138. if (self._showAdjacentScreens) {
  139. wrongAnimate(nextElem, width + relValWidth, height + relValHeight, function() {
  140. nextElem.toggleClass('rb__hiding-screen', true);
  141. }, function() {
  142. nextElem.toggleClass('rb__hiding-screen', false);
  143. }, true);
  144. wrongAnimate(prevElem, width - relValWidth, height - relValHeight, function() {
  145. prevElem.toggleClass('rb__hiding-screen', true);
  146. }, function() {
  147. prevElem.toggleClass('rb__hiding-screen', false);
  148. }, true);
  149. }
  150. wrongAnimate(elem, width, height, undefined, function() {
  151. self._isAnimate = false;
  152. self._res(true);
  153. });
  154. });
  155. };
  156. /**
  157. * Анимация удачного перехода
  158. * @param {string} side - сторона перехода
  159. * @memberOf Animation
  160. */
  161. Animation.prototype.goToCorrectSide = function(side) {
  162. var self = this,
  163. newElem = this._elementsPool.getElementBySide('center'),
  164. oldElem = this._elementsPool.getElementBySide(Utils.oppositeSide(side)),
  165. width = 100,
  166. height = 100;
  167. return new Promise(function(res, rej) {
  168. function correctAnimate(elem, startLeft, startTop, beforeFn, afterFn) {
  169. self._animate(elem, side, '-=' + value, self._correctEasing, self._correctTime, function() {
  170. startLeft -= 100;
  171. startTop -= 100;
  172. elem.css({'left': startLeft + '%', 'top': startTop + '%'});
  173. beforeFn && beforeFn();
  174. }, function() {
  175. afterFn && afterFn();
  176. });
  177. }
  178. self._updateState(res, {
  179. oldElem: oldElem,
  180. newElem: newElem
  181. });
  182. var value = 0, relValWidth = 0, relValHeight = 0;
  183. if (side === 'left') {
  184. relValWidth = -width;
  185. value = - width;
  186. }
  187. else if (side === 'right') {
  188. relValWidth = width;
  189. value = width;
  190. }
  191. else if (side === 'top') {
  192. relValHeight = -height;
  193. value = - height;
  194. }
  195. else if (side === 'bottom') {
  196. relValHeight = height;
  197. value = height;
  198. }
  199. if (self._showAdjacentScreens) {
  200. correctAnimate(oldElem, width, height, function () {
  201. oldElem.toggleClass('rb__hiding-screen', true);
  202. }, function () {
  203. oldElem.toggleClass('rb__hiding-screen', false);
  204. }, true);
  205. }
  206. correctAnimate(newElem, width + relValWidth, height + relValHeight, undefined, function() {
  207. self._isAnimate = false;
  208. self._res(true);
  209. });
  210. });
  211. };
  212. /**
  213. * Переход в центральную ячейку
  214. * @memberOf Animation
  215. */
  216. Animation.prototype.goToCenter = function() {
  217. var elem = this._elementsPool.getElementBySide('center');
  218. elem.css({'left': '0%', 'top': '0%'});
  219. };
  220. /**
  221. * Уничтожить экземпляр класса анимации
  222. * @memberOf Animation
  223. */
  224. Animation.prototype.destroy = function() {
  225. this._new && this._new.stop();
  226. this._old && this._old.stop();
  227. this._cur && this._cur.stop();
  228. this._prev && this._prev.stop();
  229. this._next && this._next.stop();
  230. this._res && this._res(false);
  231. };
  232. return Animation;
  233. });