Created
February 23, 2015 07:01
-
-
Save bbbrrriiiaaannn/a84c38d3916a49851909 to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/yikule
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>JS Bin</title> | |
<style id="jsbin-css"> | |
.scroller { | |
position: relative; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
} | |
ul { | |
list-style: none; | |
white-space: nowrap; | |
width: 100%; | |
overflow-x: scroll; | |
-webkit-overflow-scrolling: touch; | |
} | |
li { | |
display: inline-block; | |
width: 200px; | |
height: 200px; | |
margin: 10px; | |
background: red; | |
} | |
.prev, .next { | |
position: absolute; | |
top: 50%; | |
background: rgba(255, 255, 255, 0.7); | |
margin-top: -28px; | |
transition: opacity 0.3s; | |
} | |
.prev.hidden, .next.hidden { | |
opacity: 0; | |
pointer-event: none; | |
} | |
.prev { | |
left: 0; | |
padding: 20px 20px 20px 0; | |
border-radius: 0 30px 30px 0; | |
} | |
.next { | |
right: 0; | |
padding: 20px 0 20px 20px; | |
border-radius: 30px 0 0 30px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="scroller"> | |
<a class="prev hidden"><</a> | |
<a class="next">></a> | |
<ul> | |
<li>hi</li> | |
<li>hi</li> | |
<li>hi</li> | |
<li>hi</li> | |
<li>hi</li> | |
</ul> | |
</div> | |
<script id="jsbin-javascript"> | |
"use strict"; | |
var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; | |
var Scroller = (function () { | |
// set options(options) { | |
// let defaultOptions = { | |
// } | |
// this._options = Object.mixin(defaultOptions, options) // doesn't actually exist >:( | |
// } | |
function Scroller(wrapper) { | |
var _this = this; | |
var scrollable = arguments[1] === undefined ? wrapper.querySelector("ul") : arguments[1]; | |
var prev = arguments[2] === undefined ? wrapper.querySelector(".prev") : arguments[2]; | |
var next = arguments[3] === undefined ? wrapper.querySelector(".next") : arguments[3]; | |
return (function () { | |
// this.options = {} | |
_this.wrapper = wrapper; | |
_this.ele = scrollable; | |
_this.prevEle = prev; | |
_this.nextEle = next; | |
_this.isMoving = false; | |
_this.nextEle.addEventListener("click", _this.next.bind(_this)); | |
_this.prevEle.addEventListener("click", _this.prev.bind(_this)); | |
_this.ele.addEventListener("scroll", _this._debounceUtil(_this._toggleControlVisibility.bind(_this))); | |
window.addEventListener("resize", _this._toggleControlVisibility.bind(_this)); | |
_this._toggleControlVisibility(); | |
})(); | |
} | |
_prototypeProperties(Scroller, null, { | |
_debounceUtil: { | |
value: function _debounceUtil(func) { | |
var wait = arguments[1] === undefined ? 100 : arguments[1]; | |
// cribbed from http://davidwalsh.name/javascript-debounce-function | |
var timeout = undefined; | |
return function () { | |
var context = this; | |
var args = arguments; | |
var later = function () { | |
timeout = null; | |
func.apply(context, args); | |
}; | |
clearTimeout(timeout); | |
timeout = setTimeout(later, wait); | |
}; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_toggleControlVisibility: { | |
value: function _toggleControlVisibility() { | |
if (this.isMoving) return; // wait a second, geez | |
// console.log({sl: this.ele.scrollLeft, cw: this.ele.clientWidth, summed: this.ele.scrollLeft+this.ele.clientWidth, sw: this.ele.scrollWidth}); | |
this.prevEle.classList[this.ele.scrollLeft <= 0 ? "add" : "remove"]("hidden"); | |
this.nextEle.classList[this.ele.scrollLeft + this.ele.clientWidth >= this.ele.scrollWidth ? "add" : "remove"]("hidden"); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
next: { | |
value: function next() { | |
this._move(1); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
prev: { | |
value: function prev() { | |
this._move(-1); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_move: { | |
value: function _move() { | |
var vector = arguments[0] === undefined ? 1 : arguments[0]; | |
if (this.isMoving) return; | |
var _ref = [this.ele.clientWidth, this.ele.scrollLeft, this.ele.scrollWidth]; | |
var width = _ref[0]; | |
var offset = _ref[1]; | |
var scrollWidth = _ref[2]; | |
vector = vector / Math.abs(vector); | |
var newOffset = offset + vector * width; | |
newOffset = Math.min(newOffset, scrollWidth - width); | |
newOffset = Math.max(newOffset, 0); | |
this._moveItMoveIt(offset, newOffset); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_moveItMoveIt: { | |
value: function _moveItMoveIt(oldOffset, newOffset) { | |
var _this = this; | |
this.isMoving = true; | |
var startTime = Date.now(); | |
var duration = 300; | |
var currentOffset = oldOffset; | |
var animStep = function () { | |
var currentTime = Date.now(); | |
currentOffset = _this._easeInOutCirc(currentTime - startTime, oldOffset, newOffset - oldOffset, duration); | |
_this.ele.scrollLeft = currentOffset; | |
if (currentTime < startTime + duration) { | |
requestAnimationFrame(animStep); | |
} else { | |
_this.isMoving = false; | |
_this.ele.scrollLeft = newOffset; | |
_this._toggleControlVisibility(); | |
} | |
}; | |
requestAnimationFrame(animStep); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_easeInOutCirc: { | |
value: function _easeInOutCirc(currentIteration, startValue, changeInValue, totalIterations) { | |
// from http://kirupa.googlecode.com/svn/trunk/easing.js | |
if ((currentIteration /= totalIterations / 2) < 1) { | |
return changeInValue / 2 * (1 - Math.sqrt(1 - currentIteration * currentIteration)) + startValue; | |
} | |
return changeInValue / 2 * (Math.sqrt(1 - (currentIteration -= 2) * currentIteration) + 1) + startValue; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Scroller; | |
})(); | |
var yep = new Scroller(document.querySelector(".scroller")); | |
</script> | |
<script id="jsbin-source-css" type="text/css">.scroller | |
position: relative | |
* | |
margin: 0 | |
padding: 0 | |
ul | |
list-style: none | |
white-space: nowrap | |
width: 100% | |
overflow-x: scroll | |
-webkit-overflow-scrolling: touch | |
li | |
display: inline-block | |
width: 200px | |
height: 200px | |
margin: 10px | |
background: red | |
.prev, .next | |
position: absolute | |
top: 50% | |
background: rgba(255,255,255, .7) | |
margin-top: -28px | |
transition: opacity .3s | |
&.hidden | |
opacity: 0 | |
pointer-event: none | |
.prev | |
left: 0 | |
padding: 20px 20px 20px 0 | |
border-radius: 0 30px 30px 0 | |
.next | |
right: 0 | |
padding: 20px 0 20px 20px | |
border-radius: 30px 0 0 30px</script> | |
<script id="jsbin-source-javascript" type="text/javascript">"use strict"; | |
class Scroller { | |
// set options(options) { | |
// let defaultOptions = { | |
// } | |
// this._options = Object.mixin(defaultOptions, options) // doesn't actually exist >:( | |
// } | |
constructor(wrapper, scrollable=wrapper.querySelector("ul"), prev=wrapper.querySelector(".prev"), next=wrapper.querySelector(".next")) { | |
// this.options = {} | |
this.wrapper = wrapper; | |
this.ele = scrollable; | |
this.prevEle = prev; | |
this.nextEle = next; | |
this.isMoving = false; | |
this.nextEle.addEventListener("click", this.next.bind(this)); | |
this.prevEle.addEventListener("click", this.prev.bind(this)); | |
this.ele.addEventListener("scroll", this._debounceUtil(this._toggleControlVisibility.bind(this))); | |
window.addEventListener("resize", this._toggleControlVisibility.bind(this)); | |
this._toggleControlVisibility(); | |
} | |
_debounceUtil(func, wait=100) { // cribbed from http://davidwalsh.name/javascript-debounce-function | |
let timeout; | |
return function() { | |
const context = this | |
const args = arguments; | |
const later = function() { | |
timeout = null; | |
func.apply(context, args); | |
}; | |
clearTimeout(timeout); | |
timeout = setTimeout(later, wait); | |
}; | |
} | |
_toggleControlVisibility() { | |
if(this.isMoving) return; // wait a second, geez | |
// console.log({sl: this.ele.scrollLeft, cw: this.ele.clientWidth, summed: this.ele.scrollLeft+this.ele.clientWidth, sw: this.ele.scrollWidth}); | |
this.prevEle.classList[(this.ele.scrollLeft <= 0) ? "add" : "remove"]("hidden"); | |
this.nextEle.classList[(this.ele.scrollLeft + this.ele.clientWidth >= this.ele.scrollWidth) ? "add" : "remove"]("hidden"); | |
} | |
next() { | |
this._move(1); | |
} | |
prev() { | |
this._move(-1); | |
} | |
_move(vector=1) { | |
if(this.isMoving) return; | |
const [width, offset, scrollWidth] = [this.ele.clientWidth, this.ele.scrollLeft, this.ele.scrollWidth]; | |
vector = vector/Math.abs(vector); | |
let newOffset = offset + (vector*width); | |
newOffset = Math.min(newOffset, scrollWidth-width); | |
newOffset = Math.max(newOffset, 0); | |
this._moveItMoveIt(offset, newOffset); | |
} | |
_moveItMoveIt(oldOffset, newOffset) { | |
this.isMoving = true; | |
let startTime = Date.now(); | |
let duration = 300; | |
let currentOffset = oldOffset; | |
let animStep = ()=>{ | |
let currentTime = Date.now(); | |
currentOffset = this._easeInOutCirc(currentTime-startTime, oldOffset, newOffset-oldOffset, duration); | |
this.ele.scrollLeft = currentOffset; | |
if( currentTime < startTime+duration ) { | |
requestAnimationFrame(animStep); | |
} else { | |
this.isMoving = false; | |
this.ele.scrollLeft = newOffset; | |
this._toggleControlVisibility(); | |
} | |
}; | |
requestAnimationFrame(animStep); | |
} | |
_easeInOutCirc(currentIteration, startValue, changeInValue, totalIterations) { // from http://kirupa.googlecode.com/svn/trunk/easing.js | |
if ((currentIteration /= totalIterations / 2) < 1) { | |
return changeInValue / 2 * (1 - Math.sqrt(1 - currentIteration * currentIteration)) + startValue; | |
} | |
return changeInValue / 2 * (Math.sqrt(1 - (currentIteration -= 2) * currentIteration) + 1) + startValue; | |
} | |
} | |
var yep = new Scroller(document.querySelector(".scroller")); | |
</script></body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.scroller { | |
position: relative; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
} | |
ul { | |
list-style: none; | |
white-space: nowrap; | |
width: 100%; | |
overflow-x: scroll; | |
-webkit-overflow-scrolling: touch; | |
} | |
li { | |
display: inline-block; | |
width: 200px; | |
height: 200px; | |
margin: 10px; | |
background: red; | |
} | |
.prev, .next { | |
position: absolute; | |
top: 50%; | |
background: rgba(255, 255, 255, 0.7); | |
margin-top: -28px; | |
transition: opacity 0.3s; | |
} | |
.prev.hidden, .next.hidden { | |
opacity: 0; | |
pointer-event: none; | |
} | |
.prev { | |
left: 0; | |
padding: 20px 20px 20px 0; | |
border-radius: 0 30px 30px 0; | |
} | |
.next { | |
right: 0; | |
padding: 20px 0 20px 20px; | |
border-radius: 30px 0 0 30px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; | |
var Scroller = (function () { | |
// set options(options) { | |
// let defaultOptions = { | |
// } | |
// this._options = Object.mixin(defaultOptions, options) // doesn't actually exist >:( | |
// } | |
function Scroller(wrapper) { | |
var _this = this; | |
var scrollable = arguments[1] === undefined ? wrapper.querySelector("ul") : arguments[1]; | |
var prev = arguments[2] === undefined ? wrapper.querySelector(".prev") : arguments[2]; | |
var next = arguments[3] === undefined ? wrapper.querySelector(".next") : arguments[3]; | |
return (function () { | |
// this.options = {} | |
_this.wrapper = wrapper; | |
_this.ele = scrollable; | |
_this.prevEle = prev; | |
_this.nextEle = next; | |
_this.isMoving = false; | |
_this.nextEle.addEventListener("click", _this.next.bind(_this)); | |
_this.prevEle.addEventListener("click", _this.prev.bind(_this)); | |
_this.ele.addEventListener("scroll", _this._debounceUtil(_this._toggleControlVisibility.bind(_this))); | |
window.addEventListener("resize", _this._toggleControlVisibility.bind(_this)); | |
_this._toggleControlVisibility(); | |
})(); | |
} | |
_prototypeProperties(Scroller, null, { | |
_debounceUtil: { | |
value: function _debounceUtil(func) { | |
var wait = arguments[1] === undefined ? 100 : arguments[1]; | |
// cribbed from http://davidwalsh.name/javascript-debounce-function | |
var timeout = undefined; | |
return function () { | |
var context = this; | |
var args = arguments; | |
var later = function () { | |
timeout = null; | |
func.apply(context, args); | |
}; | |
clearTimeout(timeout); | |
timeout = setTimeout(later, wait); | |
}; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_toggleControlVisibility: { | |
value: function _toggleControlVisibility() { | |
if (this.isMoving) return; // wait a second, geez | |
// console.log({sl: this.ele.scrollLeft, cw: this.ele.clientWidth, summed: this.ele.scrollLeft+this.ele.clientWidth, sw: this.ele.scrollWidth}); | |
this.prevEle.classList[this.ele.scrollLeft <= 0 ? "add" : "remove"]("hidden"); | |
this.nextEle.classList[this.ele.scrollLeft + this.ele.clientWidth >= this.ele.scrollWidth ? "add" : "remove"]("hidden"); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
next: { | |
value: function next() { | |
this._move(1); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
prev: { | |
value: function prev() { | |
this._move(-1); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_move: { | |
value: function _move() { | |
var vector = arguments[0] === undefined ? 1 : arguments[0]; | |
if (this.isMoving) return; | |
var _ref = [this.ele.clientWidth, this.ele.scrollLeft, this.ele.scrollWidth]; | |
var width = _ref[0]; | |
var offset = _ref[1]; | |
var scrollWidth = _ref[2]; | |
vector = vector / Math.abs(vector); | |
var newOffset = offset + vector * width; | |
newOffset = Math.min(newOffset, scrollWidth - width); | |
newOffset = Math.max(newOffset, 0); | |
this._moveItMoveIt(offset, newOffset); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_moveItMoveIt: { | |
value: function _moveItMoveIt(oldOffset, newOffset) { | |
var _this = this; | |
this.isMoving = true; | |
var startTime = Date.now(); | |
var duration = 300; | |
var currentOffset = oldOffset; | |
var animStep = function () { | |
var currentTime = Date.now(); | |
currentOffset = _this._easeInOutCirc(currentTime - startTime, oldOffset, newOffset - oldOffset, duration); | |
_this.ele.scrollLeft = currentOffset; | |
if (currentTime < startTime + duration) { | |
requestAnimationFrame(animStep); | |
} else { | |
_this.isMoving = false; | |
_this.ele.scrollLeft = newOffset; | |
_this._toggleControlVisibility(); | |
} | |
}; | |
requestAnimationFrame(animStep); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
_easeInOutCirc: { | |
value: function _easeInOutCirc(currentIteration, startValue, changeInValue, totalIterations) { | |
// from http://kirupa.googlecode.com/svn/trunk/easing.js | |
if ((currentIteration /= totalIterations / 2) < 1) { | |
return changeInValue / 2 * (1 - Math.sqrt(1 - currentIteration * currentIteration)) + startValue; | |
} | |
return changeInValue / 2 * (Math.sqrt(1 - (currentIteration -= 2) * currentIteration) + 1) + startValue; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Scroller; | |
})(); | |
var yep = new Scroller(document.querySelector(".scroller")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment