Current File : /home/exataengenharia/public_html/node_modules/@splidejs/splide/src/js/components/Scroll/Scroll.ts |
import { EVENT_MOVE, EVENT_REFRESH, EVENT_SCROLL, EVENT_SCROLLED, EVENT_UPDATED } from '../../constants/events';
import { IDLE, SCROLLING } from '../../constants/states';
import { SLIDE } from '../../constants/types';
import { EventInterface, RequestInterval, RequestIntervalInterface } from '../../constructors';
import { Splide } from '../../core/Splide/Splide';
import { AnyFunction, BaseComponent, Components, Options } from '../../types';
import { abs, apply, approximatelyEqual, floor, max, sign } from '../../utils';
import { BASE_VELOCITY, BOUNCE_DIFF_THRESHOLD, BOUNCE_DURATION, FRICTION_FACTOR, MIN_DURATION } from './constants';
/**
* The interface for the Scroll component.
*
* @since 3.0.0
*/
export interface ScrollComponent extends BaseComponent {
scroll( position: number, duration?: number, snap?: boolean, callback?: AnyFunction ): void;
cancel(): void;
}
/**
* The component for scrolling the slider.
*
* @since 3.0.0
*
* @param Splide - A Splide instance.
* @param Components - A collection of components.
* @param options - Options.
*
* @return A Scroll component object.
*/
export function Scroll( Splide: Splide, Components: Components, options: Options ): ScrollComponent {
const { on, emit } = EventInterface( Splide );
const { state: { set } } = Splide;
const { Move } = Components;
const { getPosition, getLimit, exceededLimit, translate } = Move;
const isSlide = Splide.is( SLIDE );
/**
* Retains the active RequestInterval object.
*/
let interval: RequestIntervalInterface;
/**
* Holds the callback function.
*/
let callback: AnyFunction;
/**
* The current friction (<= 1).
*/
let friction = 1;
/**
* Called when the component is mounted.
*/
function mount(): void {
on( EVENT_MOVE, clear );
on( [ EVENT_UPDATED, EVENT_REFRESH ], cancel );
}
/**
* Scrolls the slider to the provided destination.
*
* @param destination - The destination to scroll the slider to.
* @param duration - Optional. The scroll duration. If omitted, calculates it by the distance.
* @param snap - Optional. Whether to snap the slider to the closest slide or not.
* @param onScrolled - Optional. A callback invoked after scroll ends.
* @param noConstrain - Optional. Whether to suppress constraint process when the slider exceeds bounds.
*/
function scroll(
destination: number,
duration?: number,
snap?: boolean,
onScrolled?: AnyFunction,
noConstrain?: boolean
): void {
const from = getPosition();
clear();
if ( snap && ( ! isSlide || ! exceededLimit() ) ) {
const size = Components.Layout.sliderSize();
const offset = sign( destination ) * size * floor( abs( destination ) / size ) || 0;
destination = Move.toPosition( Components.Controller.toDest( destination % size ) ) + offset;
}
const noDistance = approximatelyEqual( from, destination, 1 );
friction = 1;
duration = noDistance ? 0 : duration || max( abs( destination - from ) / BASE_VELOCITY, MIN_DURATION );
callback = onScrolled;
interval = RequestInterval( duration, onEnd, apply( update, from, destination, noConstrain ), 1 );
set( SCROLLING );
emit( EVENT_SCROLL );
interval.start();
}
/**
* Called when scroll ends or has been just canceled.
*/
function onEnd(): void {
set( IDLE );
callback && callback();
emit( EVENT_SCROLLED );
}
/**
* Called whenever the interval timer is updated.
*
* @param from - A position where scroll starts.
* @param to - A destination where the slider goes.
* @param noConstrain - Whether to suppress constraint process when the slider exceeds bounds.
* @param rate - A current rate.
*/
function update( from: number, to: number, noConstrain: boolean | undefined, rate: number ): void {
const position = getPosition();
const target = from + ( to - from ) * easing( rate );
const diff = ( target - position ) * friction;
translate( position + diff );
if ( isSlide && ! noConstrain && exceededLimit() ) {
friction *= FRICTION_FACTOR;
if ( abs( diff ) < BOUNCE_DIFF_THRESHOLD ) {
scroll( getLimit( exceededLimit( true ) ), BOUNCE_DURATION, false, callback, true );
}
}
}
/**
* Clears the active interval.
*/
function clear(): void {
if ( interval ) {
interval.cancel();
}
}
/**
* Cancels the active interval and emits the `scrolled` event.
*/
function cancel(): void {
if ( interval && ! interval.isPaused() ) {
clear();
onEnd();
}
}
/**
* The easing function.
*
* @param t - A value to ease.
*
* @return An eased value.
*/
function easing( t: number ): number {
const { easingFunc } = options;
return easingFunc ? easingFunc( t ) : 1 - Math.pow( 1 - t, 4 );
}
return {
mount,
destroy: clear,
scroll,
cancel,
};
}