From f62a04c8e9d4d803937f14466208f7d98d17f277 Mon Sep 17 00:00:00 2001
From: George Michael Brower
Date: Wed, 26 Jan 2011 19:45:34 -0700
Subject: [PATCH] Version 0.1
---
demo/demo.css | 70 +++++--
demo/demo.js | 225 +++++++++++---------
gui-tobeminified.js | 489 ++++++++++++++++++++++++++++++++++++++++++++
gui.css | 2 +-
gui.min.js | 1 +
index.html | 122 +++--------
6 files changed, 694 insertions(+), 215 deletions(-)
create mode 100644 gui-tobeminified.js
create mode 100644 gui.min.js
diff --git a/demo/demo.css b/demo/demo.css
index 0994563..bd65ce6 100644
--- a/demo/demo.css
+++ b/demo/demo.css
@@ -18,7 +18,7 @@ h1 {
font-weight: 800;
text-transform: lowercase;
line-height: 80px;
- margin: 20px 0 0 0;
+ margin: 20px 0 20px 0;
}
h1 a:link, h1 a:visited, h1 a:hover, h1 a:active {
@@ -26,20 +26,27 @@ h1 a:link, h1 a:visited, h1 a:hover, h1 a:active {
margin-right: 7px;
}
-h1 span {
-
-}
-
h1 img {
width: 45px;
height: 45px;
-moz-border-radius: 9px;
border-radius: 9px;
- margin-bottom: 20px;
+ margin-bottom: 8px;
}
h2 {
+ margin-top: 30px;
font-size: 18px;
+ margin-bottom: 24px;
+}
+
+#helvetica-demo {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 800;
+ height: 300;
+ z-index: -1;
}
pre {
@@ -50,39 +57,62 @@ pre {
font: 10px Monaco, monospace;
}
-p { font-size: 125%; max-width: 530px; line-height: 18px; margin-bottom: 36px; }
+p, ul {
+ font-size: 125%;
+ max-width: 530px;
+ line-height: 18px;
+ margin-bottom: 24px;
+}
+
+li {
+ margin-left: 18px;
+}
+
+ul#desc {
+ list-style: circle;
+ font-size: 100%;
+ max-width: 380px;
+}
a:link {
color: #00aeff;
}
+
a:visited {
color: #0fa954;
}
+
a:hover {
color: #e61d5f;
}
+
a:active {
color: #54396e;
}
footer {
-background-color: #eee;
-width: 510px;
-padding: 10px;
+ background-color: #eee;
+ width: 510px;
+ padding: 10px;
}
-#columns {
- position: fixed;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 10px;
+pre a:link,
+pre a:visited,
+pre a:active {
+color: #ccc;
}
-#columns div {
- float: left;
- width : auto;
- height: 10px;
+pre a:hover {
+color: #e61d5f;
+}
+
+code {
+ font: 10px Monaco, monospace;
+}
+
+code strong {
+ font-weight: normal;
+ color: #e61d5f;
}
/* SPAN elements with the classes below are added by prettyprint. */
diff --git a/demo/demo.js b/demo/demo.js
index 7568a34..1029d3f 100644
--- a/demo/demo.js
+++ b/demo/demo.js
@@ -1,142 +1,169 @@
-function DynamicText(message, width, height, textAscent) {
-
+function FizzyText(message) {
+
var _this = this;
-
+
+ var width = 550;
+ var height = 200;
+ var textAscent = 82;
+ var textLeft = 80;
+
+
this.growthSpeed = 0.5;
this.minSize = 0;
- this.maxSize = 3;
-
+ this.maxSize = 3.2;
+
this.noiseScale = 300;
this.noiseStrength = 10;
- this.stepSize = 1;
-
+ this.speed = 0.4;
+
this.displayOutline = false;
-
- var message = message;
-
- this.width = width;
- this.height = height;
-
+
this.textAscent = textAscent;
-
- var colors = [
- "#00aeff",
- "#0fa954",
- "#54396e",
- "#e61d5f"
- ]
-
+
+
+ var colors = ["#00aeff", "#0fa954", "#54396e", "#e61d5f"];
+
var r = document.createElement('canvas');
var s = r.getContext('2d');
-
+
var c = document.createElement('canvas');
var g = c.getContext('2d');
-
- r.setAttribute('width', width);
- c.setAttribute('width', width);
+
+ r.setAttribute('width', width);
+ c.setAttribute('width', width);
r.setAttribute('height', height);
c.setAttribute('height', height);
-
+
document.getElementById('helvetica-demo').appendChild(c);
-
- var pixels = [];
+
+ var pixels = [];
var particles = [];
-
- s.font = g.font = "800 "+textAscent+"px helvetica, arial, sans-serif";
-
- // Set reference onto particles
- for (var i = 0; i < 1000; i++) {
- particles.push( new Particle(Math.random()*width, Math.random()*height));
- }
-
- var createBitmap = function(m) {
+
+ s.font = g.font = "800 " + textAscent + "px helvetica, arial, sans-serif";
+
+ // Set reference onto particles
+ for (var i = 0; i < 1000; i++) {
+ particles.push(new Particle(Math.random() * width, Math.random() * height));
+ }
+
+ var createBitmap = function (m) {
s.fillStyle = "#fff";
s.fillRect(0, 0, width, height);
-
+
s.fillStyle = "#222";
- s.fillText(m, 0, textAscent);
-
+ s.fillText(m, textLeft, textAscent);
+
// Pull reference
var imageData = s.getImageData(0, 0, width, height);
pixels = imageData.data;
-
+
};
-
- var render = function() {
-
+
+ var render = function () {
+
g.clearRect(0, 0, width, height);
-
- if(_this.displayOutline) {
+
+ if (_this.displayOutline) {
g.globalCompositeOperation = "source-over";
g.strokeStyle = "#000";
- g.lineWidth = .25;
- g.strokeText(message, 0, textAscent);
+ g.lineWidth = .5;
+ g.strokeText(message, textLeft, textAscent);
}
-
+
g.globalCompositeOperation = "darker";
-
+
for (var i = 0; i < particles.length; i++) {
- g.fillStyle = colors[i%colors.length];
+ g.fillStyle = colors[i % colors.length];
particles[i].render();
}
};
-
- var getPosition = function(i) {
- return { x: (i - (width * 4) * Math.floor(i/(width * 4))) / 4, y: Math.floor(i/(width * 4)) };
- };
-
- var getColor = function(x, y) {
- var base = (Math.floor(y) * width + Math.floor(x)) * 4;
- var c = { r: pixels[base + 0], g: pixels[base + 1], b: pixels[base + 2], a: pixels[base + 3]};
- return "rgb("+c.r+","+c.g+","+c.b+")";
+ var getPosition = function (i) {
+ return {
+ x: (i - (width * 4) * Math.floor(i / (width * 4))) / 4,
+ y: Math.floor(i / (width * 4))
+ };
};
-
- this.__defineGetter__("message", function() {
+
+ var getColor = function (x, y) {
+ var base = (Math.floor(y) * width + Math.floor(x)) * 4;
+ var c = {
+ r: pixels[base + 0],
+ g: pixels[base + 1],
+ b: pixels[base + 2],
+ a: pixels[base + 3]
+ };
+
+ return "rgb(" + c.r + "," + c.g + "," + c.b + ")";
+ };
+
+ this.__defineGetter__("message", function () {
return message;
});
-
- this.__defineSetter__("message", function(m) {
+
+ this.__defineSetter__("message", function (m) {
message = m;
createBitmap(message);
});
-
- createBitmap(message);
- setInterval(render, 30);
-
- function Particle(x, y, c) {
- this.p = { x: x, y: y };
- this.r = 0;
-
- this.render = function() {
- var c = getColor(this.x, this.y);
-
- var angle = noise(this.p.x/_this.noiseScale, this.p.y/_this.noiseScale) * _this.noiseStrength;
- var c = getColor(this.p.x, this.p.y);
- if (c == "rgb(255,255,255)") {
- this.r -= _this.growthSpeed;
- } else {
- this.r += _this.growthSpeed;
- }
- this.p.x += Math.cos(angle) * _this.stepSize;
- this.p.y += -Math.sin(angle) * _this.stepSize;
- this.r = constrain(this.r, _this.minSize, _this.maxSize);
- if(this.r <= _this.minSize) {
- this.p.x = Math.random() * width;
- this.p.y = Math.random() * height;
- }
- g.beginPath();
- g.arc(this.p.x, this.p.y, this.r, 0, Math.PI*2, false);
- g.fill();
+
+ this.explode = function() {
+ var mag = Math.random()*30+30;
+ for (var i in particles) {
+ var angle= Math.random()*Math.PI*2;
+ particles[i].vx = Math.cos(angle)*mag;
+ particles[i].vy = Math.sin(angle)*mag;
}
- }
+ };
+ this.message = message;
- var constrain = function(v, o1, o2) {
- if (v < o1) v = o1;
- else if (v > o2) v = o2;
- return v;
- }
+ setInterval(render, 30);
+
+ function Particle(x, y, c) {
+ this.x = x;
+ this.y = y;
-}
+ this.vx = 0;
+ this.vy = 0;
+ this.r = 0;
+
+ this.render = function () {
+ var c = getColor(this.x, this.y);
+ var angle = noise(this.x / _this.noiseScale, this.y / _this.noiseScale) * _this.noiseStrength;
+
+ var onScreen = this.x > 0 && this.x < width &&
+ this.y > 0 && this.y < height;
+ var isBlack = c != "rgb(255,255,255)" &&
+ onScreen;
+
+ if (isBlack) {
+ this.r += _this.growthSpeed;
+ } else {
+ this.r -= _this.growthSpeed;
+ }
+ this.vx *= 0.5;
+ this.vy *= 0.5;
+ this.x += Math.cos(angle) * _this.speed + this.vx;
+ this.y += -Math.sin(angle) * _this.speed + this.vy;
+ this.r = constrain(this.r, _this.minSize, _this.maxSize);
+ if (this.r <= _this.minSize) {
+ this.x = Math.random() * width;
+ this.y = Math.random() * height;
+ }
+ if (this.r <= 0) {
+ return;
+ }
+ g.beginPath();
+ g.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
+ g.fill();
+ }
+ }
+
+ var constrain = function (v, o1, o2) {
+ if (v < o1) v = o1;
+ else if (v > o2) v = o2;
+ return v;
+ }
+
+}
\ No newline at end of file
diff --git a/gui-tobeminified.js b/gui-tobeminified.js
new file mode 100644
index 0000000..4dce9e3
--- /dev/null
+++ b/gui-tobeminified.js
@@ -0,0 +1,489 @@
+// This version of gui.js appends the style definitions via javascript.
+var GUI = new function() {
+
+ var _this = this;
+
+ var controllers = [];
+
+ var style = '#guidat{color:#fff;position:fixed;width:280px;z-index:200;opacity:.97;top:0;left:100%;margin-left:-300px;background-color:#fff;-moz-transition:margin-top .2s ease-out;-webkit-transition:margin-top .2s ease-out;transition:margin-top .2s ease-out;-webkit-box-shadow:0 0 10px rgba(0,0,0,0.3);-moz-box-shadow:0 0 10px rgba(0,0,0,0.3);box-shadow:0 0 10px rgba(0,0,0,0.3)}#guidat,#guidat input{font:9.5px Lucida Grande,sans-serif}#guidat-controllers{height:300px;overflow-y:auto;overflow-x:hidden;background-color:rgba(0,0,0,0.1)}#guidat-toggle{text-decoration:none;cursor:pointer;color:#fff;background-color:#222;text-align:center;display:block;padding:5px}#guidat-toggle:hover{background-color:#000}.guidat-controller{padding:3px;height:25px;clear:left;border-bottom:1px solid #222;background-color:#111}.guidat-controller,.guidat-controller input,.guidat-slider-bg,.guidat-slider-fg{-moz-transition:background-color .15s linear;-webkit-transition:background-color .15s linear;transition:background-color .15s linear}.guidat-controller.boolean:hover,.guidat-controller.function:hover{background-color:#000}.guidat-controller input{float:right;outline:none;border:0;padding:4px;margin-top:2px;background-color:#222}.guidat-controller input:hover{background-color:#444}.guidat-controller input:focus{background-color:#555}.guidat-controller.number{border-left:5px solid #00aeff}.guidat-controller.string{border-left:5px solid #1ed36f}.guidat-controller.string input{border:0;color:#1ed36f;margin-right:2px;width:148px}.guidat-controller.boolean{border-left:5px solid #54396e}.guidat-controller.function{border-left:5px solid #e61d5f}.guidat-controller.number input[type=text]{width:35px;margin-left:5px;margin-right:2px;color:#00aeff}#guidat .guidat-controller.boolean input{margin-top:6px;margin-right:2px;font-size:20px}.guidat-controller:last-child{border-bottom:none;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.5);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.5);box-shadow:0 1px 3px rgba(0,0,0,0.5)}.guidat-propertyname{padding:5px;padding-top:7px;cursor:default;display:inline-block}.guidat-slider-bg:hover,.guidat-slider-bg.active{background-color:#444}.guidat-slider-bg:hover .guidat-slider-fg,.guidat-slider-bg.active .guidat-slider-fg{background-color:#52c8ff}.guidat-slider-bg{background-color:#222;cursor:ew-resize;width:40%;margin-top:2px;float:right;height:21px}.guidat-slider-fg{background-color:#00aeff;height:20px}'
+
+
+ this.add = function() {
+
+ // We need to call GUI.start() before .add()
+ if (!started) {
+ error("Make sure to call GUI.start() in the window.onload function");
+ return;
+ }
+
+ var object = arguments[0];
+ var propertyName = arguments[1];
+
+ // Have we already added this?
+ if (alreadyControlled(object, propertyName)) {
+ 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.");
+ return;
+ }
+
+ var type = typeof value;
+ var handler = addHandlers[type];
+
+ // Do we know how to deal with this data type?
+ if (handler == undefined) {
+ error("Cannot create controller for data type \""+type+"\"");
+ return;
+ }
+
+ var controllerObject = handler.apply(this, arguments);
+
+ // Were we able to make the controller?
+ if (!controllerObject) {
+ error("Error creating controller for \""+propertyName+"\".");
+ return;
+ }
+
+ // Success.
+ controllerContainer.appendChild(controllerObject.domElement);
+ controllers.push(controllerObject);
+
+ return controllerObject;
+
+ }
+
+ var addHandlers = {
+
+ "number": function() {
+ return construct(NumberController, arguments);
+ },
+
+ "string": function() {
+ return construct(StringController, arguments);
+ },
+
+ "boolean": function() {
+ return construct(BooleanController, arguments);
+ },
+
+ "function": function() {
+ return construct(FunctionController, arguments);
+ },
+
+ };
+
+ var alreadyControlled = function(object, propertyName) {
+ for (var i in controllers) {
+ if (controllers[i].object == object &&
+ controllers[i].propertyName == propertyName) {
+ return true;
+ }
+ }
+ 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);
+ }
+ F.prototype = constructor.prototype;
+ return new F();
+ };
+
+
+
+ // GUI ... GUI
+
+ this.domElement = null;
+ var controllerContainer;
+ var started = false;
+ var open = false;
+
+ // TODO: obtain this dynamically?
+ var domElementMarginTop = 300;
+
+ this.start = function() {
+
+ var styleSheet = document.createElement('style');
+ styleSheet.setAttribute('type', 'text/css');
+ styleSheet.innerHTML = style;
+ document.getElementsByTagName('head')[0].appendChild(styleSheet);
+
+
+ this.domElement = document.createElement('div');
+ this.domElement.setAttribute('id', 'guidat');
+
+ controllerContainer = document.createElement('div');
+ controllerContainer.setAttribute('id', 'guidat-controllers');
+
+ toggleButton = document.createElement('a');
+ toggleButton.setAttribute('id', 'guidat-toggle');
+ toggleButton.setAttribute('href', '#');
+ toggleButton.innerHTML = "Show Controls";
+ toggleButton.addEventListener('click', function(e) {
+ _this.toggle();
+ e.preventDefault();
+ }, false);
+
+ this.domElement.appendChild(controllerContainer);
+ this.domElement.appendChild(toggleButton);
+
+ this.domElement.style.marginTop = -domElementMarginTop+"px";
+
+ document.body.appendChild(this.domElement);
+
+ started = true;
+
+ };
+
+ this.toggle = function() {
+
+ if (open) {
+ this.hide();
+ } else {
+ this.show();
+ }
+
+ };
+
+ this.show = function() {
+ this.domElement.style.marginTop = 0+"px";
+ toggleButton.innerHTML = "Hide Controls";
+ open = true;
+ }
+
+ this.hide = function() {
+ this.domElement.style.marginTop = -domElementMarginTop+"px";
+ toggleButton.innerHTML = "Show Controls";
+ open = false;
+ }
+
+};
+// TODO: Leaving the window while dragging the slider and then removing the mouse
+// still leaves slider in focus.
+// TODO: Problem with multiple sliders.
+var Slider = function(numberController, min, max, step, initValue) {
+
+ var min = min;
+ var max = max;
+ var step = step;
+
+ var clicked = false;
+ var _this = this;
+
+ var x, px;
+
+ this.domElement = document.createElement('div');
+ this.fg = document.createElement('div');
+ this.domElement.setAttribute('class', 'guidat-slider-bg');
+ this.fg.setAttribute('class', 'guidat-slider-fg');
+
+ this.domElement.appendChild(this.fg);
+
+ var map = function(v, i1, i2, o1, o2) {
+ var v = o1 + (o2 - o1) * ((v - i1) / (i2 - i1));
+ if (v < o1) v = o1;
+ else if (v > o2) v = o2;
+ return v;
+ }
+
+ var findPos = function(obj) {
+ var curleft = curtop = 0;
+ if (obj.offsetParent) {
+ do {
+ curleft += obj.offsetLeft;
+ curtop += obj.offsetTop;
+ } while (obj = obj.offsetParent);
+ return [curleft,curtop];
+ }
+ }
+
+ this.__defineSetter__('value', function(e) {
+
+ var pct = map(e, min, max, 0, 100);
+ this.fg.style.width = pct+"%";
+
+ });
+
+ var onDrag = function(e) {
+ if (!clicked) return;
+ var pos = findPos(_this.domElement);
+ var val = map(e.pageX, pos[0], pos[0] + _this.domElement.offsetWidth, min, max);
+ val = Math.round(val/step)*step;
+ numberController.updateValue(val);
+ }
+
+ this.domElement.addEventListener('mousedown', function(e) {
+ clicked = true;
+ x = px = e.pageX;
+ _this.domElement.setAttribute('class', 'guidat-slider-bg active');
+ _this.fg.setAttribute('class', 'guidat-slider-fg active');
+ onDrag(e);
+ }, false);
+
+
+ document.addEventListener('mouseup', function(e) {
+ _this.domElement.setAttribute('class', 'guidat-slider-bg');
+ _this.fg.setAttribute('class', 'guidat-slider-fg');
+ clicked = false;
+ }, false);
+
+ document.addEventListener('mousemove', onDrag, false);
+
+
+
+
+ this.value = initValue;
+
+}
+var Controller = function() {
+
+ var onChange = null;
+
+ this.setName = function(n) {
+ this.propertyNameElement.innerHTML = n;
+ }
+
+ this.setValue = function(n) {
+ this.object[this.propertyName] = n;
+ if (onChange != null) {
+ onChange.call(this, n);
+ }
+ }
+
+ this.getValue = function() {
+ return this.object[this.propertyName];
+ }
+
+ this.onChange = function(fnc) {
+ onChange = fnc;
+ }
+
+ this.makeUnselectable = function(elem) {
+ elem.onselectstart = function() { return false; };
+ elem.style.MozUserSelect = "none";
+ elem.style.KhtmlUserSelect = "none";
+ elem.unselectable = "on";
+ }
+
+ this.makeSelectable = function(elem) {
+ elem.onselectstart = function() { };
+ elem.style.MozUserSelect = "auto";
+ elem.style.KhtmlUserSelect = "auto";
+ elem.unselectable = "off";
+ }
+
+ this.domElement = document.createElement('div');
+ this.domElement.setAttribute('class', 'guidat-controller ' + this.type);
+
+ this.object = arguments[0];
+ this.propertyName = arguments[1];
+
+ this.propertyNameElement = document.createElement('span');
+ this.propertyNameElement.setAttribute('class', 'guidat-propertyname');
+ this.setName(this.propertyName);
+ this.domElement.appendChild(this.propertyNameElement);
+
+ this.makeUnselectable(this.domElement);
+
+};
+var BooleanController = function() {
+ this.type = "boolean";
+ Controller.apply(this, arguments);
+
+ var _this = this;
+ var input = document.createElement('input');
+ input.setAttribute('type', 'checkbox');
+
+ this.domElement.addEventListener('click', function(e) {
+ input.checked = !input.checked;
+ e.preventDefault();
+ _this.setValue(input.checked);
+ }, false);
+
+ input.addEventListener('mouseup', function(e) {
+ input.checked = !input.checked; // counteracts default.
+ }, false);
+
+ this.domElement.style.cursor = "pointer";
+ this.propertyNameElement.style.cursor = "pointer";
+ this.domElement.appendChild(input);
+
+};
+BooleanController.prototype = new Controller();
+BooleanController.prototype.constructor = BooleanController;
+var FunctionController = function() {
+ this.type = "function";
+ var _this = this;
+ Controller.apply(this, arguments);
+ this.domElement.addEventListener('click', function() {
+ _this.object[_this.propertyName].call(_this.object);
+ }, false);
+ this.domElement.style.cursor = "pointer";
+ this.propertyNameElement.style.cursor = "pointer";
+};
+FunctionController.prototype = new Controller();
+FunctionController.prototype.constructor = FunctionController;
+// TODO: Provide alternate controllers for non-html5 browsers?
+var NumberController = function() {
+
+ this.type = "number";
+
+ Controller.apply(this, arguments);
+
+ var _this = this;
+
+ // If we simply click and release a number field, we want to highlight it.
+ // This variable keeps track of whether or not we've dragged
+ var draggedNumberField = false;
+
+ var clickedNumberField = false;
+
+ var y = py = 0;
+
+ var min = arguments[2];
+ var max = arguments[3];
+ var step = arguments[4];
+
+ if (!step) {
+ if (min && max) {
+ step = (max-min)*0.01;
+ } else {
+ step = 1;
+ }
+ }
+
+ 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());
+
+ if (step) numberField.setAttribute('step', step);
+
+ this.domElement.appendChild(numberField);
+
+ var slider;
+
+ if (min != undefined && max != undefined) {
+ slider = new Slider(this, min, max, step, this.getValue());
+ this.domElement.appendChild(slider.domElement);
+ }
+
+ numberField.addEventListener('blur', function(e) {
+ var val = parseFloat(this.value);
+ if (!isNaN(val)) {
+ _this.updateValue(val);
+ } else {
+ this.value = _this.getValue();
+ }
+ }, false);
+
+ numberField.addEventListener('mousewheel', function(e) {
+ e.preventDefault();
+ this.updateValue(_this.getValue() + Math.abs(e.wheelDeltaY)/e.wheelDeltaY*step);
+ return false;
+ }, false);
+
+ numberField.addEventListener('mousedown', function(e) {
+ py = y = e.pageY;
+ clickedNumberField = true;
+ document.addEventListener('mousemove', dragNumberField, false);
+ }, false);
+
+ document.addEventListener('mouseup', function(e) {
+ document.removeEventListener('mousemove', dragNumberField, false);
+ _this.makeSelectable(GUI.domElement);
+ _this.makeSelectable(numberField);
+ if (clickedNumberField && !draggedNumberField) {
+ numberField.focus();
+ numberField.select();
+ }
+ draggedNumberField = false;
+ clickedNumberField = false;
+ }, false);
+
+ // Kinda nast
+ if (navigator.appVersion.indexOf('chrome') != -1) {
+ document.addEventListener('mouseout', function(e) {
+ document.removeEventListener('mousemove', dragNumberField, false);
+ }, false);
+ }
+
+ var dragNumberField = function(e) {
+ draggedNumberField = true;
+ e.preventDefault();
+
+ // We don't want to be highlighting this field as we scroll.
+ // Or any other fields in this gui for that matter ...
+ // TODO: Make makeUselectable go through each element and child element.
+ _this.makeUnselectable(GUI.domElement);
+ _this.makeUnselectable(numberField);
+
+ py = y;
+ y = e.pageY;
+ var dy = py - y;
+ var newVal = _this.getValue() + dy*step;
+ _this.updateValue(newVal);
+ return false;
+ }
+
+ this.updateValue = function(val) {
+
+ val = parseFloat(val);
+
+ if (min != undefined && val <= min) {
+ val = min;
+ } else if (max != undefined && val >= max) {
+ val = max;
+ }
+ _this.setValue(val);
+
+ numberField.value = _this.getValue();
+ if (slider) slider.value = _this.getValue();
+ }
+
+};
+
+NumberController.prototype = new Controller();
+NumberController.prototype.constructor = NumberController;
+var StringController = function() {
+
+ this.type = "string";
+
+ var _this = this;
+
+ Controller.apply(this, arguments);
+
+ var input = document.createElement('input');
+
+ var initialValue = this.getValue();
+
+ input.setAttribute('value', initialValue);
+ input.setAttribute('spellcheck', 'false');
+ this.domElement.addEventListener('mouseup', function() {
+ input.focus();
+ input.select();
+ }, false);
+
+ input.addEventListener('keyup', function() {
+ _this.setValue(input.value);
+ }, false);
+
+ this.domElement.appendChild(input);
+};
+StringController.prototype = new Controller();
+StringController.prototype.constructor = StringController;
\ No newline at end of file
diff --git a/gui.css b/gui.css
index 005ec90..e55b459 100644
--- a/gui.css
+++ b/gui.css
@@ -94,7 +94,7 @@
border: 0;
color: #1ed36f;
margin-right: 2px;
-width: 53%;
+width: 148px;
}
.guidat-controller.boolean {
diff --git a/gui.min.js b/gui.min.js
new file mode 100644
index 0000000..8d5d355
--- /dev/null
+++ b/gui.min.js
@@ -0,0 +1 @@
+var GUI=new function(){var g=this;var c=[];var a="#guidat{color:#fff;position:fixed;width:280px;z-index:200;opacity:.97;top:0;left:100%;margin-left:-300px;background-color:#fff;-moz-transition:margin-top .2s ease-out;-webkit-transition:margin-top .2s ease-out;transition:margin-top .2s ease-out;-webkit-box-shadow:0 0 10px rgba(0,0,0,0.3);-moz-box-shadow:0 0 10px rgba(0,0,0,0.3);box-shadow:0 0 10px rgba(0,0,0,0.3)}#guidat,#guidat input{font:9.5px Lucida Grande,sans-serif}#guidat-controllers{height:300px;overflow-y:auto;overflow-x:hidden;background-color:rgba(0,0,0,0.1)}#guidat-toggle{text-decoration:none;cursor:pointer;color:#fff;background-color:#222;text-align:center;display:block;padding:5px}#guidat-toggle:hover{background-color:#000}.guidat-controller{padding:3px;height:25px;clear:left;border-bottom:1px solid #222;background-color:#111}.guidat-controller,.guidat-controller input,.guidat-slider-bg,.guidat-slider-fg{-moz-transition:background-color .15s linear;-webkit-transition:background-color .15s linear;transition:background-color .15s linear}.guidat-controller.boolean:hover,.guidat-controller.function:hover{background-color:#000}.guidat-controller input{float:right;outline:none;border:0;padding:4px;margin-top:2px;background-color:#222}.guidat-controller input:hover{background-color:#444}.guidat-controller input:focus{background-color:#555}.guidat-controller.number{border-left:5px solid #00aeff}.guidat-controller.string{border-left:5px solid #1ed36f}.guidat-controller.string input{border:0;color:#1ed36f;margin-right:2px;width:148px}.guidat-controller.boolean{border-left:5px solid #54396e}.guidat-controller.function{border-left:5px solid #e61d5f}.guidat-controller.number input[type=text]{width:35px;margin-left:5px;margin-right:2px;color:#00aeff}#guidat .guidat-controller.boolean input{margin-top:6px;margin-right:2px;font-size:20px}.guidat-controller:last-child{border-bottom:none;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.5);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.5);box-shadow:0 1px 3px rgba(0,0,0,0.5)}.guidat-propertyname{padding:5px;padding-top:7px;cursor:default;display:inline-block}.guidat-slider-bg:hover,.guidat-slider-bg.active{background-color:#444}.guidat-slider-bg:hover .guidat-slider-fg,.guidat-slider-bg.active .guidat-slider-fg{background-color:#52c8ff}.guidat-slider-bg{background-color:#222;cursor:ew-resize;width:40%;margin-top:2px;float:right;height:21px}.guidat-slider-fg{background-color:#00aeff;height:20px}";this.add=function(){if(!h){i("Make sure to call GUI.start() in the window.onload function");return}var n=arguments[0];var l=arguments[1];if(d(n,l)){i('Controller for "'+l+'" already added.');return}var q=n[l];if(q==undefined){i(n+' either has no property "'+l+'", or the property is inaccessible.');return}var p=typeof q;var o=j[p];if(o==undefined){i('Cannot create controller for data type "'+p+'"');return}var m=o.apply(this,arguments);if(!m){i('Error creating controller for "'+l+'".');return}b.appendChild(m.domElement);c.push(m);return m};var j={number:function(){return k(NumberController,arguments)},string:function(){return k(StringController,arguments)},"boolean":function(){return k(BooleanController,arguments)},"function":function(){return k(FunctionController,arguments)},};var d=function(m,l){for(var n in c){if(c[n].object==m&&c[n].propertyName==l){return true}}return false};var i=function(l){if(typeof console.log=="function"){console.error("[GUI ERROR] "+l)}};var k=function(m,l){function n(){return m.apply(this,l)}n.prototype=m.prototype;return new n()};this.domElement=null;var b;var h=false;var f=false;var e=300;this.start=function(){var l=document.createElement("style");l.setAttribute("type","text/css");l.innerHTML=a;document.getElementsByTagName("head")[0].appendChild(l);this.domElement=document.createElement("div");this.domElement.setAttribute("id","guidat");b=document.createElement("div");b.setAttribute("id","guidat-controllers");toggleButton=document.createElement("a");toggleButton.setAttribute("id","guidat-toggle");toggleButton.setAttribute("href","#");toggleButton.innerHTML="Show Controls";toggleButton.addEventListener("click",function(m){g.toggle();m.preventDefault()},false);this.domElement.appendChild(b);this.domElement.appendChild(toggleButton);this.domElement.style.marginTop=-e+"px";document.body.appendChild(this.domElement);h=true};this.toggle=function(){if(f){this.hide()}else{this.show()}};this.show=function(){this.domElement.style.marginTop=0+"px";toggleButton.innerHTML="Hide Controls";f=true};this.hide=function(){this.domElement.style.marginTop=-e+"px";toggleButton.innerHTML="Show Controls";f=false}};var Slider=function(a,e,j,c,i){var e=e;var j=j;var c=c;var h=false;var f=this;var k,l;this.domElement=document.createElement("div");this.fg=document.createElement("div");this.domElement.setAttribute("class","guidat-slider-bg");this.fg.setAttribute("class","guidat-slider-fg");this.domElement.appendChild(this.fg);var b=function(m,p,n,q,o){var m=q+(o-q)*((m-p)/(n-p));if(mo){m=o}}return m};var g=function(m){var n=curtop=0;if(m.offsetParent){do{n+=m.offsetLeft;curtop+=m.offsetTop}while(m=m.offsetParent);return[n,curtop]}};this.__defineSetter__("value",function(n){var m=b(n,e,j,0,100);this.fg.style.width=m+"%"});var d=function(m){if(!h){return}var o=g(f.domElement);var n=b(m.pageX,o[0],o[0]+f.domElement.offsetWidth,e,j);n=Math.round(n/c)*c;a.updateValue(n)};this.domElement.addEventListener("mousedown",function(m){h=true;k=l=m.pageX;f.domElement.setAttribute("class","guidat-slider-bg active");f.fg.setAttribute("class","guidat-slider-fg active");d(m)},false);document.addEventListener("mouseup",function(m){f.domElement.setAttribute("class","guidat-slider-bg");f.fg.setAttribute("class","guidat-slider-fg");h=false},false);document.addEventListener("mousemove",d,false);this.value=i};var Controller=function(){var a=null;this.setName=function(b){this.propertyNameElement.innerHTML=b};this.setValue=function(b){this.object[this.propertyName]=b;if(a!=null){a.call(this,b)}};this.getValue=function(){return this.object[this.propertyName]};this.onChange=function(b){a=b};this.makeUnselectable=function(b){b.onselectstart=function(){return false};b.style.MozUserSelect="none";b.style.KhtmlUserSelect="none";b.unselectable="on"};this.makeSelectable=function(b){b.onselectstart=function(){};b.style.MozUserSelect="auto";b.style.KhtmlUserSelect="auto";b.unselectable="off"};this.domElement=document.createElement("div");this.domElement.setAttribute("class","guidat-controller "+this.type);this.object=arguments[0];this.propertyName=arguments[1];this.propertyNameElement=document.createElement("span");this.propertyNameElement.setAttribute("class","guidat-propertyname");this.setName(this.propertyName);this.domElement.appendChild(this.propertyNameElement);this.makeUnselectable(this.domElement)};var BooleanController=function(){this.type="boolean";Controller.apply(this,arguments);var b=this;var a=document.createElement("input");a.setAttribute("type","checkbox");this.domElement.addEventListener("click",function(c){a.checked=!a.checked;c.preventDefault();b.setValue(a.checked)},false);a.addEventListener("mouseup",function(c){a.checked=!a.checked},false);this.domElement.style.cursor="pointer";this.propertyNameElement.style.cursor="pointer";this.domElement.appendChild(a)};BooleanController.prototype=new Controller();BooleanController.prototype.constructor=BooleanController;var FunctionController=function(){this.type="function";var a=this;Controller.apply(this,arguments);this.domElement.addEventListener("click",function(){a.object[a.propertyName].call(a.object)},false);this.domElement.style.cursor="pointer";this.propertyNameElement.style.cursor="pointer"};FunctionController.prototype=new Controller();FunctionController.prototype.constructor=FunctionController;var NumberController=function(){this.type="number";Controller.apply(this,arguments);var f=this;var a=false;var g=false;var i=py=0;var e=arguments[2];var j=arguments[3];var d=arguments[4];if(!d){if(e&&j){d=(j-e)*0.01}else{d=1}}var c=document.createElement("input");c.setAttribute("id",this.propertyName);c.setAttribute("type","text");c.setAttribute("value",this.getValue());if(d){c.setAttribute("step",d)}this.domElement.appendChild(c);var b;if(e!=undefined&&j!=undefined){b=new Slider(this,e,j,d,this.getValue());this.domElement.appendChild(b.domElement)}c.addEventListener("blur",function(k){var l=parseFloat(this.value);if(!isNaN(l)){f.updateValue(l)}else{this.value=f.getValue()}},false);c.addEventListener("mousewheel",function(k){k.preventDefault();this.updateValue(f.getValue()+Math.abs(k.wheelDeltaY)/k.wheelDeltaY*d);return false},false);c.addEventListener("mousedown",function(k){py=i=k.pageY;g=true;document.addEventListener("mousemove",h,false)},false);document.addEventListener("mouseup",function(k){document.removeEventListener("mousemove",h,false);f.makeSelectable(GUI.domElement);f.makeSelectable(c);if(g&&!a){c.focus();c.select()}a=false;g=false},false);if(navigator.appVersion.indexOf("chrome")!=-1){document.addEventListener("mouseout",function(k){document.removeEventListener("mousemove",h,false)},false)}var h=function(m){a=true;m.preventDefault();f.makeUnselectable(GUI.domElement);f.makeUnselectable(c);py=i;i=m.pageY;var k=py-i;var l=f.getValue()+k*d;f.updateValue(l);return false};this.updateValue=function(k){k=parseFloat(k);if(e!=undefined&&k<=e){k=e}else{if(j!=undefined&&k>=j){k=j}}f.setValue(k);c.value=f.getValue();if(b){b.value=f.getValue()}}};NumberController.prototype=new Controller();NumberController.prototype.constructor=NumberController;var StringController=function(){this.type="string";var c=this;Controller.apply(this,arguments);var b=document.createElement("input");var a=this.getValue();b.setAttribute("value",a);b.setAttribute("spellcheck","false");this.domElement.addEventListener("mouseup",function(){b.focus();b.select()},false);b.addEventListener("keyup",function(){c.setValue(b.value)},false);this.domElement.appendChild(b)};StringController.prototype=new Controller();StringController.prototype.constructor=StringController;
\ No newline at end of file
diff --git a/index.html b/index.html
index 391a72c..7b66cfc 100644
--- a/index.html
+++ b/index.html
@@ -1,66 +1,34 @@
- GUI-DAT
+ gui-dat
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
gui-dat is a lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.
- • Download the minified source [2.3kb]
- • Contribute on GitHub!
+
+
Basic Usage
-
-
-<script type="text/javascript" src="gui.min.js"></script>
-<script type="text/javascript">
-
-var controllableObject =
- {
- numberProperty: 20,
- constrainedNum: 0,
- notchedNum: 240,
- textProperty: "a string",
- anotherTextProperty: "another string",
- booleanProperty: false,
- anotherBooleanProperty: false,
- functionProperty: function() {
- alert("I am a function!");
- }
- };
-
-window.onload = function() {
-
- GUI.start();
-
- // Creates a number box
- GUI.add(controllableObject, "numberProperty");
-
- // Creates a slider (min, max)
- GUI.add(controllableObject, "constrainedNum", -100, 100)
-
- // Creates a slider with notches
- GUI.add(controllableObject, "notchedNum", 0, 800, 100)
-
- // Creates a text field
- GUI.add(controllableObject, "textProperty");
-
- // Creates a checkbox
- GUI.add(controllableObject, "booleanProperty");
-
- // Creates a button
- GUI.add(controllableObject, "functionProperty")
- .setName("Fire a Function");
-
-};
-
-</script>
+ <script type="text/javascript" src="gui.min.js"></script>
<script type="text/javascript">
window.onload = function() {
var fizzyText = new FizzyText("gui-dat");
GUI.start();
// Adds a text field
GUI.add(fizzyText, "message");
// Adds 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);
// Adds sliders with min, max and increment.
GUI.add(fizzyText, "noiseStrength", 10, 100, 5);
// Adds a boolean checkbox
GUI.add(fizzyText, "displayOutline");
// Adds a function button
GUI.add(fizzyText, "explode")
};
</script>
+
+
+ - gui-dat will infer the type of the property you're trying to add
(based on its initial value) and create the corresponding control.
+ - The properties must be public, i.e. defined by
this.prop = value
.
+