effect-creative.js 4.8 KB
import effectInit from '../../shared/effect-init.js';
import effectTarget from '../../shared/effect-target.js';
import effectVirtualTransitionEnd from '../../shared/effect-virtual-transition-end.js';

export default function EffectCreative({
	swiper,
	extendParams,
	on
}) {
	extendParams({
		creativeEffect: {
			transformEl: null,
			limitProgress: 1,
			shadowPerProgress: false,
			progressMultiplier: 1,
			perspective: true,
			prev: {
				translate: [0, 0, 0],
				rotate: [0, 0, 0],
				opacity: 1,
				scale: 1,
			},
			next: {
				translate: [0, 0, 0],
				rotate: [0, 0, 0],
				opacity: 1,
				scale: 1,
			},
		},
	});

	const getTranslateValue = (value) => {
		if (typeof value === 'string') return value;
		return `${value}px`;
	};

	const setTranslate = () => {
		const {
			slides,
			$wrapperEl,
			slidesSizesGrid
		} = swiper;
		const params = swiper.params.creativeEffect;
		const {
			progressMultiplier: multiplier
		} = params;

		const isCenteredSlides = swiper.params.centeredSlides;

		if (isCenteredSlides) {
			const margin = slidesSizesGrid[0] / 2 - swiper.params.slidesOffsetBefore || 0;
			$wrapperEl.transform(`translateX(calc(50% - ${margin}px))`);
		}

		for (let i = 0; i < slides.length; i += 1) {
			const $slideEl = slides[i];
			const slideProgress = $slideEl.progress;
			const progress = Math.min(
				Math.max($slideEl.progress, -params.limitProgress),
				params.limitProgress,
			);
			let originalProgress = progress;

			if (!isCenteredSlides) {
				originalProgress = Math.min(
					Math.max($slideEl.originalProgress, -params.limitProgress),
					params.limitProgress,
				);
			}

			const offset = $slideEl.swiperSlideOffset;
			const t = [swiper.params.cssMode ? -offset - swiper.translate : -offset, 0, 0];
			const r = [0, 0, 0];
			let custom = false;
			if (!swiper.isHorizontal()) {
				t[1] = t[0];
				t[0] = 0;
			}
			let data = {
				translate: [0, 0, 0],
				rotate: [0, 0, 0],
				scale: 1,
				opacity: 1,
			};
			if (progress < 0) {
				data = params.next;
				custom = true;
			} else if (progress > 0) {
				data = params.prev;
				custom = true;
			}
			// set translate
			t.forEach((value, index) => {
				t[index] = `calc(${value}px + (${getTranslateValue(data.translate[index])} * ${Math.abs(
          progress * multiplier,
        )}))`;
			});
			// set rotates
			r.forEach((value, index) => {
				r[index] = data.rotate[index] * Math.abs(progress * multiplier);
			});

			// $slideEl[0].style.zIndex = -Math.abs(Math.round(slideProgress)) + slides.length;
			$slideEl.css({
				zIndex: -Math.abs(Math.round(slideProgress)) + slides.length
			})
			const translateString = t.join(', ');
			const rotateString = `rotateX(${r[0]}deg) rotateY(${r[1]}deg) rotateZ(${r[2]}deg)`;
			const scaleString =
				originalProgress < 0 ?
				`scale(${1 + (1 - data.scale) * originalProgress * multiplier})` :
				`scale(${1 - (1 - data.scale) * originalProgress * multiplier})`;
			const opacityString =
				originalProgress < 0 ?
				1 + (1 - data.opacity) * originalProgress * multiplier :
				1 - (1 - data.opacity) * originalProgress * multiplier;
			const transform = `translate3d(${translateString}) ${rotateString} ${scaleString}`;

			// Set shadows
			// if ((custom && data.shadow) || !custom) {
			//   let $shadowEl = $slideEl.children('.swiper-slide-shadow');
			//   if ($shadowEl.length === 0 && data.shadow) {
			//     $shadowEl = createShadow(params, $slideEl);
			//   }
			//   if ($shadowEl.length) {
			//     const shadowOpacity = params.shadowPerProgress
			//       ? progress * (1 / params.limitProgress)
			//       : progress;
			//     $shadowEl[0].style.opacity = Math.min(Math.max(Math.abs(shadowOpacity), 0), 1);
			//   }
			// }

			const $targetEl = effectTarget(params, $slideEl);
			$targetEl.transform(transform);
			$targetEl.css({
				opacity: opacityString
			});
			if (data.origin) {
				$targetEl.css({
					'transform-origin': data.origin
				});
			}
			if (swiper.params.willChange) {
				slides[i].willChange("transform,opacity");
			}
			slides[i].addClass('swiper-slide-creative')
		}
	};

	const setTransition = (duration) => {
		const {
			transformEl
		} = swiper.params.creativeEffect;
		const $transitionElements = transformEl ? swiper.slides.find(transformEl) : swiper.slides;
		for (let i = 0; i < $transitionElements.length; i += 1) {
			$transitionElements[i].transition(duration);
		}
		effectVirtualTransitionEnd({
			swiper,
			duration,
			transformEl,
			allSlides: true
		});
	};

	effectInit({
		effect: 'creative',
		swiper,
		on,
		setTranslate,
		setTransition,
		perspective: () => swiper.params.creativeEffect.perspective,
		overwriteParams: () => ({
			watchSlidesProgress: true,
			virtualTranslate: !swiper.params.cssMode,
		}),
	});
}