Skip to content

Commit

Permalink
feat(slides): add swiper controller (#9983)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manduro authored and brandyscarney committed Jan 12, 2017
1 parent e35a3b1 commit f499496
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 2 deletions.
22 changes: 22 additions & 0 deletions src/components/slides/slides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,22 @@ export class Slides extends Ion {
}
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`.
* Default: `slide`.
Expand Down Expand Up @@ -551,6 +567,10 @@ export class Slides extends Ion {
/** @private */
runCallbacksOnInit = true;

// Controller
controlBy = 'slide';
controlInverse = false;

// Keyboard
/**
* @private
Expand Down Expand Up @@ -827,6 +847,8 @@ export class Slides extends Ion {
/** @internal */
_slidesSizesGrid: any;
/** @internal */
_spline: any;
/** @internal */
_supportTouch: boolean;
/** @internal */
_supportGestures: boolean;
Expand Down
120 changes: 120 additions & 0 deletions src/components/slides/swiper/swiper-controller.ts
Original file line number Diff line number Diff line change
@@ -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 := ((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];
};

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);
}
}
};
4 changes: 4 additions & 0 deletions src/components/slides/swiper/swiper-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,10 @@ function onResize(s: Slides, plt: Platform, forceUpdatePagination: boolean) {
updatePagination(s);
}

if (s._spline) {
s._spline = undefined;
}

var slideChangedBySlideTo = false;
if (s.freeMode) {
var newTranslate = Math.min(Math.max(s._translate, maxTranslate(s)), minTranslate(s));
Expand Down
13 changes: 11 additions & 2 deletions src/components/slides/swiper/swiper-transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { parallaxSetTransition, parallaxSetTranslate } from './swiper-parallax';
import { Platform } from '../../../platform/platform';
import { updateProgress } from './swiper-progress';
import { updateActiveIndex } from './swiper-index';
import { SWIPER_CONTROLLER } from './swiper-controller';
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;
if (isHorizontal(s)) {
x = s._rtl ? -translate : translate;
Expand Down Expand Up @@ -51,6 +52,10 @@ export function setWrapperTranslate(s: Slides, plt: Platform, translate: any, sh
if (s.parallax) {
parallaxSetTranslate(s);
}

if (s.control) {
SWIPER_CONTROLLER.setTranslate(s, plt, s._translate, byController);
}
}


Expand Down Expand Up @@ -127,7 +132,7 @@ export function getWrapperTranslate(s: Slides, plt: Platform, axis?: any) {
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);

if (s.effect !== 'slide' && SWIPER_EFFECTS[s.effect]) {
Expand All @@ -137,4 +142,8 @@ export function setWrapperTransition(s: Slides, plt: Platform, duration: number,
if (s.parallax) {
parallaxSetTransition(s, duration);
}

if (s.control) {
SWIPER_CONTROLLER.setTransition(s, plt, duration, byController);
}
}
3 changes: 3 additions & 0 deletions src/components/slides/swiper/swiper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ export function update(s: Slides, plt: Platform, updateTranslate?: boolean) {
}

if (updateTranslate) {
if (s._spline) {
s._spline = undefined;
}
if (s.freeMode) {
forceSetTranslate();
if (s.autoHeight) {
Expand Down
35 changes: 35 additions & 0 deletions src/components/slides/test/control/app-module.ts
Original file line number Diff line number Diff line change
@@ -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 {}
40 changes: 40 additions & 0 deletions src/components/slides/test/control/main.html
Original file line number Diff line number Diff line change
@@ -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>

0 comments on commit f499496

Please sign in to comment.