feat(slides): add swiper controller (#9983)

This commit is contained in:
Job
2017-01-12 19:41:17 +01:00
committed by Brandy Carney
parent e35a3b1ab7
commit f499496e4d
7 changed files with 235 additions and 2 deletions

View File

@ -161,6 +161,22 @@ export class Slides extends Ion {
} }
private _autoplayMs: number; private _autoplayMs: number;
/**
* @input {Slides} Pass another Slides instance or array of Slides instances
* that should be controlled by this Slides instance.
* Default: `null`.
*/
@Input()
get control() {
return this._control;
}
set control(val: Slides | Slides[]) {
if (val instanceof Slides || Array.isArray(val)) {
this._control = val;
}
}
private _control: Slides | Slides[] = null;
/** /**
* @input {string} Could be `slide`, `fade`, `cube`, `coverflow` or `flip`. * @input {string} Could be `slide`, `fade`, `cube`, `coverflow` or `flip`.
* Default: `slide`. * Default: `slide`.
@ -551,6 +567,10 @@ export class Slides extends Ion {
/** @private */ /** @private */
runCallbacksOnInit = true; runCallbacksOnInit = true;
// Controller
controlBy = 'slide';
controlInverse = false;
// Keyboard // Keyboard
/** /**
* @private * @private
@ -827,6 +847,8 @@ export class Slides extends Ion {
/** @internal */ /** @internal */
_slidesSizesGrid: any; _slidesSizesGrid: any;
/** @internal */ /** @internal */
_spline: any;
/** @internal */
_supportTouch: boolean; _supportTouch: boolean;
/** @internal */ /** @internal */
_supportGestures: boolean; _supportGestures: boolean;

View File

