Skip to content

Commit

Permalink
feat(cards-effect): new Cards effect
Browse files Browse the repository at this point in the history
  • Loading branch information
nolimits4web committed Aug 11, 2021
1 parent 1c7d49e commit 21af858
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 5 deletions.
9 changes: 5 additions & 4 deletions scripts/build-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ module.exports = {
'history',
'hash-navigation',
'autoplay',
'thumbs',
'free-mode',
'grid',
'manipulation',
'effect-fade',
'effect-cube',
'effect-flip',
'effect-coverflow',
'effect-custom',
'thumbs',
'free-mode',
'grid',
'manipulation',
'effect-cards',
],
};
1 change: 1 addition & 0 deletions src/angular/src/swiper.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export class SwiperComponent implements OnInit {
@Input() fadeEffect: SwiperOptions['fadeEffect'];
@Input() flipEffect: SwiperOptions['flipEffect'];
@Input() customEffect: SwiperOptions['customEffect'];
@Input() cardsEffect: SwiperOptions['cardsEffect'];
@Input() hashNavigation: SwiperOptions['hashNavigation'];
@Input() history: SwiperOptions['history'];
@Input() keyboard: SwiperOptions['keyboard'];
Expand Down
1 change: 1 addition & 0 deletions src/angular/src/utils/params-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const paramsList = [
'fadeEffect',
'flipEffect',
'customEffect',
'cardsEffect',
'hashNavigation',
'history',
'keyboard',
Expand Down
134 changes: 134 additions & 0 deletions src/modules/effect-cards/effect-cards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
export default function EffectCards({ swiper, extendParams, on }) {
extendParams({
cardsEffect: {
transformEl: null,
},
});

const setTranslate = () => {
const { slides, activeIndex } = swiper;
const params = swiper.params.cardsEffect;
const { startTranslate, isTouched } = swiper.touchEventsData;
const currentTranslate = swiper.translate;
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = slides.eq(i);
const slideProgress = $slideEl[0].progress;
const progress = Math.min(Math.max(slideProgress, -4), 4);
let offset = $slideEl[0].swiperSlideOffset;
if (swiper.params.centeredSlides && !swiper.params.cssMode) {
swiper.$wrapperEl.transform(`translateX(${swiper.minTranslate()}px)`);
}
if (swiper.params.centeredSlides && swiper.params.cssMode) {
offset -= slides[0].swiperSlideOffset;
}
let tX = swiper.params.cssMode ? -offset - swiper.translate : -offset;
let tY = 0;
const tZ = -100 * Math.abs(progress);
let scale = 1;
let rotate = -2 * progress;

let tXAdd = 8 - Math.abs(progress) * 0.75;

const isSwipeToNext =
(i === activeIndex || i === activeIndex - 1) &&
progress > 0 &&
progress < 1 &&
(isTouched || swiper.params.cssMode) &&
currentTranslate < startTranslate;
const isSwipeToPrev =
(i === activeIndex || i === activeIndex + 1) &&
progress < 0 &&
progress > -1 &&
(isTouched || swiper.params.cssMode) &&
currentTranslate > startTranslate;
if (isSwipeToNext || isSwipeToPrev) {
const subProgress = (1 - Math.abs((Math.abs(progress) - 0.5) / 0.5)) ** 0.5;
rotate += -28 * progress * subProgress;
scale += -0.5 * subProgress;
tXAdd += 96 * subProgress;
tY = `${-25 * subProgress * Math.abs(progress)}%`;
}

if (progress < 0) {
// next
tX = `calc(${tX}px + (${tXAdd * Math.abs(progress)}%))`;
} else if (progress > 0) {
// prev
tX = `calc(${tX}px + (-${tXAdd * Math.abs(progress)}%))`;
} else {
tX = `${tX}px`;
}
if (!swiper.isHorizontal()) {
const prevY = tY;
tY = tX;
tX = prevY;
}

const scaleString =
progress < 0 ? `${1 + (1 - scale) * progress}` : `${1 - (1 - scale) * progress}`;
const transform = `
translate3d(${tX}, ${tY}, ${tZ}px)
rotateZ(${rotate}deg)
scale(${scaleString})
`;

$slideEl[0].style.zIndex = -Math.abs(Math.round(slideProgress)) + slides.length;
if (params.transformEl) {
$slideEl
.find(params.transformEl)
.css({
'backface-visibility': 'hidden',
'-webkit-backface-visibility': 'hidden',
})
.transform(transform);
} else {
$slideEl.transform(transform);
}
}
};

const setTransition = (duration) => {
const { slides, activeIndex, $wrapperEl } = swiper;
const { transformEl } = swiper.params.cardsEffect;
const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;
$transitionElements.transition(duration);

if (swiper.params.virtualTranslate && duration !== 0) {
let eventTriggered = false;
const $transitionEndTarget = transformEl
? slides.eq(activeIndex).find(transformEl)
: slides.eq(activeIndex);
// eslint-disable-next-line
$transitionEndTarget.transitionEnd(() => {
if (eventTriggered) return;
if (!swiper || swiper.destroyed) return;
eventTriggered = true;
swiper.animating = false;
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
for (let i = 0; i < triggerEvents.length; i += 1) {
$wrapperEl.trigger(triggerEvents[i]);
}
});
}
};

on('beforeInit', () => {
if (swiper.params.effect !== 'cards') return;
swiper.classNames.push(`${swiper.params.containerModifierClass}cards`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
const overwriteParams = {
watchSlidesProgress: true,
virtualTranslate: !swiper.params.cssMode,
};
Object.assign(swiper.params, overwriteParams);
Object.assign(swiper.originalParams, overwriteParams);
});
on('setTranslate', () => {
if (swiper.params.effect !== 'cards') return;
setTranslate();
});
on('setTransition', (_s, duration) => {
if (swiper.params.effect !== 'cards') return;
setTransition(duration);
});
}
7 changes: 7 additions & 0 deletions src/modules/effect-cards/effect-cards.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.swiper-container-cards {
overflow: visible;
.swiper-slide {
transform-origin: center bottom;
backface-visibility: hidden;
}
}
7 changes: 7 additions & 0 deletions src/modules/effect-cards/effect-cards.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.swiper-container-cards {
overflow: visible;
.swiper-slide {
transform-origin: center bottom;
backface-visibility: hidden;
}
}
1 change: 1 addition & 0 deletions src/react/params-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const paramsList = [
'fadeEffect',
'flipEffect',
'customEffect',
'cardsEffect',
'hashNavigation',
'history',
'keyboard',
Expand Down
1 change: 1 addition & 0 deletions src/svelte/params-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const paramsList = [
'fadeEffect',
'flipEffect',
'customEffect',
'cardsEffect',
'hashNavigation',
'history',
'keyboard',
Expand Down
14 changes: 14 additions & 0 deletions src/types/modules/effect-cards.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { CSSSelector } from '../shared';

export interface CardsEffectMethods {}

export interface CardsEffectEvents {}

export interface CardsEffectOptions {
/**
* CSS selector of the element inside of the slide to transform instead of the slide itself. Useful to use with cssMode
*
* @default null
*/
transformEl?: CSSSelector;
}
2 changes: 2 additions & 0 deletions src/types/swiper-class.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CubeEffectMethods } from './modules/effect-cube';
import { FadeEffectMethods } from './modules/effect-fade';
import { FlipEffectMethods } from './modules/effect-flip';
import { CustomEffectMethods } from './modules/effect-custom';
import { CardsEffectMethods } from './modules/effect-cards';
import { HashNavigationMethods } from './modules/hash-navigation';
import { HistoryMethods } from './modules/history';
import { KeyboardMethods } from './modules/keyboard';
Expand Down Expand Up @@ -401,6 +402,7 @@ interface Swiper extends SwiperClass<SwiperEvents> {
fadeEffect: FadeEffectMethods;
flipEffect: FlipEffectMethods;
customEffect: CustomEffectMethods;
cardsEffect: CardsEffectMethods;
hashNavigation: HashNavigationMethods;
history: HistoryMethods;
keyboard: KeyboardMethods;
Expand Down
2 changes: 2 additions & 0 deletions src/types/swiper-events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CubeEffectEvents } from './modules/effect-cube';
import { FadeEffectEvents } from './modules/effect-fade';
import { FlipEffectEvents } from './modules/effect-flip';
import { CustomEffectEvents } from './modules/effect-custom';
import { CardsEffectEvents } from './modules/effect-cards';
import { HashNavigationEvents } from './modules/hash-navigation';
import { HistoryEvents } from './modules/history';
import { KeyboardEvents } from './modules/keyboard';
Expand Down Expand Up @@ -345,6 +346,7 @@ interface SwiperEvents extends CubeEffectEvents {}
interface SwiperEvents extends FadeEffectEvents {}
interface SwiperEvents extends FlipEffectEvents {}
interface SwiperEvents extends CustomEffectEvents {}
interface SwiperEvents extends CardsEffectEvents {}
interface SwiperEvents extends HashNavigationEvents {}
interface SwiperEvents extends HistoryEvents {}
interface SwiperEvents extends KeyboardEvents {}
Expand Down
18 changes: 17 additions & 1 deletion src/types/swiper-options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CubeEffectOptions } from './modules/effect-cube';
import { FadeEffectOptions } from './modules/effect-fade';
import { FlipEffectOptions } from './modules/effect-flip';
import { CustomEffectOptions } from './modules/effect-custom';
import { CardsEffectOptions } from './modules/effect-cards';
import { HashNavigationOptions } from './modules/hash-navigation';
import { HistoryOptions } from './modules/history';
import { KeyboardOptions } from './modules/keyboard';
Expand Down Expand Up @@ -237,7 +238,7 @@ export interface SwiperOptions {
*
* This is what is not supported when it is enabled:
*
* - Cube effect
* - Cube and Cards effects
* - `speed` parameter may not have no effect
* - All transition start/end related events (use `slideChange` instead)
* - `slidesPerGroup` has limited support
Expand Down Expand Up @@ -969,6 +970,21 @@ export interface SwiperOptions {
*/
customEffect?: CustomEffectOptions;

/**
* Object with Cards-effect parameters
*
* @example
* ```js
* const swiper = new Swiper('.swiper-container', {
* effect: 'cards',
* cardsEffect: {
* // ...
* },
* });
* ```
*/
cardsEffect?: CardsEffectOptions;

/**
* Enables hash url navigation to for slides.
* Object with hash navigation parameters or boolean `true` to enable with default settings
Expand Down
1 change: 1 addition & 0 deletions src/vue/params-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const paramsList = [
'fadeEffect',
'flipEffect',
'customEffect',
'cardsEffect',
'hashNavigation',
'history',
'keyboard',
Expand Down
5 changes: 5 additions & 0 deletions src/vue/swiper-vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FadeEffectOptions,
FlipEffectOptions,
CustomEffectOptions,
CardsEffectOptions,
HashNavigationOptions,
HistoryOptions,
KeyboardOptions,
Expand Down Expand Up @@ -389,6 +390,10 @@ declare const Swiper: DefineComponent<
type: PropType<CustomEffectOptions>;
default: undefined;
};
cardsEffect: {
type: PropType<CardsEffectOptions>;
default: undefined;
};
hashNavigation: {
type: PropType<HashNavigationOptions | boolean>;
default: undefined;
Expand Down
1 change: 1 addition & 0 deletions src/vue/swiper.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ const Swiper = {
fadeEffect: { type: Object, default: undefined },
flipEffect: { type: Object, default: undefined },
customEffect: { type: Object, default: undefined },
cardsEffect: { type: Object, default: undefined },
hashNavigation: { type: [Boolean, Object], default: undefined },
history: { type: [Boolean, Object], default: undefined },
keyboard: { type: [Boolean, Object], default: undefined },
Expand Down

0 comments on commit 21af858

Please sign in to comment.