controller.mjs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { n as nextTick, k as elementTransitionEnd } from '../shared/utils.mjs';
  2. /* eslint no-bitwise: ["error", { "allow": [">>"] }] */
  3. function Controller(_ref) {
  4. let {
  5. swiper,
  6. extendParams,
  7. on
  8. } = _ref;
  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. // Given an x value (x2), return the expected y2 value:
  42. // (x1,y1) is the known point before given value,
  43. // (x3,y3) is the known point after given value.
  44. let i1;
  45. let i3;
  46. this.interpolate = function interpolate(x2) {
  47. if (!x2) return 0;
  48. // Get the indexes of x1 and x3 (the array indexes before and after given x2):
  49. i3 = binarySearch(this.x, x2);
  50. i1 = i3 - 1;
  51. // We have our indexes i1 & i3, so we can calculate already:
  52. // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
  53. return (x2 - this.x[i1]) * (this.y[i3] - this.y[i1]) / (this.x[i3] - this.x[i1]) + this.y[i1];
  54. };
  55. return this;
  56. }
  57. function getInterpolateFunction(c) {
  58. swiper.controller.spline = swiper.params.loop ? new LinearSpline(swiper.slidesGrid, c.slidesGrid) : new LinearSpline(swiper.snapGrid, c.snapGrid);
  59. }
  60. function setTranslate(_t, byController) {
  61. const controlled = swiper.controller.control;
  62. let multiplier;
  63. let controlledTranslate;
  64. const Swiper = swiper.constructor;
  65. function setControlledTranslate(c) {
  66. if (c.destroyed) return;
  67. // this will create an Interpolate function based on the snapGrids
  68. // x is the Grid of the scrolled scroller and y will be the controlled scroller
  69. // it makes sense to create this only once and recall it for the interpolation
  70. // the function does a lot of value caching for performance
  71. const translate = swiper.rtlTranslate ? -swiper.translate : swiper.translate;
  72. if (swiper.params.controller.by === 'slide') {
  73. getInterpolateFunction(c);
  74. // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
  75. // but it did not work out
  76. controlledTranslate = -swiper.controller.spline.interpolate(-translate);
  77. }
  78. if (!controlledTranslate || swiper.params.controller.by === 'container') {
  79. multiplier = (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());
  80. if (Number.isNaN(multiplier) || !Number.isFinite(multiplier)) {
  81. multiplier = 1;
  82. }
  83. controlledTranslate = (translate - swiper.minTranslate()) * multiplier + c.minTranslate();
  84. }
  85. if (swiper.params.controller.inverse) {
  86. controlledTranslate = c.maxTranslate() - controlledTranslate;
  87. }
  88. c.updateProgress(controlledTranslate);
  89. c.setTranslate(controlledTranslate, swiper);
  90. c.updateActiveIndex();
  91. c.updateSlidesClasses();
  92. }
  93. if (Array.isArray(controlled)) {
  94. for (let i = 0; i < controlled.length; i += 1) {
  95. if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
  96. setControlledTranslate(controlled[i]);
  97. }
  98. }
  99. } else if (controlled instanceof Swiper && byController !== controlled) {
  100. setControlledTranslate(controlled);
  101. }
  102. }
  103. function setTransition(duration, byController) {
  104. const Swiper = swiper.constructor;
  105. const controlled = swiper.controller.control;
  106. let i;
  107. function setControlledTransition(c) {
  108. if (c.destroyed) return;
  109. c.setTransition(duration, swiper);
  110. if (duration !== 0) {
  111. c.transitionStart();
  112. if (c.params.autoHeight) {
  113. nextTick(() => {
  114. c.updateAutoHeight();
  115. });
  116. }
  117. elementTransitionEnd(c.wrapperEl, () => {
  118. if (!controlled) return;
  119. c.transitionEnd();
  120. });
  121. }
  122. }
  123. if (Array.isArray(controlled)) {
  124. for (i = 0; i < controlled.length; i += 1) {
  125. if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
  126. setControlledTransition(controlled[i]);
  127. }
  128. }
  129. } else if (controlled instanceof Swiper && byController !== controlled) {
  130. setControlledTransition(controlled);
  131. }
  132. }
  133. function removeSpline() {
  134. if (!swiper.controller.control) return;
  135. if (swiper.controller.spline) {
  136. swiper.controller.spline = undefined;
  137. delete swiper.controller.spline;
  138. }
  139. }
  140. on('beforeInit', () => {
  141. if (typeof window !== 'undefined' && (
  142. // eslint-disable-line
  143. typeof swiper.params.controller.control === 'string' || swiper.params.controller.control instanceof HTMLElement)) {
  144. const controlElements = typeof swiper.params.controller.control === 'string' ? [...document.querySelectorAll(swiper.params.controller.control)] : [swiper.params.controller.control];
  145. controlElements.forEach(controlElement => {
  146. if (!swiper.controller.control) swiper.controller.control = [];
  147. if (controlElement && controlElement.swiper) {
  148. swiper.controller.control.push(controlElement.swiper);
  149. } else if (controlElement) {
  150. const eventName = `${swiper.params.eventsPrefix}init`;
  151. const onControllerSwiper = e => {
  152. swiper.controller.control.push(e.detail[0]);
  153. swiper.update();
  154. controlElement.removeEventListener(eventName, onControllerSwiper);
  155. };
  156. controlElement.addEventListener(eventName, onControllerSwiper);
  157. }
  158. });
  159. return;
  160. }
  161. swiper.controller.control = swiper.params.controller.control;
  162. });
  163. on('update', () => {
  164. removeSpline();
  165. });
  166. on('resize', () => {
  167. removeSpline();
  168. });
  169. on('observerUpdate', () => {
  170. removeSpline();
  171. });
  172. on('setTranslate', (_s, translate, byController) => {
  173. if (!swiper.controller.control || swiper.controller.control.destroyed) return;
  174. swiper.controller.setTranslate(translate, byController);
  175. });
  176. on('setTransition', (_s, duration, byController) => {
  177. if (!swiper.controller.control || swiper.controller.control.destroyed) return;
  178. swiper.controller.setTransition(duration, byController);
  179. });
  180. Object.assign(swiper.controller, {
  181. setTranslate,
  182. setTransition
  183. });
  184. }
  185. export { Controller as default };