mirror of
https://github.com/dataarts/dat.gui.git
synced 2024-12-12 04:08:27 +00:00
totally resizeable :)
This commit is contained in:
parent
8ba92f76cd
commit
554767fa70
@ -18,6 +18,8 @@ var NumberController = function() {
|
||||
var max = arguments[4];
|
||||
var step = arguments[5];
|
||||
|
||||
console.log("NumberController", this.propertyName, arguments);
|
||||
|
||||
if (!step) {
|
||||
if (min != undefined && max != undefined) {
|
||||
step = (max-min)*0.01;
|
||||
@ -28,8 +30,6 @@ var NumberController = function() {
|
||||
|
||||
var numberField = document.createElement('input');
|
||||
numberField.setAttribute('id', this.propertyName);
|
||||
|
||||
// Little up and down arrows are pissing me off.
|
||||
numberField.setAttribute('type', 'text');
|
||||
numberField.setAttribute('value', this.getValue());
|
||||
|
||||
@ -47,7 +47,7 @@ var NumberController = function() {
|
||||
numberField.addEventListener('blur', function(e) {
|
||||
var val = parseFloat(this.value);
|
||||
if (!isNaN(val)) {
|
||||
_this.updateValue(val);
|
||||
_this.updateDisplay();
|
||||
} else {
|
||||
this.value = _this.getValue();
|
||||
}
|
||||
|
18
demo/demo.js
18
demo/demo.js
@ -47,6 +47,7 @@ function FizzyText(message) {
|
||||
var textAscent = 82;
|
||||
var textOffsetLeft = 80;
|
||||
var noiseScale = 300;
|
||||
var frameTime = 30;
|
||||
|
||||
var colors = ["#00aeff", "#0fa954", "#54396e", "#e61d5f"];
|
||||
|
||||
@ -146,8 +147,16 @@ function FizzyText(message) {
|
||||
// the createBitmap function.
|
||||
this.message = message;
|
||||
|
||||
var loop = function() {
|
||||
// Don't render if we don't see it.
|
||||
// Would be cleaner if I dynamically acquired the top of the canvas.
|
||||
if (document.body.scrollTop < height + 20) {
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// This calls the render function every 30 milliseconds.
|
||||
setInterval(render, 30);
|
||||
setInterval(loop, frameTime);
|
||||
|
||||
// This class is responsible for drawing and moving those little
|
||||
// colored dots.
|
||||
@ -196,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 = constrain(this.r, 0, _this.maxSize);
|
||||
this.r = GUI.constrain(this.r, 0, _this.maxSize);
|
||||
|
||||
// If we're tiny, keep moving around until we find a black
|
||||
// pixel.
|
||||
@ -215,10 +224,5 @@ function FizzyText(message) {
|
||||
|
||||
}
|
||||
|
||||
var constrain = function (v, o1, o2) {
|
||||
if (v < o1) v = o1;
|
||||
else if (v > o2) v = o2;
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
33
gui.css
33
gui.css
@ -1,34 +1,43 @@
|
||||
#guidat {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 1001;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.guidat {
|
||||
color: #fff;
|
||||
position: fixed;
|
||||
width: 280px;
|
||||
z-index: 200;
|
||||
opacity: 0.97;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
margin-left: -300px;
|
||||
text-align: left;
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#guidat,
|
||||
#guidat input {
|
||||
.guidat,
|
||||
.guidat input {
|
||||
font: 9.5px Lucida Grande, sans-serif;
|
||||
}
|
||||
|
||||
#guidat-controllers {
|
||||
.guidat-controllers {
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
/*
|
||||
-moz-transition: height .2s ease-out;
|
||||
-webkit-transition: height .2s ease-out;
|
||||
transition: height .2s ease-out;
|
||||
*/
|
||||
}
|
||||
|
||||
#guidat-toggle {
|
||||
a.guidat-toggle {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
@ -39,7 +48,7 @@
|
||||
|
||||
}
|
||||
|
||||
#guidat-toggle:hover {
|
||||
a.guidat-toggle:hover {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
@ -112,7 +121,7 @@ width: 148px;
|
||||
color: #00aeff;
|
||||
}
|
||||
|
||||
#guidat .guidat-controller.boolean input {
|
||||
.guidat .guidat-controller.boolean input {
|
||||
margin-top: 6px;
|
||||
margin-right: 2px;
|
||||
font-size: 20px;
|
||||
|
251
gui.js
251
gui.js
@ -2,39 +2,177 @@ var GUI = function() {
|
||||
|
||||
var _this = this;
|
||||
|
||||
var MIN_WIDTH = 200;
|
||||
var MAX_WIDTH = 500;
|
||||
|
||||
var controllers = [];
|
||||
var listening = [];
|
||||
|
||||
var autoListen = true;
|
||||
|
||||
var listenInterval;
|
||||
|
||||
var _this = this, open = false,
|
||||
controllers = [], controllersWatched = [];
|
||||
|
||||
// Sum total of heights of controllers in this gui
|
||||
var controllerHeight;
|
||||
|
||||
var curControllerContainerHeight = 0;
|
||||
|
||||
// How big we get when we open
|
||||
var openHeight;
|
||||
|
||||
var _this = this, open = false;
|
||||
|
||||
var name;
|
||||
var width = 280;
|
||||
|
||||
var resizeTo = 0;
|
||||
var resizeTimeout;
|
||||
|
||||
this.domElement = document.createElement('div');
|
||||
this.domElement.setAttribute('id', 'guidat');
|
||||
this.domElement.setAttribute('class', 'guidat');
|
||||
this.domElement.style.width = width+'px'
|
||||
|
||||
controllerContainer = document.createElement('div');
|
||||
controllerContainer.setAttribute('id', 'guidat-controllers');
|
||||
var controllerContainer = document.createElement('div');
|
||||
controllerContainer.setAttribute('class', 'guidat-controllers');
|
||||
|
||||
// @doob
|
||||
// I think this is way more elegant than the negative margin.
|
||||
// Only wish we didn't have to see the scrollbar on its way open.
|
||||
// Any thoughts?
|
||||
controllerContainer.style.height = '0px';
|
||||
|
||||
toggleButton = document.createElement('a');
|
||||
toggleButton.setAttribute('id', 'guidat-toggle');
|
||||
var toggleButton = document.createElement('a');
|
||||
toggleButton.setAttribute('class', 'guidat-toggle');
|
||||
toggleButton.setAttribute('href', '#');
|
||||
toggleButton.innerHTML = "Show Controls";
|
||||
toggleButton.addEventListener('click', function(e) {
|
||||
_this.toggle();
|
||||
|
||||
var toggleDragged = false;
|
||||
var dragDisplacementY = 0;
|
||||
var togglePressed = false;
|
||||
|
||||
var my, pmy, mx, pmx;
|
||||
|
||||
var resize = function(e) {
|
||||
if (!open) {
|
||||
open = true;
|
||||
curControllerContainerHeight = openHeight = 0;
|
||||
}
|
||||
pmy = my;
|
||||
pmx = mx;
|
||||
my = e.pageY;
|
||||
mx = e.pageX;
|
||||
|
||||
var dmy = my - pmy;
|
||||
// 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 *= Math.pow(d, 1.5);
|
||||
|
||||
}
|
||||
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();
|
||||
|
||||
// Clears lingering slider column
|
||||
_this.domElement.style.width = (width+1)+'px';
|
||||
setTimeout(function() {
|
||||
_this.domElement.style.width = width+'px';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
if (togglePressed && toggleDragged) {
|
||||
|
||||
if (dragDisplacementX == 0) {
|
||||
|
||||
// Clears lingering slider column
|
||||
_this.domElement.style.width = (width+1)+'px';
|
||||
setTimeout(function() {
|
||||
_this.domElement.style.width = width+'px';
|
||||
}, 1);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
console.log("HIDING, wTF");
|
||||
} 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 (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;
|
||||
|
||||
@ -70,7 +208,6 @@ var GUI = function() {
|
||||
};
|
||||
|
||||
this.listen = function(whoToListenTo) {
|
||||
|
||||
var arr = whoToListenTo || listening;
|
||||
for (var i in arr) {
|
||||
arr[i].updateDisplay();
|
||||
@ -100,11 +237,6 @@ var GUI = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
var error = function(str) {
|
||||
if (typeof console.log == 'function') {
|
||||
console.error("[GUI ERROR] " + str);
|
||||
}
|
||||
};
|
||||
|
||||
var construct = function(constructor, args) {
|
||||
function F() {
|
||||
@ -121,15 +253,15 @@ var GUI = function() {
|
||||
|
||||
// Have we already added this?
|
||||
if (alreadyControlled(object, propertyName)) {
|
||||
error("Controller for \"" + propertyName+"\" already added.");
|
||||
return;
|
||||
// GUI.error("Controller for \"" + propertyName+"\" already added.");
|
||||
// return;
|
||||
}
|
||||
|
||||
var value = object[propertyName];
|
||||
|
||||
// Does this value exist? Is it accessible?
|
||||
if (value == undefined) {
|
||||
error(object + " either has no property \""+propertyName+"\", or the property is inaccessible.");
|
||||
GUI.error(object + " either has no property \""+propertyName+"\", or the property is inaccessible.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,11 +270,11 @@ var GUI = function() {
|
||||
|
||||
// Do we know how to deal with this data type?
|
||||
if (handler == undefined) {
|
||||
error("Cannot create controller for data type \""+type+"\"");
|
||||
GUI.error("Cannot create controller for data type \""+type+"\"");
|
||||
return;
|
||||
}
|
||||
|
||||
var args = [_this]; // Set first arg (parent) to this
|
||||
var args = [this]; // Set first arg (parent) to this
|
||||
for (var j = 0; j < arguments.length; j++) {
|
||||
args.push(arguments[j]);
|
||||
}
|
||||
@ -151,7 +283,7 @@ var GUI = function() {
|
||||
|
||||
// Were we able to make the controller?
|
||||
if (!controllerObject) {
|
||||
error("Error creating controller for \""+propertyName+"\".");
|
||||
GUI.error("Error creating controller for \""+propertyName+"\".");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -159,10 +291,30 @@ var GUI = function() {
|
||||
controllerContainer.appendChild(controllerObject.domElement);
|
||||
controllers.push(controllerObject);
|
||||
|
||||
// Compute sum height of controllers.
|
||||
controllerHeight = 0;
|
||||
for (var i in controllers) {
|
||||
controllerHeight += controllers[i].domElement.offsetHeight;
|
||||
}
|
||||
|
||||
openHeight = controllerHeight;
|
||||
|
||||
checkForOverflow();
|
||||
|
||||
|
||||
|
||||
return controllerObject;
|
||||
|
||||
}
|
||||
|
||||
var checkForOverflow = function() {
|
||||
if (controllerHeight - 1 > openHeight) {
|
||||
controllerContainer.style.overflowY = "auto";
|
||||
} else {
|
||||
controllerContainer.style.overflowY = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
var addHandlers = {
|
||||
"number": NumberController,
|
||||
"string": StringController,
|
||||
@ -180,12 +332,6 @@ var GUI = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
var error = function(str) {
|
||||
if (typeof console.log == 'function') {
|
||||
console.error("[GUI ERROR] " + str);
|
||||
}
|
||||
};
|
||||
|
||||
var construct = function(constructor, args) {
|
||||
function F() {
|
||||
return constructor.apply(this, args);
|
||||
@ -203,19 +349,43 @@ var GUI = function() {
|
||||
};
|
||||
|
||||
this.show = function() {
|
||||
controllerContainer.style.height = '300px';
|
||||
toggleButton.innerHTML = "Hide Controls";
|
||||
toggleButton.innerHTML = name || "Hide Controls";
|
||||
resizeTo = openHeight;
|
||||
clearTimeout(resizeTimeout);
|
||||
beginResize();
|
||||
open = true;
|
||||
}
|
||||
|
||||
this.hide = function() {
|
||||
controllerContainer.style.height = '0px';
|
||||
toggleButton.innerHTML = "Show Controls";
|
||||
toggleButton.innerHTML = name || "Show Controls";
|
||||
resizeTo = 0;
|
||||
clearTimeout(resizeTimeout);
|
||||
beginResize();
|
||||
open = false;
|
||||
}
|
||||
|
||||
this.name = function(n) {
|
||||
name = n;
|
||||
toggleButton.innerHTML = n;
|
||||
}
|
||||
|
||||
var beginResize = function() {
|
||||
//console.log("Resizing from " + curControllerContainerHeight + " to " + resizeTo);
|
||||
curControllerContainerHeight += (resizeTo - curControllerContainerHeight)*0.6;
|
||||
if (Math.abs(curControllerContainerHeight-resizeTo) < 1) {
|
||||
curControllerContainerHeight = resizeTo;
|
||||
} else {
|
||||
resizeTimeout = setTimeout(beginResize, 1000/30);
|
||||
}
|
||||
controllerContainer.style.height = Math.round(curControllerContainerHeight)+'px';
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
GUI.autoPlace = true;
|
||||
GUI.autoPlaceContainer = null;
|
||||
|
||||
// Util functions
|
||||
|
||||
GUI.makeUnselectable = function(elem) {
|
||||
@ -234,7 +404,18 @@ GUI.makeSelectable = function(elem) {
|
||||
|
||||
GUI.map = function(v, i1, i2, o1, o2) {
|
||||
var v = o1 + (o2 - o1) * ((v - i1) / (i2 - i1));
|
||||
return v;
|
||||
}
|
||||
|
||||
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.log == 'function') {
|
||||
console.GUI.error("[GUI ERROR] " + str);
|
||||
}
|
||||
};
|
||||
|
||||
|
39
index.html
39
index.html
@ -26,7 +26,6 @@
|
||||
var fizzyText = new FizzyText("gui-dat");
|
||||
|
||||
var gui = new GUI();
|
||||
document.body.appendChild( gui.domElement );
|
||||
|
||||
// Text field
|
||||
gui.add(fizzyText, "message");
|
||||
@ -72,7 +71,6 @@ window.onload = function() {
|
||||
var fizzyText = new <a href="demo/demo.js">FizzyText</a>("gui-dat");
|
||||
|
||||
var gui = new GUI();
|
||||
document.body.appendChild( gui.domElement );
|
||||
|
||||
// Text field
|
||||
gui.add(fizzyText, "message");
|
||||
@ -108,13 +106,13 @@ window.onload = function() {
|
||||
<hr/>
|
||||
<h2>Listen for variable changes <em>outside</em> of the GUI</h2>
|
||||
<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, "propName").listen();</pre>
|
||||
<pre class="prettyprint">gui.add(obj, "changingProperty").listen();</pre>
|
||||
<hr/>
|
||||
<h2>Advanced listening</h2>
|
||||
<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:
|
||||
<pre class="prettyprint">
|
||||
gui.autoListen = false; // disables internal interval
|
||||
gui.add(obj, "propName").listen();
|
||||
gui.add(obj, "changingProperty").listen();
|
||||
|
||||
// Make your own loop
|
||||
setInterval(function() {
|
||||
@ -133,6 +131,39 @@ setInterval(function() {
|
||||
gui.listenAll(); // updates ALL values managed by this gui
|
||||
}, 1000 / 60);
|
||||
</pre>
|
||||
<hr/>
|
||||
<h2>Multiple panels and custom placement</h2>
|
||||
<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>
|
||||
<!--
|
||||
<hr/>
|
||||
<h2>Secrets</h2>
|
||||
<ol id="secrets">
|
||||
<strong>gui-dat</strong> panels are resizeable. <br/>
|
||||
Press H to make panels invisible.
|
||||
</ol>
|
||||
-->
|
||||
<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>
|
||||
|
Loading…
Reference in New Issue
Block a user