Skip to content

Instantly share code, notes, and snippets.

@styks1987
Created January 16, 2018 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save styks1987/23ce58f12a3f1ec2167d233f6c197162 to your computer and use it in GitHub Desktop.
Save styks1987/23ce58f12a3f1ec2167d233f6c197162 to your computer and use it in GitHub Desktop.
ready(function(){
/**
* Discover any fancy slideshows that exist on the page
*/
function fancySlideshows () {
this.discover = function () {
var slideshows = document.querySelectorAll('.fancy-slideshow');
if (slideshows.length > 0 ){
slideshows.forEach(function(s){
new fancySlideshow(s);
}.bind(this))
}
};
this.discover();
};
/**
* Manage a single fancy slideshow instance
* @param instance - the slideshow element to start working from
*/
function fancySlideshow (instance) {
this.refs = {};
this.state = {
active_slide: null,
active_content: null,
current: 0, //the current slide index
count: 0 //how many slides there are
};
this.__construct = function () {
this.discover();
this.listen();
};
this.discover = function () {
this.refs = {
slide_container : instance.querySelector('.fancy-slideshow__slides-container'),
slides : instance.querySelectorAll('.fancy-slideshow__slide'),
content_container : instance.querySelector('.fancy-slideshow__content-container'),
content : instance.querySelectorAll('.fancy-slideshow__content'),
numbers : instance.querySelector('.fancy-slideshow__progress-numbers'),
slider : instance.querySelector('.fancy-slideshow__progress-slider'),
arrow_right : instance.querySelector('.fancy-slideshow__arrow-right'),
arrow_left: instance.querySelector('.fancy-slideshow__arrow-left')
};
//count the slides
this.state.count = this.refs.slides.length;
this.state.active_slide = this.refs.slides[0];
this.state.active_content = this.refs.content[0];
//update the numbers
this.updateNumbers();
//add a class to the bar that changes the width of the slider
this.refs.slider.classList.add('n' + this.state.count);
//update the content height
this.updateContentContainer();
};
this.listen = function () {
var hammer = new Hammer(this.refs.slide_container),
throttle = PointUtility.throttle(this.updateContentContainer.bind(this), 100, true);
//handle clicks on the controls
this.refs.arrow_left.addEventListener('click', this.handleBackward.bind(this));
this.refs.arrow_right.addEventListener('click', this.handleForward.bind(this));
//handle swiping actions on the slideshow container to update slides (Using hammer JS to detect the swipes)
hammer.on('swiperight', this.handleBackward.bind(this, 'left'));
hammer.on('swipeleft', this.handleForward.bind(this, 'right'));
window.addEventListener('resize', throttle);
};
/**
* Move the slideshow backward
* Transitions use CSS and rely on class changes
*/
this.handleBackward = function (direction) {
var go_to = null,
next_slide,
current_slide;
if(this.state.current === 0){
go_to = this.state.count - 1;
} else {
go_to = this.state.current - 1;
}
next_slide = this.refs.slides[go_to];
current_slide = this.refs.slides[this.state.current];
//update the content
this.updateContent(this.state.current, go_to);
if(direction === 'left') {
this.transitionLeft(current_slide, next_slide);
} else {
this.transitionRight(current_slide, next_slide);
}
this.state.current = go_to;
this.state.active_slide = next_slide;
this.updateBar();
this.updateNumbers();
};
/**
* Move the slideshow forward
* Transitions use CSS and rely on class changes
*/
this.handleForward = function (direction) {
var go_to = null,
next_slide,
current_slide;
if(this.state.current === this.state.count - 1){
go_to = 0;
} else {
go_to = this.state.current + 1;
}
next_slide = this.refs.slides[go_to];
current_slide = this.refs.slides[this.state.current];
//update the content
this.updateContent(this.state.current, go_to);
if(direction === 'right') {
this.transitionRight(current_slide, next_slide);
} else {
this.transitionLeft(current_slide, next_slide);
}
this.state.current = go_to;
this.state.active_slide = next_slide;
this.updateBar();
this.updateNumbers();
};
this.transitionRight = function (current_slide, next_slide) {
//set up slide to come from right
next_slide.classList.remove('animating');
next_slide.classList.add('right');
//create a tiny time hiccup for the effect to work
//this allows the slide to get off the screen before starting the animation
setTimeout(function () {
//send active back left
current_slide.classList.remove('right');
current_slide.classList.add('animating');
current_slide.classList.remove('active');
//bring next slide in from right
next_slide.classList.add('animating');
next_slide.classList.add('active');
}.bind(this), 1);
};
this.transitionLeft = function (current_slide, next_slide) {
//set up slide to come from left
next_slide.classList.remove('animating');
next_slide.classList.remove('right');
//create a tiny time hiccup for the effect to work
//this allows the slide to get off the screen before starting the animation
setTimeout(function () {
//send active back left
current_slide.classList.add('right');
current_slide.classList.add('animating');
current_slide.classList.remove('active');
//bring next slide in from right
next_slide.classList.add('animating');
next_slide.classList.add('active');
}.bind(this), 1);
};
/**
* Adds or removes the active class to the respective slide content section
* @param current_index
* @param next_index
*/
this.updateContent = function (current_index, next_index) {
this.refs.content[current_index].classList.remove('active');
this.refs.content[next_index].classList.add('active');
};
/**
* Update the slide count numbers
* Shows which slide out of how many the user is on
*/
this.updateNumbers = function () {
var nums = document.createElement('span');
nums.textContent = (this.state.current + 1 < 9 ? '0' + (this.state.current + 1) : this.state.current) + ' / ' + (this.state.count < 9 ? '0' + this.state.count : this.state.count);
this.refs.numbers.innerHTML = '';
this.refs.numbers.appendChild(nums);
};
/**
* Update the slider bar to show how far along the slideshow is
*/
this.updateBar = function () {
var percentage_advanced = this.state.current * 100;
this.refs.slider.style.transform = 'translateX(' + percentage_advanced + '%)';
};
/**
* Update the content container to be the height of the tallest bit of content
* This method is a little gross, but its what works
* @param e
*/
this.updateContentContainer = function (e) {
var tallest = 0,
clone_container = document.createElement('div');
//set up a container to hold clones of the side content parts
clone_container.style.position = 'absolute';
clone_container.style.top = '-10000px';
clone_container.style.left = '-10000px';
clone_container.style.width = this.refs.content_container.offsetWidth + 'px';
document.body.appendChild(clone_container);
//for each slide content bit, make a copy and then check the height
this.refs.content.forEach(function(item){
var clone = item.cloneNode(true);
clone.style.height = 'auto';
clone.style.position = 'relative';
clone_container.appendChild(clone);
if(clone.offsetHeight > tallest){
tallest = clone.offsetHeight;
}
clone_container.removeChild(clone);
});
//remove the clone container
clone_container.parentNode.removeChild(clone_container);
this.refs.content_container.style.minHeight = tallest + 'px';
};
this.__construct();
}
new fancySlideshows();
});
.fancy-slideshow
position: relative
.fancy-slideshow__slides-container
position: relative
background: #333
.fancy-slideshow__slides
position: relative
padding-bottom: 0
min-height: 300px
@include bp(medium)
height: auto
padding-bottom: 40%
.fancy-slideshow__slide
position: absolute
top: 0
left: 0
height: 100%
width: 100%
z-index: 1
overflow: hidden
transform: translateX(-100%)
img
display: block
position: absolute
top: 50%
left: 0
transform: translateY(-50%) translateX(-10%)
height: 100%
width: auto
max-width: none
pointer-events: none
@include bp(small)
left: 50%
transform: translateY(-50%) translateX(-50%)
@include bp(medium)
width: 100%
height: auto
max-width: 100%
&.right
transform: translateX(100%)
&.active
transform: translateX(0)
&.animating
transition: all 0.5s
.fancy-slideshow__controls
padding: 1.25em
position: absolute
bottom: 0
left: 0
width: 100%
display: flex
justify-content: space-between
align-items: center
z-index: 2
.fancy-slideshow__progress-bar
flex-grow: 1
display: block
height: 2px
background: #FFF
position: relative
.fancy-slideshow__progress-slider
width: 25%
position: absolute
bottom: -2px
height: 6px
background: $point-yellow
transition: all 0.5s
@for $i from 1 through 20
&.n#{$i}
width: 100%/$i
.fancy-slideshow__arrows
flex-grow: 0
padding: 0.5em 1em
display: flex
.fancy-slideshow__arrow-left,
.fancy-slideshow__arrow-right
width: 40px
height: 40px
border: 2px solid #ffffff
display: flex
justify-content: center
align-items: center
transition: all 0.2s
&:hover
background: #ffffff
cursor: pointer
svg
fill: $point-blue
svg
width: 25px
height: 25px
fill: #FFF
.fancy-slideshow__arrow-left
margin-right: 0.5em
svg
transform: rotate(180deg)
.fancy-slideshow__progress-numbers
flex-grow: 0
padding: 0.5em 1em
color: #FFF
font-weight: bold
.fancy-slideshow__content-container
height: 300px
position: relative
@include bp(large)
position: absolute
bottom: 100px
//roughly height of controls
right: 2em
width: 45%
z-index: 3
.fancy-slideshow__content
padding: 1.5em
opacity: 0
position: absolute
width: 100%
height: 100%
display: flex
flex-direction: column
justify-content: space-between
transition: all 0.5s
@include bp(large)
display: block
bottom: 100px
right: 0
background: rgba(255, 255, 255, 0.8)
width: 600px
height: auto
&:hover
background: rgba(255, 255, 255, 1)
&.active
opacity: 1
bottom: 0
z-index: 5
@include bp(large)
bottom: 0
.fancy-slideshow__headline
font-size: 1.5em
@include bp(medium)
font-size: 2.5em
.fancy-slideshow__copy
margin-bottom: 1em
.fancy-slideshow__byline
color: $point-blue
font-style: italic
margin-bottom: 0.875em
display: block
.fancy-slideshow__cta
padding-top: 0.25em
border-top: 1px solid $point-blue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment