Now we have a FUNCTIONING mock :)

This commit is contained in:
George Michael Brower 2011-02-02 13:12:55 -05:00
parent de420197e1
commit 5be42748bd
12 changed files with 410 additions and 344 deletions

View File

@ -1,7 +1,7 @@
var BooleanController = function() {
GUI.BooleanController = function() {
this.type = "boolean";
Controller.apply(this, arguments);
GUI.Controller.apply(this, arguments);
var _this = this;
var input = document.createElement('input');
@ -32,9 +32,8 @@ var BooleanController = function() {
val = eval(val);
} catch (e) {}
}
return Controller.prototype.setValue.call(this, val);
return GUI.Controller.prototype.setValue.call(this, val);
}
};
BooleanController.prototype = new Controller();
BooleanController.prototype.constructor = BooleanController;
GUI.extendController(GUI.BooleanController);

View File

@ -1,12 +1,11 @@
var FunctionController = function() {
GUI.FunctionController = function() {
this.type = "function";
var that = this;
Controller.apply(this, arguments);
GUI.Controller.apply(this, arguments);
this.domElement.addEventListener('click', function() {
that.object[that.propertyName].call(that.object);
}, false);
this.domElement.style.cursor = "pointer";
this.propertyNameElement.style.cursor = "pointer";
};
FunctionController.prototype = new Controller();
FunctionController.prototype.constructor = FunctionController;
GUI.extendController(GUI.FunctionController);

View File

@ -1,4 +1,4 @@
var Controller = function() {
GUI.Controller = function() {
this.parent = arguments[0];
this.object = arguments[1];
@ -14,38 +14,35 @@ var Controller = function() {
this.name(this.propertyName);
this.domElement.appendChild(this.propertyNameElement);
this.timeElement = document.createElement('div');
this.timeElement.setAttribute('class', 'guidat-time');
this.domElement.appendChild(this.timeElement);
GUI.makeUnselectable(this.domElement);
};
Controller.prototype.changeFunction = null;
GUI.Controller.prototype.changeFunction = null;
Controller.prototype.name = function(n) {
GUI.Controller.prototype.name = function(n) {
this.propertyNameElement.innerHTML = n;
return this;
};
Controller.prototype.reset = function() {
GUI.Controller.prototype.reset = function() {
this.setValue(this.initialValue);
return this;
};
Controller.prototype.listen = function() {
GUI.Controller.prototype.listen = function() {
this.parent.listenTo(this);
return this;
}
Controller.prototype.unlisten = function() {
GUI.Controller.prototype.unlisten = function() {
this.parent.unlistenTo(this); // <--- hasn't been tested yet
return this;
}
Controller.prototype.setValue = function(n) {
GUI.Controller.prototype.setValue = function(n) {
this.object[this.propertyName] = n;
if (this.changeFunction != null) {
this.changeFunction.call(this, n);
@ -56,13 +53,13 @@ Controller.prototype.setValue = function(n) {
return this;
}
Controller.prototype.getValue = function() {
GUI.Controller.prototype.getValue = function() {
return this.object[this.propertyName];
}
Controller.prototype.updateDisplay = function() {}
GUI.Controller.prototype.updateDisplay = function() {}
Controller.prototype.onChange = function(fnc) {
GUI.Controller.prototype.onChange = function(fnc) {
this.changeFunction = fnc;
return this;
}

View File

@ -1,8 +1,8 @@
var NumberController = function() {
GUI.NumberController = function() {
this.type = "number";
Controller.apply(this, arguments);
GUI.Controller.apply(this, arguments);
var _this = this;
@ -16,7 +16,22 @@ var NumberController = function() {
var min = arguments[3];
var max = arguments[4];
var step = arguments[5];
var step = arguments[5];
this.step = function(s) {
step = s;
return this;
}
this.min = function(s) {
min = s;
return this;
}
this.max = function(s) {
max = s;
return this;
}
if (!step) {
if (min != undefined && max != undefined) {
@ -38,7 +53,7 @@ var NumberController = function() {
var slider;
if (min != undefined && max != undefined) {
slider = new Slider(this, min, max, step, this.getValue());
slider = new GUI.Slider(this, min, max, step, this.getValue());
this.domElement.appendChild(slider.domElement);
}
@ -121,7 +136,7 @@ var NumberController = function() {
val = max;
}
return Controller.prototype.setValue.call(this, val);
return GUI.Controller.prototype.setValue.call(this, val);
}
@ -131,5 +146,4 @@ var NumberController = function() {
}
};
NumberController.prototype = new Controller();
NumberController.prototype.constructor = NumberController;
GUI.extendController(GUI.NumberController);

View File

@ -1,9 +1,9 @@
var StringController = function() {
GUI.StringController = function() {
this.type = "string";
var _this = this;
Controller.apply(this, arguments);
GUI.Controller.apply(this, arguments);
var input = document.createElement('input');
@ -30,5 +30,4 @@ var StringController = function() {
};
StringController.prototype = new Controller();
StringController.prototype.constructor = StringController;
GUI.extendController(GUI.StringController);

278
controllers/scrubber.js Normal file
View File

@ -0,0 +1,278 @@
// Would really love to make it so that as FEW changes as possible are required to gui.js in order to make this work. Would love to make it so you simply include gui.scrubber.min.js in addition to gui.min.js.
GUI.Controller.prototype.at = function(when, what, tween) {
this.scrubber.addPoint(new GUI.ScrubberPoint(this.scrubber, when, what));
this.scrubber.render();
return this;
}
GUI.Scrubber = function(controller, timer) {
var _this = this;
var points = [];
this.timer = timer;
this.controller = controller;
this.controller.scrubber = this;
this.domElement = document.createElement('div');
this.domElement.setAttribute('class', 'guidat-time');
var canvas = document.createElement('canvas');
this.domElement.appendChild(canvas);
this.g = canvas.getContext('2d');
var width;
var height;
this.__defineGetter__("width", function() {
return width;
});
this.__defineGetter__("height", function() {
return height;
});
controller.domElement.insertBefore(this.domElement, controller.propertyNameElement.nextSibling);
this.addPoint = function(point) {
points.push(point);
points.sort(function(a,b) {
return a.time - b.time;
});
}
this.render = function() {
// TODO: if visible ...
_this.g.clearRect(0, 0, width, height);
for (var i in points) {
points[i].render();
}
// Draw playhead
_this.g.strokeStyle = "red";
var t = Math.round(GUI.map(_this.timer.playhead, _this.timer.windowMin, _this.timer.windowMin+_this.timer.windowWidth, 0, width))+0.5;
_this.g.beginPath();
_this.g.moveTo(t, 0);
_this.g.lineTo(t, height);
_this.g.stroke();
}
this.render();
var onResize = function() {
canvas.width = width = _this.domElement.offsetWidth;
canvas.height = height = _this.domElement.offsetHeight;
_this.render();
};
window.addEventListener('resize', function(e) {
onResize();
}, false);
onResize();
this.timer.addPlayListener(this.render);
var onPlayChange = function(curTime, prevTime) {
// This assumes a SORTED point array
// And a PROGRESSING/INCREASING/GROWING playhead
for (var i = 0; i < points.length; i++) {
var cur = points[i];
if (cur.time < prevTime) {
continue;
}
if (cur.time >= prevTime && cur.time <= curTime) {
pointHandlers[_this.controller.type].call(_this, cur);
}
}
};
var pointHandlers = {
'function': function(point) {
this.controller.getValue().call(this);
},
'boolean': function(point) {
this.controller.setValue(point.value);
},
'string': function(point) {
this.controller.setValue(point.value);
},
'number': function(point) {
//
}
}
this.timer.addPlayListener(onPlayChange);
this.timer.addWindowListener(this.render);
};
GUI.ScrubberPoint = function(scrubber, time, value) {
var _this = this;
var g = scrubber.g;
var timer = scrubber.timer;
this.value = value;
var rectSize = 4;
this.__defineGetter__("time", function() {
return time;
});
this.render = function() {
var x = GUI.map(time, timer.windowMin, timer.windowMin+timer.windowWidth, 0, 1);
if (x >= 0 && x <= 1) {
x = Math.round(GUI.map(x, 0, 1, 0, scrubber.width));
}
g.save();
g.translate(x-rectSize/2, 0);
g.fillStyle = "#ffd800";
g.fillRect(0, 0, rectSize/2, scrubber.height-1);
g.fillStyle = "#ff9000";
g.fillRect(rectSize/2, 0, rectSize/2, scrubber.height-1);
g.restore();
}
}
GUI.Timer = function(gui) {
var _this = this;
this.gui = gui;
this.gui.timer = this;
var playhead = 0;
var lastPlayhead = 0;
var playListeners = [];
var windowListeners = [];
var windowMin = 0;
var windowWidth = 10000;
var thisTime;
var lastTime;
var playInterval = -1;
var playResolution = 1000/60;
var playing = false;
var millis = function() {
var d = new Date();
return d.getTime();
}
this.__defineGetter__("windowMin", function() {
return windowMin;
});
this.__defineSetter__("windowMin", function(v) {
windowMin = v;
for (var i in windowListeners) {
windowListeners[i].call(windowListeners[i]);
}
});
this.__defineGetter__("windowWidth", function() {
return windowWidth;
});
this.__defineSetter__("windowWidth", function(v) {
windowWidth = v;
for (var i in windowListeners) {
windowListeners[i].call(windowListeners[i]);
}
});
this.__defineGetter__("playhead", function() {
return playhead;
});
this.__defineSetter__("playhead", function(t) {
lastPlayhead = playhead;
playhead = t;
for (var i = 0; i < playListeners.length; i++) {
playListeners[i].call(this, playhead, lastPlayhead);
}
});
this.__defineGetter__("playing", function() {
return playing;
});
this.play = function() {
playing = true;
lastTime = millis();
if (playInterval == -1) {
playInterval = setInterval(this.update, playResolution);
}
};
this.update = function() {
thisTime = millis();
_this.playhead = _this.playhead + (thisTime - lastTime);
lastTime = thisTime;
};
this.pause = function() {
playing = false;
clearInterval(playInterval);
playInterval = -1;
};
this.playPause = function() {
if (playing) {
this.pause();
} else {
this.play();
}
}
this.stop = function() {
this.pause();
this.playhead = 0;
};
this.addPlayListener = function(fnc) {
playListeners.push(fnc);
};
this.addWindowListener = function(fnc) {
windowListeners.push(fnc);
};
}

View File

@ -1,4 +1,4 @@
var Slider = function(numberController, min, max, step, initValue) {
GUI.Slider = function(numberController, min, max, step, initValue) {
var min = min;
var max = max;

View File

@ -66,10 +66,6 @@ div.collapsed h2, div.expanded h2 {
width: 100%;
cursor: pointer;
}
h2.last {
border-bottom: 1px dotted #ccc;
margin-bottom: 20px;
}
div.expanded h2:before {
content: '-';
@ -162,10 +158,12 @@ a:active {
}
footer {
margin-top: 20px;
background-color: #eee;
width: 510px;
padding: 10px;
clear: both;
color: #444;
}

View File

@ -1,26 +0,0 @@
#guidat {
position: fixed;
width: 250px;
z-index: 200;
top: 0;
left: 100%;
margin-left: -270px;
}
#guidat-controllers {
height: 300px;
overflow-y: auto;
}
#guidat-toggle {
cursor: pointer;
}
.guidat-controller {
clear: both;
}
.guidat-controller input {
float: right;
clear: both;
}

21
gui.css
View File

@ -13,14 +13,14 @@
}
.guidat-time {
width: 75%;
float: right;
margin-top: -3px;
margin-right: -2px;
margin-left: 3px;
background-color: #333;
border-bottom: 1px solid #444;
height: 31px;
width: 75%;
float: right;
margin-top: -3px;
margin-right: -2px;
margin-left: 3px;
background-color: #333;
border-bottom: 1px solid #444;
height: 31px;
}
.guidat {
@ -47,6 +47,11 @@ height: 31px;
*/
}
.guidat-controllers hr {
height: 0;
border-top: 1px solid #000;
}
a.guidat-toggle {
text-decoration: none;
cursor: pointer;

84
gui.js
View File

@ -17,9 +17,6 @@ var GUI = function() {
var curControllerContainerHeight = 0;
// How big we get when we open
var _this = this;
var open = false;
@ -27,6 +24,8 @@ var GUI = function() {
// 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;
@ -41,7 +40,10 @@ var GUI = function() {
var controllerContainer = document.createElement('div');
controllerContainer.setAttribute('class', 'guidat-controllers');
// Firefox hack for horizontal scrolling
// For use with GUIScrubber
this.timer = null;
// Firefox hack to prevent horizontal scrolling
controllerContainer.addEventListener('DOMMouseScroll', function(e) {
var scrollAmount = this.scrollTop;
@ -80,19 +82,17 @@ var GUI = function() {
my = e.pageY;
mx = e.pageX;
var dmy = my - pmy;
var dmy = pmy-my;
if (!open) {
if (dmy > 0) {
open = true;
curControllerContainerHeight = openHeight = 1;
toggleButton.innerHTML = name || "Hide Controls";
} else {
return;
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;
@ -107,7 +107,7 @@ var GUI = function() {
dragDisplacementY += dmy;
dragDisplacementX += dmx;
openHeight += dmy;
width += dmx;
//width += dmx;
curControllerContainerHeight += dmy;
controllerContainer.style.height = openHeight+'px';
width = GUI.constrain(width, MIN_WIDTH, MAX_WIDTH);
@ -141,9 +141,9 @@ var GUI = function() {
_this.toggle();
// Clears lingering slider column
_this.domElement.style.width = (width+1)+'px';
// _this.domElement.style.width = (width+1)+'px';
setTimeout(function() {
_this.domElement.style.width = width+'px';
// _this.domElement.style.width = width+'px';
}, 1);
}
@ -194,8 +194,8 @@ var GUI = function() {
}, false);
this.domElement.appendChild(controllerContainer);
this.domElement.appendChild(toggleButton);
this.domElement.appendChild(controllerContainer);
if (GUI.autoPlace) {
if(GUI.autoPlaceContainer == null) {
@ -259,13 +259,6 @@ var GUI = function() {
this.autoListen = true;
var handlerTypes = {
"number": NumberController,
"string": StringController,
"boolean": BooleanController,
"function": FunctionController
};
var alreadyControlled = function(object, propertyName) {
for (var i in controllers) {
if (controllers[i].object == object &&
@ -285,9 +278,21 @@ var GUI = function() {
return new F();
};
this.divider = function() {
controllerContainer.appendChild(document.createElement('hr'));
}
this.add = function() {
var object = arguments[0];
if (arguments.length == 1) {
for (var i in object) {
this.add(object, i);
}
return;
}
var propertyName = arguments[1];
// Have we already added this?
@ -347,6 +352,10 @@ var GUI = function() {
openHeight = controllerHeight;
}
if (this.timer != null) {
new GUI.Scrubber(controllerObject, this.timer);
}
return controllerObject;
}
@ -361,14 +370,13 @@ var GUI = function() {
} else {
controllerContainer.style.overflowY = "hidden";
}
// console.log(controllerHeight, openHeight);
}
var addHandlers = {
"number": NumberController,
"string": StringController,
"boolean": BooleanController,
"function": FunctionController
var handlerTypes = {
"number": GUI.NumberController,
"string": GUI.StringController,
"boolean": GUI.BooleanController,
"function": GUI.FunctionController
};
var alreadyControlled = function(object, propertyName) {
@ -390,7 +398,7 @@ var GUI = function() {
};
this.reset = function() {
//
// TODO
}
// GUI ... GUI
@ -485,10 +493,8 @@ GUI.saveURL = function() {
GUI.scrollTop = -1;
// TODO: Not working in FF.
GUI.load = function(saveString) {
//GUI.savedAppearanceVars = [];
var vals = saveString.split(",");
var numGuis = parseInt(vals[0]);
@ -499,6 +505,7 @@ GUI.load = function(saveString) {
}
GUI.savedValues = vals.splice(2, vals.length);
};
GUI.savedValues = [];
@ -616,7 +623,7 @@ GUI.constrain = function (v, o1, o2) {
GUI.error = function(str) {
if (typeof console.error == 'function') {
console.GUI.error("[GUI ERROR] " + str);
console.error("[GUI ERROR] " + str);
}
};
@ -625,4 +632,9 @@ GUI.roundToDecimal = function(n, decimals) {
return Math.round(n*t)/t;
}
GUI.extendController = function(clazz) {
clazz.prototype = new GUI.Controller();
clazz.prototype.constructor = clazz;
}
if (GUI.getVarFromURL('saveString') != null) GUI.load(GUI.getVarFromURL('saveString'));

View File

@ -3,8 +3,6 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="generator" content="HTML Tidy for Linux/x86 (vers 11 February 2007), see www.w3.org" />
<title>gui-dat</title>
<link rel="icon" type="image/png" href="demo/assets/favicon.png" />
<link href="demo/demo.css" media="screen" rel="stylesheet" type="text/css" />
@ -22,6 +20,8 @@
<script type="text/javascript" src="controllers/controller.number.js">
</script>
<script type="text/javascript" src="controllers/controller.string.js">
</script>
<script type="text/javascript" src="controllers/scrubber.js">
</script>
<script type="text/javascript" src="demo/improvedNoise.js">
</script>
@ -34,16 +34,17 @@
window.onload = function() {
prettyPrint();
var fizzyText = new FizzyText("gui-dat");
var gui = new GUI();
var timer = new GUI.Timer(gui);
// Text field
gui.add(fizzyText, "message");
gui.add(fizzyText, "message")
.at(1000, "is")
.at(2000, "the")
.at(3000, "shit");
// Sliders with min and max
gui.add(fizzyText, "maxSize", 0.5, 7);
@ -57,245 +58,35 @@
gui.add(fizzyText, "displayOutline");
// Fires a function called "explode"
gui.add(fizzyText, "explode").name("Explode!"); // Specify a custom name.
gui.add(fizzyText, "explode")
.at(1000)
.at(2000)
.at(3000); // Specify a custom name.
gui.add(GUI, "showSaveString");
gui.add(GUI, "saveURL");
gui.divider();
// gui.add(timer, "playhead").step(100).listen();
gui.add(timer, "playPause");
/*
gui.add(timer, "windowMin").listen();
gui.add(timer, "windowWidth").listen();
*/
// Javascript for documentation
getCollapsables();
handleListening();
//gui.add(timer, "pause");
};
function toggle(e) {
if(this.className == 'collapsed') {
this.className = 'expanded';
} else {
this.className = 'collapsed';
}
}
function getCollapsables() {
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
};
}
collapsed = document.getElementsByClassName('collapsed');
expanded = document.getElementsByClassName('expanded');
}
function handleListening() {
for(var i = 0; i < collapsed.length; i++) {
collapsed[i].addEventListener('click', toggle, false);
}
for(var j = 0; j < expanded.length; j++) {
expanded[i].addEventListener('click', toggle, false);
}
}
//]]>
</script>
</head>
<body>
<div id="container">
<!-- GUIDAT logo -->
<div id="helvetica-demo"></div>
<!-- It gives you this! -->
<div id="notifier"></div>
<h1><a href="http://twitter.com/guidat"><img src="demo/assets/profile.png" border="0" alt="GUI-DAT flag" /></a></h1>
<p><strong>gui-dat</strong> is a lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.</p>
<ul>
<li><a href="https://github.com/jonobr1/gui-dat/raw/versions/gui.min.js"><strong>Download the minified source</strong></a> <small>[11kb]</small></li>
<li><a href="http://github.com/jonobr1/gui-dat">Contribute on GitHub!</a></li>
</ul>
<h2>Basic Usage</h2>
<pre id="demo-pre" class="prettyprint">
&lt;script type="text/javascript" src="gui.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
window.onload = function() {
var fizzyText = new <a href="demo/demo.js">FizzyText</a>("gui-dat");
var gui = new GUI();
// Text field
gui.add(fizzyText, "message");
// Sliders with min and max
gui.add(fizzyText, "maxSize", 0.5, 7);
gui.add(fizzyText, "growthSpeed", 0.01, 1);
gui.add(fizzyText, "speed", 0.1, 2);
// Sliders with min, max and increment.
gui.add(fizzyText, "noiseStrength", 10, 100, 5);
// Boolean checkbox
gui.add(fizzyText, "displayOutline");
// Fires a function called "explode"
gui.add(fizzyText, "explode").name("Explode!"); // Specify a custom name.
};
&lt;/script&gt;
</pre>
<ul id="desc">
<li><strong>gui-dat</strong> will infer the type of the property you're trying to add<br />
(based on its initial value) and create the corresponding control.</li>
<li>The properties must be public, i.e. defined by <code><strong>this</strong>.prop = value</code>.</li>
</ul>
<!--
<h2 class="collapsed">Fire a function when someone uses a control</h2>
<pre class="prettyprint">gui.add(obj, "propName").onChange(function(n) {
alert("You changed me to " + n);
});</pre>-->
<div class="collapsed">
<h2 class="section">Saving your parameters</h2>
<div class="collapsable">
<p>The simplest way to save your parameters is via <code>GUI.saveURL()</code>. This method directs your browser to a URL containing the current GUI settings.</p>
<pre class="prettyprint">
// Make a button for the url function
gui.add(GUI, "saveURL");</pre>
</div>
</div>
<div class="collapsed">
<h2 class="section">Advanced saving</h2>
<div class="collapsable">
<p>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.</p>
<p>First, add the method <code>GUI.showSaveString()</code> to a gui object:</p>
<pre class="prettyprint">var gui = new 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");</pre>
<p>Clicking the "showSaveString" button bring up an alert with a string. Copy and paste that string into the method <code>GUI.load()</code> before you instantiate any gui objects.</p>
<pre class="prettyprint">
// Replace COPIED STRING with the value you got from showSaveString()
GUI.load("COPIED STRING");
var gui = new GUI();
// Now these properties will be set to the values you just saved.
gui.add(someObject, "someProperty");
gui.add(someObject, "someOtherProperty");</pre>
<p><strong>Save strings won't work if you change the order in which you've added properties to your gui objects, or the order of the gui objects themselves.</strong>. If you want to add more parameters to your gui and use an old save string, make sure they're added after the properties whose values you've saved.</p>
</div>
</div>
<div class="collapsed">
<h2 class="section">Listen for variable changes outside of the GUI</h2>
<div class="collapsable">
<p>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 <code>listen()</code> method.</p>
<pre class="prettyprint">gui.add(obj, "changingProperty").listen();</pre>
</div>
</div>
<div class="collapsed">
<h2 class="section">Advanced listening</h2>
<div class="collapsable">
<p>By default, <strong>gui-dat</strong> will create an internal interval that checks for changes in the values you've marked with <code>listen()</code>. If you'd like to check for these changes in an interval of your own definition, use the following:</p>
<pre class="prettyprint">
gui.autoListen = false; // disables internal interval
gui.add(obj, "changingProperty").listen();
// Make your own loop
setInterval(function() {
gui.listen(); // updates values you've marked with listen()
}, 1000 / 60);</pre>
<p>Alternatively, you can forego calling <code>listen()</code> on individual controllers, and instead choose to monitor changes in <em>all</em> values controlled by your gui.</p>
<pre class="prettyprint">
gui.autoListen = false; // disables internal interval
gui.add(obj, "add");
gui.add(obj, "lotsa");
gui.add(obj, "properties");
// Make your own loop
setInterval(function() {
gui.listenAll(); // updates ALL values managed by this gui
}, 1000 / 60);</pre>
</div>
</div>
<div class="collapsed">
<h2 class="section">Multiple panels and custom placement</h2>
<div class="collapsable">
<p>You can instantiate multiple <code>GUI</code> objects and name them however you'd like.</p>
<pre class="prettyprint">var gui1 = new GUI();
var gui2 = new GUI();
// The name function overwrites the "Show Controls" text.
gui1.name("Utilities");
gui2.name("Camera Placement");</pre>
<p>By default, <strong>gui-dat</strong> 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.</p>
<pre class="prettyprint">
// Notice this belongs to the GUI class (uppercase)
// and not an instance thereof.
GUI.autoPlace = false;
var gui = new GUI();
// Do some custom styles ...
gui.domElement.style.position = "absolute";
gui.domElement.style.top = "20px";
gui.domElement.style.left = "20px";
document.getElementById("my-gui-container").appendChild( gui.domElement );</pre>
</div>
</div>
<div class="collapsed">
<h2 class="section last">Pro tips.</h2>
<div class="collapsable">
<ol id="secrets">
<li><strong>gui-dat</strong> panels are resizeable. Drag the show/hide button.</li>
<li>Pro tip #2 forthcoming.</li>
</ol>
</div>
</div>
<footer>Initiated by <a href="http://georgemichaelbrower.com/">George Michael Brower</a> and <a href="http://jonobr1.com/">Jono Brandel</a> of the Data Arts Team, Google Creative Lab.
</footer>
</body>
</html>