UNPKG

react-slick-ssr-transform

Version:

React port of slick carousel with dynamic transform width

368 lines (319 loc) 11 kB
'use strict'; import React from 'react'; import ReactDOM from 'react-dom'; import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper'; import assign from 'object-assign'; var helpers = { serverInitialize: function (props) { var slideCount = React.Children.count(props.children); var currentSlide = props.rtl ? slideCount - 1 - props.initialSlide : props.initialSlide; this.setState({ slideCount, currentSlide }); }, initialize: function (props) { const slickList = ReactDOM.findDOMNode(this.list); var slideCount = React.Children.count(props.children); var listWidth = this.getWidth(slickList); var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track)); var slideWidth; if (!props.vertical) { var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2); slideWidth = (this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow; } else { slideWidth = this.getWidth(ReactDOM.findDOMNode(this)); } const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]')); const listHeight = slideHeight * props.slidesToShow; var currentSlide = props.rtl ? slideCount - 1 - props.initialSlide : props.initialSlide; this.setState({ slideCount, slideWidth, listWidth, trackWidth, currentSlide, slideHeight, listHeight, }, function () { var targetLeft = getTrackLeft(assign({ slideIndex: this.state.currentSlide, trackRef: this.track }, props, this.state)); // getCSS function needs previously set state var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state)); this.setState({trackStyle: trackStyle}); this.autoPlay(); // once we're set up, trigger the initial autoplay. }); }, update: function (props) { const slickList = ReactDOM.findDOMNode(this.list); // This method has mostly same code as initialize method. // Refactor it var slideCount = React.Children.count(props.children); var listWidth = this.getWidth(slickList); var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track)); var slideWidth; if (!props.vertical) { var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2); slideWidth = (this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow; } else { slideWidth = this.getWidth(ReactDOM.findDOMNode(this)); } const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]')); const listHeight = slideHeight * props.slidesToShow; // pause slider if autoplay is set to false if(props.autoplay) { this.pause(); } else { this.autoPlay(); } this.setState({ slideCount, slideWidth, listWidth, trackWidth, slideHeight, listHeight, }, function () { var targetLeft = getTrackLeft(assign({ slideIndex: this.state.currentSlide, trackRef: this.track }, props, this.state)); // getCSS function needs previously set state var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state)); this.setState({trackStyle: trackStyle}); }); }, getWidth: function getWidth(elem) { return elem.getBoundingClientRect().width || elem.offsetWidth || 0; }, getHeight(elem) { return elem.getBoundingClientRect().height || elem.offsetHeight || 0; }, adaptHeight: function () { if (this.props.adaptiveHeight) { var selector = '[data-index="' + this.state.currentSlide +'"]'; if (this.list) { var slickList = ReactDOM.findDOMNode(this.list); slickList.style.height = slickList.querySelector(selector).offsetHeight + 'px'; } } }, canGoNext: function (opts){ var canGo = true; if (!opts.infinite) { if (opts.centerMode) { // check if current slide is last slide if (opts.currentSlide >= (opts.slideCount - 1)) { canGo = false; } } else { // check if all slides are shown in slider if (opts.slideCount <= opts.slidesToShow || opts.currentSlide >= (opts.slideCount - opts.slidesToShow)) { canGo = false; } } } return canGo; }, slideHandler: function (index,dontAnimate) { // Functionality of animateSlide and postSlide is merged into this function // console.log('slideHandler', index); var targetSlide, currentSlide; var targetLeft, currentLeft; var callback; if (this.props.waitForAnimate && this.state.animating) { return; } if (this.props.fade) { currentSlide = this.state.currentSlide; // Don't change slide if it's not infite and current slide is the first or last slide. if(this.props.infinite === false && (index < 0 || index >= this.state.slideCount)) { return; } // Shifting targetSlide back into the range if (index < 0) { targetSlide = index + this.state.slideCount; } else if (index >= this.state.slideCount) { targetSlide = index - this.state.slideCount; } else { targetSlide = index; } if (this.props.lazyLoad && this.state.lazyLoadedList.indexOf(targetSlide) < 0) { this.setState({ lazyLoadedList: this.state.lazyLoadedList.concat(targetSlide) }); } callback = () => { this.setState({ animating: false }); if (this.props.afterChange) { this.props.afterChange(targetSlide); } delete this.animationEndCallback; }; this.setState({ animating: true, currentSlide: targetSlide }, function () { this.animationEndCallback = setTimeout(callback, this.props.speed); }); if (this.props.beforeChange) { this.props.beforeChange(this.state.currentSlide, targetSlide); } this.autoPlay(); return; } targetSlide = index; if (targetSlide < 0) { if(this.props.infinite === false) { currentSlide = 0; } else if (this.state.slideCount % this.props.slidesToScroll !== 0) { currentSlide = this.state.slideCount - (this.state.slideCount % this.props.slidesToScroll); } else { currentSlide = this.state.slideCount + targetSlide; } } else if (targetSlide >= this.state.slideCount) { if(this.props.infinite === false) { currentSlide = this.state.slideCount - this.props.slidesToShow; } else if (this.state.slideCount % this.props.slidesToScroll !== 0) { currentSlide = 0; } else { currentSlide = targetSlide - this.state.slideCount; } } else { currentSlide = targetSlide; } targetLeft = getTrackLeft(assign({ slideIndex: targetSlide, trackRef: this.track }, this.props, this.state)); currentLeft = getTrackLeft(assign({ slideIndex: currentSlide, trackRef: this.track }, this.props, this.state)); if (this.props.infinite === false) { targetLeft = currentLeft; } if (this.props.beforeChange) { var proposedLeft = this.props.beforeChange(this.state.currentSlide, currentSlide); if (proposedLeft != null && !isNaN(proposedLeft) && this.props.infinite === false){ targetLeft = currentLeft = proposedLeft; } } if (this.props.lazyLoad) { var loaded = true; var slidesToLoad = []; for (var i = targetSlide; i < targetSlide + this.props.slidesToShow; i++ ) { loaded = loaded && (this.state.lazyLoadedList.indexOf(i) >= 0); if (!loaded) { slidesToLoad.push(i); } } if (!loaded) { this.setState({ lazyLoadedList: this.state.lazyLoadedList.concat(slidesToLoad) }); } } // Slide Transition happens here. // animated transition happens to target Slide and // non - animated transition happens to current Slide // If CSS transitions are false, directly go the current slide. if (this.props.useCSS === false || dontAnimate) { this.setState({ currentSlide: currentSlide, trackStyle: getTrackCSS(assign({left: currentLeft}, this.props, this.state)) }, function () { if (this.props.afterChange) { this.props.afterChange(currentSlide); } }); } else { var nextStateChanges = { animating: false, currentSlide: currentSlide, trackStyle: getTrackCSS(assign({left: currentLeft}, this.props, this.state)), swipeLeft: null }; callback = () => { this.setState(nextStateChanges); if (this.props.afterChange) { this.props.afterChange(currentSlide); } delete this.animationEndCallback; }; this.setState({ animating: true, currentSlide: currentSlide, trackStyle: getTrackAnimateCSS(assign({left: targetLeft}, this.props, this.state)) }, function () { this.animationEndCallback = setTimeout(callback, this.props.speed); }); } this.autoPlay(); }, swipeDirection: function (touchObject) { var xDist, yDist, r, swipeAngle; xDist = touchObject.startX - touchObject.curX; yDist = touchObject.startY - touchObject.curY; r = Math.atan2(yDist, xDist); swipeAngle = Math.round(r * 180 / Math.PI); if (swipeAngle < 0) { swipeAngle = 360 - Math.abs(swipeAngle); } if ((swipeAngle <= 45) && (swipeAngle >= 0) || (swipeAngle <= 360) && (swipeAngle >= 315)) { return (this.props.rtl === false ? 'left' : 'right'); } if ((swipeAngle >= 135) && (swipeAngle <= 225)) { return (this.props.rtl === false ? 'right' : 'left'); } if (this.props.verticalSwiping === true) { if ((swipeAngle >= 35) && (swipeAngle <= 135)) { return 'down'; } else { return 'up'; } } return 'vertical'; }, play: function(){ var nextIndex; if (!this.state.mounted) { return false } if (this.props.rtl) { nextIndex = this.state.currentSlide - this.props.slidesToScroll; } else { if (this.canGoNext(Object.assign({}, this.props,this.state))) { nextIndex = this.state.currentSlide + this.props.slidesToScroll; } else { return false; } } this.slideHandler(nextIndex); }, autoPlay: function () { if (this.state.autoPlayTimer) { clearTimeout(this.state.autoPlayTimer); } if (this.props.autoplay) { this.setState({ autoPlayTimer: setTimeout(this.play, this.props.autoplaySpeed) }); } }, pause: function () { if (this.state.autoPlayTimer) { clearTimeout(this.state.autoPlayTimer); this.setState({ autoPlayTimer: null }); } } }; export default helpers;