UNPKG

5.66 kBJavaScriptView Raw
1/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
2import { nextTick } from '../../shared/utils.js';
3export default function Controller({
4 swiper,
5 extendParams,
6 on
7}) {
8 extendParams({
9 controller: {
10 control: undefined,
11 inverse: false,
12 by: 'slide' // or 'container'
13
14 }
15 });
16 swiper.controller = {
17 control: undefined
18 };
19
20 function LinearSpline(x, y) {
21 const binarySearch = function search() {
22 let maxIndex;
23 let minIndex;
24 let guess;
25 return (array, val) => {
26 minIndex = -1;
27 maxIndex = array.length;
28
29 while (maxIndex - minIndex > 1) {
30 guess = maxIndex + minIndex >> 1;
31
32 if (array[guess] <= val) {
33 minIndex = guess;
34 } else {
35 maxIndex = guess;
36 }
37 }
38
39 return maxIndex;
40 };
41 }();
42
43 this.x = x;
44 this.y = y;
45 this.lastIndex = x.length - 1; // Given an x value (x2), return the expected y2 value:
46 // (x1,y1) is the known point before given value,
47 // (x3,y3) is the known point after given value.
48
49 let i1;
50 let i3;
51
52 this.interpolate = function interpolate(x2) {
53 if (!x2) return 0; // Get the indexes of x1 and x3 (the array indexes before and after given x2):
54
55 i3 = binarySearch(this.x, x2);
56 i1 = i3 - 1; // We have our indexes i1 & i3, so we can calculate already:
57 // y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
58
59 return (x2 - this.x[i1]) * (this.y[i3] - this.y[i1]) / (this.x[i3] - this.x[i1]) + this.y[i1];
60 };
61
62 return this;
63 } // xxx: for now i will just save one spline function to to
64
65
66 function getInterpolateFunction(c) {
67 if (!swiper.controller.spline) {
68 swiper.controller.spline = swiper.params.loop ? new LinearSpline(swiper.slidesGrid, c.slidesGrid) : new LinearSpline(swiper.snapGrid, c.snapGrid);
69 }
70 }
71
72 function setTranslate(_t, byController) {
73 const controlled = swiper.controller.control;
74 let multiplier;
75 let controlledTranslate;
76 const Swiper = swiper.constructor;
77
78 function setControlledTranslate(c) {
79 // this will create an Interpolate function based on the snapGrids
80 // x is the Grid of the scrolled scroller and y will be the controlled scroller
81 // it makes sense to create this only once and recall it for the interpolation
82 // the function does a lot of value caching for performance
83 const translate = swiper.rtlTranslate ? -swiper.translate : swiper.translate;
84
85 if (swiper.params.controller.by === 'slide') {
86 getInterpolateFunction(c); // i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
87 // but it did not work out
88
89 controlledTranslate = -swiper.controller.spline.interpolate(-translate);
90 }
91
92 if (!controlledTranslate || swiper.params.controller.by === 'container') {
93 multiplier = (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());
94 controlledTranslate = (translate - swiper.minTranslate()) * multiplier + c.minTranslate();
95 }
96
97 if (swiper.params.controller.inverse) {
98 controlledTranslate = c.maxTranslate() - controlledTranslate;
99 }
100
101 c.updateProgress(controlledTranslate);
102 c.setTranslate(controlledTranslate, swiper);
103 c.updateActiveIndex();
104 c.updateSlidesClasses();
105 }
106
107 if (Array.isArray(controlled)) {
108 for (let i = 0; i < controlled.length; i += 1) {
109 if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
110 setControlledTranslate(controlled[i]);
111 }
112 }
113 } else if (controlled instanceof Swiper && byController !== controlled) {
114 setControlledTranslate(controlled);
115 }
116 }
117
118 function setTransition(duration, byController) {
119 const Swiper = swiper.constructor;
120 const controlled = swiper.controller.control;
121 let i;
122
123 function setControlledTransition(c) {
124 c.setTransition(duration, swiper);
125
126 if (duration !== 0) {
127 c.transitionStart();
128
129 if (c.params.autoHeight) {
130 nextTick(() => {
131 c.updateAutoHeight();
132 });
133 }
134
135 c.$wrapperEl.transitionEnd(() => {
136 if (!controlled) return;
137
138 if (c.params.loop && swiper.params.controller.by === 'slide') {
139 c.loopFix();
140 }
141
142 c.transitionEnd();
143 });
144 }
145 }
146
147 if (Array.isArray(controlled)) {
148 for (i = 0; i < controlled.length; i += 1) {
149 if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
150 setControlledTransition(controlled[i]);
151 }
152 }
153 } else if (controlled instanceof Swiper && byController !== controlled) {
154 setControlledTransition(controlled);
155 }
156 }
157
158 function removeSpline() {
159 if (!swiper.controller.control) return;
160
161 if (swiper.controller.spline) {
162 swiper.controller.spline = undefined;
163 delete swiper.controller.spline;
164 }
165 }
166
167 on('beforeInit', () => {
168 swiper.controller.control = swiper.params.controller.control;
169 });
170 on('update', () => {
171 removeSpline();
172 });
173 on('resize', () => {
174 removeSpline();
175 });
176 on('observerUpdate', () => {
177 removeSpline();
178 });
179 on('setTranslate', (_s, translate, byController) => {
180 if (!swiper.controller.control) return;
181 swiper.controller.setTranslate(translate, byController);
182 });
183 on('setTransition', (_s, duration, byController) => {
184 if (!swiper.controller.control) return;
185 swiper.controller.setTransition(duration, byController);
186 });
187 Object.assign(swiper.controller, {
188 setTranslate,
189 setTransition
190 });
191}
\No newline at end of file