Skip to content

Instantly share code, notes, and snippets.

@mattjburrows
Last active August 29, 2015 13:57
Show Gist options
  • Save mattjburrows/9745121 to your computer and use it in GitHub Desktop.
Save mattjburrows/9745121 to your computer and use it in GitHub Desktop.
JS code snippets for the "Swipe activated gallery" tutorial on medium. Article URL to be confirmed.
/*
*
* Add the following functions above the var App = {}; declaration.
*
*/
function fetchComputedStyle(el, prop, pseudo) {
return window.getComputedStyle(el, (pseudo || null)).getPropertyValue(prop);
};
function calculateAspectRatio(width, height, ar) {
var ar = ar ? ar : '1536:672',
arValues = ar.split(':'),
arWidth = parseInt(arValues[0]),
arHeight = parseInt(arValues[1]);
if (!width && height) {
return Math.ceil(height * (arWidth / arHeight));
}
if (!height && width) {
return Math.ceil(width / (arWidth / arHeight));
}
};
function getPrefix(prefixes) {
var div = document.createElement('div');
// Check to see if we are dealing with an array.
if (Object.prototype.toString.call(prefixes) === '[object Array]') {
var max = prefixes.length;
while (max--) {
if (prefixes[max] in div.style) {
return prefixes[max];
}
}
}
// Else we'll assume it is an object.
else {
for (prefix in prefixes) {
if (prefix in div.style) {
return prefixes[prefix];
}
}
}
return false;
};
/*
*
* Add in the above the DOMContentLoaded event.
*
*/
App.GalleryControl = function (opts) {
this.opts = opts;
this._init();
};
App.GalleryControl.prototype.trackSlides = function (dir, dist, callback) {
var self = this,
currPos = -(App.active * this.slideWidth),
translateX = ('left' === dir) ? parseFloat(currPos - dist) : parseFloat(currPos + dist),
wrapper = this.wrapper[0];
wrapper.style[this.prefix] = 'translate(' + translateX + 'px, 0)';
if ('function' === typeof callback) {
callback();
}
};
App.GalleryControl.prototype.animateSlides = function (next, speed) {
var self = this,
next = next || 0,
speed = speed || false,
max = this.slides.length,
wrapper = this.wrapper[0],
translateX = (next * this.slideWidth),
speedPrefix = getPrefix(['transitionDuration', 'webkitTransitionDuration']),
// We know that the heading and icon animations take 0.5s to complete...
// So we need to make sure the next animation can't be initiated before everything has finished the animation cycle.
// What we are doing is minusing the swipe speed from the CSS transition speed.
// I know... the implementation is a little stinky...
timeout = speed ? (0.5 - speed).toString().replace('.', '').slice(0, 4) : 1;
// Make sure the app isn't currently animating...
// And that the new position doesn't equal the current position.
if (('translate(-' + translateX + 'px, 0)' !== wrapper.style[this.prefix])) {
App.animating = true;
this.listener.addEvent(wrapper, function transition() {
// Remove the transition property.
wrapper.style[speedPrefix] = '';
// Remove the event.
self.listener.removeEvent(wrapper, transition);
// Remove the active class.
wrapper.classList.remove(App.classes.active);
// Reset the App.animating property...
// Add a slight delay to stop any chaining.
setTimeout(function () {
App.animating = false;
}, parseFloat(timeout));
});
// Toggle the slide styles.
while (max--) {
this.slides[max].classList.remove(App.classes.active);
}
this.slides[next].classList.add(App.classes.active);
// Change the wrapper styles.
wrapper.classList.add(App.classes.active);
wrapper.style[this.prefix] = 'translate(-' + translateX + 'px, 0)';
if (speed) {
wrapper.style[speedPrefix] = speed + 's';
}
}
};
App.GalleryControl.prototype.fixSlideDimensions = function (active) {
var max = this.slides.length,
wrapper = this.wrapper[0];
// Reset the function properties.
this._config();
// Set the wrapper dimensions.
this.element.style.height = this.slideHeight + 'px';
wrapper.style.width = (this.slideWidth * max) + 'px';
wrapper.style.height = this.slideHeight + 'px';
wrapper.style.marginLeft = (this.elementWidth / 2) - (this.slideWidth / 2) + 'px';
// Set the slide dimensions.
while (max--) {
var slide = this.slides[max];
slide.style.width = this.slideWidth + 'px';
slide.style.height = this.slideHeight + 'px';
}
wrapper.style[this.prefix] = 'translate(-' + (active * this.slideWidth) + 'px, 0)';
};
App.GalleryControl.prototype._config = function () {
this.prefix = getPrefix(['transform', 'WebkitTransform']);
this.elementWidth = parseInt(fetchComputedStyle(this.element, 'width'));
this.slideWidth = ((this.elementWidth >= 1024) && ('landscape' === fetchComputedStyle(document.body, 'content', ':before'))) ? 640 : this.elementWidth;
this.slideHeight = parseFloat(calculateAspectRatio(this.slideWidth, null));
};
App.GalleryControl.prototype._init = function () {
var self = this;
// Set the function properties.
this.element = this.opts.element;
this.wrapper = this.element.querySelectorAll(this.opts.wrapper);
this.slides = this.element.querySelectorAll(this.opts.slides);
this.listener = new App.CSSListeners({
type: 'transition',
prefixes: {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'transition': 'transitionend'
}
});
// Run the function methods.
this.fixSlideDimensions(0);
return this;
};
/*
*
* Add this within the DOMContentLoaded event.
*
*/
var bannerGalleryFn = new App.GalleryControl({
element: bannerGallery,
wrapper: '.gallery-module__wrapper',
slides: '.gallery-module__slide'
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment