/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
|
import Swiper from '../core/core-class';
|
import Utils from '../../utils/utils';
|
|
const Controller = {
|
LinearSpline: function LinearSpline(x, y) {
|
const binarySearch = (function search() {
|
let maxIndex;
|
let minIndex;
|
let guess;
|
return (array, val) => {
|
minIndex = -1;
|
maxIndex = array.length;
|
while (maxIndex - minIndex > 1) {
|
guess = maxIndex + minIndex >> 1;
|
if (array[guess] <= val) {
|
minIndex = guess;
|
} else {
|
maxIndex = guess;
|
}
|
}
|
return maxIndex;
|
};
|
}());
|
this.x = x;
|
this.y = y;
|
this.lastIndex = x.length - 1;
|
// Given an x value (x2), return the expected y2 value:
|
// (x1,y1) is the known point before given value,
|
// (x3,y3) is the known point after given value.
|
let i1;
|
let i3;
|
|
this.interpolate = function interpolate(x2) {
|
if (!x2) return 0;
|
|
// Get the indexes of x1 and x3 (the array indexes before and after given x2):
|
i3 = binarySearch(this.x, x2);
|
i1 = i3 - 1;
|
|
// We have our indexes i1 & i3, so we can calculate already:
|
// y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
|
return (((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1])) + this.y[i1];
|
};
|
return this;
|
},
|
// xxx: for now i will just save one spline function to to
|
getInterpolateFunction(c) {
|
const swiper = this;
|
if (!swiper.controller.spline) {
|
swiper.controller.spline = swiper.params.loop
|
? new Controller.LinearSpline(swiper.slidesGrid, c.slidesGrid)
|
: new Controller.LinearSpline(swiper.snapGrid, c.snapGrid);
|
}
|
},
|
setTranslate(setTranslate, byController) {
|
const swiper = this;
|
const controlled = swiper.controller.control;
|
let multiplier;
|
let controlledTranslate;
|
function setControlledTranslate(c) {
|
// this will create an Interpolate function based on the snapGrids
|
// x is the Grid of the scrolled scroller and y will be the controlled scroller
|
// it makes sense to create this only once and recall it for the interpolation
|
// the function does a lot of value caching for performance
|
const translate = swiper.rtlTranslate ? -swiper.translate : swiper.translate;
|
if (swiper.params.controller.by === 'slide') {
|
swiper.controller.getInterpolateFunction(c);
|
// i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
|
// but it did not work out
|
controlledTranslate = -swiper.controller.spline.interpolate(-translate);
|
}
|
|
if (!controlledTranslate || swiper.params.controller.by === 'container') {
|
multiplier = (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());
|
controlledTranslate = ((translate - swiper.minTranslate()) * multiplier) + c.minTranslate();
|
}
|
|
if (swiper.params.controller.inverse) {
|
controlledTranslate = c.maxTranslate() - controlledTranslate;
|
}
|
c.updateProgress(controlledTranslate);
|
c.setTranslate(controlledTranslate, swiper);
|
c.updateActiveIndex();
|
c.updateSlidesClasses();
|
}
|
if (Array.isArray(controlled)) {
|
for (let i = 0; i < controlled.length; i += 1) {
|
if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
|
setControlledTranslate(controlled[i]);
|
}
|
}
|
} else if (controlled instanceof Swiper && byController !== controlled) {
|
setControlledTranslate(controlled);
|
}
|
},
|
setTransition(duration, byController) {
|
const swiper = this;
|
const controlled = swiper.controller.control;
|
let i;
|
function setControlledTransition(c) {
|
c.setTransition(duration, swiper);
|
if (duration !== 0) {
|
c.transitionStart();
|
if (c.params.autoHeight) {
|
Utils.nextTick(() => {
|
c.updateAutoHeight();
|
});
|
}
|
c.$wrapperEl.transitionEnd(() => {
|
if (!controlled) return;
|
if (c.params.loop && swiper.params.controller.by === 'slide') {
|
c.loopFix();
|
}
|
c.transitionEnd();
|
});
|
}
|
}
|
if (Array.isArray(controlled)) {
|
for (i = 0; i < controlled.length; i += 1) {
|
if (controlled[i] !== byController && controlled[i] instanceof Swiper) {
|
setControlledTransition(controlled[i]);
|
}
|
}
|
} else if (controlled instanceof Swiper && byController !== controlled) {
|
setControlledTransition(controlled);
|
}
|
},
|
};
|
export default {
|
name: 'controller',
|
params: {
|
controller: {
|
control: undefined,
|
inverse: false,
|
by: 'slide', // or 'container'
|
},
|
},
|
create() {
|
const swiper = this;
|
Utils.extend(swiper, {
|
controller: {
|
control: swiper.params.controller.control,
|
getInterpolateFunction: Controller.getInterpolateFunction.bind(swiper),
|
setTranslate: Controller.setTranslate.bind(swiper),
|
setTransition: Controller.setTransition.bind(swiper),
|
},
|
});
|
},
|
on: {
|
update() {
|
const swiper = this;
|
if (!swiper.controller.control) return;
|
if (swiper.controller.spline) {
|
swiper.controller.spline = undefined;
|
delete swiper.controller.spline;
|
}
|
},
|
resize() {
|
const swiper = this;
|
if (!swiper.controller.control) return;
|
if (swiper.controller.spline) {
|
swiper.controller.spline = undefined;
|
delete swiper.controller.spline;
|
}
|
},
|
observerUpdate() {
|
const swiper = this;
|
if (!swiper.controller.control) return;
|
if (swiper.controller.spline) {
|
swiper.controller.spline = undefined;
|
delete swiper.controller.spline;
|
}
|
},
|
setTranslate(translate, byController) {
|
const swiper = this;
|
if (!swiper.controller.control) return;
|
swiper.controller.setTranslate(translate, byController);
|
},
|
setTransition(duration, byController) {
|
const swiper = this;
|
if (!swiper.controller.control) return;
|
swiper.controller.setTransition(duration, byController);
|
},
|
},
|
};
|