UNPKG

slider-pro-js

Version:

Modular JavaScript slider that is dependency-free, rich-featured, flexible and easy to use

355 lines (276 loc) 13.2 kB
import { resolveUnit } from '../../helpers/util.js'; class Layer { // Reference to the layer jQuery element layerEl; // Indicates whether a layer is currently visible or hidden visible = false; // Indicates whether the layer was styled styled = false; // Holds the data attributes added to the layer data = null; // Indicates the layer's reference point (topLeft, bottomLeft, topRight or bottomRight) position = null; // Indicates which CSS property (left or right) will be used for positioning the layer horizontalProperty = null; // Indicates which CSS property (top or bottom) will be used for positioning the layer verticalProperty = null; // Indicates the value of the horizontal position horizontalPosition = null; // Indicates the value of the vertical position verticalPosition = null; // Indicates how much the layers needs to be scaled scaleRatio = 1; // Reference to the timer that will be used to hide/show the layers delayTimer = null; // Reference to the timer that will be used to hide the layers automatically after a given time interval stayTimer = null; constructor( layerEl ) { this.layerEl = layerEl; this.init(); } // Initialize the layers init() { this.layerEl.setAttribute( 'data-layer-init', true ); if ( this.layerEl.classList.contains( 'sp-static' ) ) { this.setStyle(); } else { this.layerEl.style.visibility = 'hidden'; } } // Set the size and position of the layer setStyle() { this.styled = true; // Get the data attributes specified in HTML this.data = this.layerEl.dataset; if ( typeof this.data.width !== 'undefined' ) { this.layerEl.style.width = resolveUnit( this.data.width ); } if ( typeof this.data.height !== 'undefined' ) { this.layerEl.style.height = resolveUnit( this.data.height ); } if ( typeof this.data.depth !== 'undefined' ) { this.layerEl.style.zIndex = this.data.depth; } this.position = this.data.position ? ( this.data.position ).toLowerCase() : 'topleft'; if ( this.position.indexOf( 'right' ) !== -1 ) { this.horizontalProperty = 'right'; } else if ( this.position.indexOf( 'left' ) !== -1 ) { this.horizontalProperty = 'left'; } else { this.horizontalProperty = 'center'; } if ( this.position.indexOf( 'bottom' ) !== -1 ) { this.verticalProperty = 'bottom'; } else if ( this.position.indexOf( 'top' ) !== -1 ) { this.verticalProperty = 'top'; } else { this.verticalProperty = 'center'; } this.setPosition(); this.scale( this.scaleRatio ); } // Set the position of the layer setPosition() { let inlineStyle = this.layerEl.getAttribute( 'style' ); this.horizontalPosition = typeof this.data.horizontal !== 'undefined' ? this.data.horizontal : 0; this.verticalPosition = typeof this.data.vertical !== 'undefined' ? this.data.vertical : 0; // Set the horizontal position of the layer based on the data set if ( this.horizontalProperty === 'center' ) { // prevent content wrapping while setting the width if ( this.layerEl.tagName !== 'IMG' && ( typeof inlineStyle === 'undefined' || ( typeof inlineStyle !== 'undefined' && inlineStyle.indexOf( 'width' ) === -1 ) ) ) { this.layerEl.style.whiteSpace = 'nowrap'; this.layerEl.style.width = resolveUnit( this.layerEl.offsetWidth ); } this.layerEl.style.marginLeft = 'auto'; this.layerEl.style.marginRight = 'auto'; this.layerEl.style.left = resolveUnit( this.horizontalPosition ); this.layerEl.style.right = 0; } else { this.layerEl.style[ this.horizontalProperty ] = resolveUnit( this.horizontalPosition ); } // Set the vertical position of the layer based on the data set if ( this.verticalProperty === 'center' ) { // prevent content wrapping while setting the height if ( this.layerEl.tagName !== 'IMG' && ( typeof inlineStyle === 'undefined' || ( typeof inlineStyle !== 'undefined' && inlineStyle.indexOf( 'height' ) === -1 ) ) ) { this.layerEl.style.whiteSpace = 'nowrap'; this.layerEl.style.height = resolveUnit( this.layerEl.offsetHeight ); } this.layerEl.style.marginTop = 'auto'; this.layerEl.style.marginBottom = 'auto'; this.layerEl.style.top = resolveUnit( this.verticalPosition ); this.layerEl.style.bottom = 0; } else { this.layerEl.style[ this.verticalProperty ] = resolveUnit( this.verticalPosition ); } } // Scale the layer scale( ratio ) { // Return if the layer is set to be unscalable if ( this.layerEl.classList.contains( 'sp-no-scale' ) ) { return; } // Store the ratio (even if the layer is not ready to be scaled yet) this.scaleRatio = ratio; // Return if the layer is not styled yet if ( this.styled === false ) { return; } let horizontalProperty = this.horizontalProperty === 'center' ? 'left' : this.horizontalProperty, verticalProperty = this.verticalProperty === 'center' ? 'top' : this.verticalProperty, css = {}; // Apply the scaling css[ 'transformOrigin' ] = this.horizontalProperty + ' ' + this.verticalProperty; css[ 'transform' ] = 'scale(' + this.scaleRatio + ')'; // If the position is not set to a percentage value, apply the scaling to the position if ( isNaN( this.horizontalPosition ) === false || this.horizontalPosition.indexOf( 'px' ) !== -1 ) { css[ horizontalProperty ] = resolveUnit( this.horizontalPosition * this.scaleRatio ); } // If the position is not set to a percentage value, apply the scaling to the position if ( isNaN( this.verticalPosition ) === false || this.verticalPosition.indexOf( 'px' ) !== -1 ) { css[ verticalProperty ] = resolveUnit( this.verticalPosition * this.scaleRatio ); } // If the width or height is set to a percentage value, increase the percentage in order to // maintain the same layer to slide proportions. This is necessary because otherwise the scaling // transform would minimize the layers more than intended. if ( typeof this.data.width === 'string' && this.data.width.indexOf( '%' ) !== -1 ) { css.width = ( parseInt( this.data.width, 10 ) / this.scaleRatio ).toString() + '%'; } if ( typeof this.data.height === 'string' && this.data.height.indexOf( '%' ) !== -1 ) { css.height = ( parseInt( this.data.height, 10 ) / this.scaleRatio ).toString() + '%'; } for ( let property in css ) { this.layerEl.style[ property ] = css[ property ]; } } // Show the layer show( callback ) { if ( this.visible === true ) { return; } this.visible = true; // First, style the layer if it's not already styled if ( this.styled === false ) { this.setStyle(); } let offset = typeof this.data.showOffset !== 'undefined' ? this.data.showOffset : 50, duration = typeof this.data.showDuration !== 'undefined' ? this.data.showDuration / 1000 : 0.4, delay = typeof this.data.showDelay !== 'undefined' ? this.data.showDelay : 10, stayDuration = typeof this.data.stayDuration !== 'undefined' ? parseInt( this.data.stayDuration, 10 ) : -1; let start = { 'opacity': 0, 'visibility': 'visible' }, target = { 'opacity': 1 }, transformValues = ''; start[ 'transform' ] = 'scale(' + this.scaleRatio + ')'; target[ 'transform' ] = 'scale(' + this.scaleRatio + ')'; target[ 'transition' ] = 'opacity ' + duration + 's'; if ( typeof this.data.showTransition !== 'undefined' ) { if ( this.data.showTransition === 'left' ) { transformValues = offset + 'px, 0'; } else if ( this.data.showTransition === 'right' ) { transformValues = '-' + offset + 'px, 0'; } else if ( this.data.showTransition === 'up' ) { transformValues = '0, ' + offset + 'px'; } else if ( this.data.showTransition === 'down') { transformValues = '0, -' + offset + 'px'; } start[ 'transform' ] += ' translate3d(' + transformValues + ', 0)'; target[ 'transform' ] += ' translate3d(0, 0, 0)'; target[ 'transition' ] += ', ' + 'transform ' + duration + 's'; } const transitionEndHandler = ( event ) => { if ( event.target !== event.currentTarget ) { return; } this.layerEl.removeEventListener( 'transitionend', transitionEndHandler ); this.layerEl.style.transition = ''; // Hide the layer after a given time interval if ( stayDuration !== -1 ) { this.stayTimer = setTimeout(function() { this.hide(); this.stayTimer = null; }, stayDuration ); } if ( typeof callback !== 'undefined' ) { callback(); } }; // Listen when the layer animation is complete this.layerEl.addEventListener( 'transitionend', transitionEndHandler ); for ( let property in start ) { this.layerEl.style[ property ] = start[ property ]; } this.delayTimer = setTimeout( () => { for ( let property in target ) { this.layerEl.style[ property ] = target[ property ]; } }, delay ); } // Hide the layer hide( callback ) { if ( this.visible === false ) { return; } let offset = typeof this.data.hideOffset !== 'undefined' ? this.data.hideOffset : 50, duration = typeof this.data.hideDuration !== 'undefined' ? this.data.hideDuration / 1000 : 0.4, delay = typeof this.data.hideDelay !== 'undefined' ? this.data.hideDelay : 10; this.visible = false; // If the layer is hidden before it hides automatically, clear the timer if ( this.stayTimer !== null ) { clearTimeout( this.stayTimer ); } // Animate the layers with CSS3 or with JavaScript let transformValues = '', target = { 'opacity': 0 }; target[ 'transform' ] = 'scale(' + this.scaleRatio + ')'; target[ 'transition' ] = 'opacity ' + duration + 's'; if ( typeof this.data.hideTransition !== 'undefined' ) { if ( this.data.hideTransition === 'left' ) { transformValues = '-' + offset + 'px, 0'; } else if ( this.data.hideTransition === 'right' ) { transformValues = offset + 'px, 0'; } else if ( this.data.hideTransition === 'up' ) { transformValues = '0, -' + offset + 'px'; } else if ( this.data.hideTransition === 'down' ) { transformValues = '0, ' + offset + 'px'; } target[ 'transform' ] += ' translate3d(' + transformValues + ', 0)'; target[ 'transition' ] += ', ' + 'transform ' + duration + 's'; } // Listen when the layer animation is complete const transitionEndHandler = ( event ) => { if ( event.target !== event.currentTarget ) { return; } this.layerEl.removeEventListener( 'transitionend', transitionEndHandler ); this.layerEl.style.removeProperty( 'transition' ); // Hide the layer after transition if ( this.visible === false ) { this.layerEl.style.visibility = 'hidden'; } if ( typeof callback !== 'undefined' ) { callback(); } }; this.layerEl.addEventListener( 'transitionend', transitionEndHandler ); this.delayTimer = setTimeout( () => { for ( let property in target ) { this.layerEl.style[ property ] = target[ property ]; } }, delay ); } isVisible() { if ( this.visible === false || this.layerEl.offsetParent === null ) { return false; } return true; } // Destroy the layer destroy() { this.layerEl.removeAttribute( 'style' ); this.layerEl.removeAttribute( 'data-layer-init' ); clearTimeout( this.delayTimer ); clearTimeout( this.stayTimer ); this.delayTimer = null; this.stayTimer = null; } } export default Layer;