Created
July 23, 2015 19:47
-
-
Save mattkelley/4eee7bc61b645ef0f56b to your computer and use it in GitHub Desktop.
range slider module
This file contains hidden or 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
var on = function(items, scope) { | |
items.forEach(function(item) { | |
return item.e.map(function(e) { | |
item.context.addEventListener(e,item.fn,false) | |
}) | |
}) | |
} | |
var off = function(items) { | |
items.forEach(function(item) { | |
return item.e.map(function(e) { | |
item.context.removeEventListener(e,item.fn,false) | |
}) | |
}) | |
} | |
// move the element to a percentage point | |
var to = function(el, percent) { | |
// This is for sanity but also for visual. The playhead shouldn't leave the progress bar. | |
var clamp = Math.min(Math.max(percent, 0.2), 99.8); | |
// Convert this into matrices stuff later | |
['webkitTransform', 'MozTransform', 'msTransform', 'transform'].forEach(function(v) { | |
el.style[v] = 'translateX(' + clamp + '%)'; | |
}); | |
} | |
// calculate the percentage point | |
var percentage = function(el, event) { | |
var x = (event.touches) ? event.touches[0].clientX : event.clientX; | |
var position = x - el.getBoundingClientRect().left; | |
var percentage = 100 * position / el.offsetWidth; | |
return Math.min(Math.max(percentage, 0), 100); | |
} | |
/** | |
* Range slider | |
* Creates a simple UI slider for scrubbing video or volume | |
* @param {Element} el | |
*/ | |
function Range(el) { | |
// store passed element | |
this._el = el; | |
// current percentage of the range element | |
this._position = 0; | |
// amount of move events in the current range adjustment | |
this._count = 0; | |
// create elements, and the event configuration | |
this.create(); | |
}; | |
// Enable the range slider events | |
Range.prototype.enable = function() { | |
on([this._e.start]); | |
}; | |
// Disable the range slider events | |
Range.prototype.disable = function() { | |
off([this._e.start]); | |
}; | |
// Get the range current position | |
Range.prototype.get = function() { | |
return this._position; | |
}; | |
// Set the range position | |
Range.prototype.set = function() { | |
this._position = percent; | |
to(this._time, this._position); | |
}; | |
// Handle touchstart and mousedown events | |
Range.prototype._start = function() { | |
event.stopPropagation(); | |
on([this._e.move, this._e.stop]); | |
this.trigger('begin', {type: 'begin', srcEvent: event, percent: this._position}); | |
if (this._position !== percentage(this._bar, event)) { | |
this.move(event); | |
} | |
}; | |
// Handle touchmove and mousemove events | |
Range.prototype._move = function() { | |
event.stopPropagation(); | |
this._position = percentage(this._bar, event); | |
to(this._time, this._position); | |
this.trigger('move', {type: 'move', srcEvent: event, count: ++this._count, percent: this._position}); | |
}; | |
// Handle touchend and mouseup events | |
Range.prototype._stop = function() { | |
event.stopPropagation(); | |
off([this._e.move, this._e.stop]); | |
this.trigger('end', {type: 'end', srcEvent: event, percent: this._position }); | |
this._count = 0; | |
}; | |
// Destroy the Range slider elements and remove event listeners | |
Range.prototype.destroy = function() { | |
off([this._e.start, this._e.move, this._e.stop]); | |
this._bar.removeChild(this._time); | |
this._el.removeChild(this._bar); | |
this._el.classList.remove('ivp-control-progress'); | |
}; | |
// Create the Range markup and event configuration | |
Range.prototype.create = function() { | |
// Bar is the outer element always visibile | |
this._bar = document.createElement('div'); | |
this._bar.className = 'ivp-progress-bar'; | |
// Time is the inner element which slides | |
this._time = document.createElement('div'); | |
this._time.className = 'ivp-progress-time'; | |
this._bar.appendChild(this._time); | |
// @NOTE modifying passed element here - not sure if I like this or not | |
this._el.classList.add('ivp-control-progress'); | |
this._el.appendChild(this._bar); | |
var _this = this; | |
this._e = { | |
start: { | |
context: this._bar, | |
e: ['mousedown', 'touchstart'], | |
fn: function() { | |
_this._start.apply(_this, arguments); | |
} | |
}, | |
move: { | |
context: document, | |
e: ['mousemove', 'touchmove'], | |
fn: function() { | |
_this._move.apply(_this, arguments); | |
} | |
}, | |
stop: { | |
context: document, | |
e: ['mouseup', 'touchend'], | |
fn: function() { | |
_this._stop.apply(_this, arguments) | |
} | |
} | |
} | |
}; | |
// Export the Range class as default | |
export default Range; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment