2011-02-02 18:12:55 +00:00
// Would really love to make it so that as FEW changes as possible are required to gui.js in order to make this work. Would love to make it so you simply include gui.scrubber.min.js in addition to gui.min.js.
GUI . Controller . prototype . at = function ( when , what , tween ) {
2011-02-02 20:51:58 +00:00
this . scrubber . add ( new GUI . ScrubberPoint ( this . scrubber , when , what ) ) ;
2011-02-02 18:12:55 +00:00
this . scrubber . render ( ) ;
return this ;
}
GUI . Scrubber = function ( controller , timer ) {
var _this = this ;
2011-02-02 19:43:49 +00:00
this . points = [ ] ;
2011-02-02 18:12:55 +00:00
this . timer = timer ;
this . controller = controller ;
this . controller . scrubber = this ;
2011-02-02 20:51:58 +00:00
this . playing = false ;
this . sort = function ( ) {
this . points . sort ( function ( a , b ) {
return a . time - b . time ;
} ) ;
}
this . add = function ( p ) {
this . points . push ( p ) ;
this . sort ( ) ;
}
this . controller . addChangeListener ( function ( newVal ) {
2011-02-03 00:01:12 +00:00
2011-02-02 20:51:58 +00:00
if ( ! _this . playing ) {
if ( _this . timer . activePoint == null ) {
_this . timer . activePoint = new GUI . ScrubberPoint ( _this , _this . timer . playhead , newVal ) ;
2011-02-03 00:01:12 +00:00
_this . add ( _this . timer . activePoint ) ;
2011-02-02 20:51:58 +00:00
_this . render ( ) ;
} else {
_this . timer . activePoint . value = newVal ;
}
}
} ) ;
2011-02-02 18:12:55 +00:00
this . domElement = document . createElement ( 'div' ) ;
this . domElement . setAttribute ( 'class' , 'guidat-time' ) ;
var canvas = document . createElement ( 'canvas' ) ;
this . domElement . appendChild ( canvas ) ;
this . g = canvas . getContext ( '2d' ) ;
var width ;
2011-02-02 20:51:58 +00:00
var position ;
2011-02-02 18:12:55 +00:00
var height ;
2011-02-03 00:01:12 +00:00
var mx , pmx ;
2011-02-02 18:12:55 +00:00
this . _ _defineGetter _ _ ( "width" , function ( ) {
return width ;
} ) ;
this . _ _defineGetter _ _ ( "height" , function ( ) {
return height ;
} ) ;
controller . domElement . insertBefore ( this . domElement , controller . propertyNameElement . nextSibling ) ;
this . render = function ( ) {
// TODO: if visible ...
_this . g . clearRect ( 0 , 0 , width , height ) ;
2011-02-02 19:43:49 +00:00
for ( var i in _this . points ) {
_this . points [ i ] . render ( ) ;
2011-02-02 18:12:55 +00:00
}
// Draw playhead
_this . g . strokeStyle = "red" ;
2011-02-02 19:43:49 +00:00
_this . g . lineWidth = 1 ;
2011-02-02 18:12:55 +00:00
var t = Math . round ( GUI . map ( _this . timer . playhead , _this . timer . windowMin , _this . timer . windowMin + _this . timer . windowWidth , 0 , width ) ) + 0.5 ;
_this . g . beginPath ( ) ;
_this . g . moveTo ( t , 0 ) ;
_this . g . lineTo ( t , height ) ;
_this . g . stroke ( ) ;
}
this . render ( ) ;
2011-02-02 20:51:58 +00:00
2011-02-02 18:12:55 +00:00
var onResize = function ( ) {
canvas . width = width = _this . domElement . offsetWidth ;
canvas . height = height = _this . domElement . offsetHeight ;
2011-02-02 20:51:58 +00:00
position = GUI . getOffset ( canvas ) ;
2011-02-02 18:12:55 +00:00
_this . render ( ) ;
} ;
window . addEventListener ( 'resize' , function ( e ) {
onResize ( ) ;
} , false ) ;
2011-02-02 20:51:58 +00:00
var scrub = function ( e ) {
var t = GUI . map ( e . pageX , position . left , position . left + width , _this . timer . windowMin , _this . timer . windowMin + _this . timer . windowWidth ) ;
2011-02-03 00:01:12 +00:00
2011-02-02 20:51:58 +00:00
_this . timer . playhead = t ;
2011-02-03 00:01:12 +00:00
/ *
if ( t < _this . timer . windowMin + _this . timer . windowWidth / 5 ) {
_this . timer . windowMin = _this . timer . playhead - _this . timer . windowWidth / 5 ;
}
if ( t > _this . timer . windowMin + _this . timer . windowWidth - _this . timer . windowWidth / 5 ) {
_this . timer . windowMin = _this . timer . playhead + _this . timer . windowWidth / 5 - _this . timer . windowWidth ;
} * /
}
var dragActive = function ( e ) {
mx = e . pageX ;
var t = GUI . map ( mx - pmx , 0 , width , 0 , _this . timer . windowWidth ) ;
_this . timer . activePoint . time += t ;
pmx = mx ;
_this . sort ( ) ;
_this . timer . playhead += t ;
2011-02-02 20:51:58 +00:00
}
canvas . addEventListener ( 'mousedown' , function ( e ) {
if ( _this . timer . hoverPoint != null ) {
_this . timer . activePoint = _this . timer . hoverPoint ;
_this . timer . playhead = _this . timer . activePoint . time ;
2011-02-03 00:01:12 +00:00
pmx = mx = e . pageX ;
document . addEventListener ( "mousemove" , dragActive , false ) ;
2011-02-02 20:51:58 +00:00
} else {
_this . timer . activePoint = null ;
2011-02-03 00:01:12 +00:00
_this . timer . hoverPoint = null ;
2011-02-02 20:51:58 +00:00
scrub ( e ) ;
document . body . style . cursor = "text" ;
document . addEventListener ( 'mousemove' , scrub , false ) ;
_this . render ( ) ;
}
} , false ) ;
canvas . addEventListener ( 'mousemove' , function ( e ) {
_this . timer . hoverPoint = null ;
for ( var i in _this . points ) {
var cur = _this . points [ i ] ;
if ( cur . isHovering ( e . pageX - position . left ) ) {
_this . timer . hoverPoint = cur ;
}
}
2011-02-03 00:45:12 +00:00
if ( _this . timer . hoverPoint == null ) {
document . body . style . cursor = "pointer" ;
} else {
document . body . style . cursor = "auto" ;
}
2011-02-02 20:51:58 +00:00
_this . render ( ) ;
} ) ;
document . addEventListener ( 'mouseup' , function ( ) {
document . body . style . cursor = "auto" ;
2011-02-03 00:01:12 +00:00
document . removeEventListener ( "mousemove" , dragActive , false ) ;
2011-02-02 20:51:58 +00:00
document . removeEventListener ( 'mousemove' , scrub , false ) ;
} , false ) ;
2011-02-02 18:12:55 +00:00
onResize ( ) ;
this . timer . addPlayListener ( this . render ) ;
var onPlayChange = function ( curTime , prevTime ) {
2011-02-02 20:51:58 +00:00
_this . playing = true ;
2011-02-02 18:12:55 +00:00
// This assumes a SORTED point array
// And a PROGRESSING/INCREASING/GROWING playhead
2011-02-02 19:43:49 +00:00
if ( _this . controller . type == "number" ) {
var closestToLeft = null ;
for ( var i = 0 ; i < _this . points . length ; i ++ ) {
var cur = _this . points [ i ] ;
if ( cur . time >= curTime && i > 0 ) {
closestToLeft = _this . points [ i - 1 ] ;
2011-02-02 20:51:58 +00:00
break ;
2011-02-02 19:43:49 +00:00
}
}
2011-02-03 00:01:12 +00:00
if ( closestToLeft != null && closestToLeft . time <= curTime ) {
2011-02-02 19:43:49 +00:00
2011-02-03 00:01:12 +00:00
var n = closestToLeft . next ;
if ( n != null ) {
// Interpolate.
var t = GUI . map ( curTime , closestToLeft . time , n . time , 0 , 1 ) ;
t = closestToLeft . tween ( t ) ;
var val = GUI . map ( t , 0 , 1 , closestToLeft . value , n . value ) ;
_this . controller . setValue ( val ) ;
}
2011-02-02 19:43:49 +00:00
2011-02-02 18:12:55 +00:00
}
2011-02-02 19:43:49 +00:00
} else {
for ( var i = 0 ; i < _this . points . length ; i ++ ) {
var cur = _this . points [ i ] ;
if ( cur . time < prevTime ) {
continue ;
}
if ( cur . time >= prevTime && cur . time <= curTime ) {
pointHandlers [ _this . controller . type ] . call ( _this , cur ) ;
}
}
}
2011-02-02 18:12:55 +00:00
2011-02-02 20:51:58 +00:00
_this . playing = false ;
2011-02-02 18:12:55 +00:00
} ;
var pointHandlers = {
'function' : function ( point ) {
this . controller . getValue ( ) . call ( this ) ;
} ,
'boolean' : function ( point ) {
this . controller . setValue ( point . value ) ;
} ,
'string' : function ( point ) {
this . controller . setValue ( point . value ) ;
} ,
}
this . timer . addPlayListener ( onPlayChange ) ;
this . timer . addWindowListener ( this . render ) ;
} ;
GUI . ScrubberPoint = function ( scrubber , time , value ) {
2011-02-03 00:01:12 +00:00
var _this = this ;
2011-02-02 19:43:49 +00:00
2011-02-02 18:12:55 +00:00
var g = scrubber . g ;
var timer = scrubber . timer ;
2011-02-02 19:43:49 +00:00
var type = scrubber . controller . type ;
2011-02-02 20:51:58 +00:00
var x , y ;
this . hold = false ;
this . value = value ;
var barSize = 4 ;
var rectSize = 7 ;
var c1 = "#ffd800" ;
var c2 = "#ff9000" ;
2011-02-02 18:12:55 +00:00
2011-02-02 19:43:49 +00:00
this . tween = function ( t ) {
return t ;
} ;
2011-02-02 18:12:55 +00:00
2011-02-03 00:01:12 +00:00
this . remove = function ( ) {
scrubber . points . splice ( scrubber . points . indexOf ( this ) , 1 ) ;
scrubber . render ( ) ;
} ;
2011-02-02 20:51:58 +00:00
this . isHovering = function ( xx ) {
return xx >= x - rectSize / 2 && xx <= x + rectSize / 2 ;
} ;
2011-02-02 18:12:55 +00:00
2011-02-02 19:43:49 +00:00
this . _ _defineGetter _ _ ( "next" , function ( ) {
if ( scrubber . points . length <= 1 ) {
return null ;
2011-02-02 18:12:55 +00:00
}
2011-02-02 19:43:49 +00:00
var i = scrubber . points . indexOf ( this ) ;
if ( i + 1 >= scrubber . points . length ) {
return null ;
}
2011-02-02 18:12:55 +00:00
2011-02-02 19:43:49 +00:00
return scrubber . points [ i + 1 ] ;
2011-02-02 20:51:58 +00:00
2011-02-02 18:12:55 +00:00
} ) ;
2011-02-02 19:43:49 +00:00
this . _ _defineGetter _ _ ( "time" , function ( ) {
return time ;
2011-02-02 18:12:55 +00:00
} ) ;
2011-02-03 00:01:12 +00:00
this . _ _defineSetter _ _ ( "time" , function ( s ) {
time = s ;
} ) ;
2011-02-02 18:12:55 +00:00
2011-02-02 19:43:49 +00:00
this . render = function ( ) {
2011-02-02 18:12:55 +00:00
2011-02-02 20:51:58 +00:00
x = GUI . map ( time , timer . windowMin , timer . windowMin + timer . windowWidth , 0 , 1 ) ;
2011-02-02 19:43:49 +00:00
if ( x >= 0 && x <= 1 ) {
x = Math . round ( GUI . map ( x , 0 , 1 , 0 , scrubber . width ) ) ;
2011-02-03 00:01:12 +00:00
} else {
return ;
2011-02-02 18:12:55 +00:00
}
2011-02-02 19:43:49 +00:00
2011-02-02 20:51:58 +00:00
y = scrubber . height / 2 ;
2011-02-03 00:01:12 +00:00
if ( scrubber . timer . activePoint == this ) {
g . fillStyle = "#fff" ; //
} else if ( scrubber . timer . hoverPoint == this ) {
g . fillStyle = "#ddd" ;
} else {
g . fillStyle = "#ccc" ;
}
2011-02-02 19:43:49 +00:00
switch ( type ) {
case "number" :
g . save ( ) ;
var n = this . next ;
if ( n != null ) {
var nx = GUI . constrain ( GUI . map ( n . time , timer . windowMin , timer . windowMin + timer . windowWidth , 0 , 1 ) ) ;
if ( nx >= 0 && nx <= 1 ) {
nx = Math . round ( GUI . map ( nx , 0 , 1 , 0 , scrubber . width ) ) ;
}
g . lineWidth = rectSize / 2
g . strokeStyle = "#222" ;
g . beginPath ( ) ;
g . moveTo ( nx , y ) ;
g . lineTo ( x , y ) ;
g . stroke ( ) ;
}
g . translate ( x , y ) ;
g . rotate ( Math . PI / 4 ) ;
2011-02-03 00:01:12 +00:00
// g.fillStyle = c1;
2011-02-02 19:43:49 +00:00
g . fillRect ( - rectSize / 2 , - rectSize / 2 , rectSize , rectSize ) ;
g . restore ( ) ;
break ;
default :
g . save ( ) ;
g . translate ( x - barSize / 2 , 0 ) ;
2011-02-02 20:51:58 +00:00
//g.fillStyle = c1;
2011-02-02 19:43:49 +00:00
g . fillRect ( 0 , 0 , barSize / 2 , scrubber . height - 1 ) ;
2011-02-02 20:51:58 +00:00
//g.fillStyle = c2;
2011-02-02 19:43:49 +00:00
g . fillRect ( barSize / 2 , 0 , barSize / 2 , scrubber . height - 1 ) ;
g . restore ( ) ;
2011-02-02 18:12:55 +00:00
}
2011-02-02 19:43:49 +00:00
2011-02-02 18:12:55 +00:00
}
2011-02-02 19:43:49 +00:00
}