@ -0,0 +1,120 @@
import { Slides } from '../slides';
import { Platform } from '../../../platform/platform';
import { fixLoop, onTransitionEnd, onTransitionStart } from './swiper';
import { updateActiveIndex } from './swiper-index';
import { isHorizontal, maxTranslate, minTranslate } from './swiper-utils';
import { updateProgress } from './swiper-progress';
import { setWrapperTransition, setWrapperTranslate } from './swiper-transition';
/*=========================
Controller
===========================*/
export const SWIPER_CONTROLLER = {
LinearSpline: function (s: Slides, plt: Platform, x: any, y: any) {
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.
var i1, i3;
this.interpolate = function (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 := ((x2x1) × (y3y1)) ÷ (x3x1) + y1
return ((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1]) + this.y[i1];
};
var binarySearch = (function () {
var maxIndex, minIndex, guess;
return function (array, val) {
minIndex = -1;
maxIndex = array.length;
while (maxIndex - minIndex > 1)
if (array[guess = maxIndex + minIndex >> 1] <= val) {
minIndex = guess;
} else {
maxIndex = guess;
}
return maxIndex;
};
})();
},
// xxx: for now i will just save one spline function to to
getInterpolateFunction: function (s: Slides, plt: Platform, c: Slides) {
if (!s._spline) s._spline = s.loop ?
new SWIPER_CONTROLLER.LinearSpline(s, plt, s._slidesGrid, c._slidesGrid) :
new SWIPER_CONTROLLER.LinearSpline(s, plt, s._snapGrid, c._snapGrid);
},
setTranslate: function (s: Slides, plt: Platform, translate: number, byController: Slides) {
var controlled = s.control;
var multiplier, controlledTranslate;
function setControlledTranslate(c: Slides) {
// 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
translate = c._rtl && isHorizontal(c) ? -s._translate : s._translate;
if (s.controlBy === 'slide') {
SWIPER_CONTROLLER.getInterpolateFunction(s, plt, 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 = -s._spline.interpolate(-translate);
}
if (!controlledTranslate || s.controlBy === 'container') {
multiplier = (maxTranslate(c) - minTranslate(c)) / (maxTranslate(s) - minTranslate(s));
controlledTranslate = (translate - minTranslate(s)) * multiplier + minTranslate(c);
}
if (s.controlInverse) {
controlledTranslate = maxTranslate(c) - controlledTranslate;
}
updateProgress(c, controlledTranslate);
setWrapperTranslate(c, plt, controlledTranslate, false, s);
updateActiveIndex(c);
}
if (Array.isArray(controlled)) {
for (var i = 0; i < controlled.length; i++) {
if (controlled[i] !== byController) {
setControlledTranslate(controlled[i]);
}
}
} else if (byController !== controlled) {
setControlledTranslate(controlled);
}
},
setTransition: function (s: Slides, plt: Platform, duration: number, byController: Slides) {
var controlled = s.control;
var i;
function setControlledTransition(c: Slides) {
setWrapperTransition(c, plt, duration, s);
if (duration !== 0) {
onTransitionStart(c);
plt.transitionEnd(c._wrapper, () => {
if (!controlled) return;
if (c.loop && s.controlBy === 'slide') {
fixLoop(c, plt);
}
onTransitionEnd(c, plt);
});
}
}
if (Array.isArray(controlled)) {
for (i = 0; i < controlled.length; i++) {
if (controlled[i] !== byController) {
setControlledTransition(controlled[i]);
}
}
} else if (byController !== controlled) {
setControlledTransition(controlled);
}
}
};

View File

@ -832,6 +832,10 @@ function onResize(s: Slides, plt: Platform, forceUpdatePagination: boolean) {
updatePagination(s); updatePagination(s);
} }
if (s._spline) {
s._spline = undefined;
}
var slideChangedBySlideTo = false; var slideChangedBySlideTo = false;
if (s.freeMode) { if (s.freeMode) {
var newTranslate = Math.min(Math.max(s._translate, maxTranslate(s)), minTranslate(s)); var newTranslate = Math.min(Math.max(s._translate, maxTranslate(s)), minTranslate(s));

View File

@ -4,10 +4,11 @@ import { parallaxSetTransition, parallaxSetTranslate } from './swiper-parallax';
import { Platform } from '../../../platform/platform'; import { Platform } from '../../../platform/platform';
import { updateProgress } from './swiper-progress'; import { updateProgress } from './swiper-progress';
import { updateActiveIndex } from './swiper-index'; import { updateActiveIndex } from './swiper-index';
import { SWIPER_CONTROLLER } from './swiper-controller';
import { SWIPER_EFFECTS } from './swiper-effects'; import { SWIPER_EFFECTS } from './swiper-effects';
export function setWrapperTranslate(s: Slides, plt: Platform, translate: any, shouldUpdateActiveIndex?: boolean, byController?: any) { export function setWrapperTranslate(s: Slides, plt: Platform, translate: any, shouldUpdateActiveIndex?: boolean, byController?: Slides) {
var x = 0, y = 0, z = 0; var x = 0, y = 0, z = 0;
if (isHorizontal(s)) { if (isHorizontal(s)) {
x = s._rtl ? -translate : translate; x = s._rtl ? -translate : translate;
@ -51,6 +52,10 @@ export function setWrapperTranslate(s: Slides, plt: Platform, translate: any, sh
if (s.parallax) { if (s.parallax) {
parallaxSetTranslate(s); parallaxSetTranslate(s);
} }
if (s.control) {
SWIPER_CONTROLLER.setTranslate(s, plt, s._translate, byController);
}
} }
@ -127,7 +132,7 @@ export function getWrapperTranslate(s: Slides, plt: Platform, axis?: any) {
return getTranslate(s, plt, s._wrapper, axis); return getTranslate(s, plt, s._wrapper, axis);
} }
export function setWrapperTransition(s: Slides, plt: Platform, duration: number, byController?: any) { export function setWrapperTransition(s: Slides, plt: Platform, duration: number, byController?: Slides) {
transition(s._wrapper, duration); transition(s._wrapper, duration);
if (s.effect !== 'slide' && SWIPER_EFFECTS[s.effect]) { if (s.effect !== 'slide' && SWIPER_EFFECTS[s.effect]) {
@ -137,4 +142,8 @@ export function setWrapperTransition(s: Slides, plt: Platform, duration: number,
if (s.parallax) { if (s.parallax) {
parallaxSetTransition(s, duration); parallaxSetTransition(s, duration);
} }
if (s.control) {
SWIPER_CONTROLLER.setTransition(s, plt, duration, byController);
}
} }

View File

@ -618,6 +618,9 @@ export function update(s: Slides, plt: Platform, updateTranslate?: boolean) {
} }
if (updateTranslate) { if (updateTranslate) {
if (s._spline) {
s._spline = undefined;
}
if (s.freeMode) { if (s.freeMode) {
forceSetTranslate(); forceSetTranslate();
if (s.autoHeight) { if (s.autoHeight) {

View File

@ -0,0 +1,35 @@
import { Component, ViewChild, NgModule } from '@angular/core';
import { IonicApp, IonicModule, Slides } from '../../../..';
@Component({
templateUrl: 'main.html'
})
export class MyPage {
@ViewChild('firstSlider') slider1: Slides;
@ViewChild('secondSlider') slider2: Slides;
}
@Component({
template: `<ion-nav [root]="root"></ion-nav>`
})
export class E2EApp {
root: any = MyPage;
}
@NgModule({
declarations: [
E2EApp,
MyPage
],
imports: [
IonicModule.forRoot(E2EApp)
],
bootstrap: [IonicApp],
entryComponents: [
E2EApp,
MyPage
]
})
export class AppModule {}

View File

@ -0,0 +1,40 @@
<ion-content no-bounce>
<div style="height: 200px; background-color: #eee;">
<ion-slides class="my-slides" #firstSlider [control]="secondSlider">
<ion-slide padding>
<h1>Slide 1</h1>
</ion-slide>
<ion-slide padding>
<h1>Slide 2</h1>
</ion-slide>
<ion-slide padding>
<h1>Slide 3</h1>
</ion-slide>
</ion-slides>
</div>
<div style="height: 200px; background-color: #ddd;">
<ion-slides class="my-slides" #secondSlider [control]="firstSlider">
<ion-slide padding>
<h1>Slide 1</h1>
</ion-slide>
<ion-slide padding>
<h1>Slide 2</h1>
</ion-slide>
<ion-slide padding>
<h1>Slide 3</h1>
</ion-slide>
</ion-slides>
</div>
</ion-content>