controller.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import {
  2. nextTick
  3. } from '../../shared/utils.js';
  4. export default function Controller({
  5. swiper,
  6. extendParams,
  7. on
  8. }) {
  9. extendParams({
  10. controller: {
  11. control: undefined,
  12. inverse: false,
  13. by: 'slide', // or 'container'
  14. },
  15. });
  16. swiper.controller = {
  17. control: undefined,
  18. };
  19. function LinearSpline(x, y) {
  20. const binarySearch = (function search() {
  21. let maxIndex;
  22. let minIndex;
  23. let guess;
  24. return (array, val) => {
  25. minIndex = -1;
  26. maxIndex = array.length;
  27. while (maxIndex - minIndex > 1) {
  28. guess = (maxIndex + minIndex) >> 1;
  29. if (array[guess] <= val) {
  30. minIndex = guess;
  31. } else {
  32. maxIndex = guess;
  33. }
  34. }
  35. return maxIndex;
  36. };
  37. })();
  38. this.x = x;
  39. this.y = y;
  40. this.lastIndex = x.length - 1;
  41. let i1;
  42. let i3;
  43. this.interpolate = function interpolate(x2) {
  44. if (!x2) return 0;
  45. i3 = binarySearch(this.x, x2);
  46. i1 = i3 - 1;
  47. return (
  48. ((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1]) + this.y[i1]
  49. );
  50. };
  51. return this;
  52. }
  53. function getInterpolateFunction(c) {
  54. swiper.controller.spline = swiper.params.loop ?
  55. new LinearSpline(swiper.slidesGrid, c.slidesGrid) :
  56. new LinearSpline(swiper.snapGrid, c.snapGrid);
  57. }
  58. function setTranslate(_t, byController) {
  59. const controlled = swiper.controller.control;
  60. let multiplier;
  61. let controlledTranslate;
  62. const Swiper = swiper.constructor;
  63. function setControlledTranslate(c) {
  64. if (c.destroyed) return;
  65. const translate = swiper.rtlTranslate ? -swiper.translate : swiper.translate;
  66. if (swiper.params.controller.by === 'slide') {
  67. getInterpolateFunction(c);
  68. controlledTranslate = -swiper.controller.spline.interpolate(-translate);
  69. }
  70. if (!controlledTranslate || swiper.params.controller.by === 'container') {
  71. multiplier =
  72. (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());
  73. if (Number.isNaN(multiplier) || !Number.isFinite(multiplier)) {
  74. multiplier = 1;
  75. }
  76. controlledTranslate = (translate - swiper.minTranslate()) * multiplier + c.minTranslate();
  77. }
  78. if (swiper.params.controller.inverse) {
  79. controlledTranslate = c.maxTranslate() - controlledTranslate;
  80. }
  81. c.updateProgress(controlledTranslate);
  82. c.setTranslate(controlledTranslate, swiper);
  83. c.updateActiveIndex();
  84. c.updateSlidesClasses();
  85. }
  86. if (Array.isArray(controlled)) {
  87. for (let i = 0; i < controlled.length; i += 1) {
  88. if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
  89. setControlledTranslate(controlled[i]);
  90. }
  91. }
  92. } else if (controlled instanceof Swiper && byController !== controlled) {
  93. setControlledTranslate(controlled);
  94. }
  95. }
  96. function setTransition(duration, byController) {
  97. const Swiper = swiper.constructor;
  98. const controlled = swiper.controller.control;
  99. let i;
  100. function setControlledTransition(c) {
  101. if (c.destroyed) return;
  102. c.setTransition(duration, swiper);
  103. if (duration !== 0) {
  104. c.transitionStart();
  105. if (c.params.autoHeight) {
  106. nextTick(() => {
  107. c.updateAutoHeight();
  108. });
  109. }
  110. }
  111. }
  112. if (Array.isArray(controlled)) {
  113. for (i = 0; i < controlled.length; i += 1) {
  114. if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
  115. setControlledTransition(controlled[i]);
  116. }
  117. }
  118. } else if (controlled instanceof Swiper && byController !== controlled) {
  119. setControlledTransition(controlled);
  120. }
  121. }
  122. function removeSpline() {
  123. if (!swiper.controller.control) return;
  124. if (swiper.controller.spline) {
  125. swiper.controller.spline = undefined;
  126. delete swiper.controller.spline;
  127. }
  128. }
  129. on('beforeInit', () => {
  130. if (
  131. typeof window !== 'undefined' && // eslint-disable-line
  132. (typeof swiper.params.controller.control === 'string' ||
  133. swiper.params.controller.control instanceof HTMLElement)
  134. ) {
  135. const controlElement = document.querySelector(swiper.params.controller.control);
  136. if (controlElement && controlElement.swiper) {
  137. swiper.controller.control = controlElement.swiper;
  138. } else if (controlElement) {
  139. const onControllerSwiper = (e) => {
  140. swiper.controller.control = e.detail[0];
  141. swiper.update();
  142. controlElement.removeEventListener('init', onControllerSwiper);
  143. };
  144. controlElement.addEventListener('init', onControllerSwiper);
  145. }
  146. return;
  147. }
  148. swiper.controller.control = swiper.params.controller.control;
  149. });
  150. on('update', () => {
  151. removeSpline();
  152. });
  153. on('resize', () => {
  154. removeSpline();
  155. });
  156. on('observerUpdate', () => {
  157. removeSpline();
  158. });
  159. on('setTranslate', (_s, translate, byController) => {
  160. if (!swiper.controller.control || swiper.controller.control.destroyed) return;
  161. swiper.controller.setTranslate(translate, byController);
  162. });
  163. on('setTransition', (_s, duration, byController) => {
  164. if (!swiper.controller.control || swiper.controller.control.destroyed) return;
  165. swiper.controller.setTransition(duration, byController);
  166. });
  167. Object.assign(swiper.controller, {
  168. setTranslate,
  169. setTransition,
  170. });
  171. }