2013-12-18 23:27:02 +00:00
/ * *
* dat - gui JavaScript Controller Library
* http : //code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team , Google Creative Lab
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
* /
2014-02-08 17:57:40 +00:00
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( factory ) ;
} else {
// Browser globals
root . dat = factory ( ) ;
}
} ( this , function ( ) {
2013-12-18 23:27:02 +00:00
/** @namespace */
2014-02-08 17:57:40 +00:00
var dat = dat || { } ;
/** @namespace */
dat . gui = dat . gui || { } ;
/** @namespace */
dat . utils = dat . utils || { } ;
/** @namespace */
dat . controllers = dat . controllers || { } ;
/** @namespace */
dat . dom = dat . dom || { } ;
/** @namespace */
dat . color = dat . color || { } ;
dat . utils . css = ( function ( ) {
return {
load : function ( url , doc ) {
doc = doc || document ;
var link = doc . createElement ( 'link' ) ;
link . type = 'text/css' ;
link . rel = 'stylesheet' ;
link . href = url ;
doc . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( link ) ;
} ,
inject : function ( css , doc ) {
doc = doc || document ;
var injected = document . createElement ( 'style' ) ;
injected . type = 'text/css' ;
injected . innerHTML = css ;
doc . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( injected ) ;
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ( ) ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
dat . utils . common = ( function ( ) {
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
var ARR _EACH = Array . prototype . forEach ;
var ARR _SLICE = Array . prototype . slice ;
/ * *
* Band - aid methods for things that should be a lot easier in JavaScript .
* Implementation and structure inspired by underscore . js
* http : //documentcloud.github.com/underscore/
* /
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
return {
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
BREAK : { } ,
extend : function ( target ) {
this . each ( ARR _SLICE . call ( arguments , 1 ) , function ( obj ) {
for ( var key in obj )
if ( ! this . isUndefined ( obj [ key ] ) )
target [ key ] = obj [ key ] ;
} , this ) ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
return target ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
} ,
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
defaults : function ( target ) {
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
this . each ( ARR _SLICE . call ( arguments , 1 ) , function ( obj ) {
for ( var key in obj )
if ( this . isUndefined ( target [ key ] ) )
target [ key ] = obj [ key ] ;
} , this ) ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
return target ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
} ,
compose : function ( ) {
var toCall = ARR _SLICE . call ( arguments ) ;
return function ( ) {
var args = ARR _SLICE . call ( arguments ) ;
for ( var i = toCall . length - 1 ; i >= 0 ; i -- ) {
args = [ toCall [ i ] . apply ( this , args ) ] ;
}
return args [ 0 ] ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
each : function ( obj , itr , scope ) {
if ( ! obj ) return ;
if ( ARR _EACH && obj . forEach && obj . forEach === ARR _EACH ) {
obj . forEach ( itr , scope ) ;
} else if ( obj . length === obj . length + 0 ) { // Is number but not NaN
for ( var key = 0 , l = obj . length ; key < l ; key ++ )
if ( key in obj && itr . call ( scope , obj [ key ] , key ) === this . BREAK )
return ;
} else {
for ( var key in obj )
if ( itr . call ( scope , obj [ key ] , key ) === this . BREAK )
return ;
}
} ,
defer : function ( fnc ) {
setTimeout ( fnc , 0 ) ;
} ,
toArray : function ( obj ) {
if ( obj . toArray ) return obj . toArray ( ) ;
return ARR _SLICE . call ( obj ) ;
} ,
isUndefined : function ( obj ) {
return obj === undefined ;
} ,
isNull : function ( obj ) {
return obj === null ;
} ,
isNaN : function ( obj ) {
return obj !== obj ;
} ,
isArray : Array . isArray || function ( obj ) {
return obj . constructor === Array ;
} ,
isObject : function ( obj ) {
return obj === Object ( obj ) ;
} ,
isNumber : function ( obj ) {
return obj === obj + 0 ;
} ,
isString : function ( obj ) {
return obj === obj + '' ;
} ,
isBoolean : function ( obj ) {
return obj === false || obj === true ;
} ,
isFunction : function ( obj ) {
return Object . prototype . toString . call ( obj ) === '[object Function]' ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ;
} ) ( ) ;
dat . controllers . Controller = ( function ( common ) {
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ class An "abstract" class that represents a given property of an object .
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
*
* @ member dat . controllers
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
var Controller = function ( object , property ) {
this . initialValue = object [ property ] ;
/ * *
* Those who extend this class will put their DOM elements in here .
* @ type { DOMElement }
* /
this . domElement = document . createElement ( 'div' ) ;
/ * *
* The object to manipulate
* @ type { Object }
* /
this . object = object ;
/ * *
* The name of the property to manipulate
* @ type { String }
* /
this . property = property ;
/ * *
* The function to be called on change .
* @ type { Function }
* @ ignore
* /
this . _ _onChange = undefined ;
/ * *
* The function to be called on finishing change .
* @ type { Function }
* @ ignore
* /
this . _ _onFinishChange = undefined ;
} ;
common . extend (
Controller . prototype ,
/** @lends dat.controllers.Controller.prototype */
{
/ * *
* Specify that a function fire every time someone changes the value with
* this Controller .
*
* @ param { Function } fnc This function will be called whenever the value
* is modified via this Controller .
* @ returns { dat . controllers . Controller } this
* /
onChange : function ( fnc ) {
this . _ _onChange = fnc ;
return this ;
} ,
/ * *
* Specify that a function fire every time someone "finishes" changing
* the value wih this Controller . Useful for values that change
* incrementally like numbers or strings .
*
* @ param { Function } fnc This function will be called whenever
* someone "finishes" changing the value via this Controller .
* @ returns { dat . controllers . Controller } this
* /
onFinishChange : function ( fnc ) {
this . _ _onFinishChange = fnc ;
return this ;
} ,
/ * *
* Change the value of < code > object [ property ] < / c o d e >
*
* @ param { Object } newValue The new value of < code > object [ property ] < / c o d e >
* /
setValue : function ( newValue ) {
this . object [ this . property ] = newValue ;
if ( this . _ _onChange ) {
this . _ _onChange . call ( this , newValue ) ;
}
this . updateDisplay ( ) ;
return this ;
} ,
/ * *
* Gets the value of < code > object [ property ] < / c o d e >
*
* @ returns { Object } The current value of < code > object [ property ] < / c o d e >
* /
getValue : function ( ) {
return this . object [ this . property ] ;
} ,
/ * *
* Refreshes the visual display of a Controller in order to keep sync
* with the object ' s current value .
* @ returns { dat . controllers . Controller } this
* /
updateDisplay : function ( ) {
return this ;
} ,
/ * *
* @ returns { Boolean } true if the value has deviated from initialValue
* /
isModified : function ( ) {
return this . initialValue !== this . getValue ( )
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
return Controller ;
} ) ( dat . utils . common ) ;
dat . dom . dom = ( function ( common ) {
var EVENT _MAP = {
'HTMLEvents' : [ 'change' ] ,
'MouseEvents' : [ 'click' , 'mousemove' , 'mousedown' , 'mouseup' , 'mouseover' ] ,
'KeyboardEvents' : [ 'keydown' ]
} ;
var EVENT _MAP _INV = { } ;
common . each ( EVENT _MAP , function ( v , k ) {
common . each ( v , function ( e ) {
EVENT _MAP _INV [ e ] = k ;
} ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
var CSS _VALUE _PIXELS = /(\d+(\.\d+)?)px/ ;
function cssValueToPixels ( val ) {
if ( val === '0' || common . isUndefined ( val ) ) return 0 ;
var match = val . match ( CSS _VALUE _PIXELS ) ;
if ( ! common . isNull ( match ) ) {
return parseFloat ( match [ 1 ] ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
// TODO ...ems? %?
return 0 ;
}
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ namespace
* @ member dat . dom
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
var dom = {
/ * *
*
* @ param elem
* @ param selectable
* /
makeSelectable : function ( elem , selectable ) {
if ( elem === undefined || elem . style === undefined ) return ;
elem . onselectstart = selectable ? function ( ) {
return false ;
} : function ( ) {
} ;
elem . style . MozUserSelect = selectable ? 'auto' : 'none' ;
elem . style . KhtmlUserSelect = selectable ? 'auto' : 'none' ;
elem . unselectable = selectable ? 'on' : 'off' ;
} ,
/ * *
*
* @ param elem
* @ param horizontal
* @ param vertical
* /
makeFullscreen : function ( elem , horizontal , vertical ) {
if ( common . isUndefined ( horizontal ) ) horizontal = true ;
if ( common . isUndefined ( vertical ) ) vertical = true ;
elem . style . position = 'absolute' ;
if ( horizontal ) {
elem . style . left = 0 ;
elem . style . right = 0 ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
if ( vertical ) {
elem . style . top = 0 ;
elem . style . bottom = 0 ;
}
} ,
/ * *
*
* @ param elem
* @ param eventType
* @ param params
* /
fakeEvent : function ( elem , eventType , params , aux ) {
params = params || { } ;
var className = EVENT _MAP _INV [ eventType ] ;
if ( ! className ) {
throw new Error ( 'Event type ' + eventType + ' not supported.' ) ;
}
var evt = document . createEvent ( className ) ;
switch ( className ) {
case 'MouseEvents' :
var clientX = params . x || params . clientX || 0 ;
var clientY = params . y || params . clientY || 0 ;
evt . initMouseEvent ( eventType , params . bubbles || false ,
params . cancelable || true , window , params . clickCount || 1 ,
0 , //screen X
0 , //screen Y
clientX , //client X
clientY , //client Y
false , false , false , false , 0 , null ) ;
break ;
case 'KeyboardEvents' :
var init = evt . initKeyboardEvent || evt . initKeyEvent ; // webkit || moz
common . defaults ( params , {
cancelable : true ,
ctrlKey : false ,
altKey : false ,
shiftKey : false ,
metaKey : false ,
keyCode : undefined ,
charCode : undefined
} ) ;
init ( eventType , params . bubbles || false ,
params . cancelable , window ,
params . ctrlKey , params . altKey ,
params . shiftKey , params . metaKey ,
params . keyCode , params . charCode ) ;
break ;
default :
evt . initEvent ( eventType , params . bubbles || false ,
params . cancelable || true ) ;
break ;
}
common . defaults ( evt , aux ) ;
elem . dispatchEvent ( evt ) ;
} ,
/ * *
*
* @ param elem
* @ param event
* @ param func
* @ param bool
* /
bind : function ( elem , event , func , bool ) {
bool = bool || false ;
if ( elem . addEventListener )
elem . addEventListener ( event , func , bool ) ;
else if ( elem . attachEvent )
elem . attachEvent ( 'on' + event , func ) ;
return dom ;
} ,
/ * *
*
* @ param elem
* @ param event
* @ param func
* @ param bool
* /
unbind : function ( elem , event , func , bool ) {
bool = bool || false ;
if ( elem . removeEventListener )
elem . removeEventListener ( event , func , bool ) ;
else if ( elem . detachEvent )
elem . detachEvent ( 'on' + event , func ) ;
return dom ;
} ,
/ * *
*
* @ param elem
* @ param className
* /
addClass : function ( elem , className ) {
2013-12-18 23:27:02 +00:00
if ( elem . className === undefined ) {
2014-02-08 17:57:40 +00:00
elem . className = className ;
} else if ( elem . className !== className ) {
2013-12-18 23:27:02 +00:00
var classes = elem . className . split ( / +/ ) ;
2014-02-08 17:57:40 +00:00
if ( classes . indexOf ( className ) == - 1 ) {
classes . push ( className ) ;
elem . className = classes . join ( ' ' ) . replace ( /^\s+/ , '' ) . replace ( /\s+$/ , '' ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
return dom ;
} ,
/ * *
*
* @ param elem
* @ param className
* /
removeClass : function ( elem , className ) {
if ( className ) {
if ( elem . className === undefined ) {
// elem.className = className;
} else if ( elem . className === className ) {
elem . removeAttribute ( 'class' ) ;
} else {
var classes = elem . className . split ( / +/ ) ;
var index = classes . indexOf ( className ) ;
if ( index != - 1 ) {
classes . splice ( index , 1 ) ;
elem . className = classes . join ( ' ' ) ;
}
}
} else {
elem . className = undefined ;
}
return dom ;
} ,
hasClass : function ( elem , className ) {
return new RegExp ( '(?:^|\\s+)' + className + '(?:\\s+|$)' ) . test ( elem . className ) || false ;
} ,
/ * *
*
* @ param elem
* /
getWidth : function ( elem ) {
var style = getComputedStyle ( elem ) ;
return cssValueToPixels ( style [ 'border-left-width' ] ) +
cssValueToPixels ( style [ 'border-right-width' ] ) +
cssValueToPixels ( style [ 'padding-left' ] ) +
cssValueToPixels ( style [ 'padding-right' ] ) +
cssValueToPixels ( style [ 'width' ] ) ;
} ,
/ * *
*
* @ param elem
* /
getHeight : function ( elem ) {
var style = getComputedStyle ( elem ) ;
return cssValueToPixels ( style [ 'border-top-width' ] ) +
cssValueToPixels ( style [ 'border-bottom-width' ] ) +
cssValueToPixels ( style [ 'padding-top' ] ) +
cssValueToPixels ( style [ 'padding-bottom' ] ) +
cssValueToPixels ( style [ 'height' ] ) ;
} ,
/ * *
*
* @ param elem
* /
getOffset : function ( elem ) {
var offset = { left : 0 , top : 0 } ;
if ( elem . offsetParent ) {
do {
offset . left += elem . offsetLeft ;
offset . top += elem . offsetTop ;
} while ( elem = elem . offsetParent ) ;
}
return offset ;
} ,
// http://stackoverflow.com/posts/2684561/revisions
/ * *
*
* @ param elem
* /
isActive : function ( elem ) {
return elem === document . activeElement && ( elem . type || elem . href ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ;
return dom ;
} ) ( dat . utils . common ) ;
dat . controllers . OptionController = ( function ( Controller , dom , common ) {
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ class Provides a select input to alter the property of an object , using a
* list of accepted values .
2013-12-18 23:27:02 +00:00
*
2014-02-08 17:57:40 +00:00
* @ extends dat . controllers . Controller
2013-12-18 23:27:02 +00:00
*
2014-02-08 17:57:40 +00:00
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
* @ param { Object | string [ ] } options A map of labels to acceptable values , or
* a list of acceptable string values .
2013-12-18 23:27:02 +00:00
*
2014-02-08 17:57:40 +00:00
* @ member dat . controllers
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
var OptionController = function ( object , property , options ) {
OptionController . superclass . call ( this , object , property ) ;
var _this = this ;
/ * *
* The drop down menu
* @ ignore
* /
this . _ _select = document . createElement ( 'select' ) ;
if ( common . isArray ( options ) ) {
var map = { } ;
common . each ( options , function ( element ) {
map [ element ] = element ;
} ) ;
options = map ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
common . each ( options , function ( value , key ) {
var opt = document . createElement ( 'option' ) ;
opt . innerHTML = key ;
opt . setAttribute ( 'value' , value ) ;
_this . _ _select . appendChild ( opt ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
// Acknowledge original value
this . updateDisplay ( ) ;
dom . bind ( this . _ _select , 'change' , function ( ) {
var desiredValue = this . options [ this . selectedIndex ] . value ;
_this . setValue ( desiredValue ) ;
} ) ;
this . domElement . appendChild ( this . _ _select ) ;
} ;
OptionController . superclass = Controller ;
common . extend (
OptionController . prototype ,
Controller . prototype ,
{
setValue : function ( v ) {
var toReturn = OptionController . superclass . prototype . setValue . call ( this , v ) ;
if ( this . _ _onFinishChange ) {
this . _ _onFinishChange . call ( this , this . getValue ( ) ) ;
}
return toReturn ;
} ,
updateDisplay : function ( ) {
this . _ _select . value = this . getValue ( ) ;
return OptionController . superclass . prototype . updateDisplay . call ( this ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
return OptionController ;
} ) ( dat . controllers . Controller ,
dat . dom . dom ,
dat . utils . common ) ;
dat . controllers . NumberController = ( function ( Controller , common ) {
/ * *
* @ class Represents a given property of an object that is a number .
*
* @ extends dat . controllers . Controller
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
* @ param { Object } [ params ] Optional parameters
* @ param { Number } [ params . min ] Minimum allowed value
* @ param { Number } [ params . max ] Maximum allowed value
* @ param { Number } [ params . step ] Increment by which to change value
*
* @ member dat . controllers
* /
var NumberController = function ( object , property , params ) {
NumberController . superclass . call ( this , object , property ) ;
params = params || { } ;
this . _ _min = params . min ;
this . _ _max = params . max ;
this . _ _step = params . step ;
if ( common . isUndefined ( this . _ _step ) ) {
if ( this . initialValue == 0 ) {
this . _ _impliedStep = 1 ; // What are we, psychics?
} else {
// Hey Doug, check this out.
this . _ _impliedStep = Math . pow ( 10 , Math . floor ( Math . log ( this . initialValue ) / Math . LN10 ) ) / 10 ;
}
2013-12-18 23:27:02 +00:00
} else {
2014-02-08 17:57:40 +00:00
this . _ _impliedStep = this . _ _step ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . _ _precision = numDecimals ( this . _ _impliedStep ) ;
} ;
NumberController . superclass = Controller ;
common . extend (
NumberController . prototype ,
Controller . prototype ,
/** @lends dat.controllers.NumberController.prototype */
{
setValue : function ( v ) {
if ( this . _ _min !== undefined && v < this . _ _min ) {
v = this . _ _min ;
} else if ( this . _ _max !== undefined && v > this . _ _max ) {
v = this . _ _max ;
}
if ( this . _ _step !== undefined && v % this . _ _step != 0 ) {
v = Math . round ( v / this . _ _step ) * this . _ _step ;
}
return NumberController . superclass . prototype . setValue . call ( this , v ) ;
} ,
/ * *
* Specify a minimum value for < code > object [ property ] < / c o d e > .
*
* @ param { Number } minValue The minimum value for
* < code > object [ property ] < / c o d e >
* @ returns { dat . controllers . NumberController } this
* /
min : function ( v ) {
this . _ _min = v ;
return this ;
} ,
/ * *
* Specify a maximum value for < code > object [ property ] < / c o d e > .
*
* @ param { Number } maxValue The maximum value for
* < code > object [ property ] < / c o d e >
* @ returns { dat . controllers . NumberController } this
* /
max : function ( v ) {
this . _ _max = v ;
return this ;
} ,
/ * *
* Specify a step value that dat . controllers . NumberController
* increments by .
*
* @ param { Number } stepValue The step value for
* dat . controllers . NumberController
* @ default if minimum and maximum specified increment is 1 % of the
* difference otherwise stepValue is 1
* @ returns { dat . controllers . NumberController } this
* /
step : function ( v ) {
this . _ _step = v ;
this . _ _impliedStep = v ;
this . _ _precision = numDecimals ( v ) ;
return this ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
function numDecimals ( x ) {
x = x . toString ( ) ;
if ( x . indexOf ( '.' ) > - 1 ) {
return x . length - x . indexOf ( '.' ) - 1 ;
} else {
return 0 ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
return NumberController ;
} ) ( dat . controllers . Controller ,
dat . utils . common ) ;
dat . controllers . NumberControllerBox = ( function ( NumberController , dom , common ) {
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ class Represents a given property of an object that is a number and
* provides an input element with which to manipulate it .
*
* @ extends dat . controllers . Controller
* @ extends dat . controllers . NumberController
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
* @ param { Object } [ params ] Optional parameters
* @ param { Number } [ params . min ] Minimum allowed value
* @ param { Number } [ params . max ] Maximum allowed value
* @ param { Number } [ params . step ] Increment by which to change value
*
* @ member dat . controllers
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
var NumberControllerBox = function ( object , property , params ) {
this . _ _truncationSuspended = false ;
NumberControllerBox . superclass . call ( this , object , property , params ) ;
var _this = this ;
/ * *
* { Number } Previous mouse y position
* @ ignore
* /
var prev _y ;
this . _ _input = document . createElement ( 'input' ) ;
this . _ _input . setAttribute ( 'type' , 'text' ) ;
// Makes it so manually specified values are not truncated.
dom . bind ( this . _ _input , 'change' , onChange ) ;
dom . bind ( this . _ _input , 'blur' , onBlur ) ;
dom . bind ( this . _ _input , 'mousedown' , onMouseDown ) ;
dom . bind ( this . _ _input , 'keydown' , function ( e ) {
// When pressing entire, you can be as precise as you want.
if ( e . keyCode === 13 ) {
_this . _ _truncationSuspended = true ;
this . blur ( ) ;
_this . _ _truncationSuspended = false ;
}
} ) ;
function onChange ( ) {
var attempted = parseFloat ( _this . _ _input . value ) ;
if ( ! common . isNaN ( attempted ) ) _this . setValue ( attempted ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function onBlur ( ) {
onChange ( ) ;
if ( _this . _ _onFinishChange ) {
_this . _ _onFinishChange . call ( _this , _this . getValue ( ) ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
function onMouseDown ( e ) {
dom . bind ( window , 'mousemove' , onMouseDrag ) ;
dom . bind ( window , 'mouseup' , onMouseUp ) ;
prev _y = e . clientY ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function onMouseDrag ( e ) {
var diff = prev _y - e . clientY ;
_this . setValue ( _this . getValue ( ) + diff * _this . _ _impliedStep ) ;
prev _y = e . clientY ;
}
function onMouseUp ( ) {
dom . unbind ( window , 'mousemove' , onMouseDrag ) ;
dom . unbind ( window , 'mouseup' , onMouseUp ) ;
}
this . updateDisplay ( ) ;
this . domElement . appendChild ( this . _ _input ) ;
} ;
NumberControllerBox . superclass = NumberController ;
common . extend (
NumberControllerBox . prototype ,
NumberController . prototype ,
{
updateDisplay : function ( ) {
this . _ _input . value = this . _ _truncationSuspended ? this . getValue ( ) : roundToDecimal ( this . getValue ( ) , this . _ _precision ) ;
return NumberControllerBox . superclass . prototype . updateDisplay . call ( this ) ;
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
function roundToDecimal ( value , decimals ) {
var tenTo = Math . pow ( 10 , decimals ) ;
return Math . round ( value * tenTo ) / tenTo ;
}
return NumberControllerBox ;
} ) ( dat . controllers . NumberController ,
dat . dom . dom ,
dat . utils . common ) ;
dat . controllers . NumberControllerSlider = ( function ( NumberController , dom , css , common , styleSheet ) {
/ * *
* @ class Represents a given property of an object that is a number , contains
* a minimum and maximum , and provides a slider element with which to
* manipulate it . It should be noted that the slider element is made up of
* < code > & lt ; div & gt ; < / c o d e > t a g s , < s t r o n g > n o t < / s t r o n g > t h e h t m l 5
* < code > & lt ; slider & gt ; < / c o d e > e l e m e n t .
*
* @ extends dat . controllers . Controller
* @ extends dat . controllers . NumberController
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
* @ param { Number } minValue Minimum allowed value
* @ param { Number } maxValue Maximum allowed value
* @ param { Number } stepValue Increment by which to change value
*
* @ member dat . controllers
* /
var NumberControllerSlider = function ( object , property , min , max , step ) {
NumberControllerSlider . superclass . call ( this , object , property , { min : min , max : max , step : step } ) ;
var _this = this ;
this . _ _background = document . createElement ( 'div' ) ;
this . _ _foreground = document . createElement ( 'div' ) ;
dom . bind ( this . _ _background , 'mousedown' , onMouseDown ) ;
dom . addClass ( this . _ _background , 'slider' ) ;
dom . addClass ( this . _ _foreground , 'slider-fg' ) ;
function onMouseDown ( e ) {
dom . bind ( window , 'mousemove' , onMouseDrag ) ;
dom . bind ( window , 'mouseup' , onMouseUp ) ;
onMouseDrag ( e ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function onMouseDrag ( e ) {
e . preventDefault ( ) ;
var offset = dom . getOffset ( _this . _ _background ) ;
var width = dom . getWidth ( _this . _ _background ) ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
_this . setValue (
map ( e . clientX , offset . left , offset . left + width , _this . _ _min , _this . _ _max )
) ;
return false ;
}
function onMouseUp ( ) {
dom . unbind ( window , 'mousemove' , onMouseDrag ) ;
dom . unbind ( window , 'mouseup' , onMouseUp ) ;
if ( _this . _ _onFinishChange ) {
_this . _ _onFinishChange . call ( _this , _this . getValue ( ) ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
this . updateDisplay ( ) ;
this . _ _background . appendChild ( this . _ _foreground ) ;
this . domElement . appendChild ( this . _ _background ) ;
} ;
NumberControllerSlider . superclass = NumberController ;
/ * *
* Injects default stylesheet for slider elements .
* /
NumberControllerSlider . useDefaultStyles = function ( ) {
css . inject ( styleSheet ) ;
} ;
common . extend (
NumberControllerSlider . prototype ,
NumberController . prototype ,
{
updateDisplay : function ( ) {
var pct = ( this . getValue ( ) - this . _ _min ) / ( this . _ _max - this . _ _min ) ;
this . _ _foreground . style . width = pct * 100 + '%' ;
return NumberControllerSlider . superclass . prototype . updateDisplay . call ( this ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
) ;
function map ( v , i1 , i2 , o1 , o2 ) {
return o1 + ( o2 - o1 ) * ( ( v - i1 ) / ( i2 - i1 ) ) ;
}
return NumberControllerSlider ;
} ) ( dat . controllers . NumberController ,
dat . dom . dom ,
dat . utils . css ,
dat . utils . common ,
"/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}" ) ;
dat . controllers . FunctionController = ( function ( Controller , dom , common ) {
/ * *
* @ class Provides a GUI interface to fire a specified method , a property of an object .
*
* @ extends dat . controllers . Controller
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
*
* @ member dat . controllers
* /
var FunctionController = function ( object , property , text ) {
FunctionController . superclass . call ( this , object , property ) ;
var _this = this ;
this . _ _button = document . createElement ( 'div' ) ;
this . _ _button . innerHTML = text === undefined ? 'Fire' : text ;
dom . bind ( this . _ _button , 'click' , function ( e ) {
e . preventDefault ( ) ;
_this . fire ( ) ;
return false ;
} ) ;
dom . addClass ( this . _ _button , 'button' ) ;
this . domElement . appendChild ( this . _ _button ) ;
} ;
FunctionController . superclass = Controller ;
common . extend (
FunctionController . prototype ,
Controller . prototype ,
{
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
fire : function ( ) {
if ( this . _ _onChange ) {
this . _ _onChange . call ( this ) ;
}
if ( this . _ _onFinishChange ) {
this . _ _onFinishChange . call ( this , this . getValue ( ) ) ;
}
this . getValue ( ) . call ( this . object ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
) ;
return FunctionController ;
} ) ( dat . controllers . Controller ,
dat . dom . dom ,
dat . utils . common ) ;
dat . controllers . BooleanController = ( function ( Controller , dom , common ) {
/ * *
* @ class Provides a checkbox input to alter the boolean property of an object .
* @ extends dat . controllers . Controller
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
*
* @ member dat . controllers
* /
var BooleanController = function ( object , property ) {
BooleanController . superclass . call ( this , object , property ) ;
var _this = this ;
this . _ _prev = this . getValue ( ) ;
this . _ _checkbox = document . createElement ( 'input' ) ;
this . _ _checkbox . setAttribute ( 'type' , 'checkbox' ) ;
dom . bind ( this . _ _checkbox , 'change' , onChange , false ) ;
this . domElement . appendChild ( this . _ _checkbox ) ;
// Match original value
this . updateDisplay ( ) ;
function onChange ( ) {
_this . setValue ( ! _this . _ _prev ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ;
BooleanController . superclass = Controller ;
common . extend (
BooleanController . prototype ,
Controller . prototype ,
{
setValue : function ( v ) {
var toReturn = BooleanController . superclass . prototype . setValue . call ( this , v ) ;
if ( this . _ _onFinishChange ) {
this . _ _onFinishChange . call ( this , this . getValue ( ) ) ;
}
this . _ _prev = this . getValue ( ) ;
return toReturn ;
} ,
updateDisplay : function ( ) {
if ( this . getValue ( ) === true ) {
this . _ _checkbox . setAttribute ( 'checked' , 'checked' ) ;
this . _ _checkbox . checked = true ;
} else {
this . _ _checkbox . checked = false ;
}
return BooleanController . superclass . prototype . updateDisplay . call ( this ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
) ;
return BooleanController ;
} ) ( dat . controllers . Controller ,
dat . dom . dom ,
dat . utils . common ) ;
dat . color . toString = ( function ( common ) {
return function ( color ) {
if ( color . a == 1 || common . isUndefined ( color . a ) ) {
var s = color . hex . toString ( 16 ) ;
while ( s . length < 6 ) {
s = '0' + s ;
}
return '#' + s ;
} else {
return 'rgba(' + Math . round ( color . r ) + ',' + Math . round ( color . g ) + ',' + Math . round ( color . b ) + ',' + color . a + ')' ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
} ) ( dat . utils . common ) ;
dat . color . interpret = ( function ( toString , common ) {
var result , toReturn ;
var interpret = function ( ) {
toReturn = false ;
var original = arguments . length > 1 ? common . toArray ( arguments ) : arguments [ 0 ] ;
common . each ( INTERPRETATIONS , function ( family ) {
if ( family . litmus ( original ) ) {
common . each ( family . conversions , function ( conversion , conversionName ) {
result = conversion . read ( original ) ;
if ( toReturn === false && result !== false ) {
toReturn = result ;
result . conversionName = conversionName ;
result . conversion = conversion ;
return common . BREAK ;
}
} ) ;
return common . BREAK ;
}
} ) ;
return toReturn ;
} ;
var INTERPRETATIONS = [
// Strings
{
litmus : common . isString ,
conversions : {
THREE _CHAR _HEX : {
read : function ( original ) {
var test = original . match ( /^#([A-F0-9])([A-F0-9])([A-F0-9])$/i ) ;
if ( test === null ) return false ;
return {
space : 'HEX' ,
hex : parseInt (
'0x' +
test [ 1 ] . toString ( ) + test [ 1 ] . toString ( ) +
test [ 2 ] . toString ( ) + test [ 2 ] . toString ( ) +
test [ 3 ] . toString ( ) + test [ 3 ] . toString ( ) )
} ;
} ,
write : toString
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
SIX _CHAR _HEX : {
read : function ( original ) {
var test = original . match ( /^#([A-F0-9]{6})$/i ) ;
if ( test === null ) return false ;
return {
space : 'HEX' ,
hex : parseInt ( '0x' + test [ 1 ] . toString ( ) )
} ;
} ,
write : toString
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
CSS _RGB : {
read : function ( original ) {
var test = original . match ( /^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/ ) ;
if ( test === null ) return false ;
return {
space : 'RGB' ,
r : parseFloat ( test [ 1 ] ) ,
g : parseFloat ( test [ 2 ] ) ,
b : parseFloat ( test [ 3 ] )
} ;
} ,
write : toString
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
CSS _RGBA : {
read : function ( original ) {
var test = original . match ( /^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/ ) ;
if ( test === null ) return false ;
return {
space : 'RGB' ,
r : parseFloat ( test [ 1 ] ) ,
g : parseFloat ( test [ 2 ] ) ,
b : parseFloat ( test [ 3 ] ) ,
a : parseFloat ( test [ 4 ] )
} ;
} ,
write : toString
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
// Numbers
{
litmus : common . isNumber ,
conversions : {
HEX : {
read : function ( original ) {
return {
space : 'HEX' ,
hex : original ,
conversionName : 'HEX'
}
} ,
write : function ( color ) {
return color . hex ;
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
// Arrays
{
litmus : common . isArray ,
conversions : {
RGB _ARRAY : {
read : function ( original ) {
if ( original . length != 3 ) return false ;
2013-12-18 23:27:02 +00:00
return {
space : 'RGB' ,
2014-02-08 17:57:40 +00:00
r : original [ 0 ] ,
g : original [ 1 ] ,
b : original [ 2 ]
} ;
} ,
write : function ( color ) {
return [ color . r , color . g , color . b ] ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
RGBA _ARRAY : {
read : function ( original ) {
if ( original . length != 4 ) return false ;
return {
space : 'RGB' ,
r : original [ 0 ] ,
g : original [ 1 ] ,
b : original [ 2 ] ,
a : original [ 3 ]
} ;
} ,
write : function ( color ) {
return [ color . r , color . g , color . b , color . a ] ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
} ,
// Objects
{
litmus : common . isObject ,
conversions : {
RGBA _OBJ : {
read : function ( original ) {
if ( common . isNumber ( original . r ) &&
common . isNumber ( original . g ) &&
common . isNumber ( original . b ) &&
common . isNumber ( original . a ) ) {
return {
space : 'RGB' ,
r : original . r ,
g : original . g ,
b : original . b ,
a : original . a
}
}
return false ;
} ,
write : function ( color ) {
2013-12-18 23:27:02 +00:00
return {
2014-02-08 17:57:40 +00:00
r : color . r ,
g : color . g ,
b : color . b ,
a : color . a
2013-12-18 23:27:02 +00:00
}
}
} ,
2014-02-08 17:57:40 +00:00
RGB _OBJ : {
read : function ( original ) {
if ( common . isNumber ( original . r ) &&
common . isNumber ( original . g ) &&
common . isNumber ( original . b ) ) {
return {
space : 'RGB' ,
r : original . r ,
g : original . g ,
b : original . b
}
}
return false ;
} ,
write : function ( color ) {
return {
r : color . r ,
g : color . g ,
b : color . b
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
HSVA _OBJ : {
read : function ( original ) {
if ( common . isNumber ( original . h ) &&
common . isNumber ( original . s ) &&
common . isNumber ( original . v ) &&
common . isNumber ( original . a ) ) {
return {
space : 'HSV' ,
h : original . h ,
s : original . s ,
v : original . v ,
a : original . a
}
}
return false ;
} ,
write : function ( color ) {
2013-12-18 23:27:02 +00:00
return {
2014-02-08 17:57:40 +00:00
h : color . h ,
s : color . s ,
v : color . v ,
a : color . a
2013-12-18 23:27:02 +00:00
}
}
} ,
2014-02-08 17:57:40 +00:00
HSV _OBJ : {
read : function ( original ) {
if ( common . isNumber ( original . h ) &&
common . isNumber ( original . s ) &&
common . isNumber ( original . v ) ) {
return {
space : 'HSV' ,
h : original . h ,
s : original . s ,
v : original . v
}
}
return false ;
} ,
write : function ( color ) {
return {
h : color . h ,
s : color . s ,
v : color . v
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
}
] ;
return interpret ;
} ) ( dat . color . toString ,
dat . utils . common ) ;
dat . GUI = dat . gui . GUI = ( function ( css , saveDialogueContents , styleSheet , controllerFactory , Controller , BooleanController , FunctionController , NumberControllerBox , NumberControllerSlider , OptionController , ColorController , requestAnimationFrame , CenteredDiv , dom , common ) {
css . inject ( styleSheet ) ;
/** Outer-most className for GUI's */
var CSS _NAMESPACE = 'dg' ;
var HIDE _KEY _CODE = 72 ;
/** The only value shared between the JS and SCSS. Use caution. */
var CLOSE _BUTTON _HEIGHT = 20 ;
var DEFAULT _DEFAULT _PRESET _NAME = 'Default' ;
var SUPPORTS _LOCAL _STORAGE = ( function ( ) {
try {
return 'localStorage' in window && window [ 'localStorage' ] !== null ;
} catch ( e ) {
return false ;
}
} ) ( ) ;
var SAVE _DIALOGUE ;
/** Have we yet to create an autoPlace GUI? */
var auto _place _virgin = true ;
/** Fixed position div that auto place GUI's go inside */
var auto _place _container ;
/** Are we hiding the GUI's ? */
var hide = false ;
/** GUI's which should be hidden */
var hideable _guis = [ ] ;
/ * *
* A lightweight controller library for JavaScript . It allows you to easily
* manipulate variables and fire functions on the fly .
* @ class
*
* @ member dat . gui
*
* @ param { Object } [ params ]
* @ param { String } [ params . name ] The name of this GUI .
* @ param { Object } [ params . load ] JSON object representing the saved state of
* this GUI .
* @ param { Boolean } [ params . auto = true ]
* @ param { dat . gui . GUI } [ params . parent ] The GUI I ' m nested in .
* @ param { Boolean } [ params . closed ] If true , starts closed
* /
var GUI = function ( params ) {
var _this = this ;
/ * *
* Outermost DOM Element
* @ type DOMElement
* /
this . domElement = document . createElement ( 'div' ) ;
this . _ _ul = document . createElement ( 'ul' ) ;
this . domElement . appendChild ( this . _ _ul ) ;
dom . addClass ( this . domElement , CSS _NAMESPACE ) ;
/ * *
* Nested GUI ' s by name
* @ ignore
* /
this . _ _folders = { } ;
this . _ _controllers = [ ] ;
/ * *
* List of objects I ' m remembering for save , only used in top level GUI
* @ ignore
* /
this . _ _rememberedObjects = [ ] ;
/ * *
* Maps the index of remembered objects to a map of controllers , only used
* in top level GUI .
*
* @ private
* @ ignore
*
* @ example
* [
* {
* propertyName : Controller ,
* anotherPropertyName : Controller
* } ,
* {
* propertyName : Controller
* }
* ]
* /
this . _ _rememberedObjectIndecesToControllers = [ ] ;
this . _ _listening = [ ] ;
params = params || { } ;
// Default parameters
params = common . defaults ( params , {
autoPlace : true ,
width : GUI . DEFAULT _WIDTH
} ) ;
params = common . defaults ( params , {
resizable : params . autoPlace ,
hideable : params . autoPlace
} ) ;
if ( ! common . isUndefined ( params . load ) ) {
// Explicit preset
if ( params . preset ) params . load . preset = params . preset ;
} else {
params . load = { preset : DEFAULT _DEFAULT _PRESET _NAME } ;
}
if ( common . isUndefined ( params . parent ) && params . hideable ) {
hideable _guis . push ( this ) ;
}
// Only root level GUI's are resizable.
params . resizable = common . isUndefined ( params . parent ) && params . resizable ;
if ( params . autoPlace && common . isUndefined ( params . scrollable ) ) {
params . scrollable = true ;
}
// params.scrollable = common.isUndefined(params.parent) && params.scrollable === true;
// Not part of params because I don't want people passing this in via
// constructor. Should be a 'remembered' value.
var use _local _storage =
SUPPORTS _LOCAL _STORAGE &&
localStorage . getItem ( getLocalStorageHash ( this , 'isLocal' ) ) === 'true' ;
var saveToLocalStorage ;
Object . defineProperties ( this ,
/** @lends dat.gui.GUI.prototype */
{
/ * *
* The parent < code > GUI < / c o d e >
* @ type dat . gui . GUI
* /
parent : {
get : function ( ) {
return params . parent ;
}
} ,
scrollable : {
get : function ( ) {
return params . scrollable ;
}
} ,
/ * *
* Handles < code > GUI < / c o d e > ' s e l e m e n t p l a c e m e n t f o r y o u
* @ type Boolean
* /
autoPlace : {
get : function ( ) {
return params . autoPlace ;
}
} ,
/ * *
* The identifier for a set of saved values
* @ type String
* /
preset : {
get : function ( ) {
if ( _this . parent ) {
return _this . getRoot ( ) . preset ;
} else {
return params . load . preset ;
}
} ,
set : function ( v ) {
if ( _this . parent ) {
_this . getRoot ( ) . preset = v ;
} else {
params . load . preset = v ;
}
setPresetSelectIndex ( this ) ;
_this . revert ( ) ;
}
} ,
/ * *
* The width of < code > GUI < / c o d e > e l e m e n t
* @ type Number
* /
width : {
get : function ( ) {
return params . width ;
} ,
set : function ( v ) {
params . width = v ;
setWidth ( _this , v ) ;
}
} ,
/ * *
* The name of < code > GUI < / c o d e > . U s e d f o r f o l d e r s . i . e
* a folder ' s name
* @ type String
* /
name : {
get : function ( ) {
return params . name ;
} ,
set : function ( v ) {
// TODO Check for collisions among sibling folders
params . name = v ;
if ( title _row _name ) {
title _row _name . innerHTML = params . name ;
}
}
} ,
/ * *
* Whether the < code > GUI < / c o d e > i s c o l l a p s e d o r n o t
* @ type Boolean
* /
closed : {
get : function ( ) {
return params . closed ;
} ,
set : function ( v ) {
params . closed = v ;
if ( params . closed ) {
dom . addClass ( _this . _ _ul , GUI . CLASS _CLOSED ) ;
} else {
dom . removeClass ( _this . _ _ul , GUI . CLASS _CLOSED ) ;
}
// For browsers that aren't going to respect the CSS transition,
// Lets just check our height against the window height right off
// the bat.
this . onResize ( ) ;
if ( _this . _ _closeButton ) {
_this . _ _closeButton . innerHTML = v ? GUI . TEXT _OPEN : GUI . TEXT _CLOSED ;
}
}
} ,
/ * *
* Contains all presets
* @ type Object
* /
load : {
get : function ( ) {
return params . load ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
/ * *
* Determines whether or not to use < a href = "https://developer.mozilla.org/en/DOM/Storage#localStorage" > localStorage < / a > a s t h e m e a n s f o r
* < code > remember < / c o d e > i n g
* @ type Boolean
* /
useLocalStorage : {
get : function ( ) {
return use _local _storage ;
} ,
set : function ( bool ) {
if ( SUPPORTS _LOCAL _STORAGE ) {
use _local _storage = bool ;
if ( bool ) {
dom . bind ( window , 'unload' , saveToLocalStorage ) ;
} else {
dom . unbind ( window , 'unload' , saveToLocalStorage ) ;
}
localStorage . setItem ( getLocalStorageHash ( _this , 'isLocal' ) , bool ) ;
}
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ;
// Are we a root level GUI?
if ( common . isUndefined ( params . parent ) ) {
params . closed = false ;
dom . addClass ( this . domElement , GUI . CLASS _MAIN ) ;
dom . makeSelectable ( this . domElement , false ) ;
// Are we supposed to be loading locally?
if ( SUPPORTS _LOCAL _STORAGE ) {
if ( use _local _storage ) {
_this . useLocalStorage = true ;
var saved _gui = localStorage . getItem ( getLocalStorageHash ( this , 'gui' ) ) ;
if ( saved _gui ) {
params . load = JSON . parse ( saved _gui ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . _ _closeButton = document . createElement ( 'div' ) ;
this . _ _closeButton . innerHTML = GUI . TEXT _CLOSED ;
dom . addClass ( this . _ _closeButton , GUI . CLASS _CLOSE _BUTTON ) ;
this . domElement . appendChild ( this . _ _closeButton ) ;
dom . bind ( this . _ _closeButton , 'click' , function ( ) {
_this . closed = ! _this . closed ;
} ) ;
// Oh, you're a nested GUI!
} else {
if ( params . closed === undefined ) {
params . closed = true ;
}
var title _row _name = document . createTextNode ( params . name ) ;
dom . addClass ( title _row _name , 'controller-name' ) ;
var title _row = addRow ( _this , title _row _name ) ;
var on _click _title = function ( e ) {
e . preventDefault ( ) ;
_this . closed = ! _this . closed ;
return false ;
} ;
dom . addClass ( this . _ _ul , GUI . CLASS _CLOSED ) ;
dom . addClass ( title _row , 'title' ) ;
dom . bind ( title _row , 'click' , on _click _title ) ;
if ( ! params . closed ) {
this . closed = false ;
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
if ( params . autoPlace ) {
if ( common . isUndefined ( params . parent ) ) {
if ( auto _place _virgin ) {
auto _place _container = document . createElement ( 'div' ) ;
dom . addClass ( auto _place _container , CSS _NAMESPACE ) ;
dom . addClass ( auto _place _container , GUI . CLASS _AUTO _PLACE _CONTAINER ) ;
document . body . appendChild ( auto _place _container ) ;
auto _place _virgin = false ;
}
// Put it in the dom for you.
auto _place _container . appendChild ( this . domElement ) ;
// Apply the auto styles
dom . addClass ( this . domElement , GUI . CLASS _AUTO _PLACE ) ;
}
// Make it not elastic.
if ( ! this . parent ) setWidth ( _this , params . width ) ;
}
dom . bind ( window , 'resize' , function ( ) { _this . onResize ( ) } ) ;
dom . bind ( this . _ _ul , 'webkitTransitionEnd' , function ( ) { _this . onResize ( ) ; } ) ;
dom . bind ( this . _ _ul , 'transitionend' , function ( ) { _this . onResize ( ) } ) ;
dom . bind ( this . _ _ul , 'oTransitionEnd' , function ( ) { _this . onResize ( ) } ) ;
this . onResize ( ) ;
if ( params . resizable ) {
addResizeHandle ( this ) ;
}
saveToLocalStorage = function ( ) {
if ( SUPPORTS _LOCAL _STORAGE && localStorage . getItem ( getLocalStorageHash ( _this , 'isLocal' ) ) === 'true' ) {
localStorage . setItem ( getLocalStorageHash ( _this , 'gui' ) , JSON . stringify ( _this . getSaveObject ( ) ) ) ;
}
}
// expose this method publicly
this . saveToLocalStorageIfPossible = saveToLocalStorage ;
var root = _this . getRoot ( ) ;
function resetWidth ( ) {
var root = _this . getRoot ( ) ;
root . width += 1 ;
common . defer ( function ( ) {
root . width -= 1 ;
} ) ;
}
if ( ! params . parent ) {
resetWidth ( ) ;
}
} ;
GUI . toggleHide = function ( ) {
hide = ! hide ;
common . each ( hideable _guis , function ( gui ) {
gui . domElement . style . zIndex = hide ? - 999 : 999 ;
gui . domElement . style . opacity = hide ? 0 : 1 ;
} ) ;
} ;
GUI . CLASS _AUTO _PLACE = 'a' ;
GUI . CLASS _AUTO _PLACE _CONTAINER = 'ac' ;
GUI . CLASS _MAIN = 'main' ;
GUI . CLASS _CONTROLLER _ROW = 'cr' ;
GUI . CLASS _TOO _TALL = 'taller-than-window' ;
GUI . CLASS _CLOSED = 'closed' ;
GUI . CLASS _CLOSE _BUTTON = 'close-button' ;
GUI . CLASS _DRAG = 'drag' ;
GUI . DEFAULT _WIDTH = 245 ;
GUI . TEXT _CLOSED = 'Close Controls' ;
GUI . TEXT _OPEN = 'Open Controls' ;
dom . bind ( window , 'keydown' , function ( e ) {
if ( document . activeElement . type !== 'text' &&
( e . which === HIDE _KEY _CODE || e . keyCode == HIDE _KEY _CODE ) ) {
GUI . toggleHide ( ) ;
}
} , false ) ;
common . extend (
GUI . prototype ,
/** @lends dat.gui.GUI */
2013-12-18 23:27:02 +00:00
{
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ param object
* @ param property
* @ returns { dat . controllers . Controller } The new controller that was added .
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
add : function ( object , property ) {
return add (
this ,
object ,
property ,
{
factoryArgs : Array . prototype . slice . call ( arguments , 2 )
}
) ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
/ * *
* @ param object
* @ param property
* @ returns { dat . controllers . ColorController } The new controller that was added .
* @ instance
* /
addColor : function ( object , property ) {
return add (
this ,
object ,
property ,
{
color : true
}
) ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ param controller
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
remove : function ( controller ) {
// TODO listening?
this . _ _ul . removeChild ( controller . _ _li ) ;
this . _ _controllers . slice ( this . _ _controllers . indexOf ( controller ) , 1 ) ;
var _this = this ;
common . defer ( function ( ) {
_this . onResize ( ) ;
} ) ;
} ,
destroy : function ( ) {
if ( this . autoPlace ) {
auto _place _container . removeChild ( this . domElement ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ param name
* @ returns { dat . gui . GUI } The new folder .
* @ throws { Error } if this GUI already has a folder by the specified
* name
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
addFolder : function ( name ) {
// We have to prevent collisions on names in order to have a key
// by which to remember saved values
if ( this . _ _folders [ name ] !== undefined ) {
throw new Error ( 'You already have a folder in this GUI by the' +
' name "' + name + '"' ) ;
}
var new _gui _params = { name : name , parent : this } ;
// We need to pass down the autoPlace trait so that we can
// attach event listeners to open/close folder actions to
// ensure that a scrollbar appears if the window is too short.
new _gui _params . autoPlace = this . autoPlace ;
// Do we have saved appearance data for this folder?
if ( this . load && // Anything loaded?
this . load . folders && // Was my parent a dead-end?
this . load . folders [ name ] ) { // Did daddy remember me?
// Start me closed if I was closed
new _gui _params . closed = this . load . folders [ name ] . closed ;
// Pass down the loaded data
new _gui _params . load = this . load . folders [ name ] ;
}
var gui = new GUI ( new _gui _params ) ;
this . _ _folders [ name ] = gui ;
var li = addRow ( this , gui . domElement ) ;
dom . addClass ( li , 'folder' ) ;
return gui ;
} ,
open : function ( ) {
this . closed = false ;
} ,
close : function ( ) {
this . closed = true ;
} ,
onResize : function ( ) {
var root = this . getRoot ( ) ;
if ( root . scrollable ) {
var top = dom . getOffset ( root . _ _ul ) . top ;
var h = 0 ;
common . each ( root . _ _ul . childNodes , function ( node ) {
if ( ! ( root . autoPlace && node === root . _ _save _row ) )
h += dom . getHeight ( node ) ;
} ) ;
if ( window . innerHeight - top - CLOSE _BUTTON _HEIGHT < h ) {
dom . addClass ( root . domElement , GUI . CLASS _TOO _TALL ) ;
root . _ _ul . style . height = window . innerHeight - top - CLOSE _BUTTON _HEIGHT + 'px' ;
2013-12-18 23:27:02 +00:00
} else {
2014-02-08 17:57:40 +00:00
dom . removeClass ( root . domElement , GUI . CLASS _TOO _TALL ) ;
root . _ _ul . style . height = 'auto' ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
if ( root . _ _resize _handle ) {
common . defer ( function ( ) {
root . _ _resize _handle . style . height = root . _ _ul . offsetHeight + 'px' ;
} ) ;
}
if ( root . _ _closeButton ) {
root . _ _closeButton . style . width = root . width + 'px' ;
}
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* Mark objects for saving . The order of these objects cannot change as
* the GUI grows . When remembering new objects , append them to the end
* of the list .
*
* @ param { Object ... } objects
* @ throws { Error } if not called on a top level GUI .
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
remember : function ( ) {
if ( common . isUndefined ( SAVE _DIALOGUE ) ) {
SAVE _DIALOGUE = new CenteredDiv ( ) ;
SAVE _DIALOGUE . domElement . innerHTML = saveDialogueContents ;
}
if ( this . parent ) {
throw new Error ( "You can only call remember on a top level GUI." ) ;
}
var _this = this ;
common . each ( Array . prototype . slice . call ( arguments ) , function ( object ) {
if ( _this . _ _rememberedObjects . length == 0 ) {
addSaveMenu ( _this ) ;
}
if ( _this . _ _rememberedObjects . indexOf ( object ) == - 1 ) {
_this . _ _rememberedObjects . push ( object ) ;
}
} ) ;
if ( this . autoPlace ) {
// Set save row width
setWidth ( this , this . width ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ returns { dat . gui . GUI } the topmost parent GUI of a nested GUI .
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
getRoot : function ( ) {
var gui = this ;
while ( gui . parent ) {
gui = gui . parent ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
return gui ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
/ * *
2014-02-08 17:57:40 +00:00
* @ returns { Object } a JSON object representing the current state of
* this GUI as well as its remembered properties .
* @ instance
2013-12-18 23:27:02 +00:00
* /
2014-02-08 17:57:40 +00:00
getSaveObject : function ( ) {
var toReturn = this . load ;
toReturn . closed = this . closed ;
// Am I remembering any values?
if ( this . _ _rememberedObjects . length > 0 ) {
toReturn . preset = this . preset ;
if ( ! toReturn . remembered ) {
toReturn . remembered = { } ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
toReturn . remembered [ this . preset ] = getCurrentPreset ( this ) ;
}
toReturn . folders = { } ;
common . each ( this . _ _folders , function ( element , key ) {
toReturn . folders [ key ] = element . getSaveObject ( ) ;
} ) ;
return toReturn ;
} ,
save : function ( ) {
if ( ! this . load . remembered ) {
this . load . remembered = { } ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . load . remembered [ this . preset ] = getCurrentPreset ( this ) ;
markPresetModified ( this , false ) ;
this . saveToLocalStorageIfPossible ( ) ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
saveAs : function ( presetName ) {
if ( ! this . load . remembered ) {
// Retain default values upon first save
this . load . remembered = { } ;
this . load . remembered [ DEFAULT _DEFAULT _PRESET _NAME ] = getCurrentPreset ( this , true ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . load . remembered [ presetName ] = getCurrentPreset ( this ) ;
this . preset = presetName ;
addPresetOption ( this , presetName , true ) ;
this . saveToLocalStorageIfPossible ( ) ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
revert : function ( gui ) {
common . each ( this . _ _controllers , function ( controller ) {
// Make revert work on Default.
if ( ! this . getRoot ( ) . load . remembered ) {
controller . setValue ( controller . initialValue ) ;
} else {
recallSavedValue ( gui || this . getRoot ( ) , controller ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} , this ) ;
common . each ( this . _ _folders , function ( folder ) {
folder . revert ( folder ) ;
} ) ;
if ( ! gui ) {
markPresetModified ( this . getRoot ( ) , false ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ,
listen : function ( controller ) {
var init = this . _ _listening . length == 0 ;
this . _ _listening . push ( controller ) ;
if ( init ) updateDisplays ( this . _ _listening ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
function add ( gui , object , property , params ) {
if ( object [ property ] === undefined ) {
throw new Error ( "Object " + object + " has no property \"" + property + "\"" ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
var controller ;
if ( params . color ) {
controller = new ColorController ( object , property ) ;
} else {
var factoryArgs = [ object , property ] . concat ( params . factoryArgs ) ;
controller = controllerFactory . apply ( gui , factoryArgs ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
if ( params . before instanceof Controller ) {
params . before = params . before . _ _li ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
recallSavedValue ( gui , controller ) ;
dom . addClass ( controller . domElement , 'c' ) ;
var name = document . createElement ( 'span' ) ;
dom . addClass ( name , 'property-name' ) ;
name . innerHTML = controller . property ;
var container = document . createElement ( 'div' ) ;
container . appendChild ( name ) ;
container . appendChild ( controller . domElement ) ;
var li = addRow ( gui , container , params . before ) ;
dom . addClass ( li , GUI . CLASS _CONTROLLER _ROW ) ;
dom . addClass ( li , typeof controller . getValue ( ) ) ;
augmentController ( gui , li , controller ) ;
gui . _ _controllers . push ( controller ) ;
return controller ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
/ * *
* Add a row to the end of the GUI or before another row .
*
* @ param gui
* @ param [ dom ] If specified , inserts the dom content in the new row
* @ param [ liBefore ] If specified , places the new row before another row
* /
function addRow ( gui , dom , liBefore ) {
var li = document . createElement ( 'li' ) ;
if ( dom ) li . appendChild ( dom ) ;
if ( liBefore ) {
gui . _ _ul . insertBefore ( li , params . before ) ;
} else {
gui . _ _ul . appendChild ( li ) ;
2014-01-23 07:26:25 +00:00
}
2014-02-08 17:57:40 +00:00
gui . onResize ( ) ;
return li ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function augmentController ( gui , li , controller ) {
controller . _ _li = li ;
controller . _ _gui = gui ;
common . extend ( controller , {
options : function ( options ) {
if ( arguments . length > 1 ) {
controller . remove ( ) ;
return add (
gui ,
controller . object ,
controller . property ,
{
before : controller . _ _li . nextElementSibling ,
factoryArgs : [ common . toArray ( arguments ) ]
}
) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
if ( common . isArray ( options ) || common . isObject ( options ) ) {
controller . remove ( ) ;
return add (
gui ,
controller . object ,
controller . property ,
{
before : controller . _ _li . nextElementSibling ,
factoryArgs : [ options ]
}
) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
name : function ( v ) {
controller . _ _li . firstElementChild . firstElementChild . innerHTML = v ;
return controller ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
listen : function ( ) {
controller . _ _gui . listen ( controller ) ;
return controller ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
remove : function ( ) {
controller . _ _gui . remove ( controller ) ;
return controller ;
}
} ) ;
// All sliders should be accompanied by a box.
if ( controller instanceof NumberControllerSlider ) {
var box = new NumberControllerBox ( controller . object , controller . property ,
{ min : controller . _ _min , max : controller . _ _max , step : controller . _ _step } ) ;
common . each ( [ 'updateDisplay' , 'onChange' , 'onFinishChange' ] , function ( method ) {
var pc = controller [ method ] ;
var pb = box [ method ] ;
controller [ method ] = box [ method ] = function ( ) {
var args = Array . prototype . slice . call ( arguments ) ;
pc . apply ( controller , args ) ;
return pb . apply ( box , args ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ;
dom . addClass ( li , 'has-slider' ) ;
controller . domElement . insertBefore ( box . domElement , controller . domElement . firstElementChild ) ;
}
else if ( controller instanceof NumberControllerBox ) {
var r = function ( returned ) {
// Have we defined both boundaries?
if ( common . isNumber ( controller . _ _min ) && common . isNumber ( controller . _ _max ) ) {
// Well, then lets just replace this with a slider.
controller . remove ( ) ;
return add (
gui ,
controller . object ,
controller . property ,
{
before : controller . _ _li . nextElementSibling ,
factoryArgs : [ controller . _ _min , controller . _ _max , controller . _ _step ]
} ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
return returned ;
} ;
controller . min = common . compose ( r , controller . min ) ;
controller . max = common . compose ( r , controller . max ) ;
}
else if ( controller instanceof BooleanController ) {
dom . bind ( li , 'click' , function ( ) {
dom . fakeEvent ( controller . _ _checkbox , 'click' ) ;
} ) ;
dom . bind ( controller . _ _checkbox , 'click' , function ( e ) {
e . stopPropagation ( ) ; // Prevents double-toggle
} )
}
else if ( controller instanceof FunctionController ) {
dom . bind ( li , 'click' , function ( ) {
dom . fakeEvent ( controller . _ _button , 'click' ) ;
} ) ;
dom . bind ( li , 'mouseover' , function ( ) {
dom . addClass ( controller . _ _button , 'hover' ) ;
} ) ;
dom . bind ( li , 'mouseout' , function ( ) {
dom . removeClass ( controller . _ _button , 'hover' ) ;
} ) ;
}
else if ( controller instanceof ColorController ) {
dom . addClass ( li , 'color' ) ;
controller . updateDisplay = common . compose ( function ( r ) {
li . style . borderLeftColor = controller . _ _color . toString ( ) ;
return r ;
} , controller . updateDisplay ) ;
controller . updateDisplay ( ) ;
}
controller . setValue = common . compose ( function ( r ) {
if ( gui . getRoot ( ) . _ _preset _select && controller . isModified ( ) ) {
markPresetModified ( gui . getRoot ( ) , true ) ;
}
return r ;
} , controller . setValue ) ;
}
function recallSavedValue ( gui , controller ) {
// Find the topmost GUI, that's where remembered objects live.
var root = gui . getRoot ( ) ;
// Does the object we're controlling match anything we've been told to
// remember?
var matched _index = root . _ _rememberedObjects . indexOf ( controller . object ) ;
// Why yes, it does!
if ( matched _index != - 1 ) {
// Let me fetch a map of controllers for thcommon.isObject.
var controller _map =
root . _ _rememberedObjectIndecesToControllers [ matched _index ] ;
// Ohp, I believe this is the first controller we've created for this
// object. Lets make the map fresh.
if ( controller _map === undefined ) {
controller _map = { } ;
root . _ _rememberedObjectIndecesToControllers [ matched _index ] =
controller _map ;
}
// Keep track of this controller
controller _map [ controller . property ] = controller ;
// Okay, now have we saved any values for this controller?
if ( root . load && root . load . remembered ) {
var preset _map = root . load . remembered ;
// Which preset are we trying to load?
var preset ;
if ( preset _map [ gui . preset ] ) {
preset = preset _map [ gui . preset ] ;
} else if ( preset _map [ DEFAULT _DEFAULT _PRESET _NAME ] ) {
// Uhh, you can have the default instead?
preset = preset _map [ DEFAULT _DEFAULT _PRESET _NAME ] ;
} else {
// Nada.
return ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
// Did the loaded object remember thcommon.isObject?
if ( preset [ matched _index ] &&
// Did we remember this particular property?
preset [ matched _index ] [ controller . property ] !== undefined ) {
// We did remember something for this guy ...
var value = preset [ matched _index ] [ controller . property ] ;
// And that's what it is.
controller . initialValue = value ;
controller . setValue ( value ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function getLocalStorageHash ( gui , key ) {
// TODO how does this deal with multiple GUI's?
return document . location . href + '.' + key ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function addSaveMenu ( gui ) {
var div = gui . _ _save _row = document . createElement ( 'li' ) ;
dom . addClass ( gui . domElement , 'has-save' ) ;
gui . _ _ul . insertBefore ( div , gui . _ _ul . firstChild ) ;
dom . addClass ( div , 'save-row' ) ;
var gears = document . createElement ( 'span' ) ;
gears . innerHTML = ' ' ;
dom . addClass ( gears , 'button gears' ) ;
// TODO replace with FunctionController
var button = document . createElement ( 'span' ) ;
button . innerHTML = 'Save' ;
dom . addClass ( button , 'button' ) ;
dom . addClass ( button , 'save' ) ;
var button2 = document . createElement ( 'span' ) ;
button2 . innerHTML = 'New' ;
dom . addClass ( button2 , 'button' ) ;
dom . addClass ( button2 , 'save-as' ) ;
var button3 = document . createElement ( 'span' ) ;
button3 . innerHTML = 'Revert' ;
dom . addClass ( button3 , 'button' ) ;
dom . addClass ( button3 , 'revert' ) ;
var select = gui . _ _preset _select = document . createElement ( 'select' ) ;
if ( gui . load && gui . load . remembered ) {
common . each ( gui . load . remembered , function ( value , key ) {
addPresetOption ( gui , key , key == gui . preset ) ;
} ) ;
} else {
addPresetOption ( gui , DEFAULT _DEFAULT _PRESET _NAME , false ) ;
}
dom . bind ( select , 'change' , function ( ) {
for ( var index = 0 ; index < gui . _ _preset _select . length ; index ++ ) {
gui . _ _preset _select [ index ] . innerHTML = gui . _ _preset _select [ index ] . value ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
gui . preset = this . value ;
} ) ;
div . appendChild ( select ) ;
div . appendChild ( gears ) ;
div . appendChild ( button ) ;
div . appendChild ( button2 ) ;
div . appendChild ( button3 ) ;
if ( SUPPORTS _LOCAL _STORAGE ) {
var saveLocally = document . getElementById ( 'dg-save-locally' ) ;
var explain = document . getElementById ( 'dg-local-explain' ) ;
saveLocally . style . display = 'block' ;
var localStorageCheckBox = document . getElementById ( 'dg-local-storage' ) ;
if ( localStorage . getItem ( getLocalStorageHash ( gui , 'isLocal' ) ) === 'true' ) {
localStorageCheckBox . setAttribute ( 'checked' , 'checked' ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function showHideExplain ( ) {
explain . style . display = gui . useLocalStorage ? 'block' : 'none' ;
}
showHideExplain ( ) ;
// TODO: Use a boolean controller, fool!
dom . bind ( localStorageCheckBox , 'change' , function ( ) {
gui . useLocalStorage = ! gui . useLocalStorage ;
showHideExplain ( ) ;
} ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
var newConstructorTextArea = document . getElementById ( 'dg-new-constructor' ) ;
dom . bind ( newConstructorTextArea , 'keydown' , function ( e ) {
if ( e . metaKey && ( e . which === 67 || e . keyCode == 67 ) ) {
SAVE _DIALOGUE . hide ( ) ;
2013-12-18 23:27:02 +00:00
}
} ) ;
2014-02-08 17:57:40 +00:00
dom . bind ( gears , 'click' , function ( ) {
newConstructorTextArea . innerHTML = JSON . stringify ( gui . getSaveObject ( ) , undefined , 2 ) ;
SAVE _DIALOGUE . show ( ) ;
newConstructorTextArea . focus ( ) ;
newConstructorTextArea . select ( ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
dom . bind ( button , 'click' , function ( ) {
gui . save ( ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
dom . bind ( button2 , 'click' , function ( ) {
var presetName = prompt ( 'Enter a new preset name.' ) ;
if ( presetName ) gui . saveAs ( presetName ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
dom . bind ( button3 , 'click' , function ( ) {
gui . revert ( ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
// div.appendChild(button2);
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function addResizeHandle ( gui ) {
gui . _ _resize _handle = document . createElement ( 'div' ) ;
common . extend ( gui . _ _resize _handle . style , {
width : '6px' ,
marginLeft : '-3px' ,
height : '200px' ,
cursor : 'ew-resize' ,
position : 'absolute'
// border: '1px solid blue'
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
var pmouseX ;
dom . bind ( gui . _ _resize _handle , 'mousedown' , dragStart ) ;
dom . bind ( gui . _ _closeButton , 'mousedown' , dragStart ) ;
gui . domElement . insertBefore ( gui . _ _resize _handle , gui . domElement . firstElementChild ) ;
function dragStart ( e ) {
e . preventDefault ( ) ;
pmouseX = e . clientX ;
dom . addClass ( gui . _ _closeButton , GUI . CLASS _DRAG ) ;
dom . bind ( window , 'mousemove' , drag ) ;
dom . bind ( window , 'mouseup' , dragStop ) ;
return false ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function drag ( e ) {
e . preventDefault ( ) ;
gui . width += pmouseX - e . clientX ;
gui . onResize ( ) ;
pmouseX = e . clientX ;
return false ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function dragStop ( ) {
dom . removeClass ( gui . _ _closeButton , GUI . CLASS _DRAG ) ;
dom . unbind ( window , 'mousemove' , drag ) ;
dom . unbind ( window , 'mouseup' , dragStop ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function setWidth ( gui , w ) {
gui . domElement . style . width = w + 'px' ;
// Auto placed save-rows are position fixed, so we have to
// set the width manually if we want it to bleed to the edge
if ( gui . _ _save _row && gui . autoPlace ) {
gui . _ _save _row . style . width = w + 'px' ;
} if ( gui . _ _closeButton ) {
gui . _ _closeButton . style . width = w + 'px' ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
function getCurrentPreset ( gui , useInitialValues ) {
var toReturn = { } ;
// For each object I'm remembering
common . each ( gui . _ _rememberedObjects , function ( val , index ) {
var saved _values = { } ;
// The controllers I've made for thcommon.isObject by property
var controller _map =
gui . _ _rememberedObjectIndecesToControllers [ index ] ;
// Remember each value for each property
common . each ( controller _map , function ( controller , property ) {
saved _values [ property ] = useInitialValues ? controller . initialValue : controller . getValue ( ) ;
} ) ;
// Save the values for thcommon.isObject
toReturn [ index ] = saved _values ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
return toReturn ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function addPresetOption ( gui , name , setSelected ) {
var opt = document . createElement ( 'option' ) ;
opt . innerHTML = name ;
opt . value = name ;
gui . _ _preset _select . appendChild ( opt ) ;
if ( setSelected ) {
gui . _ _preset _select . selectedIndex = gui . _ _preset _select . length - 1 ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
function setPresetSelectIndex ( gui ) {
for ( var index = 0 ; index < gui . _ _preset _select . length ; index ++ ) {
if ( gui . _ _preset _select [ index ] . value == gui . preset ) {
gui . _ _preset _select . selectedIndex = index ;
}
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function markPresetModified ( gui , modified ) {
var opt = gui . _ _preset _select [ gui . _ _preset _select . selectedIndex ] ;
// console.log('mark', modified, opt);
if ( modified ) {
opt . innerHTML = opt . value + "*" ;
} else {
opt . innerHTML = opt . value ;
}
}
function updateDisplays ( controllerArray ) {
if ( controllerArray . length != 0 ) {
requestAnimationFrame ( function ( ) {
updateDisplays ( controllerArray ) ;
} ) ;
}
common . each ( controllerArray , function ( c ) {
c . updateDisplay ( ) ;
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
return GUI ;
} ) ( dat . utils . css ,
"<div id=\"dg-save\" class=\"dg dialogue\">\n\n Here's the new load parameter for your <code>GUI</code>'s constructor:\n\n <textarea id=\"dg-new-constructor\"></textarea>\n\n <div id=\"dg-save-locally\">\n\n <input id=\"dg-local-storage\" type=\"checkbox\"/> Automatically save\n values to <code>localStorage</code> on exit.\n\n <div id=\"dg-local-explain\">The values saved to <code>localStorage</code> will\n override those passed to <code>dat.GUI</code>'s constructor. This makes it\n easier to work incrementally, but <code>localStorage</code> is fragile,\n and your friends may not see the same values you do.\n \n </div>\n \n </div>\n\n</div>" ,
" . dg { \ n /** Clear list styles */ \ n /* Auto-place container */ \ n /* Auto-placed GUI's */ \ n /* Line items that don't contain folders. */ \ n /** Folder names */ \ n /** Hides closed items */ \ n /** Controller row */ \ n /** Name-half (left) */ \ n /** Controller-half (right) */ \ n /** Controller placement */ \ n /** Shorter number boxes when slider is present. */ \ n /** Ensure the entire boolean and function row shows a hand */ } \ n . dg ul { \ n list - style : none ; \ n margin : 0 ; \ n padding : 0 ; \ n width : 100 % ; \ n clear : both ; } \ n . dg . ac { \ n position : fixed ; \ n top : 0 ; \ n left : 0 ; \ n right : 0 ; \ n height : 0 ; \ n z - index : 0 ; } \ n . dg : not ( . ac ) . main { \ n /** Exclude mains in ac so that we don't hide close button */ \ n overflow : hidden ; } \ n . dg . main { \ n - webkit - transition : opacity 0.1 s linear ; \ n - o - transition : opacity 0.1 s linear ; \ n - moz - transition : opacity 0.1 s linear ; \ n transition : opacity 0.1 s linear ; } \ n . dg . main . taller - than - window { \ n overflow - y : auto ; } \ n . dg . main . taller - than - window . close - button { \ n opacity : 1 ; \ n /* TODO, these are style notes */ \ n margin - top : - 1 px ; \ n border - top : 1 px solid # 2 c2c2c ; } \ n . dg . main ul . closed . close - button { \ n opacity : 1 ! important ; } \ n . dg . main : hover . close - button , \ n . dg . main . close - button . drag { \ n opacity : 1 ; } \ n . dg . main . close - button { \ n /*opacity: 0;*/ \ n - webkit - transition : opacity 0.1 s linear ; \ n - o - transition : opacity 0.1 s linear ; \ n - moz - transition : opacity 0.1 s linear ; \ n transition : opacity 0.1 s linear ; \ n border : 0 ; \ n position : absolute ; \ n line - height : 19 px ; \ n height : 20 px ; \ n /* TODO, these are style notes */ \ n cursor : pointer ; \ n text - align : center ; \ n background - color : # 000 ; } \ n . dg . main . close - button : hover { \ n background - color : # 111 ; } \ n . dg . a { \ n float : right ; \ n margin - right : 15 px ; \ n overflow - x : hidden ; } \ n . dg . a . has - save > ul { \ n margin - top : 27 px ; } \ n . dg . a . has - save > ul . closed { \ n margin - top : 0 ; } \ n . dg . a . save - row { \ n position : fixed ; \ n top : 0 ; \ n z - index : 1002 ; } \ n . dg li { \ n - webkit - transition : height 0.1 s ease - out ; \ n - o - transition : height 0.1 s ease - out ; \ n - moz - transition : height 0.1 s ease - out ; \ n transition : height 0.1 s ease - out ; } \ n . dg li : not ( . folder ) { \ n cursor : auto ; \ n height : 27 px ; \ n line - height : 27 px ; \ n overflow : hidden ; \ n padding : 0 4 px 0 5 px ; } \ n . dg li . folder { \ n padding : 0 ; \ n border - left : 4 px solid rgba ( 0 , 0 , 0 , 0 ) ; } \ n . dg li . title { \ n cursor : pointer ; \ n margin - left : - 4 px ; } \ n . dg . closed li : not ( . title ) , \ n . dg . closed ul li , \ n . dg . closed ul li > * { \ n height : 0 ; \ n overflow : hidden ; \ n border : 0 ; } \ n . dg . cr { \ n clear : both ; \ n padding - left : 3 px ; \ n height : 27 px ; } \ n . dg . property - name { \ n cursor : default ; \ n float : left ; \ n clear : left ; \ n width : 40 % ; \ n overflow : hidden ; \ n text - overflow : ellipsis ; } \ n . dg . c { \ n float : left ; \ n width : 60 % ; } \ n . dg . c input [ type = text ] { \ n border : 0 ; \ n margin - top : 4 px ; \ n padding : 3 px ; \ n width : 100 % ; \ n float : right ; } \ n . dg . has - slider input [ type = text ] { \ n width : 30 % ; \ n /*display: none;*/ \ n margin - left : 0 ; } \ n . dg . slider { \ n float : left ; \ n width : 66 % ; \ n margin - left : - 5 px ; \ n margin - right : 0 ; \ n height : 19 px ; \ n margin - top : 4 px ; } \ n . dg . slider - fg { \ n height : 100 % ; } \ n . dg . c input [ type = checkbox ] { \ n margin - top : 9 px ; } \ n . dg . c select { \ n margin - top : 5 px ; } \ n . dg . cr . function , \ n . dg . cr . function . property - name , \ n . dg . cr . function * , \ n . dg . cr . boolean , \ n . dg . cr . boolean * { \ n cursor : pointer ; } \ n . dg . selector { \ n display : none ; \ n position : absolute ; \ n margin - left : - 9 px ; \ n margin - top : 23 px ; \ n z - index : 10 ; } \ n . dg . c : hover . selector , \ n . dg . selector . drag { \ n display : block ; } \ n . dg li . save - row { \ n padding : 0 ; } \ n . dg li . save - row . button { \ n display : inline - block ; \ n padding : 0 px 6 px ; } \ n . dg . dialogue { \ n background - color : # 222 ; \ n
dat . controllers . factory = ( function ( OptionController , NumberControllerBox , NumberControllerSlider , StringController , FunctionController , BooleanController , common ) {
return function ( object , property ) {
var initialValue = object [ property ] ;
// Providing options?
if ( common . isArray ( arguments [ 2 ] ) || common . isObject ( arguments [ 2 ] ) ) {
return new OptionController ( object , property , arguments [ 2 ] ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
// Providing a map?
if ( common . isNumber ( initialValue ) ) {
if ( common . isNumber ( arguments [ 2 ] ) && common . isNumber ( arguments [ 3 ] ) ) {
// Has min and max.
return new NumberControllerSlider ( object , property , arguments [ 2 ] , arguments [ 3 ] ) ;
} else {
return new NumberControllerBox ( object , property , { min : arguments [ 2 ] , max : arguments [ 3 ] } ) ;
}
}
if ( common . isString ( initialValue ) ) {
return new StringController ( object , property ) ;
}
if ( common . isFunction ( initialValue ) ) {
return new FunctionController ( object , property , '' ) ;
}
if ( common . isBoolean ( initialValue ) ) {
return new BooleanController ( object , property ) ;
}
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ( dat . controllers . OptionController ,
dat . controllers . NumberControllerBox ,
dat . controllers . NumberControllerSlider ,
dat . controllers . StringController = ( function ( Controller , dom , common ) {
/ * *
* @ class Provides a text input to alter the string property of an object .
*
* @ extends dat . controllers . Controller
*
* @ param { Object } object The object to be manipulated
* @ param { string } property The name of the property to be manipulated
*
* @ member dat . controllers
* /
var StringController = function ( object , property ) {
StringController . superclass . call ( this , object , property ) ;
var _this = this ;
this . _ _input = document . createElement ( 'input' ) ;
this . _ _input . setAttribute ( 'type' , 'text' ) ;
dom . bind ( this . _ _input , 'keyup' , onChange ) ;
dom . bind ( this . _ _input , 'change' , onChange ) ;
dom . bind ( this . _ _input , 'blur' , onBlur ) ;
dom . bind ( this . _ _input , 'keydown' , function ( e ) {
if ( e . keyCode === 13 ) {
this . blur ( ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ;
function onChange ( ) {
_this . setValue ( _this . _ _input . value ) ;
}
function onBlur ( ) {
if ( _this . _ _onFinishChange ) {
_this . _ _onFinishChange . call ( _this , _this . getValue ( ) ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
this . updateDisplay ( ) ;
this . domElement . appendChild ( this . _ _input ) ;
} ;
StringController . superclass = Controller ;
common . extend (
StringController . prototype ,
Controller . prototype ,
{
updateDisplay : function ( ) {
// Stops the caret from moving on account of:
// keyup -> setValue -> updateDisplay
if ( ! dom . isActive ( this . _ _input ) ) {
this . _ _input . value = this . getValue ( ) ;
}
return StringController . superclass . prototype . updateDisplay . call ( this ) ;
}
}
) ;
return StringController ;
} ) ( dat . controllers . Controller ,
dat . dom . dom ,
dat . utils . common ) ,
dat . controllers . FunctionController ,
dat . controllers . BooleanController ,
dat . utils . common ) ,
dat . controllers . Controller ,
dat . controllers . BooleanController ,
dat . controllers . FunctionController ,
dat . controllers . NumberControllerBox ,
dat . controllers . NumberControllerSlider ,
dat . controllers . OptionController ,
dat . controllers . ColorController = ( function ( Controller , dom , Color , interpret , common ) {
var ColorController = function ( object , property ) {
ColorController . superclass . call ( this , object , property ) ;
this . _ _color = new Color ( this . getValue ( ) ) ;
this . _ _temp = new Color ( 0 ) ;
var _this = this ;
this . domElement = document . createElement ( 'div' ) ;
dom . makeSelectable ( this . domElement , false ) ;
this . _ _selector = document . createElement ( 'div' ) ;
this . _ _selector . className = 'selector' ;
this . _ _saturation _field = document . createElement ( 'div' ) ;
this . _ _saturation _field . className = 'saturation-field' ;
this . _ _field _knob = document . createElement ( 'div' ) ;
this . _ _field _knob . className = 'field-knob' ;
this . _ _field _knob _border = '2px solid ' ;
this . _ _hue _knob = document . createElement ( 'div' ) ;
this . _ _hue _knob . className = 'hue-knob' ;
this . _ _hue _field = document . createElement ( 'div' ) ;
this . _ _hue _field . className = 'hue-field' ;
this . _ _input = document . createElement ( 'input' ) ;
this . _ _input . type = 'text' ;
this . _ _input _textShadow = '0 1px 1px ' ;
dom . bind ( this . _ _input , 'keydown' , function ( e ) {
if ( e . keyCode === 13 ) { // on enter
onBlur . call ( this ) ;
}
} ) ;
dom . bind ( this . _ _input , 'blur' , onBlur ) ;
dom . bind ( this . _ _selector , 'mousedown' , function ( e ) {
dom
. addClass ( this , 'drag' )
. bind ( window , 'mouseup' , function ( e ) {
dom . removeClass ( _this . _ _selector , 'drag' ) ;
} ) ;
} ) ;
var value _field = document . createElement ( 'div' ) ;
common . extend ( this . _ _selector . style , {
width : '122px' ,
height : '102px' ,
padding : '3px' ,
backgroundColor : '#222' ,
boxShadow : '0px 1px 3px rgba(0,0,0,0.3)'
} ) ;
common . extend ( this . _ _field _knob . style , {
position : 'absolute' ,
width : '12px' ,
height : '12px' ,
border : this . _ _field _knob _border + ( this . _ _color . v < . 5 ? '#fff' : '#000' ) ,
boxShadow : '0px 1px 3px rgba(0,0,0,0.5)' ,
borderRadius : '12px' ,
zIndex : 1
} ) ;
common . extend ( this . _ _hue _knob . style , {
position : 'absolute' ,
width : '15px' ,
height : '2px' ,
borderRight : '4px solid #fff' ,
zIndex : 1
} ) ;
common . extend ( this . _ _saturation _field . style , {
width : '100px' ,
height : '100px' ,
border : '1px solid #555' ,
marginRight : '3px' ,
display : 'inline-block' ,
cursor : 'pointer'
} ) ;
common . extend ( value _field . style , {
width : '100%' ,
height : '100%' ,
background : 'none'
} ) ;
linearGradient ( value _field , 'top' , 'rgba(0,0,0,0)' , '#000' ) ;
common . extend ( this . _ _hue _field . style , {
width : '15px' ,
height : '100px' ,
display : 'inline-block' ,
border : '1px solid #555' ,
cursor : 'ns-resize'
} ) ;
hueGradient ( this . _ _hue _field ) ;
common . extend ( this . _ _input . style , {
outline : 'none' ,
// width: '120px',
textAlign : 'center' ,
// padding: '4px',
// marginBottom: '6px',
color : '#fff' ,
border : 0 ,
fontWeight : 'bold' ,
textShadow : this . _ _input _textShadow + 'rgba(0,0,0,0.7)'
} ) ;
dom . bind ( this . _ _saturation _field , 'mousedown' , fieldDown ) ;
dom . bind ( this . _ _field _knob , 'mousedown' , fieldDown ) ;
dom . bind ( this . _ _hue _field , 'mousedown' , function ( e ) {
setH ( e ) ;
dom . bind ( window , 'mousemove' , setH ) ;
dom . bind ( window , 'mouseup' , unbindH ) ;
} ) ;
function fieldDown ( e ) {
setSV ( e ) ;
// document.body.style.cursor = 'none';
dom . bind ( window , 'mousemove' , setSV ) ;
dom . bind ( window , 'mouseup' , unbindSV ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function unbindSV ( ) {
dom . unbind ( window , 'mousemove' , setSV ) ;
dom . unbind ( window , 'mouseup' , unbindSV ) ;
// document.body.style.cursor = 'default';
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function onBlur ( ) {
var i = interpret ( this . value ) ;
if ( i !== false ) {
_this . _ _color . _ _state = i ;
_this . setValue ( _this . _ _color . toOriginal ( ) ) ;
} else {
this . value = _this . _ _color . toString ( ) ;
2013-12-18 23:27:02 +00:00
}
}
2014-02-08 17:57:40 +00:00
function unbindH ( ) {
dom . unbind ( window , 'mousemove' , setH ) ;
dom . unbind ( window , 'mouseup' , unbindH ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . _ _saturation _field . appendChild ( value _field ) ;
this . _ _selector . appendChild ( this . _ _field _knob ) ;
this . _ _selector . appendChild ( this . _ _saturation _field ) ;
this . _ _selector . appendChild ( this . _ _hue _field ) ;
this . _ _hue _field . appendChild ( this . _ _hue _knob ) ;
this . domElement . appendChild ( this . _ _input ) ;
this . domElement . appendChild ( this . _ _selector ) ;
this . updateDisplay ( ) ;
function setSV ( e ) {
e . preventDefault ( ) ;
var w = dom . getWidth ( _this . _ _saturation _field ) ;
var o = dom . getOffset ( _this . _ _saturation _field ) ;
var s = ( e . clientX - o . left + document . body . scrollLeft ) / w ;
var v = 1 - ( e . clientY - o . top + document . body . scrollTop ) / w ;
if ( v > 1 ) v = 1 ;
else if ( v < 0 ) v = 0 ;
if ( s > 1 ) s = 1 ;
else if ( s < 0 ) s = 0 ;
_this . _ _color . v = v ;
_this . _ _color . s = s ;
2013-12-18 23:27:02 +00:00
_this . setValue ( _this . _ _color . toOriginal ( ) ) ;
2014-02-08 17:57:40 +00:00
return false ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function setH ( e ) {
e . preventDefault ( ) ;
var s = dom . getHeight ( _this . _ _hue _field ) ;
var o = dom . getOffset ( _this . _ _hue _field ) ;
var h = 1 - ( e . clientY - o . top + document . body . scrollTop ) / s ;
if ( h > 1 ) h = 1 ;
else if ( h < 0 ) h = 0 ;
_this . _ _color . h = h * 360 ;
_this . setValue ( _this . _ _color . toOriginal ( ) ) ;
return false ;
}
} ;
ColorController . superclass = Controller ;
common . extend (
ColorController . prototype ,
Controller . prototype ,
{
updateDisplay : function ( ) {
var i = interpret ( this . getValue ( ) ) ;
if ( i !== false ) {
var mismatch = false ;
// Check for mismatch on the interpreted value.
common . each ( Color . COMPONENTS , function ( component ) {
if ( ! common . isUndefined ( i [ component ] ) &&
! common . isUndefined ( this . _ _color . _ _state [ component ] ) &&
i [ component ] !== this . _ _color . _ _state [ component ] ) {
mismatch = true ;
return { } ; // break
}
} , this ) ;
// If nothing diverges, we keep our previous values
// for statefulness, otherwise we recalculate fresh
if ( mismatch ) {
common . extend ( this . _ _color . _ _state , i ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
common . extend ( this . _ _temp . _ _state , this . _ _color . _ _state ) ;
this . _ _temp . a = 1 ;
var flip = ( this . _ _color . v < . 5 || this . _ _color . s > . 5 ) ? 255 : 0 ;
var _flip = 255 - flip ;
common . extend ( this . _ _field _knob . style , {
marginLeft : 100 * this . _ _color . s - 7 + 'px' ,
marginTop : 100 * ( 1 - this . _ _color . v ) - 7 + 'px' ,
backgroundColor : this . _ _temp . toString ( ) ,
border : this . _ _field _knob _border + 'rgb(' + flip + ',' + flip + ',' + flip + ')'
} ) ;
this . _ _hue _knob . style . marginTop = ( 1 - this . _ _color . h / 360 ) * 100 + 'px'
this . _ _temp . s = 1 ;
this . _ _temp . v = 1 ;
linearGradient ( this . _ _saturation _field , 'left' , '#fff' , this . _ _temp . toString ( ) ) ;
common . extend ( this . _ _input . style , {
backgroundColor : this . _ _input . value = this . _ _color . toString ( ) ,
color : 'rgb(' + flip + ',' + flip + ',' + flip + ')' ,
textShadow : this . _ _input _textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip + ',.7)'
} ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
) ;
var vendors = [ '-moz-' , '-o-' , '-webkit-' , '-ms-' , '' ] ;
function linearGradient ( elem , x , a , b ) {
elem . style . background = '' ;
common . each ( vendors , function ( vendor ) {
elem . style . cssText += 'background: ' + vendor + 'linear-gradient(' + x + ', ' + a + ' 0%, ' + b + ' 100%); ' ;
} ) ;
}
function hueGradient ( elem ) {
elem . style . background = '' ;
elem . style . cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'
elem . style . cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem . style . cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem . style . cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem . style . cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
}
return ColorController ;
} ) ( dat . controllers . Controller ,
dat . dom . dom ,
dat . color . Color = ( function ( interpret , math , toString , common ) {
var Color = function ( ) {
this . _ _state = interpret . apply ( this , arguments ) ;
if ( this . _ _state === false ) {
throw 'Failed to interpret color arguments' ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
this . _ _state . a = this . _ _state . a || 1 ;
2013-12-18 23:27:02 +00:00
2014-02-08 17:57:40 +00:00
} ;
Color . COMPONENTS = [ 'r' , 'g' , 'b' , 'h' , 's' , 'v' , 'hex' , 'a' ] ;
common . extend ( Color . prototype , {
toString : function ( ) {
return toString ( this ) ;
} ,
toOriginal : function ( ) {
return this . _ _state . conversion . write ( this ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ;
defineRGBComponent ( Color . prototype , 'r' , 2 ) ;
defineRGBComponent ( Color . prototype , 'g' , 1 ) ;
defineRGBComponent ( Color . prototype , 'b' , 0 ) ;
defineHSVComponent ( Color . prototype , 'h' ) ;
defineHSVComponent ( Color . prototype , 's' ) ;
defineHSVComponent ( Color . prototype , 'v' ) ;
Object . defineProperty ( Color . prototype , 'a' , {
get : function ( ) {
return this . _ _state . a ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
set : function ( v ) {
2014-02-08 17:57:40 +00:00
this . _ _state . a = v ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
Object . defineProperty ( Color . prototype , 'hex' , {
2013-12-18 23:27:02 +00:00
get : function ( ) {
2014-02-08 17:57:40 +00:00
if ( ! this . _ _state . space !== 'HEX' ) {
this . _ _state . hex = math . rgb _to _hex ( this . r , this . g , this . b ) ;
}
return this . _ _state . hex ;
2013-12-18 23:27:02 +00:00
} ,
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
set : function ( v ) {
2014-02-08 17:57:40 +00:00
this . _ _state . space = 'HEX' ;
this . _ _state . hex = v ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
} ) ;
2014-02-08 17:57:40 +00:00
function defineRGBComponent ( target , component , componentHexIndex ) {
Object . defineProperty ( target , component , {
get : function ( ) {
if ( this . _ _state . space === 'RGB' ) {
return this . _ _state [ component ] ;
}
recalculateRGB ( this , component , componentHexIndex ) ;
return this . _ _state [ component ] ;
} ,
set : function ( v ) {
if ( this . _ _state . space !== 'RGB' ) {
recalculateRGB ( this , component , componentHexIndex ) ;
this . _ _state . space = 'RGB' ;
}
this . _ _state [ component ] = v ;
}
} ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function defineHSVComponent ( target , component ) {
Object . defineProperty ( target , component , {
get : function ( ) {
if ( this . _ _state . space === 'HSV' )
return this . _ _state [ component ] ;
recalculateHSV ( this ) ;
return this . _ _state [ component ] ;
} ,
set : function ( v ) {
if ( this . _ _state . space !== 'HSV' ) {
recalculateHSV ( this ) ;
this . _ _state . space = 'HSV' ;
}
this . _ _state [ component ] = v ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
function recalculateRGB ( color , component , componentHexIndex ) {
if ( color . _ _state . space === 'HEX' ) {
color . _ _state [ component ] = math . component _from _hex ( color . _ _state . hex , componentHexIndex ) ;
} else if ( color . _ _state . space === 'HSV' ) {
common . extend ( color . _ _state , math . hsv _to _rgb ( color . _ _state . h , color . _ _state . s , color . _ _state . v ) ) ;
2013-12-18 23:27:02 +00:00
} else {
2014-02-08 17:57:40 +00:00
throw 'Corrupted color state' ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
function recalculateHSV ( color ) {
var result = math . rgb _to _hsv ( color . r , color . g , color . b ) ;
common . extend ( color . _ _state ,
{
s : result . s ,
v : result . v
}
) ;
if ( ! common . isNaN ( result . h ) ) {
color . _ _state . h = result . h ;
} else if ( common . isUndefined ( color . _ _state . h ) ) {
color . _ _state . h = 0 ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
}
return Color ;
} ) ( dat . color . interpret ,
dat . color . math = ( function ( ) {
var tmpComponent ;
return {
hsv _to _rgb : function ( h , s , v ) {
var hi = Math . floor ( h / 60 ) % 6 ;
var f = h / 60 - Math . floor ( h / 60 ) ;
var p = v * ( 1.0 - s ) ;
var q = v * ( 1.0 - ( f * s ) ) ;
var t = v * ( 1.0 - ( ( 1.0 - f ) * s ) ) ;
var c = [
[ v , t , p ] ,
[ q , v , p ] ,
[ p , v , t ] ,
[ p , q , v ] ,
[ t , p , v ] ,
[ v , p , q ]
] [ hi ] ;
return {
r : c [ 0 ] * 255 ,
g : c [ 1 ] * 255 ,
b : c [ 2 ] * 255
} ;
} ,
rgb _to _hsv : function ( r , g , b ) {
var min = Math . min ( r , g , b ) ,
max = Math . max ( r , g , b ) ,
delta = max - min ,
h , s ;
if ( max != 0 ) {
s = delta / max ;
} else {
return {
h : NaN ,
s : 0 ,
v : 0
} ;
}
if ( r == max ) {
h = ( g - b ) / delta ;
} else if ( g == max ) {
h = 2 + ( b - r ) / delta ;
} else {
h = 4 + ( r - g ) / delta ;
}
h /= 6 ;
if ( h < 0 ) {
h += 1 ;
}
return {
h : h * 360 ,
s : s ,
v : max / 255
} ;
} ,
rgb _to _hex : function ( r , g , b ) {
var hex = this . hex _with _component ( 0 , 2 , r ) ;
hex = this . hex _with _component ( hex , 1 , g ) ;
hex = this . hex _with _component ( hex , 0 , b ) ;
return hex ;
} ,
component _from _hex : function ( hex , componentIndex ) {
return ( hex >> ( componentIndex * 8 ) ) & 0xFF ;
} ,
hex _with _component : function ( hex , componentIndex , value ) {
return value << ( tmpComponent = componentIndex * 8 ) | ( hex & ~ ( 0xFF << tmpComponent ) ) ;
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
2013-12-18 23:27:02 +00:00
}
2014-02-08 17:57:40 +00:00
} ) ( ) ,
dat . color . toString ,
dat . utils . common ) ,
dat . color . interpret ,
dat . utils . common ) ,
dat . utils . requestAnimationFrame = ( function ( ) {
/ * *
* requirejs version of Paul Irish ' s RequestAnimationFrame
* http : //paulirish.com/2011/requestanimationframe-for-smart-animating/
* /
return window . webkitRequestAnimationFrame ||
window . mozRequestAnimationFrame ||
window . oRequestAnimationFrame ||
window . msRequestAnimationFrame ||
function ( callback , element ) {
window . setTimeout ( callback , 1000 / 60 ) ;
} ;
} ) ( ) ,
dat . dom . CenteredDiv = ( function ( dom , common ) {
var CenteredDiv = function ( ) {
this . backgroundElement = document . createElement ( 'div' ) ;
common . extend ( this . backgroundElement . style , {
backgroundColor : 'rgba(0,0,0,0.8)' ,
top : 0 ,
left : 0 ,
display : 'none' ,
zIndex : '1000' ,
opacity : 0 ,
WebkitTransition : 'opacity 0.2s linear'
} ) ;
dom . makeFullscreen ( this . backgroundElement ) ;
this . backgroundElement . style . position = 'fixed' ;
this . domElement = document . createElement ( 'div' ) ;
common . extend ( this . domElement . style , {
position : 'fixed' ,
display : 'none' ,
zIndex : '1001' ,
opacity : 0 ,
WebkitTransition : '-webkit-transform 0.2s ease-out, opacity 0.2s linear'
} ) ;
document . body . appendChild ( this . backgroundElement ) ;
document . body . appendChild ( this . domElement ) ;
var _this = this ;
dom . bind ( this . backgroundElement , 'click' , function ( ) {
_this . hide ( ) ;
} ) ;
} ;
CenteredDiv . prototype . show = function ( ) {
var _this = this ;
this . backgroundElement . style . display = 'block' ;
this . domElement . style . display = 'block' ;
this . domElement . style . opacity = 0 ;
// this.domElement.style.top = '52%';
this . domElement . style . webkitTransform = 'scale(1.1)' ;
this . layout ( ) ;
common . defer ( function ( ) {
_this . backgroundElement . style . opacity = 1 ;
_this . domElement . style . opacity = 1 ;
_this . domElement . style . webkitTransform = 'scale(1)' ;
} ) ;
} ;
CenteredDiv . prototype . hide = function ( ) {
var _this = this ;
var hide = function ( ) {
_this . domElement . style . display = 'none' ;
_this . backgroundElement . style . display = 'none' ;
dom . unbind ( _this . domElement , 'webkitTransitionEnd' , hide ) ;
dom . unbind ( _this . domElement , 'transitionend' , hide ) ;
dom . unbind ( _this . domElement , 'oTransitionEnd' , hide ) ;
2013-12-18 23:27:02 +00:00
} ;
2014-02-08 17:57:40 +00:00
dom . bind ( this . domElement , 'webkitTransitionEnd' , hide ) ;
dom . bind ( this . domElement , 'transitionend' , hide ) ;
dom . bind ( this . domElement , 'oTransitionEnd' , hide ) ;
this . backgroundElement . style . opacity = 0 ;
// this.domElement.style.top = '48%';
this . domElement . style . opacity = 0 ;
this . domElement . style . webkitTransform = 'scale(1.1)' ;
2013-12-18 23:27:02 +00:00
} ;
2014-02-08 17:57:40 +00:00
CenteredDiv . prototype . layout = function ( ) {
this . domElement . style . left = window . innerWidth / 2 - dom . getWidth ( this . domElement ) / 2 + 'px' ;
this . domElement . style . top = window . innerHeight / 2 - dom . getHeight ( this . domElement ) / 2 + 'px' ;
} ;
function lockScroll ( e ) {
console . log ( e ) ;
}
return CenteredDiv ;
} ) ( dat . dom . dom ,
dat . utils . common ) ,
dat . dom . dom ,
dat . utils . common ) ;
return dat ;
} ) ) ;