diff --git a/.gitignore b/.gitignore index ee21cd1..723ef36 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -GUIDAT.tmproj \ No newline at end of file +.idea \ No newline at end of file diff --git a/demo/demo.js b/demo/demo.js index 0cc49ef..72f4c7a 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -26,7 +26,7 @@ function FizzyText(message) { createBitmap(message); }); - // We can even add functions to the GUI! As long as they have + // We can even add functions to the DAT.GUI! As long as they have // 0 arguments, we can call them from the dat-gui panel. this.explode = function() { @@ -205,7 +205,7 @@ function FizzyText(message) { this.x += Math.cos(angle) * _this.speed + this.vx; this.y += -Math.sin(angle) * _this.speed + this.vy; - this.r = GUI.constrain(this.r, 0, _this.maxSize); + this.r = DAT.GUI.constrain(this.r, 0, _this.maxSize); // If we're tiny, keep moving around until we find a black // pixel. diff --git a/index.html b/index.html index 5a72f9f..6798fe4 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,6 @@
-gui-dat is a lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.
+dat.gui is a lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.
this.prop = value
.The simplest way to save your parameters is via GUI.saveURL()
. This method directs your browser to a URL containing the current GUI settings.
The simplest way to save your parameters is via DAT.GUI.saveURL()
. This method directs your browser to a URL containing the current GUI settings.
// Make a button for the url function -gui.add(GUI, "saveURL");+gui.add(DAT.GUI, "saveURL");
Let's say you'd like to share your settings with someone. Instead of sending a long link with lots of parameters stored in it, you can make your saved settings the defaults.
-First, add the method GUI.showSaveString()
to a gui object:
var gui = new GUI(); +-First, add the method
+DAT.GUI.showSaveString()
to a gui object:var gui = new DAT.GUI(); // Add some stuff (and pretend I change their values); gui.add(someObject, "someProperty"); gui.add(someObject, "someOtherProperty"); // Make a save button. -gui.add(GUI, "showSaveString");+gui.add(DAT.GUI, "showSaveString");
Clicking the "showSaveString" button bring up an alert with a string. Copy and paste that string into the method GUI.load()
before you instantiate any gui objects.
Clicking the "showSaveString" button bring up an alert with a string. Copy and paste that string into the method DAT.GUI.load()
before you instantiate any gui objects.
// Replace COPIED STRING with the value you got from showSaveString() -GUI.load("COPIED STRING"); +DAT.GUI.load("COPIED STRING"); -var gui = new GUI(); +var gui = new DAT.GUI(); // Now these properties will be set to the values you just saved. gui.add(someObject, "someProperty"); @@ -239,7 +239,7 @@ gui.add(obj, "propertyName").options({'Small': 1, 'Medium': 2, 'Large': 3}); });
Finally, if you'd like to do a little something extra when a function is called, use the following:
gui.add(obj, "functionName").onFire(function() { - alert("You called a function with gui-dat"); + alert("You called a function with dat.gui"); });
Let's say you have a variable that changes by itself from time to time. If you'd like the GUI to reflect those changes, use the listen()
method.
Let's say you have a variable that changes by itself from time to time. If you'd like the DAT.GUI to reflect those changes, use the listen()
method.
gui.add(obj, "changingProperty").listen();
By default, gui-dat will create an internal interval that checks for changes in the values you've marked with listen()
. If you'd like to check for these changes in an interval of your own definition, use the following:
By default, dat.gui will create an internal interval that checks for changes in the values you've marked with listen()
. If you'd like to check for these changes in an interval of your own definition, use the following:
gui.autoListen = false; // disables internal interval gui.add(obj, "changingProperty").listen(); @@ -287,21 +287,21 @@ setInterval(function() {Multiple panels and custom placement
-You can instantiate multiple
-GUI
objects and name them however you'd like.var gui1 = new GUI(); -var gui2 = new GUI(); +You can instantiate multiple
+DAT.GUI
objects and name them however you'd like.var gui1 = new DAT.GUI(); +var gui2 = new DAT.GUI(); // The name function overwrites the "Show Controls" text. gui1.name("Utilities"); gui2.name("Camera Placement");-By default, gui-dat panels will be automatically added to the HTML document and fixed to the top of the screen. You can disable this behavior / styling and append the gui DOM element to a container of your choosing.
+By default, dat.gui panels will be automatically added to the HTML document and fixed to the top of the screen. You can disable this behavior / styling and append the gui DOM element to a container of your choosing.
-// Notice this belongs to the GUI class (uppercase) +// Notice this belongs to the DAT.GUI class (uppercase) // and not an instance thereof. -GUI.autoPlace = false; +DAT.GUI.autoPlace = false; -var gui = new GUI(); +var gui = new DAT.GUI(); // Do some custom styles ... gui.domElement.style.position = "absolute"; @@ -318,7 +318,7 @@ document.getElementById("my-gui-container").appendChild( gui.domElement );-
diff --git a/src/controllers/boolean.js b/src/controllers/boolean.js index 1d2ceb9..d85e35d 100644 --- a/src/controllers/boolean.js +++ b/src/controllers/boolean.js @@ -1,7 +1,7 @@ -GUI.BooleanController = function() { +DAT.GUI.BooleanController = function() { this.type = "boolean"; - GUI.Controller.apply(this, arguments); + DAT.GUI.Controller.apply(this, arguments); var _this = this; var input = document.createElement('input'); @@ -40,8 +40,8 @@ GUI.BooleanController = function() { val = eval(val); } catch (e) {} } - return GUI.Controller.prototype.setValue.call(this, val); + return DAT.GUI.Controller.prototype.setValue.call(this, val); }; }; -GUI.extendController(GUI.BooleanController); +DAT.GUI.extendController(DAT.GUI.BooleanController); diff --git a/src/controllers/controller.js b/src/controllers/controller.js index c054fa0..d5f2165 100644 --- a/src/controllers/controller.js +++ b/src/controllers/controller.js @@ -1,4 +1,4 @@ -GUI.Controller = function() { +DAT.GUI.Controller = function() { this.parent = arguments[0]; this.object = arguments[1]; @@ -14,34 +14,34 @@ GUI.Controller = function() { this.name(this.propertyName); this.domElement.appendChild(this.propertyNameElement); - GUI.makeUnselectable(this.domElement); + DAT.GUI.makeUnselectable(this.domElement); }; -GUI.Controller.prototype.changeFunction = null; -GUI.Controller.prototype.finishChangeFunction = null; +DAT.GUI.Controller.prototype.changeFunction = null; +DAT.GUI.Controller.prototype.finishChangeFunction = null; -GUI.Controller.prototype.name = function(n) { +DAT.GUI.Controller.prototype.name = function(n) { this.propertyNameElement.innerHTML = n; return this; }; -GUI.Controller.prototype.reset = function() { +DAT.GUI.Controller.prototype.reset = function() { this.setValue(this.initialValue); return this; }; -GUI.Controller.prototype.listen = function() { +DAT.GUI.Controller.prototype.listen = function() { this.parent.listenTo(this); return this; }; -GUI.Controller.prototype.unlisten = function() { +DAT.GUI.Controller.prototype.unlisten = function() { this.parent.unlistenTo(this); // <--- hasn't been tested yet return this; }; -GUI.Controller.prototype.setValue = function(n) { +DAT.GUI.Controller.prototype.setValue = function(n) { this.object[this.propertyName] = n; if (this.changeFunction != null) { this.changeFunction.call(this, n); @@ -50,23 +50,23 @@ GUI.Controller.prototype.setValue = function(n) { return this; }; -GUI.Controller.prototype.getValue = function() { +DAT.GUI.Controller.prototype.getValue = function() { return this.object[this.propertyName]; }; -GUI.Controller.prototype.updateDisplay = function() {}; +DAT.GUI.Controller.prototype.updateDisplay = function() {}; -GUI.Controller.prototype.onChange = function(fnc) { +DAT.GUI.Controller.prototype.onChange = function(fnc) { this.changeFunction = fnc; return this; }; -GUI.Controller.prototype.onFinishChange = function(fnc) { +DAT.GUI.Controller.prototype.onFinishChange = function(fnc) { this.finishChangeFunction = fnc; return this; }; -GUI.Controller.prototype.options = function() { +DAT.GUI.Controller.prototype.options = function() { var _this = this; var select = document.createElement('select'); if (arguments.length == 1) { diff --git a/src/controllers/function.js b/src/controllers/function.js index 75c84b9..ae2e132 100644 --- a/src/controllers/function.js +++ b/src/controllers/function.js @@ -1,10 +1,10 @@ -GUI.FunctionController = function() { +DAT.GUI.FunctionController = function() { this.type = "function"; var _this = this; - GUI.Controller.apply(this, arguments); + DAT.GUI.Controller.apply(this, arguments); this.domElement.addEventListener('click', function() { _this.fire(); @@ -26,4 +26,4 @@ GUI.FunctionController = function() { _this.object[_this.propertyName].call(_this.object); }; }; -GUI.extendController(GUI.FunctionController); +DAT.GUI.extendController(DAT.GUI.FunctionController); diff --git a/src/controllers/number.js b/src/controllers/number.js index a08ecc0..7f819a1 100644 --- a/src/controllers/number.js +++ b/src/controllers/number.js @@ -1,8 +1,8 @@ -GUI.NumberController = function() { +DAT.GUI.NumberController = function() { this.type = "number"; - GUI.Controller.apply(this, arguments); + DAT.GUI.Controller.apply(this, arguments); var _this = this; @@ -38,7 +38,7 @@ GUI.NumberController = function() { var slider; if (min != undefined && max != undefined) { - slider = new GUI.Slider(this, min, max, step, this.getValue()); + slider = new DAT.GUI.Slider(this, min, max, step, this.getValue()); this.domElement.appendChild(slider.domElement); } @@ -83,8 +83,8 @@ GUI.NumberController = function() { var mouseup = function(e) { document.removeEventListener('mousemove', dragNumberField, false); - GUI.makeSelectable(_this.parent.domElement); - GUI.makeSelectable(numberField); + DAT.GUI.makeSelectable(_this.parent.domElement); + DAT.GUI.makeSelectable(numberField); if (clickedNumberField && !draggedNumberField) { numberField.focus(); numberField.select(); @@ -107,8 +107,8 @@ GUI.NumberController = function() { // Or any other fields in this gui for that matter ... // TODO: Make makeUselectable go through each element and child element. - GUI.makeUnselectable(_this.parent.domElement); - GUI.makeUnselectable(numberField); + DAT.GUI.makeUnselectable(_this.parent.domElement); + DAT.GUI.makeUnselectable(numberField); if(slider) slider.domElement.className += ' active'; @@ -123,7 +123,7 @@ GUI.NumberController = function() { this.options = function() { _this.noSlider(); _this.domElement.removeChild(numberField); - return GUI.Controller.prototype.options.apply(this, arguments); + return DAT.GUI.Controller.prototype.options.apply(this, arguments); }; this.noSlider = function() { @@ -143,14 +143,14 @@ GUI.NumberController = function() { val = max; } - return GUI.Controller.prototype.setValue.call(this, val); + return DAT.GUI.Controller.prototype.setValue.call(this, val); }; this.updateDisplay = function() { - numberField.value = GUI.roundToDecimal(_this.getValue(), 4); + numberField.value = DAT.GUI.roundToDecimal(_this.getValue(), 4); if (slider) slider.value = _this.getValue(); }; }; -GUI.extendController(GUI.NumberController); +DAT.GUI.extendController(DAT.GUI.NumberController); diff --git a/src/controllers/slider.js b/src/controllers/slider.js index dc19180..d9cc958 100644 --- a/src/controllers/slider.js +++ b/src/controllers/slider.js @@ -1,4 +1,4 @@ -GUI.Slider = function(numberController, min, max, step, initValue) { +DAT.GUI.Slider = function(numberController, min, max, step, initValue) { var clicked = false; var _this = this; @@ -16,7 +16,8 @@ GUI.Slider = function(numberController, min, max, step, initValue) { var onDrag = function(e) { if (!clicked) return; var pos = findPos(_this.domElement); - var val = GUI.map(e.pageX, pos[0], pos[0] + _this.domElement.offsetWidth, min, max); + var val = DAT.GUI.map(e.pageX, pos[0], pos[0] + _this.domElement + .offsetWidth, min, max); val = Math.round(val/step)*step; numberController.setValue(val); }; @@ -54,7 +55,7 @@ GUI.Slider = function(numberController, min, max, step, initValue) { }; this.__defineSetter__('value', function(e) { - var pct = GUI.map(e, min, max, 0, 100); + var pct = DAT.GUI.map(e, min, max, 0, 100); this.fg.style.width = pct+"%"; }); diff --git a/src/controllers/string.js b/src/controllers/string.js index 1b6fa45..55a884a 100644 --- a/src/controllers/string.js +++ b/src/controllers/string.js @@ -1,9 +1,9 @@ -GUI.StringController = function() { +DAT.GUI.StringController = function() { this.type = "string"; var _this = this; - GUI.Controller.apply(this, arguments); + DAT.GUI.Controller.apply(this, arguments); var input = document.createElement('input'); @@ -37,11 +37,11 @@ GUI.StringController = function() { this.options = function() { _this.domElement.removeChild(input); - return GUI.Controller.prototype.options.apply(this, arguments); + return DAT.GUI.Controller.prototype.options.apply(this, arguments); }; this.domElement.appendChild(input); }; -GUI.extendController(GUI.StringController); +DAT.GUI.extendController(DAT.GUI.StringController); diff --git a/src/gui.js b/src/gui.js index 222d8b0..1ac8544 100644 --- a/src/gui.js +++ b/src/gui.js @@ -1,661 +1,665 @@ -var GUI = function(parameters) { +var DAT = DAT || {}; - if (parameters == undefined) { - parameters = {}; - } +DAT.GUI = function(parameters) { - var _this = this; - - var MIN_WIDTH = 240; - var MAX_WIDTH = 500; - - var controllers = []; - var listening = []; - - var autoListen = true; - - var listenInterval; - - // Sum total of heights of controllers in this gui - var controllerHeight; - - var curControllerContainerHeight = 0; + if (parameters == undefined) { + parameters = {}; + } - var _this = this; + var MIN_WIDTH = 240; + var MAX_WIDTH = 500; - var open = false; - var width = 280; + var controllers = []; + var listening = []; + + var autoListen = true; + + var listenInterval; + + // Sum total of heights of controllers in this gui + var controllerHeight; + + var curControllerContainerHeight = 0; + + var _this = this; + + var open = false; + var width = 280; + + // Prevents checkForOverflow bug in which loaded gui appearance + // settings are not respected by presence of scrollbar. + var explicitOpenHeight = false; + + // How big we get when we open + var openHeight; + + var name; + + var resizeTo = 0; + var resizeTimeout; + + + this.domElement = document.createElement('div'); + this.domElement.setAttribute('class', 'guidat'); + this.domElement.style.width = width + 'px'; + + var controllerContainer = document.createElement('div'); + controllerContainer.setAttribute('class', 'guidat-controllers'); + + // Firefox hack to prevent horizontal scrolling + controllerContainer.addEventListener('DOMMouseScroll', function(e) { + + var scrollAmount = this.scrollTop; + + if (e.wheelDelta) { + scrollAmount += e.wheelDelta; + } else if (e.detail) { + scrollAmount += e.detail; + } + + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + + controllerContainer.scrollTop = scrollAmount; + + }, false); + + controllerContainer.style.height = '0px'; + + var toggleButton = document.createElement('a'); + toggleButton.setAttribute('class', 'guidat-toggle'); + toggleButton.setAttribute('href', '#'); + toggleButton.innerHTML = "Show Controls"; + + var toggleDragged = false; + var dragDisplacementY = 0; + var togglePressed = false; + + var my, pmy, mx, pmx; + + var resize = function(e) { + pmy = my; + pmx = mx; + my = e.pageY; + mx = e.pageX; + + var dmy = my - pmy; + + if (!open) { + if (dmy > 0) { + open = true; + curControllerContainerHeight = openHeight = 1; + toggleButton.innerHTML = name || "Hide Controls"; + } else { + return; + } + } + + // TODO: Flip this if you want to resize to the left. + var dmx = pmx - mx; + + if (dmy > 0 && + curControllerContainerHeight > controllerHeight) { + var d = DAT.GUI.map(curControllerContainerHeight, controllerHeight, controllerHeight + 100, 1, 0); + dmy *= d; + } + + toggleDragged = true; + dragDisplacementY += dmy; + dragDisplacementX += dmx; + openHeight += dmy; + width += dmx; + curControllerContainerHeight += dmy; + controllerContainer.style.height = openHeight + 'px'; + width = DAT.GUI.constrain(width, MIN_WIDTH, MAX_WIDTH); + _this.domElement.style.width = width + 'px'; + checkForOverflow(); + }; + + toggleButton.addEventListener('mousedown', function(e) { + pmy = my = e.pageY; + pmx = mx = e.pageX; + togglePressed = true; + e.preventDefault(); + dragDisplacementY = 0; + dragDisplacementX = 0; + document.addEventListener('mousemove', resize, false); + return false; + + }, false); + + toggleButton.addEventListener('click', function(e) { + e.preventDefault(); + return false; + }, false); + + document.addEventListener('mouseup', function(e) { + + if (togglePressed && !toggleDragged) { + _this.toggle(); + } + + if (togglePressed && toggleDragged) { + + if (dragDisplacementX == 0) { + adaptToScrollbar(); + } + + if (openHeight > controllerHeight) { + + clearTimeout(resizeTimeout); + openHeight = resizeTo = controllerHeight; + beginResize(); + + } else if (controllerContainer.children.length >= 1) { + + var singleControllerHeight = controllerContainer.children[0].offsetHeight; + clearTimeout(resizeTimeout); + var target = Math.round(curControllerContainerHeight / singleControllerHeight) * singleControllerHeight - 1; + resizeTo = target; + if (resizeTo <= 0) { + _this.hide(); + openHeight = singleControllerHeight * 2; + } else { + openHeight = resizeTo; + beginResize(); + } + } + } + ; + + + document.removeEventListener('mousemove', resize, false); + e.preventDefault(); + toggleDragged = false; + togglePressed = false; + + return false; + + }, false); + + this.domElement.appendChild(controllerContainer); + this.domElement.appendChild(toggleButton); + + if (parameters.domElement) { + DAT.GUI.autoPlace = false; + parameters.domElement.appendChild(this.domElement); + } + + if (DAT.GUI.autoPlace) { + if (DAT.GUI.autoPlaceContainer == null) { + DAT.GUI.autoPlaceContainer = document.createElement('div'); + DAT.GUI.autoPlaceContainer.setAttribute("id", "guidat"); + + document.body.appendChild(DAT.GUI.autoPlaceContainer); + } + DAT.GUI.autoPlaceContainer.appendChild(this.domElement); + } + + this.autoListenIntervalTime = 1000 / 60; + + var createListenInterval = function() { + listenInterval = setInterval(function() { + _this.listen(); + }, this.autoListenIntervalTime); + }; + + this.__defineSetter__("autoListen", function(v) { + autoListen = v; + if (!autoListen) { + clearInterval(listenInterval); + } else { + if (listening.length > 0) createListenInterval(); + } + }); + + this.__defineGetter__("autoListen", function(v) { + return autoListen; + }); + + this.listenTo = function(controller) { + // TODO: check for duplicates + if (listening.length == 0) { + createListenInterval(); + } + listening.push(controller); + }; + + this.unlistenTo = function(controller) { + // TODO: test this + for (var i = 0; i < listening.length; i++) { + if (listening[i] == controller) listening.splice(i, 1); + } + if (listening.length <= 0) { + clearInterval(listenInterval); + } + }; + + this.listen = function(whoToListenTo) { + var arr = whoToListenTo || listening; + for (var i in arr) { + arr[i].updateDisplay(); + } + }; + + this.listenAll = function() { + this.listen(controllers); + } + + this.autoListen = true; + + var alreadyControlled = function(object, propertyName) { + for (var i in controllers) { + if (controllers[i].object == object && + controllers[i].propertyName == propertyName) { + return true; + } + } + return false; + }; + + + var construct = function(constructor, args) { + function F() { + return constructor.apply(this, args); + } + + F.prototype = constructor.prototype; + return new F(); + }; + + this.add = function() { + + var object = arguments[0]; + var propertyName = arguments[1]; + + // Have we already added this? + if (alreadyControlled(object, propertyName)) { + // DAT.GUI.error("Controller for \"" + propertyName+"\" already added."); + // return; + } + + var value = object[propertyName]; + + // Does this value exist? Is it accessible? + if (value == undefined) { + DAT.GUI.error(object + " either has no property \"" + propertyName + "\", or the property is inaccessible."); + return; + } + + var type = typeof value; + var handler = handlerTypes[type]; + + // Do we know how to deal with this data type? + if (handler == undefined) { + DAT.GUI.error("Cannot create controller for data type \"" + type + "\""); + return; + } + + var args = [this]; // Set first arg (parent) to this + for (var j = 0; j < arguments.length; j++) { + args.push(arguments[j]); + } + + var controllerObject = construct(handler, args); + + // Were we able to make the controller? + if (!controllerObject) { + DAT.GUI.error("Error creating controller for \"" + propertyName + "\"."); + return; + } + + // Success. + controllerContainer.appendChild(controllerObject.domElement); + controllers.push(controllerObject); + DAT.GUI.allControllers.push(controllerObject); + + // Do we have a saved value for this controller? + if (type != "function" && + DAT.GUI.saveIndex < DAT.GUI.savedValues.length) { + controllerObject.setValue(DAT.GUI.savedValues[DAT.GUI.saveIndex]); + DAT.GUI.saveIndex++; + } + + // Compute sum height of controllers. + checkForOverflow(); // Prevents checkForOverflow bug in which loaded gui appearance // settings are not respected by presence of scrollbar. - var explicitOpenHeight = false; + if (!explicitOpenHeight) { + openHeight = controllerHeight; + } - // How big we get when we open - var openHeight; - - var name; - - var resizeTo = 0; - var resizeTimeout; - + return controllerObject; - this.domElement = document.createElement('div'); - this.domElement.setAttribute('class', 'guidat'); - this.domElement.style.width = width+'px'; + } - var controllerContainer = document.createElement('div'); - controllerContainer.setAttribute('class', 'guidat-controllers'); - - // Firefox hack to prevent horizontal scrolling - controllerContainer.addEventListener('DOMMouseScroll', function(e) { - - var scrollAmount = this.scrollTop; - - if (e.wheelDelta) { - scrollAmount+=e.wheelDelta; - } else if (e.detail) { - scrollAmount+=e.detail; - } - - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - - controllerContainer.scrollTop = scrollAmount; - + var checkForOverflow = function() { + controllerHeight = 0; + for (var i in controllers) { + controllerHeight += controllers[i].domElement.offsetHeight; + } + if (controllerHeight - 1 > openHeight) { + controllerContainer.style.overflowY = "auto"; + } else { + controllerContainer.style.overflowY = "hidden"; + } + }; + + var handlerTypes = { + "number": DAT.GUI.NumberController, + "string": DAT.GUI.StringController, + "boolean": DAT.GUI.BooleanController, + "function": DAT.GUI.FunctionController + }; + + var alreadyControlled = function(object, propertyName) { + for (var i in controllers) { + if (controllers[i].object == object && + controllers[i].propertyName == propertyName) { + return true; + } + } + return false; + }; + + var construct = function(constructor, args) { + + function F() { + return constructor.apply(this, args); + } + + F.prototype = constructor.prototype; + return new F(); + }; + + this.reset = function() { + // TODO + } + + // DAT.GUI ... DAT.GUI + + this.toggle = function() { + open ? this.hide() : this.show(); + }; + + this.show = function() { + toggleButton.innerHTML = name || "Hide Controls"; + resizeTo = openHeight; + clearTimeout(resizeTimeout); + beginResize(); + open = true; + } + + this.hide = function() { + toggleButton.innerHTML = name || "Show Controls"; + resizeTo = 0; + clearTimeout(resizeTimeout); + beginResize(); + open = false; + } + + this.name = function(n) { + name = n; + toggleButton.innerHTML = n; + } + + // used in saveURL + this.appearanceVars = function() { + return [open, width, openHeight, controllerContainer.scrollTop] + } + + var beginResize = function() { + //console.log("Resizing from " + curControllerContainerHeight + " to " + resizeTo); + curControllerContainerHeight += (resizeTo - curControllerContainerHeight) * 0.6; + if (Math.abs(curControllerContainerHeight - resizeTo) < 1) { + curControllerContainerHeight = resizeTo; + adaptToScrollbar(); + + } else { + resizeTimeout = setTimeout(beginResize, 1000 / 30); + } + controllerContainer.style.height = Math.round(curControllerContainerHeight) + 'px'; + checkForOverflow(); + } + + var adaptToScrollbar = function() { + // Clears lingering slider column + _this.domElement.style.width = (width + 1) + 'px'; + setTimeout(function() { + _this.domElement.style.width = width + 'px'; + }, 1); + }; + + // Load saved appearance: + + if (DAT.GUI.guiIndex < DAT.GUI.savedAppearanceVars.length) { + + width = parseInt(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][1]); + _this.domElement.style.width = width + "px"; + + openHeight = parseInt(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][2]); + explicitOpenHeight = true; + if (eval(DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][0]) == true) { + curControllerContainerHeight = openHeight; + var t = DAT.GUI.savedAppearanceVars[DAT.GUI.guiIndex][3] + + // Hack. + setTimeout(function() { + controllerContainer.scrollTop = t; + }, 0); + + if (DAT.GUI.scrollTop > -1) { + document.body.scrollTop = DAT.GUI.scrollTop; + } + resizeTo = openHeight; + this.show(); + } + + DAT.GUI.guiIndex++; + } + + DAT.GUI.allGuis.push(this); + + // Add hide listener if this is the first DAT.GUI. + if (DAT.GUI.allGuis.length == 1) { + window.addEventListener('keyup', function(e) { + // Hide on "H" + if (e.keyCode == 72) { + DAT.GUI.toggleHide(); + } }, false); - - controllerContainer.style.height = '0px'; - - var toggleButton = document.createElement('a'); - toggleButton.setAttribute('class', 'guidat-toggle'); - toggleButton.setAttribute('href', '#'); - toggleButton.innerHTML = "Show Controls"; - - var toggleDragged = false; - var dragDisplacementY = 0; - var togglePressed = false; - - var my, pmy, mx, pmx; - - var resize = function(e) { - pmy = my; - pmx = mx; - my = e.pageY; - mx = e.pageX; - - var dmy = my - pmy; - - if (!open) { - if (dmy > 0) { - open = true; - curControllerContainerHeight = openHeight = 1; - toggleButton.innerHTML = name || "Hide Controls"; - } else { - return; - } - } - - // TODO: Flip this if you want to resize to the left. - var dmx = pmx - mx; - - if (dmy > 0 && - curControllerContainerHeight > controllerHeight) { - var d = GUI.map(curControllerContainerHeight, controllerHeight, controllerHeight + 100, 1, 0); - dmy *= d; - } - - toggleDragged = true; - dragDisplacementY += dmy; - dragDisplacementX += dmx; - openHeight += dmy; - width += dmx; - curControllerContainerHeight += dmy; - controllerContainer.style.height = openHeight+'px'; - width = GUI.constrain(width, MIN_WIDTH, MAX_WIDTH); - _this.domElement.style.width = width+'px'; - checkForOverflow(); - }; - - toggleButton.addEventListener('mousedown', function(e) { - pmy = my = e.pageY; - pmx = mx = e.pageX; - togglePressed = true; - e.preventDefault(); - dragDisplacementY = 0; - dragDisplacementX = 0; - document.addEventListener('mousemove', resize, false); - return false; - - }, false); - - toggleButton.addEventListener('click', function(e) { - e.preventDefault(); - return false; - }, false); - - document.addEventListener('mouseup', function(e) { - - if (togglePressed && !toggleDragged) { - _this.toggle(); - } - - if (togglePressed && toggleDragged) { - - if (dragDisplacementX == 0) { - adaptToScrollbar(); - } - - if (openHeight > controllerHeight) { - - clearTimeout(resizeTimeout); - openHeight = resizeTo = controllerHeight; - beginResize(); - - } else if (controllerContainer.children.length >= 1) { - - var singleControllerHeight = controllerContainer.children[0].offsetHeight; - clearTimeout(resizeTimeout); - var target = Math.round(curControllerContainerHeight/singleControllerHeight)*singleControllerHeight-1; - resizeTo = target; - if (resizeTo <= 0) { - _this.hide(); - openHeight = singleControllerHeight*2; - } else { - openHeight = resizeTo; - beginResize(); - } - } - }; - - - document.removeEventListener('mousemove', resize, false); - e.preventDefault(); - toggleDragged = false; - togglePressed = false; - - return false; - - }, false); - - this.domElement.appendChild(controllerContainer); - this.domElement.appendChild(toggleButton); - - if ( parameters.domElement ) { - GUI.autoPlace = false; - parameters.domElement.appendChild(this.domElement); - } - - if (GUI.autoPlace) { - if(GUI.autoPlaceContainer == null) { - GUI.autoPlaceContainer = document.createElement('div'); - GUI.autoPlaceContainer.setAttribute("id", "guidat"); - - document.body.appendChild(GUI.autoPlaceContainer); - } - GUI.autoPlaceContainer.appendChild(this.domElement); - } - - this.autoListenIntervalTime = 1000/60; - - var createListenInterval = function() { - listenInterval = setInterval(function() { - _this.listen(); - }, this.autoListenIntervalTime); - }; - - this.__defineSetter__("autoListen", function(v) { - autoListen = v; - if (!autoListen) { - clearInterval(listenInterval); - } else { - if (listening.length > 0) createListenInterval(); - } - }); - - this.__defineGetter__("autoListen", function(v) { - return autoListen; - }); - - this.listenTo = function(controller) { - // TODO: check for duplicates - if (listening.length == 0) { - createListenInterval(); - } - listening.push(controller); - }; - - this.unlistenTo = function(controller) { - // TODO: test this - for(var i = 0; i < listening.length; i++) { - if(listening[i] == controller) listening.splice(i, 1); - } - if(listening.length <= 0) { - clearInterval(listenInterval); - } - }; - - this.listen = function(whoToListenTo) { - var arr = whoToListenTo || listening; - for (var i in arr) { - arr[i].updateDisplay(); - } - }; - - this.listenAll = function() { - this.listen(controllers); - } - - this.autoListen = true; - - var alreadyControlled = function(object, propertyName) { - for (var i in controllers) { - if (controllers[i].object == object && - controllers[i].propertyName == propertyName) { - return true; - } - } - return false; - }; - - - var construct = function(constructor, args) { - function F() { - return constructor.apply(this, args); - } - F.prototype = constructor.prototype; - return new F(); - }; - - this.add = function() { - - var object = arguments[0]; - var propertyName = arguments[1]; - - // Have we already added this? - if (alreadyControlled(object, propertyName)) { - // GUI.error("Controller for \"" + propertyName+"\" already added."); - // return; - } - - var value = object[propertyName]; - - // Does this value exist? Is it accessible? - if (value == undefined) { - GUI.error(object + " either has no property \""+propertyName+"\", or the property is inaccessible."); - return; - } - - var type = typeof value; - var handler = handlerTypes[type]; - - // Do we know how to deal with this data type? - if (handler == undefined) { - GUI.error("Cannot create controller for data type \""+type+"\""); - return; - } - - var args = [this]; // Set first arg (parent) to this - for (var j = 0; j < arguments.length; j++) { - args.push(arguments[j]); - } - - var controllerObject = construct(handler, args); - - // Were we able to make the controller? - if (!controllerObject) { - GUI.error("Error creating controller for \""+propertyName+"\"."); - return; - } - - // Success. - controllerContainer.appendChild(controllerObject.domElement); - controllers.push(controllerObject); - GUI.allControllers.push(controllerObject); - - // Do we have a saved value for this controller? - if (type != "function" && - GUI.saveIndex < GUI.savedValues.length) { - controllerObject.setValue(GUI.savedValues[GUI.saveIndex]); - GUI.saveIndex++; - } - - // Compute sum height of controllers. - checkForOverflow(); - - // Prevents checkForOverflow bug in which loaded gui appearance - // settings are not respected by presence of scrollbar. - if (!explicitOpenHeight) { - openHeight = controllerHeight; - } - - return controllerObject; - - } - - var checkForOverflow = function() { - controllerHeight = 0; - for (var i in controllers) { - controllerHeight += controllers[i].domElement.offsetHeight; - } - if (controllerHeight - 1 > openHeight) { - controllerContainer.style.overflowY = "auto"; - } else { - controllerContainer.style.overflowY = "hidden"; - } - }; - - var handlerTypes = { - "number": GUI.NumberController, - "string": GUI.StringController, - "boolean": GUI.BooleanController, - "function": GUI.FunctionController - }; - - var alreadyControlled = function(object, propertyName) { - for (var i in controllers) { - if (controllers[i].object == object && - controllers[i].propertyName == propertyName) { - return true; - } - } - return false; - }; - - var construct = function(constructor, args) { - - function F() { - return constructor.apply(this, args); - } - F.prototype = constructor.prototype; - return new F(); - }; - - this.reset = function() { - // TODO - } - - // GUI ... GUI - - this.toggle = function() { - open ? this.hide() : this.show(); - }; - - this.show = function() { - toggleButton.innerHTML = name || "Hide Controls"; - resizeTo = openHeight; - clearTimeout(resizeTimeout); - beginResize(); - open = true; - } - - this.hide = function() { - toggleButton.innerHTML = name || "Show Controls"; - resizeTo = 0; - clearTimeout(resizeTimeout); - beginResize(); - open = false; - } - - this.name = function(n) { - name = n; - toggleButton.innerHTML = n; - } - - // used in saveURL - this.appearanceVars = function() { - return [open, width, openHeight, controllerContainer.scrollTop] - } - - var beginResize = function() { - //console.log("Resizing from " + curControllerContainerHeight + " to " + resizeTo); - curControllerContainerHeight += (resizeTo - curControllerContainerHeight)*0.6; - if (Math.abs(curControllerContainerHeight-resizeTo) < 1) { - curControllerContainerHeight = resizeTo; - adaptToScrollbar(); - - } else { - resizeTimeout = setTimeout(beginResize, 1000/30); - } - controllerContainer.style.height = Math.round(curControllerContainerHeight)+'px'; - checkForOverflow(); - } - - var adaptToScrollbar = function() { - // Clears lingering slider column - _this.domElement.style.width = (width+1)+'px'; - setTimeout(function() { - _this.domElement.style.width = width+'px'; - }, 1); - }; - - // Load saved appearance: - - if (GUI.guiIndex < GUI.savedAppearanceVars.length) { - - - width = parseInt(GUI.savedAppearanceVars[GUI.guiIndex][1]); - _this.domElement.style.width = width+"px"; - - openHeight = parseInt(GUI.savedAppearanceVars[GUI.guiIndex][2]); - explicitOpenHeight = true; - if (eval(GUI.savedAppearanceVars[GUI.guiIndex][0]) == true) { - curControllerContainerHeight = openHeight; - var t = GUI.savedAppearanceVars[GUI.guiIndex][3] - - // Hack. - setTimeout(function() { - controllerContainer.scrollTop = t; - }, 0); - - if (GUI.scrollTop > -1) { - document.body.scrollTop = GUI.scrollTop; - } - resizeTo = openHeight; - this.show(); - } - - GUI.guiIndex++; - } - - GUI.allGuis.push(this); - - // Add hide listener if this is the first GUI. - if (GUI.allGuis.length == 1) { - window.addEventListener('keyup', function(e) { - // Hide on "H" - if (e.keyCode == 72) { - GUI.toggleHide(); - } - }, false); - } + } }; // Do not set this directly. -GUI.hidden = false; - +DAT.GUI.hidden = false; // Static members -GUI.autoPlace = true; -GUI.autoPlaceContainer = null; -GUI.allControllers = []; -GUI.allGuis = []; +DAT.GUI.autoPlace = true; +DAT.GUI.autoPlaceContainer = null; +DAT.GUI.allControllers = []; +DAT.GUI.allGuis = []; -GUI.toggleHide = function() { - if (GUI.hidden) { - GUI.show(); - } else { - GUI.hide(); - } +DAT.GUI.toggleHide = function() { + if (DAT.GUI.hidden) { + DAT.GUI.show(); + } else { + DAT.GUI.hide(); + } } -GUI.show = function() { - GUI.hidden = false; - for (var i in GUI.allGuis) { - GUI.allGuis[i].domElement.style.display = "block"; - } +DAT.GUI.show = function() { + DAT.GUI.hidden = false; + for (var i in DAT.GUI.allGuis) { + DAT.GUI.allGuis[i].domElement.style.display = "block"; + } } -GUI.hide = function() { - GUI.hidden = true; - for (var i in GUI.allGuis) { - GUI.allGuis[i].domElement.style.display = "none"; - } +DAT.GUI.hide = function() { + DAT.GUI.hidden = true; + for (var i in DAT.GUI.allGuis) { + DAT.GUI.allGuis[i].domElement.style.display = "none"; + } } -GUI.saveURL = function() { - var url = GUI.replaceGetVar("saveString", GUI.getSaveString()); - window.location = url; +DAT.GUI.saveURL = function() { + var url = DAT.GUI.replaceGetVar("saveString", DAT.GUI.getSaveString()); + window.location = url; }; -GUI.scrollTop = -1; +DAT.GUI.scrollTop = -1; -GUI.load = function(saveString) { +DAT.GUI.load = function(saveString) { - //GUI.savedAppearanceVars = []; - var vals = saveString.split(","); - var numGuis = parseInt(vals[0]); - GUI.scrollTop = parseInt(vals[1]); - for (var i = 0; i < numGuis; i++) { - var appr = vals.splice(2, 4); - GUI.savedAppearanceVars.push(appr); - } + //DAT.GUI.savedAppearanceVars = []; + var vals = saveString.split(","); + var numGuis = parseInt(vals[0]); + DAT.GUI.scrollTop = parseInt(vals[1]); + for (var i = 0; i < numGuis; i++) { + var appr = vals.splice(2, 4); + DAT.GUI.savedAppearanceVars.push(appr); + } - GUI.savedValues = vals.splice(2, vals.length); + DAT.GUI.savedValues = vals.splice(2, vals.length); }; -GUI.savedValues = []; -GUI.savedAppearanceVars = []; +DAT.GUI.savedValues = []; +DAT.GUI.savedAppearanceVars = []; -GUI.getSaveString = function() { +DAT.GUI.getSaveString = function() { - var vals = [], - i; + var vals = [], + i; - vals.push(GUI.allGuis.length); - vals.push(document.body.scrollTop); + vals.push(DAT.GUI.allGuis.length); + vals.push(document.body.scrollTop); - for (i in GUI.allGuis) { - var av = GUI.allGuis[i].appearanceVars(); - for (var j = 0; j < av.length; j++) { - vals.push(av[j]); - } + for (i in DAT.GUI.allGuis) { + var av = DAT.GUI.allGuis[i].appearanceVars(); + for (var j = 0; j < av.length; j++) { + vals.push(av[j]); + } + } + + for (i in DAT.GUI.allControllers) { + + // We don't save values for functions. + if (DAT.GUI.allControllers[i].type == "function") { + continue; } - for (i in GUI.allControllers) { - - // We don't save values for functions. - if (GUI.allControllers[i].type == "function") { - continue; - } - - var v = GUI.allControllers[i].getValue(); - - // Round numbers so they don't get enormous - if (GUI.allControllers[i].type == "number") { - v = GUI.roundToDecimal(v, 4); - } - - vals.push(v); + var v = DAT.GUI.allControllers[i].getValue(); + // Round numbers so they don't get enormous + if (DAT.GUI.allControllers[i].type == "number") { + v = DAT.GUI.roundToDecimal(v, 4); } - return vals.join(','); + vals.push(v); + + } + + return vals.join(','); }; -GUI.getVarFromURL = function(v) { +DAT.GUI.getVarFromURL = function(v) { - var vars = [], hash; - var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + var vars = [], hash; + var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); - for (var i = 0; i < hashes.length; i++) { - hash = hashes[i].split("="); - if (hash == undefined) continue; - if (hash[0] == v) { - return hash[1]; - } + for (var i = 0; i < hashes.length; i++) { + hash = hashes[i].split("="); + if (hash == undefined) continue; + if (hash[0] == v) { + return hash[1]; } + } - return null; + return null; }; -GUI.replaceGetVar = function(varName, val) { +DAT.GUI.replaceGetVar = function(varName, val) { - var vars = [], hash; - var loc = window.location.href; - var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); + var vars = [], hash; + var loc = window.location.href; + var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); - for (var i = 0; i < hashes.length; i++) { - hash = hashes[i].split("="); - if (hash == undefined) continue; - if (hash[0] == varName) { - return loc.replace(hash[1], val); - } + for (var i = 0; i < hashes.length; i++) { + hash = hashes[i].split("="); + if (hash == undefined) continue; + if (hash[0] == varName) { + return loc.replace(hash[1], val); } + } - if (window.location.href.indexOf('?') != -1) { - return loc + "&"+varName+"="+val; - } + if (window.location.href.indexOf('?') != -1) { + return loc + "&" + varName + "=" + val; + } - return loc+"?"+varName+"="+val; + return loc + "?" + varName + "=" + val; }; -GUI.saveIndex = 0; -GUI.guiIndex = 0; +DAT.GUI.saveIndex = 0; +DAT.GUI.guiIndex = 0; -GUI.showSaveString = function() { - alert(GUI.getSaveString()); +DAT.GUI.showSaveString = function() { + alert(DAT.GUI.getSaveString()); }; // Util functions -GUI.makeUnselectable = function(elem) { - elem.onselectstart = function() { return false; }; - elem.style.MozUserSelect = "none"; - elem.style.KhtmlUserSelect = "none"; - elem.unselectable = "on"; +DAT.GUI.makeUnselectable = function(elem) { + elem.onselectstart = function() { + return false; + }; + elem.style.MozUserSelect = "none"; + elem.style.KhtmlUserSelect = "none"; + elem.unselectable = "on"; }; -GUI.makeSelectable = function(elem) { - elem.onselectstart = function() { }; - elem.style.MozUserSelect = "auto"; - elem.style.KhtmlUserSelect = "auto"; - elem.unselectable = "off"; +DAT.GUI.makeSelectable = function(elem) { + elem.onselectstart = function() { + }; + elem.style.MozUserSelect = "auto"; + elem.style.KhtmlUserSelect = "auto"; + elem.unselectable = "off"; }; -GUI.map = function(v, i1, i2, o1, o2) { - return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); +DAT.GUI.map = function(v, i1, i2, o1, o2) { + return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); }; -GUI.constrain = function (v, o1, o2) { - if (v < o1) v = o1; - else if (v > o2) v = o2; - return v; +DAT.GUI.constrain = function (v, o1, o2) { + if (v < o1) v = o1; + else if (v > o2) v = o2; + return v; }; -GUI.error = function(str) { - if (typeof console.error == 'function') { - console.error("[GUI ERROR] " + str); - } +DAT.GUI.error = function(str) { + if (typeof console.error == 'function') { + console.error("[DAT.GUI ERROR] " + str); + } }; -GUI.roundToDecimal = function(n, decimals) { - var t = Math.pow(10, decimals); - return Math.round(n*t)/t; +DAT.GUI.roundToDecimal = function(n, decimals) { + var t = Math.pow(10, decimals); + return Math.round(n * t) / t; }; -GUI.extendController = function(clazz) { - clazz.prototype = new GUI.Controller(); - clazz.prototype.constructor = clazz; +DAT.GUI.extendController = function(clazz) { + clazz.prototype = new DAT.GUI.Controller(); + clazz.prototype.constructor = clazz; }; -if (GUI.getVarFromURL('saveString') != null) GUI.load(GUI.getVarFromURL('saveString')); +if (DAT.GUI.getVarFromURL('saveString') != null) DAT.GUI.load(DAT.GUI.getVarFromURL('saveString'));- gui-dat panels are resizeable. Drag the show/hide button.
+- dat.gui panels are resizeable. Drag the show/hide button.
- Press 'H' to show/hide GUI's.