I've created a custom Soundcloud Player with the widget api and a graphic progress bar made in this way:
<a id="slider-handle" href="#" style="left: 0"></a>
I dynamically move the left attribute following the current position of the track (I did a conversion from milliseconds to a percentage value). And this works fine. Now I would let the people to seek through the song moving this anchor element back and forth (like a range input). Is it possible to do this with jquery?
Here is the full code, which is more clear if you try it playing a song in the right-bottom corner: http://jsfiddle.net/7s2joet2/27/
I'll have a go at this:
First, you need to set draggable="false"
on the #slider-handle
because browsers that support HTML5 drag & drop will show the 'forbidden' cursor when you drag it ().
We need the following properties to accurately position the drag handle:
Event.clientX
: the current x coordinate of the cursorElement.clientWidth
: the rendered width of the element in pixelsElement.offsetLeft
: the rendered offset of the element in pixels from the left of the pageWe need flags to keep track of state (has the user clicked? has the user left the widget?):
isToggled
: true
when a user clicks the progress bar or handleisMdown
: true
when a user clicks the handleAdding the following code to yours, and changing some of the existing code:
var isMdown = false, // gets set to true when user clicks the handle
isToggled = false, // gets set to true when user clicks the bar or handle
progress = $('#progress'),
percentage= null, // keeps track of the last %
handleW = 8, // width of the handle, req. for positioning
handle = document.getElementById('slider-handle'),
range = document.getElementById('slider-range');
// main position adjustment function
var setPos = function(e) {
var posxBuffer = e.clientX - progress.offset().left,
w = this.clientWidth;
widget.getDuration(function(duration){
widget.seekTo(percentage*duration/100);
handle.style.left = percentage + '%';
range.style.width = percentage + '%';
});
isToggled = false;
isMdown = false;
};
// we just need to update the % value here and set some flags
progress.on('mousedown', function(e) {
isToggled = true;
var posxBuffer = e.clientX - progress.offset().left,
w = this.clientWidth;
percentage = ((posxBuffer-handleW)*100)/w;
if (e.target === handle)
isMdown = true;
});
progress.on('mouseover', function(e) {
// if the user has previously triggered a mousedown event, he is now dragging
// => adjust handle position, but not time progress
if (isMdown) {
var posxBuffer = e.clientX- progress.offset().left,
w = this.clientWidth;
percentage = ((posxBuffer-handleW)*100)/w;
handle.style.left = percentage + '%';
range.style.width = percentage + '%';
}
});
// when a user has clicked the progress bar and releases the button,
// set the position
progress.on('mouseup', setPos);
// when a user is still dragging but leaves the progress bar,
// release and set to last position
progress.on('mouseleave', function(e) {
if (isMdown)
setPos(e);
});
widget.bind(SC.Widget.Events.PLAY_PROGRESS, function(){
widget.getPosition(function(position){
widget.getDuration(function(duration){
$('#seekms').text(duration);
// Just as a bonus, the code for transforming ms into a MM:SS format =)
var mins = (position/1000/60 < 10 ? '0' : '') + Math.floor(position/1000/60),
secs = (position/1000%60 < 10 ? '0' : '') + Math.floor((position/1000) %60);
$('#bufferms').text(mins + ':' + secs);
// only updated if the user already moused down on either handler or bar
if (isToggled || isMdown)
return;
var percentage = position*100/duration;
$("#slider-range").css("width", percentage + '%');
$("#slider-handle").css("left", percentage + '%');
$('#inputseek').val(percentage);
});
});
});
See it in action: http://jsfiddle.net/7s2joet2/31/ (note: I made the handle + bar bigger so it'd be easier to drag)