Skip to content

Instantly share code, notes, and snippets.

@pwwilson
Created October 10, 2013 16:45
Show Gist options
  • Save pwwilson/6921611 to your computer and use it in GitHub Desktop.
Save pwwilson/6921611 to your computer and use it in GitHub Desktop.
code
/*
* --------------------------------------------------------
*
* Global Audio Player
* Base class
*
* --------------------------------------------------------
*/
define(['jquery', 'backbone', 'moment'],
function ($, Backbone, moment) {
'use strict';
var $this;
var PlayerView = Backbone.View.extend({
template: HBS.player,
eventTypes: { start: 'mousedown', move: 'mousemove', end: 'mouseup', select: 'click' },
isPhoneGap: false,
delegate: null,
mediaTimer: null,
audioPlayer: null,
audioElem: null,
isDragging: false,
isPaused: true,
wasPausedBeforeScrub: false,
liveTime: 0,
farthestBuffer: 0,
scrubIsDirty: false,
dragPercX: 0,
isLive: true,
cues: [],
cueIndx: 0,
handle: null,
_date: null,
timeLapsed: 0,
intervalTime: 150,
initialize: function () {
// Override // tODO: Can implement Backbone super()
// $this = this;
},
render: function () {
$this = this;
$this.$el.html(this.template(this.model));
$this.transitionIn(); // TODO: call externally instead
App.EventDispatcher.on('app:render', $this.onAppReady); // Dispatching more than once?
console.log("*** RENDER", moment(), this.model);
$this.reset();
return this;
},
onAppReady: function() {
App.EventDispatcher.off('app:render', $this.onAppReady);
$this.cues = $this.model.cues;
$this.setUpPlayer(); // Mobile will be overwritten
$this.setUpBindings();
console.log("### ON APP READY ###");
//// $this.playAudio();
},
setUpPlayer: function() {
$this.audioPlayer = new Audio();
$this.audioPlayer.src = "../audio/test.mp3";
$this.$el.append($this.audioPlayer);
$this.audioElem = document.getElementsByTagName("audio")[0];
$this.audioPlayer.addEventListener('loadedmetadata', this.onMetaData, true);
},
setUpBindings: function(){
$('#player .icon-btn').bind($this.eventTypes.select, function(e){
var classes = $(e.currentTarget).attr('class');
switch ( true ) {
case classes.indexOf("RegularPlay01") != -1:
$this.playAudio();
$(e.currentTarget).addClass('RegularPause').removeClass('RegularPlay01');
break;
case classes.indexOf("RegularPause") != -1:
$this.pauseAudio();
$(e.currentTarget).addClass('RegularPlay01').removeClass('RegularPause');
break;
case classes.indexOf("control-skip") != -1:
//
break;
case classes.indexOf("RegularPrev") != -1:
var newTime;
if ( $this.getCurrentTime() < 15) {
newTime = 0;
} else {
newTime = $this.getCurrentTime() - 15;
}
$this.setCurrentTime(newTime);
break;
case classes.indexOf("RegularNext") != -1:
//
$this.setCurrentTime(20);
//
break;
default:
console.log("### Button has no class", $(e.currentTarget).attr('class'));
}
});
$('.progress-bar-progress').css({width: 0});
$this.mediaTimer = setInterval(function () {
if ( $this.getDuration() <= 0 ) return;
if ( $this.isDragging ) {
if ( $this.scrubIsDirty ) {
$this.playAudio();
$this.scrubIsDirty = false;
} else {
$this.pauseAudio();
}
$this.setCurrentTime($this.dragPercX * $this.getDuration());
}
$('#player .time-readout').html(moment({seconds: moment($this.getCurrentTime())}).format('mm:ss')+"/"+moment({seconds: moment($this.getDuration())}).format('mm:ss'));
var perComplete = (($this.getCurrentTime()/$this.getDuration())*100).toFixed(2)+'%';
$('.progress-bar-progress').css({width: perComplete});
if ( ($this.timeLapsed/1000)/$this.getDuration() < 1 ) {
var elapsedPerComplete = ((($this.timeLapsed/1000)/$this.getDuration())*100).toFixed(2)+'%';
$('.progress-bar-buffer').css({width: elapsedPerComplete});
}
$this.handle.css({left: perComplete});
// TODO: Error check
if ( $this.getCurrentTime() >= $this.cues[$this.cueIndx].time ) {
$this[$this.cues[$this.cueIndx].action].apply($this);
$this.cueIndx++;
}
$this.timeLapsed += $this.intervalTime;
}, $this.intervalTime);
$this.setUpDragging();
},
setUpDragging: function(){
$this.handle = $('.drag-handle');
$this.handle.bind($this.eventTypes.start, function(e) {
e.preventDefault();
$this.isDragging = true;
$this.wasPausedBeforeScrub = $this.isPaused;
$this.zoomInMode();
$this.bindMovingDragger();
});
},
bindMovingDragger: function() {
$(document).bind($this.eventTypes.move, $this.onMove);
$(document).bind($this.eventTypes.end, $this.onEnd);
},
unbindMovingDragger: function() {
$(document).unbind($this.eventTypes.move, $this.onMove);
$(document).unbind($this.eventTypes.end, $this.onEnd);
},
onMove: function(e) {
e.preventDefault();
if ( $this.isDragging ) {
var xPos;
if ( e.originalEvent.touches && e.originalEvent.touches.length ) {
xPos = e.originalEvent.touches[0].pageX;
} else if( e.originalEvent.changedTouches && e.originalEvent.changedTouches.length ) {
xPos = e.originalEvent.changedTouches[0];
} else {
xPos = e.pageX;
}
// Check that we haven't passed live point
if ( xPos > parseInt($('.progress-bar-buffer').css('width')) ) {
$this.isLive = true;
// console.log("### Live", xPos, parseInt($('.progress-bar-buffer').css('width')));
} else {
$this.isLive = false;
$this.dragPercX = Math.max(0, xPos / parseInt($('.controls-container').css('width'), 10));
$this.scrubIsDirty = true;
}
}
},
onEnd: function(e) {
e.preventDefault();
if ( $this.isDragging ) {
// $this.handle.css('background', '#808');
$this.isDragging = false;
if ( $this.wasPausedBeforeScrub ) {
$this.pauseAudio();
} else {
$this.playAudio();
}
$this.zoomOutMode();
$this.unbindMovingDragger();
}
},
// tODO: Refactor zoom related into mobile-only class once built. Empty implementation in this class.
// tODO: Fix tick mark layering bug
zoomInMode: function() {
$('.drag-handle-circle').transition({ scale: 3.0 });
$('.progress-bar').transition({ scale: 2.8 });
$('.player .full').hide();
$('.player .mini').show();
},
zoomOutMode: function() {
$('.drag-handle-circle').transition({ scale: 1.0 });
$('.progress-bar').transition({ scale: 1.0 });
$('.player .full').show();
$('.player .mini').hide();
},
drawCues: function() {
_.each($this.cues, function(cue, indx){
var tick = $('.progress-bar-background').append("<div class='progress-bar-tick'></div>");
var perc = (cue.time/$this.getDuration())*100;
$('.progress-bar-tick:last').css({'left': perc+'%'});
if ( cue.visible != true ) {
$('.progress-bar-tick:last').hide();
}
});
},
setData: function() {
// Populate with new model here...
},
onMetaData: function() {
if ( $this.cues.length > 0 ) {
$this.drawCues();
}
},
reset: function() {
// Use before feeding in new data
// tODO: zero out progress bar buffer
// tODO: redraw cues
//
$this.timeLapsed = 0;
},
destroy: function() {
// TODO: destroy all and kill interval
},
transitionIn: function(){
//// TweenMax.from(this.container, .5, {delay: 1, top: -120, ease: Back.easeOut});
},
transitionOut: function(){
//// TweenMax.to(this.container, .4, {delay: 1, top: -120, ease: Back.easeIn});
},
// Audio api Methods
playAudio: function() {
$this.isPaused = false;
$this.audioPlayer.play();
},
pauseAudio: function() {
$this.isPaused = true;
$this.audioPlayer.pause();
},
getCurrentTime: function() {
return $this.audioElem.currentTime;
},
setCurrentTime: function(tm) {
$this.audioElem.currentTime = tm;
},
getDuration: function() {
return $this.audioElem.duration;
},
// Cue Point Methods
callTestMethodOne: function(){
console.log("### CALLED ###");
},
callTestMethodTwo: function(){
console.log("### CALLED 2 ###");
}
});
return PlayerView;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment