This commit is contained in:
George Michael Brower 2011-11-07 13:24:02 -08:00
parent 5207fed918
commit b531665963
56 changed files with 17327 additions and 4376 deletions

View File

@ -1,5 +0,0 @@
**dat.gui** is a lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.
Check the [index page](http://dataarts.github.com/dat.gui/) for usage.
Initiated by [George Michael Brower](http://georgemichaelbrower.com/) and [Jono Brandel](http://jonobr1.com/) of the Data Arts Team, Google Creative Lab.

View File

@ -1,22 +0,0 @@
/**
* Provides requestAnimationFrame in a cross browser way.
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 );
};
} )();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

View File

@ -1,231 +0,0 @@
function FizzyText(message) {
var that = this;
// These are the variables that we manipulate with gui-dat.
// Notice they're all defined with "this". That makes them public.
// Otherwise, gui-dat can't see them.
this.growthSpeed = 0.2; // how fast do particles change size?
this.maxSize = 5.59; // how big can they get?
this.noiseStrength = 10; // how turbulent is the flow?
this.speed = 0.4; // how fast do particles move?
this.displayOutline = false; // should we draw the message as a stroke?
this.framesRendered = 0;
// __defineGetter__ and __defineSetter__ makes JavaScript believe that
// we've defined a variable 'this.message'. This way, whenever we
// change the message variable, we can call some more functions.
this.__defineGetter__("message", function () {
return message;
});
this.__defineSetter__("message", function (m) {
message = m;
createBitmap(message);
});
// 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() {
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;
}
};
////////////////////////////////////////////////////////////////
var _this = this;
var width = 550;
var height = 200;
var textAscent = 101;
var textOffsetLeft = 80;
var noiseScale = 300;
var frameTime = 30;
var colors = ["#00aeff", "#0fa954", "#54396e", "#e61d5f"];
// This is the context we use to get a bitmap of text using
// the getImageData function.
var r = document.createElement('canvas');
var s = r.getContext('2d');
// This is the context we actually use to draw.
var c = document.createElement('canvas');
var g = c.getContext('2d');
r.setAttribute('width', width);
c.setAttribute('width', width);
r.setAttribute('height', height);
c.setAttribute('height', height);
// Add our demo to the HTML
document.getElementById('helvetica-demo').appendChild(c);
// Stores bitmap image
var pixels = [];
// Stores a list of particles
var particles = [];
// Set g.font to the same font as the bitmap canvas, incase we
// want to draw some outlines.
s.font = g.font = "800 82px helvetica, arial, sans-serif";
// Instantiate some particles
for (var i = 0; i < 1000; i++) {
particles.push(new Particle(Math.random() * width, Math.random() * height));
}
// This function creates a bitmap of pixels based on your message
// It's called every time we change the message property.
var createBitmap = function (msg) {
s.fillStyle = "#fff";
s.fillRect(0, 0, width, height);
s.fillStyle = "#222";
s.fillText(msg, textOffsetLeft, textAscent);
// Pull reference
var imageData = s.getImageData(0, 0, width, height);
pixels = imageData.data;
};
// Called once per frame, updates the animation.
var render = function () {
that.framesRendered ++;
g.clearRect(0, 0, width, height);
if (_this.displayOutline) {
g.globalCompositeOperation = "source-over";
g.strokeStyle = "#000";
g.lineWidth = .5;
g.strokeText(message, textOffsetLeft, textAscent);
}
g.globalCompositeOperation = "darker";
for (var i = 0; i < particles.length; i++) {
g.fillStyle = colors[i % colors.length];
particles[i].render();
}
};
// Returns x, y coordinates for a given index in the pixel array.
var getPosition = function (i) {
return {
x: (i - (width * 4) * Math.floor(i / (width * 4))) / 4,
y: Math.floor(i / (width * 4))
};
};
// Returns a color for a given pixel in the pixel array.
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 calls the setter we've defined above, so it also calls
// the createBitmap function.
this.message = message;
var loop = function() {
requestAnimationFrame(loop);
// 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.
loop();
// This class is responsible for drawing and moving those little
// colored dots.
function Particle(x, y, c) {
// Position
this.x = x;
this.y = y;
// Size of particle
this.r = 0;
// This velocity is used by the explode function.
this.vx = 0;
this.vy = 0;
// Called every frame
this.render = function () {
// What color is the pixel we're sitting on top of?
var c = getColor(this.x, this.y);
// Where should we move?
var angle = noise(this.x / noiseScale, this.y / noiseScale) * _this.noiseStrength;
// Are we within the boundaries of the image?
var onScreen = this.x > 0 && this.x < width &&
this.y > 0 && this.y < height;
var isBlack = c != "rgb(255,255,255)" && onScreen;
// If we're on top of a black pixel, grow.
// If not, shrink.
if (isBlack) {
this.r += _this.growthSpeed;
} else {
this.r -= _this.growthSpeed;
}
// This velocity is used by the explode function.
this.vx *= 0.5;
this.vy *= 0.5;
// Change our position based on the flow field and our
// explode velocity.
this.x += Math.cos(angle) * _this.speed + this.vx;
this.y += -Math.sin(angle) * _this.speed + this.vy;
this.r = DAT.GUI.constrain(this.r, 0, _this.maxSize);
// If we're tiny, keep moving around until we find a black
// pixel.
if (this.r <= 0) {
this.x = Math.random() * width;
this.y = Math.random() * height;
return; // Don't draw!
}
// Draw the circle.
g.beginPath();
g.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
g.fill();
}
}
}

View File

@ -1,265 +0,0 @@
* {
padding: 0px;
margin: 0px;
}
body {
font: 9.5px/13px Lucida Grande, sans-serif;
padding: 0 20px 20px 20px;
}
#container {
max-width: 530px;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Helvetica Neue", helvetica, arial, sans-serif;
color: #222;
}
hr {
border: 0;
height: 0;
border-top: 1px dotted #ccc;
}
h1 {
font-size: 80px;
font-weight: 800;
text-transform: lowercase;
line-height: 80px;
margin: 39px 0 20px 0;
}
h1 a:link, h1 a:visited, h1 a:hover, h1 a:active {
text-decoration: none;
margin-right: 7px;
}
h1 img {
width: 45px;
height: 45px;
margin-bottom: 8px;
}
h2 {
margin-top: 30px;
font-size: 18px;
margin-bottom: 24px;
}
h2.section {
margin: 0;
padding: 20px 0px 20px 0px;
cursor: pointer;
border-top: 1px dotted #ccc;
-webkit-transition: color 0.15s linear;
}
h2.section:hover {
color: #00aeff;
}
div.collapsed h2, div.expanded h2 {
float: left;
clear: both;
width: 100%;
cursor: pointer;
}
.last {
margin-bottom: 0px !important;
}
.first {
margin-top: 0px;
}
div.trans {
border-top: 1px dotted #ccc;
margin: 0px 0px 20px 0px;
}
ol#secrets {
padding: 0px;
margin: 0px;
}
div.expanded h2:before {
content: '-';
}
div.collapsed h2:before {
content: '+';
}
div.expanded h2:before, div.collapsed h2:before {
font-weight: normal;
line-height: 2px;
float: left;
margin-top: 6px;
margin-right: 6px;
font-size: 9px;
font-family: Monaco, monospace;
}
div.collapsable>div {
padding-bottom: 10px;
}
div.collapsable {
overflow: hidden;
clear: both;
-moz-transition: height .2s ease-out;
-webkit-transition: height .2s ease-out;
transition: height .2s ease-out;
}
div.collapsable div {
padding-bottom: 20px;
margin-bottom: -20px;
height: auto;
}
div.collapsed .collapsable {
overflow: hidden;
clear: both;
height: 0;
}
div.expanded {
cursor: pointer;
}
#helvetica-demo {
position: absolute;
left: 0;
top: 0;
width: 800;
height: 300;
z-index: -1;
}
#notifier {
position: fixed;
right: 0;
top: 230px;
width: 271px;
height: 142px;
background: url("assets/itgivesyouthis.jpg") center 0 no-repeat;
z-index: -2;
margin: 30px 22px 0 0;
}
pre {
margin: 20px 0 20px 0;
padding: 15px;
background-color: #222;
max-width: 500px;
font: 10px Monaco, monospace;
clear: both;
}
p, ul, ol {
font-size: 125%;
clear: both;
line-height: 18px;
margin-bottom: 24px;
}
li {
margin-left: 22px;
}
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 {
margin-top: 20px;
background-color: #eee;
width: 510px;
padding: 10px;
clear: both;
color: #444;
}
pre a:link,
pre a:visited,
pre a:active,
pre a:hover {
color: #ccc;
}
code {
font: 10px Monaco, monospace;
}
code strong {
font-weight: normal;
color: #e61d5f;
}
.str {
color: #0fa954;
}
.kwd {
color: #e61d5f;
}
.com {
color: #555;
}
.typ {
color: #ccc;
}
.lit {
color: #00aeff;
}
.pun, .opn, .clo {
color: #777;
}
.pln {
color: #ccc;
}
.tag {
color: #555;
}
.atn {
color: #555;
}
.atv {
color: #777;
}
.dec {
color: #606;
}

View File

@ -1,181 +0,0 @@
// http://mrl.nyu.edu/~perlin/noise/
var ImprovedNoise = function () {
var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,
23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,
174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,
133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,
89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,
202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,
248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,
178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,
14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,
93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
for ( var i = 0; i < 256 ; i++ ) {
p[ 256 + i ] = p[ i ];
}
function fade( t ) {
return t * t * t * ( t * ( t * 6 - 15 ) + 10 );
}
function lerp( t, a, b ) {
return a + t * ( b - a );
}
function grad( hash, x, y, z ) {
var h = hash & 15;
var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ( ( h & 1 ) == 0 ? u : -u ) + ( ( h & 2 ) == 0 ? v : -v );
}
return {
noise: function ( x, y, z ) {
var floorX = Math.floor( x ), floorY = Math.floor( y ), floorZ = Math.floor( z );
var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;
x -= floorX;
y -= floorY;
z -= floorZ;
var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1;
var u = fade( x ), v = fade( y ), w = fade( z );
var A = p[ X ] + Y, AA = p[ A ] + Z, AB = p[ A + 1 ] + Z, B = p[ X + 1 ] + Y, BA = p[ B ] + Z, BB = p[ B + 1 ] + Z;
return lerp( w, lerp( v, lerp( u, grad( p[ AA ], x, y, z ),
grad( p[ BA ], xMinus1, y, z ) ),
lerp( u, grad( p[ AB ], x, yMinus1, z ),
grad( p[ BB ], xMinus1, yMinus1, z ) ) ),
lerp( v, lerp( u, grad( p[ AA + 1 ], x, y, zMinus1 ),
grad( p[ BA + 1 ], xMinus1, y, z - 1 ) ),
lerp( u, grad( p[ AB + 1 ], x, yMinus1, zMinus1 ),
grad( p[ BB + 1 ], xMinus1, yMinus1, zMinus1 ) ) ) );
}
}
}
var currentRandom = Math.random;
// Pseudo-random generator
function Marsaglia(i1, i2) {
// from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c
var z=i1 || 362436069, w= i2 || 521288629;
var nextInt = function() {
z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF;
w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF;
return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF;
};
this.nextDouble = function() {
var i = nextInt() / 4294967296;
return i < 0 ? 1 + i : i;
};
this.nextInt = nextInt;
}
Marsaglia.createRandomized = function() {
var now = new Date();
return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
};
// Noise functions and helpers
function PerlinNoise(seed) {
var rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized();
var i, j;
// http://www.noisemachine.com/talk1/17b.html
// http://mrl.nyu.edu/~perlin/noise/
// generate permutation
var p = new Array(512);
for(i=0;i<256;++i) { p[i] = i; }
for(i=0;i<256;++i) { var t = p[j = rnd.nextInt() & 0xFF]; p[j] = p[i]; p[i] = t; }
// copy to avoid taking mod in p[0];
for(i=0;i<256;++i) { p[i + 256] = p[i]; }
function grad3d(i,x,y,z) {
var h = i & 15; // convert into 12 gradient directions
var u = h<8 ? x : y,
v = h<4 ? y : h===12||h===14 ? x : z;
return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v);
}
function grad2d(i,x,y) {
var v = (i & 1) === 0 ? x : y;
return (i&2) === 0 ? -v : v;
}
function grad1d(i,x) {
return (i&1) === 0 ? -x : x;
}
function lerp(t,a,b) { return a + t * (b - a); }
this.noise3d = function(x, y, z) {
var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255;
x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z;
var p0 = p[X]+Y, p00 = p[p0] + Z, p01 = p[p0 + 1] + Z, p1 = p[X + 1] + Y, p10 = p[p1] + Z, p11 = p[p1 + 1] + Z;
return lerp(fz,
lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x-1, y, z)),
lerp(fx, grad3d(p[p01], x, y-1, z), grad3d(p[p11], x-1, y-1,z))),
lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z-1), grad3d(p[p10 + 1], x-1, y, z-1)),
lerp(fx, grad3d(p[p01 + 1], x, y-1, z-1), grad3d(p[p11 + 1], x-1, y-1,z-1))));
};
this.noise2d = function(x, y) {
var X = Math.floor(x)&255, Y = Math.floor(y)&255;
x -= Math.floor(x); y -= Math.floor(y);
var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y;
var p0 = p[X]+Y, p1 = p[X + 1] + Y;
return lerp(fy,
lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x-1, y)),
lerp(fx, grad2d(p[p0 + 1], x, y-1), grad2d(p[p1 + 1], x-1, y-1)));
};
this.noise1d = function(x) {
var X = Math.floor(x)&255;
x -= Math.floor(x);
var fx = (3-2*x)*x*x;
return lerp(fx, grad1d(p[X], x), grad1d(p[X+1], x-1));
};
}
// these are lifted from Processing.js
// processing defaults
var noiseProfile = { generator: undefined, octaves: 4, fallout: 0.5, seed: undefined};
function noise(x, y, z) {
if(noiseProfile.generator === undefined) {
// caching
noiseProfile.generator = new PerlinNoise(noiseProfile.seed);
}
var generator = noiseProfile.generator;
var effect = 1, k = 1, sum = 0;
for(var i=0; i<noiseProfile.octaves; ++i) {
effect *= noiseProfile.fallout;
switch (arguments.length) {
case 1:
sum += effect * (1 + generator.noise1d(k*x))/2; break;
case 2:
sum += effect * (1 + generator.noise2d(k*x, k*y))/2; break;
case 3:
sum += effect * (1 + generator.noise3d(k*x, k*y, k*z))/2; break;
}
k *= 2;
}
return sum;
};

File diff suppressed because it is too large Load Diff

13
example.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript" src="build/dat.gui.min.js"></script>
<script type="text/javascript">
var obj = { x: 5 };
var gui = new dat.GUI();
gui.add(obj, 'x', 0, 10);
</script>
</body>
</html>

View File

@ -1,402 +0,0 @@
<!doctype html>
<html>
<head>
<title>dat.gui</title>
<link rel='icon' type='image/png' href='docs/assets/favicon.png'/>
<!--Minified build-->
<!--<script type='text/javascript' src='build/DAT.GUI.min.js'></script>-->
<!--Build--->
<!--<script type='text/javascript' src='build/DAT.GUI.js'></script>-->
<!--All source-->
<link href='src/DAT/GUI/GUI.css' media='screen' rel='stylesheet' type='text/css'/>
<script type='text/javascript' src='src/DAT/GUI/GUI.js'></script>
<script type='text/javascript' src='src/DAT/GUI/ControllerNumberSlider.js'></script>
<script type='text/javascript' src='src/DAT/GUI/Controller.js'></script>
<script type='text/javascript' src='src/DAT/GUI/ControllerBoolean.js'></script>
<script type='text/javascript' src='src/DAT/GUI/ControllerString.js'></script>
<script type='text/javascript' src='src/DAT/GUI/ControllerFunction.js'></script>
<script type='text/javascript' src='src/DAT/GUI/ControllerNumber.js'></script>
<!--Demo-->
<link href='docs/docs.css' media='screen' rel='stylesheet' type='text/css'/>
<script type='text/javascript' src='docs/RequestAnimationFrame.js'></script>
<script type='text/javascript' src='docs/improvedNoise.js'></script>
<script type='text/javascript' src='docs/prettify.js'></script>
<script type='text/javascript' src='docs/demo.js'></script>
<script type='text/javascript'>
//<![CDATA[
window.onload = function() {
prettyPrint();
var fizzyText = new FizzyText('dat.gui');
var gui = new DAT.GUI();
// Text field
gui.add(fizzyText, 'message');
// Sliders with min + max
gui.add(fizzyText, 'maxSize').min(0.5).max(7);
gui.add(fizzyText, 'growthSpeed').min(0.01).max(1).step(0.05);
gui.add(fizzyText, 'speed', 0.1, 2, 0.05); // shorthand for min/max/step
// 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.
// Javascript for documentation
getCollapsables();
handleListening();
};
function toggle(e) {
var collapsable = this.childNodes[3],
wrapper = collapsable.childNodes[1];
if (this.className === 'collapsed') {
this.className = 'expanded';
collapsable.style.height = wrapper.clientHeight + 'px';
} else {
this.className = 'collapsed';
collapsable.style.height = '0px';
}
}
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='docs/assets/profile.png'
border='0' alt='dat.gui flag'/></a>
</h1>
<p><strong>dat.gui</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/dataarts/dat.gui/raw/build/DAT.GUI.min.js'><strong>Download the minified source</strong></a>
<small id='buildsizemin'>[19.7kb]
</small>
</li>
<li>
<a href='https://github.com/dataarts/dat.gui/raw/build/DAT.GUI.js'><strong>Download the uncompressed source</strong></a>
<small id='buildsize'>[34.1kb]
</small>
</li>
<li><a href='http://github.com/dataarts/dat.gui'>Contribute on GitHub!</a></li>
</ul>
<h2>Basic Usage</h2>
<pre id='demo-pre' class='prettyprint'>
&lt;script type='text/javascript' src='DAT.GUI.min.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'&gt;
window.onload = function() {
var fizzyText = new <a href='docs/demo.js'>FizzyText</a>('dat.gui');
var gui = new DAT.GUI();
// Text field
gui.add(fizzyText, 'message');
// Sliders with min + max
gui.add(fizzyText, 'maxSize').min(0.5).max(7);
gui.add(fizzyText, 'growthSpeed').min(0.01).max(1).step(0.05);
gui.add(fizzyText, 'speed', 0.1, 2, 0.05); // shorthand for min/max/step
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><code>DAT.GUI</code> 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'>-->
<!--<div>-->
<!--<p>The simplest way to save your parameters is via-->
<!--<code>DAT.GUI.saveURL()</code>. This method directs your browser to a-->
<!--URL containing the current GUI settings.</p>-->
<!--<pre class='prettyprint last'>-->
<!--// Make a button for the url function-->
<!--gui.add(DAT.GUI, 'saveURL');</pre>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
<!--<div class='collapsed'>-->
<!--<h2 class='section'>Advanced saving</h2>-->
<!--<div class='collapsable'>-->
<!--<div>-->
<!--<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>DAT.GUI.showSaveString()</code> to a gui-->
<!--object:</p>-->
<!--<pre class='prettyprint'>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(DAT.GUI, 'showSaveString');</pre>-->
<!--<p>Clicking the 'showSaveString' button bring up an alert with a string.-->
<!--Copy and paste that string into the method <code>DAT.GUI.load()</code>-->
<!--before you instantiate any gui objects.</p>-->
<!--<pre class='prettyprint'>-->
<!--// Replace COPIED STRING with the value you got from showSaveString()-->
<!--DAT.GUI.load('COPIED STRING');-->
<!--var gui = new DAT.GUI();-->
<!--// Now these properties will be set to the values you just saved.-->
<!--gui.add(someObject, 'someProperty');-->
<!--gui.add(someObject, 'someOtherProperty');</pre>-->
<!--<p class='last'><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>-->
<div class='collapsed'>
<h2 class='section'>Choosing from a list of values</h2>
<div class='collapsable'>
<div>
<pre class='prettyprint first last'>gui.add(obj, 'propertyName').options(1, 2, 3, 5, 8);
// Alternatively, you can specify custom labels using object syntax
gui.add(obj, 'propertyName').options({'Small': 1, 'Medium': 2, 'Large': 3});
</pre>
</div>
</div>
</div>
<div class='collapsed'>
<h2 class='section'>Listen for variable changes inside the GUI</h2>
<div class='collapsable'>
<div>
<p>To fire a function whenever a user changes a variable via the GUI, use
the following syntax:</p>
<pre class='prettyprint'>gui.add(obj, 'propertyName').onChange(function(newValue) {
alert('You changed me to ' + newValue);
});</pre>
<p>This can be slightly annoying for types like number or string. You may
not want to fire a function while the user is sliding, or while they're
typing. To fire a function when the user has <em>finished</em> making
changes, use the following:</p>
<pre class='prettyprint'>gui.add(obj, 'propertyName').onFinishChange(function(newValue) {
alert('You just finished changing me to ' + newValue);
});</pre>
<p>Finally, if you'd like to do a little something extra when a function
is called, use the following:</p>
<pre class='prettyprint last'>gui.add(obj, 'functionName').onFire(function() {
alert('You called a function with dat.gui');
});</pre>
</div>
</div>
</div>
<div class='collapsed'>
<h2 class='section'>Listen for variable changes outside of the GUI</h2>
<div class='collapsable'>
<div>
<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 last'>gui.add(obj, 'changingProperty').listen();</pre>
</div>
</div>
</div>
<div class='collapsed'>
<h2 class='section'>Advanced listening</h2>
<div class='collapsable'>
<div>
<p>By default, <code>DAT.GUI</code> 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 last'>
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>
<div class='collapsed'>
<h2 class='section'>Multiple panels and custom placement</h2>
<div class='collapsable'>
<div>
<p>You can instantiate multiple <code>DAT.GUI</code> objects and name them
however you'd like.</p>
<pre class='prettyprint'>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');</pre>
<p>By default, <code>DAT.GUI</code> panels will be automatically added
to the HTML document and fixed to the top of the screen from right to
left. You can disable this behavior and append the gui DOM element to
a container of your choosing.</p>
<pre class='prettyprint last'>
// Notice this belongs to the DAT.GUI class (uppercase)
// and not an instance thereof.
DAT.GUI.autoPlace = false;
var gui = new DAT.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>
<div class='collapsed'>
<h2 class='section'>Pro tips.</h2>
<div class='collapsable'>
<div>
<ol id='secrets'>
<li><code>DAT.GUI</code> panels are resizeable. Drag the open/close
button.
</li>
<li>Press 'H' to show/hide GUI&apos;s.</li>
</ol>
</div>
</div>
</div>
<div class='trans'>&nbsp;</div>
<footer class='trans'>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>

89
readme.wiki Normal file
View File

@ -0,0 +1,89 @@
=dat.GUI=
A lightweight graphical user interface for changing variables in JavaScript.
Get started with dat.GUI by reading the tutorial at [http://workshop.chromeexperiments.com/examples/gui].
----
==Packaged Builds==
The easiest way to use dat.GUI in your code is by using the built source at {{{build/dat.gui.min.js}}}. These built JavaScript files bundle all the necessary dependencies to run dat.GUI.
In your {{{head}}} tag, include the following code:
{{{
<script type="text/javascript" src="dat.gui.min.js"></script>
}}}
----
==Using dat.GUI with require.js==
Internally, dat.GUI uses [http://requirejs.org/ require.js] to handle dependency management. If you're making changes to the source and want to see the effects of your changes without building, use require js.
In your {{{head}}} tag, include the following code:
{{{
<script data-main="path/to/main" src="path/to/requirejs/require.js"></script>
}}}
Then, in {{{path/to/main.js}}}:
{{{
require([
'path/to/gui/module/GUI'
], function(GUI) {
// No namespace necessary
var gui = new GUI();
});
}}}
----
==Directory Contents==
* build: Concatenated source code.
* src: Modular code in [http://requirejs.org/ require.js] format. Also includes css, [http://sass-lang.com/ scss], and html, some of which is included during build.
* tests: [https://github.com/jquery/qunit QUnit] test suite.
* utils: [http://nodejs.org/ node.js] utility scripts for compiling source.
----
==Building your own dat.GUI==
In the terminal, enter the following:
{{{
$ cd utils
$ node build_gui.js
}}}
This will create a namespaced, unminified build of dat.GUI at {{{build/dat.gui.js}}}
_To export minified source using Closure Compiler, open {{{utils/build_gui.js}}} and set the {{{minify}}} parameter to {{{true}}}._
----
==Change log==
===0.5===
* Moved to requirejs for dependency management.
* Changed global namespace from *DAT* to *dat* (lowercase).
* Added support for color controllers. See [http://workshop.chromeexperiments.com/examples/gui/#4--Color-Controllers Color Controllers].
* Added support for folders. See [http://workshop.chromeexperiments.com/examples/gui/#3--Folders Folders].
* Added support for saving named presets. See [http://workshop.chromeexperiments.com/examples/gui/examples/gui/#6--Presets Presets].
* Removed `height` parameter from GUI constructor. Scrollbar automatically induced when window is too short.
* `dat.GUI.autoPlace` parameter removed. Use `new dat.GUI( { autoPlace: false } )`. See [http://workshop.chromeexperiments.com/examples/gui/#9--Custom-Placement Custom Placement].
* `gui.autoListen` and `gui.listenAll()` removed. See [http://workshop.chromeexperiments.com/examples/gui/#11--Updating-the-Display-Manually Updating The Display Manually].
* `dat.GUI.load` removed. See [http://workshop.chromeexperiments.com/examples/gui/#5--Saving-Values Saving Values].
* Made Controller code completely agnostic of GUI. Controllers can easily be created independent of a GUI panel.
===0.4===
* Migrated from GitHub to Google Code.
----
==Thanks==
The following libraries and open-source projects were used in the development of dat.GUI.
* [http://requirejs.org/ require.js]
* [http://sass-lang.com/ Sass]
* [http://nodejs.org/ node.js]
* [https://github.com/jquery/qunit QUnit] / [http://jquery.com jquery]

View File

@ -1,114 +0,0 @@
DAT.GUI.Controller = function() {
this.parent = arguments[0];
this.object = arguments[1];
this.propertyName = arguments[2];
//if (arguments.length > 0) this.initialValue = this.propertyName[this.object];
if (arguments.length > 0) this.initialValue = this.object[this.propertyName];
this.domElement = document.createElement('div');
this.domElement.setAttribute('class', 'guidat-controller ' + this.type);
this.propertyNameElement = document.createElement('span');
this.propertyNameElement.setAttribute('class', 'guidat-propertyname');
this.name(this.propertyName);
this.domElement.appendChild(this.propertyNameElement);
DAT.GUI.makeUnselectable(this.domElement);
};
DAT.GUI.Controller.prototype.changeFunction = null;
DAT.GUI.Controller.prototype.finishChangeFunction = null;
DAT.GUI.Controller.prototype.name = function(n) {
this.propertyNameElement.innerHTML = n;
return this;
};
DAT.GUI.Controller.prototype.reset = function() {
this.setValue(this.initialValue);
return this;
};
DAT.GUI.Controller.prototype.listen = function() {
this.parent.listenTo(this);
return this;
};
DAT.GUI.Controller.prototype.unlisten = function() {
this.parent.unlistenTo(this); // <--- hasn't been tested yet
return this;
};
DAT.GUI.Controller.prototype.setValue = function(n) {
if(this.object[this.propertyName] != undefined){
this.object[this.propertyName] = n;
}else{
var o = new Object();
o[this.propertyName] = n;
this.object.set(o);
}
if (this.changeFunction != null) {
this.changeFunction.call(this, n);
}
this.updateDisplay();
return this;
};
DAT.GUI.Controller.prototype.getValue = function() {
var val = this.object[this.propertyName];
if(val == undefined) val = this.object.get(this.propertyName);
return val;
};
DAT.GUI.Controller.prototype.updateDisplay = function() {
};
DAT.GUI.Controller.prototype.onChange = function(fnc) {
this.changeFunction = fnc;
return this;
};
DAT.GUI.Controller.prototype.onFinishChange = function(fnc) {
this.finishChangeFunction = fnc;
return this;
};
DAT.GUI.Controller.prototype.options = function() {
var _this = this;
var select = document.createElement('select');
if (arguments.length == 1) {
var arr = arguments[0];
for (var i in arr) {
var opt = document.createElement('option');
opt.innerHTML = i;
opt.setAttribute('value', arr[i]);
if (arguments[i] == this.getValue()) {
opt.selected = true;
}
select.appendChild(opt);
}
} else {
for (var i = 0; i < arguments.length; i++) {
var opt = document.createElement('option');
opt.innerHTML = arguments[i];
opt.setAttribute('value', arguments[i]);
if (arguments[i] == this.getValue()) {
opt.selected = true;
}
select.appendChild(opt);
}
}
select.addEventListener('change', function() {
_this.setValue(this.value);
if (_this.finishChangeFunction != null) {
_this.finishChangeFunction.call(this, _this.getValue());
}
}, false);
_this.domElement.appendChild(select);
return this;
};

View File

@ -1,43 +0,0 @@
DAT.GUI.ControllerBoolean = function() {
this.type = "boolean";
DAT.GUI.Controller.apply(this, arguments);
var _this = this;
var input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.checked = this.getValue();
this.setValue(this.getValue());
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);
this.updateDisplay = function() {
input.checked = _this.getValue();
};
this.setValue = function(val) {
if (typeof val != "boolean") {
try {
val = eval(val);
} catch (e) {
}
}
return DAT.GUI.Controller.prototype.setValue.call(this, val);
};
};
DAT.GUI.extendController(DAT.GUI.ControllerBoolean);

View File

@ -1,30 +0,0 @@
DAT.GUI.ControllerFunction = function() {
this.type = "function";
var _this = this;
DAT.GUI.Controller.apply(this, arguments);
this.domElement.addEventListener('click', function() {
_this.fire();
}, false);
this.domElement.style.cursor = "pointer";
this.propertyNameElement.style.cursor = "pointer";
var fireFunction = null;
this.onFire = function(fnc) {
fireFunction = fnc;
return this;
}
this.fire = function() {
if (fireFunction != null) {
fireFunction.call(this);
}
_this.object[_this.propertyName].call(_this.object);
};
};
DAT.GUI.extendController(DAT.GUI.ControllerFunction);

View File

@ -1,243 +0,0 @@
DAT.GUI.ControllerNumber = function() {
this.type = "number";
DAT.GUI.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 draggingHorizontal = false;
var draggingVertical = false;
var y = 0, py = 0;
var min = arguments[3];
var max = arguments[4];
var step = arguments[5];
var defaultStep = function() {
step = (max - min) * 0.01;
};
this.min = function() {
var needsSlider = false;
if (min == undefined && max != undefined) {
needsSlider = true;
}
if (arguments.length == 0) {
return min;
} else {
min = arguments[0];
}
if (needsSlider) {
addSlider();
if (step == undefined) {
defaultStep();
}
}
return _this;
};
this.max = function() {
var needsSlider = false;
if (min != undefined && max == undefined) {
needsSlider = true;
}
if (arguments.length == 0) {
return max;
} else {
max = arguments[0];
}
if (needsSlider) {
addSlider();
if (step == undefined) {
defaultStep();
}
}
return _this;
};
this.step = function() {
if (arguments.length == 0) {
return step;
} else {
step = arguments[0];
}
return _this;
};
this.getMin = function() {
return min;
};
this.getMax = function() {
return max;
};
this.getStep = function() {
if (step == undefined) {
if (max != undefined && min != undefined) {
return (max-min)/100;
} else {
return 1;
}
} else {
return step;
}
}
var numberField = document.createElement('input');
numberField.setAttribute('id', this.propertyName);
numberField.setAttribute('type', 'text');
numberField.setAttribute('value', this.getValue());
if (step) numberField.setAttribute('step', step);
this.domElement.appendChild(numberField);
var slider;
var addSlider = function() {
slider = new DAT.GUI.ControllerNumberSlider(_this, min, max, step, _this.getValue());
_this.domElement.appendChild(slider.domElement);
};
if (min != undefined && max != undefined) {
addSlider();
}
numberField.addEventListener('blur', function() {
var val = parseFloat(this.value);
if (slider) {
DAT.GUI.removeClass(_this.domElement, 'active');
}
if (!isNaN(val)) {
_this.setValue(val);
}
}, false);
numberField.addEventListener('mousewheel', function(e) {
e.preventDefault();
_this.setValue(_this.getValue() + Math.abs(e.wheelDeltaY) / e.wheelDeltaY * _this.getStep());
return false;
}, false);
numberField.addEventListener('mousedown', function(e) {
py = y = e.pageY;
clickedNumberField = true;
DAT.GUI.makeSelectable(numberField);
document.addEventListener('mousemove', dragNumberField, false);
document.addEventListener('mouseup', mouseup, false);
}, false);
// Handle up arrow and down arrow
numberField.addEventListener('keydown', function(e) {
var newVal;
switch (e.keyCode) {
case 13: // enter
newVal = parseFloat(this.value);
_this.setValue(newVal);
break;
case 38: // up
newVal = _this.getValue() + _this.getStep();
_this.setValue(newVal);
break;
case 40: // down
newVal = _this.getValue() - _this.getStep();
_this.setValue(newVal);
break;
}
}, false);
var mouseup = function(e) {
document.removeEventListener('mousemove', dragNumberField, false);
DAT.GUI.makeSelectable(numberField);
if (clickedNumberField && !draggedNumberField) {
//numberField.focus();
//numberField.select();
}
draggedNumberField = false;
clickedNumberField = false;
if (_this.finishChangeFunction != null) {
_this.finishChangeFunction.call(this, _this.getValue());
}
draggingHorizontal = false;
draggingVertical = false;
document.removeEventListener('mouseup', mouseup, false);
};
var dragNumberField = function(e) {
py = y;
y = e.pageY;
var dy = py - y;
if (!draggingHorizontal && !draggingVertical) {
if (dy == 0) {
draggingHorizontal = true;
} else {
draggingVertical = true;
}
}
if (draggingHorizontal) {
return true;
}
DAT.GUI.addClass(_this.domElement, 'active');
DAT.GUI.makeUnselectable(_this.parent.domElement);
DAT.GUI.makeUnselectable(numberField);
draggedNumberField = true;
e.preventDefault();
var newVal = _this.getValue() + dy * _this.getStep();
_this.setValue(newVal);
return false;
};
this.options = function() {
_this.noSlider();
_this.domElement.removeChild(numberField);
return DAT.GUI.Controller.prototype.options.apply(this, arguments);
};
this.noSlider = function() {
if (slider) {
_this.domElement.removeChild(slider.domElement);
}
return this;
};
this.setValue = function(val) {
val = parseFloat(val);
if (min != undefined && val <= min) {
val = min;
} else if (max != undefined && val >= max) {
val = max;
}
return DAT.GUI.Controller.prototype.setValue.call(this, val);
};
this.updateDisplay = function() {
numberField.value = DAT.GUI.roundToDecimal(_this.getValue(), 4);
if (slider) slider.value = _this.getValue();
};
};
DAT.GUI.extendController(DAT.GUI.ControllerNumber);

View File

@ -1,64 +0,0 @@
DAT.GUI.ControllerNumberSlider = function(numberController, min, max, step, initValue) {
var clicked = false;
var _this = this;
var x, px;
this.domElement = document.createElement('div');
this.domElement.setAttribute('class', 'guidat-slider-bg');
this.fg = document.createElement('div');
this.fg.setAttribute('class', 'guidat-slider-fg');
this.domElement.appendChild(this.fg);
var onDrag = function(e) {
if (!clicked) return;
var pos = findPos(_this.domElement);
var val = DAT.GUI.map(e.pageX, pos[0], pos[0] + _this.domElement
.offsetWidth, numberController.getMin(), numberController.getMax());
val = Math.round(val / numberController.getStep()) * numberController
.getStep();
numberController.setValue(val);
};
this.domElement.addEventListener('mousedown', function(e) {
clicked = true;
x = px = e.pageX;
DAT.GUI.addClass(numberController.domElement, 'active');
onDrag(e);
document.addEventListener('mouseup', mouseup, false);
}, false);
var mouseup = function(e) {
DAT.GUI.removeClass(numberController.domElement, 'active');
clicked = false;
if (numberController.finishChangeFunction != null) {
numberController.finishChangeFunction.call(this,
numberController.getValue());
}
document.removeEventListener('mouseup', mouseup, false);
};
var findPos = function(obj) {
var curleft = 0, curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while ((obj = obj.offsetParent));
return [curleft,curtop];
}
};
this.__defineSetter__('value', function(e) {
this.fg.style.width = DAT.GUI.map(e, numberController.getMin(),
numberController.getMax(), 0, 100) + "%";
});
document.addEventListener('mousemove', onDrag, false);
this.value = initValue;
};

View File

@ -1,57 +0,0 @@
DAT.GUI.ControllerString = function() {
this.type = "string";
var _this = this;
DAT.GUI.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);
// TODO: getting messed up on ctrl a
input.addEventListener('keyup', function(e) {
if (e.keyCode == 13 && _this.finishChangeFunction != null) {
_this.finishChangeFunction.call(this, _this.getValue());
input.blur();
}
_this.setValue(input.value);
}, false);
input.addEventListener('mousedown', function(e) {
DAT.GUI.makeSelectable(input);
}, false);
input.addEventListener('blur', function() {
DAT.GUI.supressHotKeys = false;
if (_this.finishChangeFunction != null) {
_this.finishChangeFunction.call(this, _this.getValue());
}
}, false);
input.addEventListener('focus', function() {
DAT.GUI.supressHotKeys = true;
}, false);
this.updateDisplay = function() {
input.value = _this.getValue();
};
this.options = function() {
_this.domElement.removeChild(input);
return DAT.GUI.Controller.prototype.options.apply(this, arguments);
};
this.domElement.appendChild(input);
};
DAT.GUI.extendController(DAT.GUI.ControllerString);

View File

@ -1,168 +0,0 @@
#guidat {
position: fixed;
top: 0;
right: 0;
width: auto;
z-index: 1001;
text-align: right;
}
.guidat {
color: #fff;
opacity: 0.97;
text-align: left;
float: right;
margin-right: 20px;
margin-bottom: 20px;
background-color: #fff;
}
.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);
}
a.guidat-toggle:link,
a.guidat-toggle:visited,
a.guidat-toggle:active {
text-decoration: none;
cursor: pointer;
color: #fff;
background-color: #222;
text-align: center;
display: block;
padding: 5px;
}
a.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 0.15s linear;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.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 select {
margin-top: 4px;
float: right;
}
.guidat-controller input:hover {
background-color: #444;
}
.guidat-controller input:focus,
.guidat-controller.active input {
background-color: #555;
color: #fff;
}
.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: 0px 1px 3px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
}
.guidat-propertyname {
padding: 5px;
padding-top: 7px;
cursor: default;
display: inline-block;
}
.guidat-controller .guidat-slider-bg:hover,
.guidat-controller.active .guidat-slider-bg {
background-color: #444;
}
.guidat-controller .guidat-slider-bg .guidat-slider-fg:hover,
.guidat-controller.active .guidat-slider-bg .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 {
cursor: ew-resize;
background-color: #00aeff;
height: 21px;
}

File diff suppressed because it is too large Load Diff

189
src/dat/color/Color.js Normal file
View File

@ -0,0 +1,189 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/color/interpret',
'dat/color/math',
'dat/color/toString',
'dat/utils/common'
], function(interpret, math, toString, common) {
var Color = function() {
this.__state = interpret.apply(this, arguments);
if (this.__state === false) {
throw 'Failed to interpret color arguments';
}
this.__state.a = this.__state.a || 1;
};
Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];
common.extend(Color.prototype, {
toString: function() {
return toString(this);
},
toOriginal: function() {
return this.__state.conversion.write(this);
}
});
defineRGBComponent(Color.prototype, 'r', 2);
defineRGBComponent(Color.prototype, 'g', 1);
defineRGBComponent(Color.prototype, 'b', 0);
defineHSVComponent(Color.prototype, 'h');
defineHSVComponent(Color.prototype, 's');
defineHSVComponent(Color.prototype, 'v');
Object.defineProperty(Color.prototype, 'a', {
get: function() {
return this.__state.a;
},
set: function(v) {
this.__state.a = v;
}
});
Object.defineProperty(Color.prototype, 'hex', {
get: function() {
if (!this.__state.space !== 'HEX') {
this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b);
}
return this.__state.hex;
},
set: function(v) {
this.__state.space = 'HEX';
this.__state.hex = v;
}
});
function defineRGBComponent(target, component, componentHexIndex) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'RGB') {
return this.__state[component];
}
recalculateRGB(this, component, componentHexIndex);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'RGB') {
recalculateRGB(this, component, componentHexIndex);
this.__state.space = 'RGB';
}
this.__state[component] = v;
}
});
}
function defineHSVComponent(target, component) {
Object.defineProperty(target, component, {
get: function() {
if (this.__state.space === 'HSV')
return this.__state[component];
recalculateHSV(this);
return this.__state[component];
},
set: function(v) {
if (this.__state.space !== 'HSV') {
recalculateHSV(this);
this.__state.space = 'HSV';
}
this.__state[component] = v;
}
});
}
function recalculateRGB(color, component, componentHexIndex) {
if (color.__state.space === 'HEX') {
color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex);
} else if (color.__state.space === 'HSV') {
common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v));
} else {
throw 'Corrupted color state';
}
}
function recalculateHSV(color) {
var result = math.rgb_to_hsv(color.r, color.g, color.b);
common.extend(color.__state,
{
s: result.s,
v: result.v
}
);
if (!common.isNaN(result.h)) {
color.__state.h = result.h;
} else if (common.isUndefined(color.__state.h)) {
color.__state.h = 0;
}
}
return Color;
});

340
src/dat/color/interpret.js Normal file
View File

@ -0,0 +1,340 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/color/toString',
'dat/utils/common'
], function(toString, common) {
var result, toReturn;
var interpret = function() {
toReturn = false;
var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0];
common.each(INTERPRETATIONS, function(family) {
if (family.litmus(original)) {
common.each(family.conversions, function(conversion, conversionName) {
result = conversion.read(original);
if (toReturn === false && result !== false) {
toReturn = result;
result.conversionName = conversionName;
result.conversion = conversion;
return common.BREAK;
}
});
return common.BREAK;
}
});
return toReturn;
};
var INTERPRETATIONS = [
// Strings
{
litmus: common.isString,
conversions: {
THREE_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt(
'0x' +
test[1].toString() + test[1].toString() +
test[2].toString() + test[2].toString() +
test[3].toString() + test[3].toString())
};
},
write: toString
},
SIX_CHAR_HEX: {
read: function(original) {
var test = original.match(/^#([A-F0-9]{6})$/i);
if (test === null) return false;
return {
space: 'HEX',
hex: parseInt('0x' + test[1].toString())
};
},
write: toString
},
CSS_RGB: {
read: function(original) {
var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3])
};
},
write: toString
},
CSS_RGBA: {
read: function(original) {
var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);
if (test === null) return false;
return {
space: 'RGB',
r: parseFloat(test[1]),
g: parseFloat(test[2]),
b: parseFloat(test[3]),
a: parseFloat(test[4])
};
},
write: toString
}
}
},
// Numbers
{
litmus: common.isNumber,
conversions: {
HEX: {
read: function(original) {
return {
space: 'HEX',
hex: original,
conversionName: 'HEX'
}
},
write: function(color) {
return color.hex;
}
}
}
},
// Arrays
{
litmus: common.isArray,
conversions: {
RGB_ARRAY: {
read: function(original) {
if (original.length != 3) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2]
};
},
write: function(color) {
return [color.r, color.g, color.b];
}
},
RGBA_ARRAY: {
read: function(original) {
if (original.length != 4) return false;
return {
space: 'RGB',
r: original[0],
g: original[1],
b: original[2],
a: original[3]
};
},
write: function(color) {
return [color.r, color.g, color.b, color.a];
}
}
}
},
// Objects
{
litmus: common.isObject,
conversions: {
RGBA_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b) &&
common.isNumber(original.a)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b,
a: original.a
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b,
a: color.a
}
}
},
RGB_OBJ: {
read: function(original) {
if (common.isNumber(original.r) &&
common.isNumber(original.g) &&
common.isNumber(original.b)) {
return {
space: 'RGB',
r: original.r,
g: original.g,
b: original.b
}
}
return false;
},
write: function(color) {
return {
r: color.r,
g: color.g,
b: color.b
}
}
},
HSVA_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v) &&
common.isNumber(original.a)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v,
a: original.a
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v,
a: color.a
}
}
},
HSV_OBJ: {
read: function(original) {
if (common.isNumber(original.h) &&
common.isNumber(original.s) &&
common.isNumber(original.v)) {
return {
space: 'HSV',
h: original.h,
s: original.s,
v: original.v
}
}
return false;
},
write: function(color) {
return {
h: color.h,
s: color.s,
v: color.v
}
}
}
}
}
];
return interpret;
});

100
src/dat/color/math.js Normal file
View File

@ -0,0 +1,100 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
], function() {
var tmpComponent;
return {
hsv_to_rgb: function(h, s, v) {
var hi = Math.floor(h / 60) % 6;
var f = h / 60 - Math.floor(h / 60);
var p = v * (1.0 - s);
var q = v * (1.0 - (f * s));
var t = v * (1.0 - ((1.0 - f) * s));
var c = [
[v, t, p],
[q, v, p],
[p, v, t],
[p, q, v],
[t, p, v],
[v, p, q]
][hi];
return {
r: c[0] * 255,
g: c[1] * 255,
b: c[2] * 255
};
},
rgb_to_hsv: function(r, g, b) {
var min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s;
if (max != 0) {
s = delta / max;
} else {
return {
h: NaN,
s: 0,
v: 0
};
}
if (r == max) {
h = (g - b) / delta;
} else if (g == max) {
h = 2 + (b - r) / delta;
} else {
h = 4 + (r - g) / delta;
}
h /= 6;
if (h < 0) {
h += 1;
}
return {
h: h * 360,
s: s,
v: max / 255
};
},
rgb_to_hex: function(r, g, b) {
var hex = this.hex_with_component(0, 2, r);
hex = this.hex_with_component(hex, 1, g);
hex = this.hex_with_component(hex, 0, b);
return hex;
},
component_from_hex: function(hex, componentIndex) {
return (hex >> (componentIndex * 8)) & 0xFF;
},
hex_with_component: function(hex, componentIndex, value) {
return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));
}
}
});

37
src/dat/color/toString.js Normal file
View File

@ -0,0 +1,37 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/utils/common'
], function(common) {
return function(color) {
if (color.a == 1 || common.isUndefined(color.a)) {
var s = color.hex.toString(16);
while (s.length < 6) {
s = '0' + s;
}
return '#' + s;
} else {
return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';
}
}
});

View File

@ -0,0 +1,96 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/dom/dom',
'dat/utils/common'
], function(Controller, dom, common) {
/**
* @class Provides a checkbox input to alter the boolean property of an object.
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var BooleanController = function(object, property) {
BooleanController.superclass.call(this, object, property);
var _this = this;
var _prev = this.getValue();
this.__checkbox = document.createElement('input');
this.__checkbox.setAttribute('type', 'checkbox');
dom.bind(this.__checkbox, 'change', onChange, false);
this.domElement.appendChild(this.__checkbox);
// Match original value
this.updateDisplay();
function onChange() {
var cur = !_this.getValue();
if (cur !== _prev) {
_this.setValue(cur);
} else {
_this.setValue(!cur);
}
_prev = cur;
}
};
BooleanController.superclass = Controller;
common.extend(
BooleanController.prototype,
Controller.prototype,
{
setValue: function(v) {
var toReturn = BooleanController.superclass.prototype.setValue.call(this, v);
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
this.__prev = this.getValue();
return toReturn;
},
updateDisplay: function() {
if (this.getValue() === true) {
this.__checkbox.setAttribute('checked', 'checked');
} else {
this.__checkbox.removeAttribute('checked');
}
return BooleanController.superclass.prototype.updateDisplay.call(this);
}
}
);
return BooleanController;
});

View File

@ -0,0 +1,324 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/dom/dom',
'dat/color/Color',
'dat/color/interpret',
'dat/utils/common'
], function(Controller, dom, Color, interpret, common) {
var ColorController = function(object, property) {
ColorController.superclass.call(this, object, property);
this.__color = new Color(this.getValue());
this.__temp = new Color(0);
var _this = this;
this.domElement = document.createElement('div');
dom.makeSelectable(this.domElement, false);
this.__selector = document.createElement('div');
this.__selector.className = 'selector';
this.__saturation_field = document.createElement('div');
this.__saturation_field.className = 'saturation-field';
this.__field_knob = document.createElement('div');
this.__field_knob.className = 'field-knob';
this.__field_knob_border = '2px solid ';
this.__hue_knob = document.createElement('div');
this.__hue_knob.className = 'hue-knob';
this.__hue_field = document.createElement('div');
this.__hue_field.className = 'hue-field';
this.__input = document.createElement('input');
this.__input.type = 'text';
this.__input_textShadow = '0 1px 1px ';
dom.bind(this.__input, 'keydown', function(e) {
if (e.keyCode === 13) { // on enter
onBlur.call(this);
}
});
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__selector, 'mousedown', function(e) {
dom
.addClass(this, 'drag')
.bind(window, 'mouseup', function(e) {
dom.removeClass(_this.__selector, 'drag');
});
});
var value_field = document.createElement('div');
common.extend(this.__selector.style, {
width: '122px',
height: '102px',
padding: '3px',
backgroundColor: '#222',
boxShadow: '0px 1px 3px rgba(0,0,0,0.3)'
});
common.extend(this.__field_knob.style, {
position: 'absolute',
width: '12px',
height: '12px',
border: this.__field_knob_border + (this.__color.v < .5 ? '#fff' : '#000'),
boxShadow: '0px 1px 3px rgba(0,0,0,0.5)',
borderRadius: '12px',
zIndex: 1
});
common.extend(this.__hue_knob.style, {
position: 'absolute',
width: '15px',
height: '2px',
borderRight: '4px solid #fff',
zIndex: 1
});
common.extend(this.__saturation_field.style, {
width: '100px',
height: '100px',
border: '1px solid #555',
marginRight: '3px',
display: 'inline-block',
cursor: 'pointer'
});
common.extend(value_field.style, {
width: '100%',
height: '100%',
background: 'none'
});
linearGradient(value_field, 'top', 'rgba(0,0,0,0)', '#000');
common.extend(this.__hue_field.style, {
width: '15px',
height: '100px',
display: 'inline-block',
border: '1px solid #555',
cursor: 'ns-resize'
});
hueGradient(this.__hue_field);
common.extend(this.__input.style, {
outline: 'none',
// width: '120px',
textAlign: 'center',
// padding: '4px',
// marginBottom: '6px',
color: '#fff',
border: 0,
fontWeight: 'bold',
textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)'
});
dom.bind(this.__saturation_field, 'mousedown', fieldDown);
dom.bind(this.__field_knob, 'mousedown', fieldDown);
dom.bind(this.__hue_field, 'mousedown', function(e) {
setH(e);
dom.bind(window, 'mousemove', setH);
dom.bind(window, 'mouseup', unbindH);
});
function fieldDown(e) {
setSV(e);
// document.body.style.cursor = 'none';
dom.bind(window, 'mousemove', setSV);
dom.bind(window, 'mouseup', unbindSV);
}
function unbindSV() {
dom.unbind(window, 'mousemove', setSV);
dom.unbind(window, 'mouseup', unbindSV);
// document.body.style.cursor = 'default';
}
function onBlur() {
var i = interpret(this.value);
if (i !== false) {
_this.__color.__state = i;
_this.setValue(_this.__color.toOriginal());
} else {
this.value = _this.__color.toString();
}
}
function unbindH() {
dom.unbind(window, 'mousemove', setH);
dom.unbind(window, 'mouseup', unbindH);
}
this.__saturation_field.appendChild(value_field);
this.__selector.appendChild(this.__field_knob);
this.__selector.appendChild(this.__saturation_field);
this.__selector.appendChild(this.__hue_field);
this.__hue_field.appendChild(this.__hue_knob);
this.domElement.appendChild(this.__input);
this.domElement.appendChild(this.__selector);
this.updateDisplay();
function setSV(e) {
e.preventDefault();
var w = dom.getWidth(_this.__saturation_field);
var o = dom.getOffset(_this.__saturation_field);
var s = (e.clientX - o.left + document.body.scrollLeft) / w;
var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w;
if (v > 1) v = 1;
else if (v < 0) v = 0;
if (s > 1) s = 1;
else if (s < 0) s = 0;
_this.__color.v = v;
_this.__color.s = s;
_this.setValue(_this.__color.toOriginal());
return false;
}
function setH(e) {
e.preventDefault();
var s = dom.getHeight(_this.__hue_field);
var o = dom.getOffset(_this.__hue_field);
var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s;
if (h > 1) h = 1;
else if (h < 0) h = 0;
_this.__color.h = h * 360;
_this.setValue(_this.__color.toOriginal());
return false;
}
};
ColorController.superclass = Controller;
common.extend(
ColorController.prototype,
Controller.prototype,
{
updateDisplay: function() {
var i = interpret(this.getValue());
if (i !== false) {
var mismatch = false;
// Check for mismatch on the interpreted value.
common.each(Color.COMPONENTS, function(component) {
if (!common.isUndefined(i[component]) &&
!common.isUndefined(this.__color.__state[component]) &&
i[component] !== this.__color.__state[component]) {
mismatch = true;
return {}; // break
}
}, this);
// If nothing diverges, we keep our previous values
// for statefulness, otherwise we recalculate fresh
if (mismatch) {
common.extend(this.__color.__state, i);
}
}
common.extend(this.__temp.__state, this.__color.__state);
this.__temp.a = 1;
var flip = (this.__color.v < .5 || this.__color.s > .5) ? 255 : 0;
var _flip = 255 - flip;
common.extend(this.__field_knob.style, {
marginLeft: 100 * this.__color.s - 7 + 'px',
marginTop: 100 * (1 - this.__color.v) - 7 + 'px',
backgroundColor: this.__temp.toString(),
border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip +')'
});
this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px'
this.__temp.s = 1;
this.__temp.v = 1;
linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toString());
common.extend(this.__input.style, {
backgroundColor: this.__input.value = this.__color.toString(),
color: 'rgb(' + flip + ',' + flip + ',' + flip +')',
textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip +',.7)'
});
}
}
);
var vendors = ['-moz-','-o-','-webkit-','-ms-',''];
function linearGradient(elem, x, a, b) {
elem.style.background = '';
common.each(vendors, function(vendor) {
elem.style.cssText += 'background: ' + vendor + 'linear-gradient('+x+', '+a+' 0%, ' + b + ' 100%); ';
});
}
function hueGradient(elem) {
elem.style.background = '';
elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'
elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'
}
return ColorController;
});

View File

@ -0,0 +1,144 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/utils/common'
], function(common) {
/**
* @class An "abstract" class that represents a given property of an object.
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var Controller = function(object, property) {
this.initialValue = object[property];
/**
* Those who extend this class will put their DOM elements in here.
* @type {DOMElement}
*/
this.domElement = document.createElement('div');
/**
* The object to manipulate
* @type {Object}
*/
this.object = object;
/**
* The name of the property to manipulate
* @type {String}
*/
this.property = property;
/**
* The function to be called on change.
* @type {Function}
* @ignore
*/
this.__onChange = undefined;
/**
* The function to be called on finishing change.
* @type {Function}
* @ignore
*/
this.__onFinishChange = undefined;
};
common.extend(
Controller.prototype,
/** @lends dat.controllers.Controller.prototype */
{
/**
* Specify that a function fire every time someone changes the value with
* this Controller.
*
* @param {Function} fnc This function will be called whenever the value
* is modified via this Controller.
* @returns {dat.controllers.Controller} this
*/
onChange: function(fnc) {
this.__onChange = fnc;
return this;
},
/**
* Specify that a function fire every time someone "finishes" changing
* the value wih this Controller. Useful for values that change
* incrementally like numbers or strings.
*
* @param {Function} fnc This function will be called whenever
* someone "finishes" changing the value via this Controller.
* @returns {dat.controllers.Controller} this
*/
onFinishChange: function(fnc) {
this.__onFinishChange = fnc;
return this;
},
/**
* Change the value of <code>object[property]</code>
*
* @param {Object} newValue The new value of <code>object[property]</code>
*/
setValue: function(newValue) {
this.object[this.property] = newValue;
if (this.__onChange) {
this.__onChange.call(this, newValue);
}
this.updateDisplay();
return this;
},
/**
* Gets the value of <code>object[property]</code>
*
* @returns {Object} The current value of <code>object[property]</code>
*/
getValue: function() {
return this.object[this.property];
},
/**
* Refreshes the visual display of a Controller in order to keep sync
* with the object's current value.
* @returns {dat.controllers.Controller} this
*/
updateDisplay: function() {
return this;
},
/**
* @returns {Boolean} true if the value has deviated from initialValue
*/
isModified: function() {
return this.initialValue !== this.getValue()
}
}
);
return Controller;
});

View File

@ -0,0 +1,72 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/dom/dom',
'dat/utils/common'
], function(Controller, dom, common) {
/**
* @class Provides a GUI interface to fire a specified method, a property of an object.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var FunctionController = function(object, property, text) {
FunctionController.superclass.call(this, object, property);
var _this = this;
this.__button = document.createElement('div');
this.__button.innerHTML = text === undefined ? 'Fire' : text;
dom.bind(this.__button, 'click', function() {
_this.fire();
});
dom.addClass(this.__button, 'button');
this.domElement.appendChild(this.__button);
};
FunctionController.superclass = Controller;
common.extend(
FunctionController.prototype,
Controller.prototype,
{
fire: function() {
if (this.__onChange) {
this.__onChange.call(this);
}
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
this.getValue().call(this.object);
}
}
);
return FunctionController;
});

View File

@ -0,0 +1,143 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/utils/common'
], function(Controller, common) {
/**
* @class Represents a given property of an object that is a number.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object} [params] Optional parameters
* @param {Number} [params.min] Minimum allowed value
* @param {Number} [params.max] Maximum allowed value
* @param {Number} [params.step] Increment by which to change value
*
* @member dat.controllers
*/
var NumberController = function(object, property, params) {
NumberController.superclass.call(this, object, property);
params = params || {};
this.__min = params.min;
this.__max = params.max;
this.__step = params.step;
if (common.isUndefined(this.__step)) {
if (this.initialValue == 0) {
this.__impliedStep = 1; // What are we, psychics?
} else {
// Hey Doug, check this out.
this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue)/Math.LN10))/10;
}
} else {
this.__impliedStep = this.__step;
}
this.__precision = numDecimals(this.__impliedStep);
};
NumberController.superclass = Controller;
common.extend(
NumberController.prototype,
Controller.prototype,
/** @lends dat.controllers.NumberController.prototype */
{
setValue: function(v) {
if (this.__min !== undefined && v < this.__min) {
v = this.__min;
} else if (this.__max !== undefined && v > this.__max) {
v = this.__max;
}
if (this.__step !== undefined && v % this.__step != 0) {
v = Math.round(v / this.__step) * this.__step;
}
return NumberController.superclass.prototype.setValue.call(this, v);
},
/**
* Specify a minimum value for <code>object[property]</code>.
*
* @param {Number} minValue The minimum value for
* <code>object[property]</code>
* @returns {dat.controllers.NumberController} this
*/
min: function(v) {
this.__min = v;
return this;
},
/**
* Specify a maximum value for <code>object[property]</code>.
*
* @param {Number} maxValue The maximum value for
* <code>object[property]</code>
* @returns {dat.controllers.NumberController} this
*/
max: function(v) {
this.__max = v;
return this;
},
/**
* Specify a step value that dat.controllers.NumberController
* increments by.
*
* @param {Number} stepValue The step value for
* dat.controllers.NumberController
* @default if minimum and maximum specified increment is 1% of the
* difference otherwise stepValue is 1
* @returns {dat.controllers.NumberController} this
*/
step: function(v) {
this.__step = v;
return this;
}
}
);
function numDecimals(x) {
x = x.toString();
if (x.indexOf('.') > -1) {
return x.length - x.indexOf('.') - 1;
} else {
return 0;
}
}
return NumberController;
});

View File

@ -0,0 +1,134 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/NumberController',
'dat/dom/dom',
'dat/utils/common'
], function(NumberController, dom, common) {
/**
* @class Represents a given property of an object that is a number and
* provides an input element with which to manipulate it.
*
* @extends dat.controllers.Controller
* @extends dat.controllers.NumberController
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object} [params] Optional parameters
* @param {Number} [params.min] Minimum allowed value
* @param {Number} [params.max] Maximum allowed value
* @param {Number} [params.step] Increment by which to change value
*
* @member dat.controllers
*/
var NumberControllerBox = function(object, property, params) {
this.__truncationSuspended = false;
NumberControllerBox.superclass.call(this, object, property, params);
var _this = this;
/**
* {Number} Previous mouse y position
* @ignore
*/
var prev_y;
this.__input = document.createElement('input');
this.__input.setAttribute('type', 'text');
// Makes it so manually specified values are not truncated.
dom.bind(this.__input, 'change', onChange);
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__input, 'mousedown', onMouseDown);
dom.bind(this.__input, 'keydown', function(e) {
// When pressing entire, you can be as precise as you want.
if (e.keyCode === 13) {
_this.__truncationSuspended = true;
this.blur();
_this.__truncationSuspended = false;
}
});
function onChange() {
var attempted = parseFloat(_this.__input.value);
if (!common.isNaN(attempted)) _this.setValue(attempted);
}
function onBlur() {
onChange();
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
function onMouseDown(e) {
dom.bind(window, 'mousemove', onMouseDrag);
dom.bind(window, 'mouseup', onMouseUp);
prev_y = e.clientY;
}
function onMouseDrag(e) {
var diff = prev_y - e.clientY;
_this.setValue(_this.getValue() + diff * _this.__impliedStep);
prev_y = e.clientY;
}
function onMouseUp() {
dom.unbind(window, 'mousemove', onMouseDrag);
dom.unbind(window, 'mouseup', onMouseUp);
}
this.updateDisplay();
this.domElement.appendChild(this.__input);
};
NumberControllerBox.superclass = NumberController;
common.extend(
NumberControllerBox.prototype,
NumberController.prototype,
{
updateDisplay: function() {
this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision);
return NumberControllerBox.superclass.prototype.updateDisplay.call(this);
}
}
);
function roundToDecimal(value, decimals) {
var tenTo = Math.pow(10, decimals);
return Math.round(value * tenTo) / tenTo;
}
return NumberControllerBox;
});

View File

@ -0,0 +1,43 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
.slider {
box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);
height: 1em;
border-radius: 1em;
background-color: #eee;
padding: 0 0.5em;
overflow: hidden;
}
.slider-fg {
padding: 1px 0 2px 0;
background-color: #aaa;
height: 1em;
margin-left: -0.5em;
padding-right: 0.5em;
border-radius: 1em 0 0 1em;
}
.slider-fg:after {
display: inline-block;
border-radius: 1em;
background-color: #fff;
border: 1px solid #aaa;
content: '';
float: right;
margin-right: -1em;
margin-top: -1px;
height: 0.9em;
width: 0.9em;
}

View File

@ -0,0 +1,129 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/NumberController',
'dat/dom/dom',
'dat/utils/css',
'dat/utils/common',
'text!dat/controllers/NumberControllerSlider.css'
],
function(NumberController, dom, css, common, styleSheet) {
/**
* @class Represents a given property of an object that is a number, contains
* a minimum and maximum, and provides a slider element with which to
* manipulate it. It should be noted that the slider element is made up of
* <code>&lt;div&gt;</code> tags, <strong>not</strong> the html5
* <code>&lt;slider&gt;</code> element.
*
* @extends dat.controllers.Controller
* @extends dat.controllers.NumberController
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Number} minValue Minimum allowed value
* @param {Number} maxValue Maximum allowed value
* @param {Number} stepValue Increment by which to change value
*
* @member dat.controllers
*/
var NumberControllerSlider = function(object, property, min, max, step) {
NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step });
var _this = this;
this.__background = document.createElement('div');
this.__foreground = document.createElement('div');
dom.bind(this.__background, 'mousedown', onMouseDown);
dom.addClass(this.__background, 'slider');
dom.addClass(this.__foreground, 'slider-fg');
function onMouseDown(e) {
dom.bind(window, 'mousemove', onMouseDrag);
dom.bind(window, 'mouseup', onMouseUp);
onMouseDrag(e);
}
function onMouseDrag(e) {
e.preventDefault();
var offset = dom.getOffset(_this.__background);
var width = dom.getWidth(_this.__background);
_this.setValue(
map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max)
);
return false;
}
function onMouseUp() {
dom.unbind(window, 'mousemove', onMouseDrag);
dom.unbind(window, 'mouseup', onMouseUp);
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
this.updateDisplay();
this.__background.appendChild(this.__foreground);
this.domElement.appendChild(this.__background);
};
NumberControllerSlider.superclass = NumberController;
/**
* Injects default stylesheet for slider elements.
*/
NumberControllerSlider.useDefaultStyles = function() {
css.inject(styleSheet);
};
common.extend(
NumberControllerSlider.prototype,
NumberController.prototype,
{
updateDisplay: function() {
var pct = (this.getValue() - this.__min)/(this.__max - this.__min);
this.__foreground.style.width = pct*100+'%';
return NumberControllerSlider.superclass.prototype.updateDisplay.call(this);
}
}
);
function map(v, i1, i2, o1, o2) {
return o1 + (o2 - o1) * ((v - i1) / (i2 - i1));
}
return NumberControllerSlider;
});

View File

@ -0,0 +1,103 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/dom/dom',
'dat/utils/common'
],
function(Controller, dom, common) {
/**
* @class Provides a select input to alter the property of an object, using a
* list of accepted values.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object|string[]} options A map of labels to acceptable values, or
* a list of acceptable string values.
*
* @member dat.controllers
*/
var OptionController = function(object, property, options) {
OptionController.superclass.call(this, object, property);
var _this = this;
/**
* The drop down menu
* @ignore
*/
this.__select = document.createElement('select');
if (common.isArray(options)) {
var map = {};
common.each(options, function(element) {
map[element] = element;
});
options = map;
}
common.each(options, function(value, key) {
var opt = document.createElement('option');
opt.innerHTML = key;
opt.setAttribute('value', value);
_this.__select.appendChild(opt);
});
// Acknowledge original value
this.updateDisplay();
dom.bind(this.__select, 'change', function() {
var desiredValue = this.options[this.selectedIndex].value;
_this.setValue(desiredValue);
});
this.domElement.appendChild(this.__select);
};
OptionController.superclass = Controller;
common.extend(
OptionController.prototype,
Controller.prototype,
{
setValue: function(v) {
var toReturn = OptionController.superclass.prototype.setValue.call(this, v);
if (this.__onFinishChange) {
this.__onFinishChange.call(this, this.getValue());
}
return toReturn;
},
updateDisplay: function() {
this.__select.value = this.getValue();
return OptionController.superclass.prototype.updateDisplay.call(this);
}
}
);
return OptionController;
});

View File

@ -0,0 +1,89 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/Controller',
'dat/dom/dom',
'dat/utils/common'
], function(Controller, dom, common) {
/**
* @class Provides a text input to alter the string property of an object.
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
*
* @member dat.controllers
*/
var StringController = function(object, property) {
StringController.superclass.call(this, object, property);
var _this = this;
this.__input = document.createElement('input');
this.__input.setAttribute('type', 'text');
dom.bind(this.__input, 'keyup', onChange);
dom.bind(this.__input, 'change', onChange);
dom.bind(this.__input, 'blur', onBlur);
dom.bind(this.__input, 'keydown', function(e) {
if (e.keyCode === 13) {
this.blur();
}
});
function onChange() {
_this.setValue(_this.__input.value);
}
function onBlur() {
if (_this.__onFinishChange) {
_this.__onFinishChange.call(_this, _this.getValue());
}
}
this.updateDisplay();
this.domElement.appendChild(this.__input);
};
StringController.superclass = Controller;
common.extend(
StringController.prototype,
Controller.prototype,
{
updateDisplay: function() {
// Stops the caret from moving on account of:
// keyup -> setValue -> updateDisplay
if (!dom.isActive(this.__input)) {
this.__input.value = this.getValue();
}
return StringController.superclass.prototype.updateDisplay.call(this);
}
}
);
return StringController;
});

View File

@ -0,0 +1,65 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/controllers/OptionController',
'dat/controllers/NumberControllerBox',
'dat/controllers/NumberControllerSlider',
'dat/controllers/StringController',
'dat/controllers/FunctionController',
'dat/controllers/BooleanController',
'dat/utils/common'
],
function(OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) {
return function(object, property) {
var initialValue = object[property];
// Providing options?
if (common.isArray(arguments[2]) || common.isObject(arguments[2])) {
return new OptionController(object, property, arguments[2]);
}
// Providing a map?
if (common.isNumber(initialValue)) {
if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) {
// Has min and max.
return new NumberControllerSlider(object, property, arguments[2], arguments[3]);
} else {
return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] });
}
}
if (common.isString(initialValue)) {
return new StringController(object, property);
}
if (common.isFunction(initialValue)) {
return new FunctionController(object, property, '');
}
if (common.isBoolean(initialValue)) {
return new BooleanController(object, property);
}
}
});

109
src/dat/dom/CenteredDiv.js Normal file
View File

@ -0,0 +1,109 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/dom/dom',
'dat/utils/common'
], function(dom, common) {
var CenteredDiv = function() {
this.backgroundElement = document.createElement('div');
common.extend(this.backgroundElement.style, {
backgroundColor: 'rgba(0,0,0,0.5)',
display: 'none',
zIndex: '1000',
opacity: 0,
WebkitTransition: 'opacity 0.2s linear'
});
dom.makeFullscreen(this.backgroundElement);
this.domElement = document.createElement('div');
common.extend(this.domElement.style, {
position: 'fixed',
display: 'none',
left: '50%',
top: '50%',
zIndex: '1001',
opacity: 0,
WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear'
});
document.body.appendChild(this.backgroundElement);
document.body.appendChild(this.domElement);
var _this = this;
dom.bind(this.backgroundElement, 'click', function() {
_this.hide();
});
};
CenteredDiv.prototype.show = function() {
var _this = this;
this.backgroundElement.style.display = 'block';
this.domElement.style.display = 'block';
this.domElement.style.opacity = 0;
// this.domElement.style.top = '52%';
this.domElement.style.webkitTransform = 'scale(1.1)';
this.layout();
common.defer(function() {
_this.backgroundElement.style.opacity = 1;
_this.domElement.style.opacity = 1;
_this.domElement.style.webkitTransform = 'scale(1)';
});
};
CenteredDiv.prototype.hide = function() {
var _this = this;
var hide = function() {
_this.domElement.style.display = 'none';
_this.backgroundElement.style.display = 'none';
dom.unbind(_this.domElement, 'webkitTransitionEnd', hide);
dom.unbind(_this.domElement, 'transitionend', hide);
dom.unbind(_this.domElement, 'oTransitionEnd', hide);
};
dom.bind(this.domElement, 'webkitTransitionEnd', hide);
dom.bind(this.domElement, 'transitionend', hide);
dom.bind(this.domElement, 'oTransitionEnd', hide);
this.backgroundElement.style.opacity = 0;
// this.domElement.style.top = '48%';
this.domElement.style.opacity = 0;
this.domElement.style.webkitTransform = 'scale(1.1)';
};
CenteredDiv.prototype.layout = function() {
this.domElement.style.marginLeft = -dom.getWidth(this.domElement) / 2 + 'px';
this.domElement.style.marginTop = -dom.getHeight(this.domElement) / 2 + 'px';
};
return CenteredDiv;
});

287
src/dat/dom/dom.js Normal file
View File

@ -0,0 +1,287 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
'dat/utils/common'
], function(common) {
var EVENT_MAP = {
'HTMLEvents': ['change'],
'MouseEvents': ['click','mousemove','mousedown','mouseup', 'mouseover'],
'KeyboardEvents': ['keydown']
};
var EVENT_MAP_INV = {};
common.each(EVENT_MAP, function(v, k) {
common.each(v, function(e) {
EVENT_MAP_INV[e] = k;
});
});
var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/;
function cssValueToPixels(val) {
if (val === '0' || common.isUndefined(val)) return 0;
var match = val.match(CSS_VALUE_PIXELS);
if (!common.isNull(match)) {
return parseFloat(match[1]);
}
// TODO ...ems? %?
return 0;
}
/**
* @namespace
* @member dat.dom
*/
var dom = {
/**
*
* @param elem
* @param selectable
*/
makeSelectable: function(elem, selectable) {
if (elem === undefined || elem.style === undefined) return;
elem.onselectstart = selectable ? function() {
return false;
} : function() {
};
elem.style.MozUserSelect = selectable ? 'auto' : 'none';
elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none';
elem.unselectable = selectable ? 'on' : 'off';
},
/**
*
* @param elem
* @param horizontal
* @param vertical
*/
makeFullscreen: function(elem, horizontal, vertical) {
if (common.isUndefined(horizontal)) horizontal = true;
if (common.isUndefined(vertical)) vertical = true;
elem.style.position = 'absolute';
if (horizontal) {
elem.style.left = 0;
elem.style.right = 0;
}
if (vertical) {
elem.style.top = 0;
elem.style.bottom = 0;
}
},
/**
*
* @param elem
* @param eventType
* @param params
*/
fakeEvent: function(elem, eventType, params, aux) {
params = params || {};
var className = EVENT_MAP_INV[eventType];
if (!className) {
throw new Error('Event type ' + eventType + ' not supported.');
}
var evt = document.createEvent(className);
switch (className) {
case 'MouseEvents':
var clientX = params.x || params.clientX || 0;
var clientY = params.y || params.clientY || 0;
evt.initMouseEvent(eventType, params.bubbles || false,
params.cancelable || true, window, params.clickCount || 1,
0, //screen X
0, //screen Y
clientX, //client X
clientY, //client Y
false, false, false, false, 0, null);
break;
case 'KeyboardEvents':
var init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz
common.defaults(params, {
cancelable: true,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
keyCode: undefined,
charCode: undefined
});
init(eventType, params.bubbles || false,
params.cancelable, window,
params.ctrlKey, params.altKey,
params.shiftKey, params.metaKey,
params.keyCode, params.charCode);
break;
default:
evt.initEvent(eventType, params.bubbles || false,
params.cancelable || true);
break;
}
common.defaults(evt, aux);
elem.dispatchEvent(evt);
},
/**
*
* @param elem
* @param event
* @param func
* @param bool
*/
bind: function(elem, event, func, bool) {
bool = bool || false;
if (elem.addEventListener)
elem.addEventListener(event, func, bool);
else if (elem.attachEvent)
elem.attachEvent('on' + event, func);
return dom;
},
/**
*
* @param elem
* @param event
* @param func
* @param bool
*/
unbind: function(elem, event, func, bool) {
bool = bool || false;
if (elem.removeEventListener)
elem.removeEventListener(event, func, bool);
else if (elem.detachEvent)
elem.detachEvent('on' + event, func);
return dom;
},
/**
*
* @param elem
* @param className
*/
addClass: function(elem, className) {
if (elem.className === undefined) {
elem.className = className;
} else if (elem.className !== className) {
var classes = elem.className.split(/ +/);
if (classes.indexOf(className) == -1) {
classes.push(className);
elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, '');
}
}
return dom;
},
/**
*
* @param elem
* @param className
*/
removeClass: function(elem, className) {
if (className) {
if (elem.className === undefined) {
// elem.className = className;
} else if (elem.className === className) {
elem.removeAttribute('class');
} else {
var classes = elem.className.split(/ +/);
var index = classes.indexOf(className);
if (index != -1) {
classes.splice(index, 1);
elem.className = classes.join(' ');
}
}
} else {
elem.className = undefined;
}
return dom;
},
hasClass: function(elem, className) {
return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false;
},
/**
*
* @param elem
*/
getWidth: function(elem) {
var style = getComputedStyle(elem);
return cssValueToPixels(style['border-left-width']) +
cssValueToPixels(style['border-right-width']) +
cssValueToPixels(style['padding-left']) +
cssValueToPixels(style['padding-right']) +
cssValueToPixels(style['width']);
},
/**
*
* @param elem
*/
getHeight: function(elem) {
var style = getComputedStyle(elem);
return cssValueToPixels(style['border-top-width']) +
cssValueToPixels(style['border-bottom-width']) +
cssValueToPixels(style['padding-top']) +
cssValueToPixels(style['padding-bottom']) +
cssValueToPixels(style['height']);
},
/**
*
* @param elem
*/
getOffset: function(elem) {
var offset = {left: 0, top:0};
if (elem.offsetParent) {
do {
offset.left += elem.offsetLeft;
offset.top += elem.offsetTop;
} while (elem = elem.offsetParent);
}
return offset;
},
// http://stackoverflow.com/posts/2684561/revisions
/**
*
* @param elem
*/
isActive: function(elem) {
return elem === document.activeElement && ( elem.type || elem.href );
}
};
return dom;
});

221
src/dat/gui/_structure.scss Normal file
View File

@ -0,0 +1,221 @@
$nest-margin: 4px;
$row-height: 27px;
.dg {
/** Clear list styles */
ul {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
clear: both;
}
/* Auto-place container */
&.ac {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 0;
z-index: 0;
}
&.main {
@include transition(opacity, 0.1s, linear);
/*overflow-y: hidden;*/
&.taller-than-window {
overflow-y: auto;
}
}
/* Auto-placed GUI's */
&.a {
float: right;
margin-right: 15px;
overflow-x: hidden;
&.has-save {
margin-top: $row-height;
}
.save-row {
position: fixed;
top: 0;
z-index: 1002;
}
}
/* Line items that don't contain folders. */
li:not(.folder) {
cursor: auto;
height: $row-height;
line-height: $row-height;
overflow: hidden;
padding: 0 4px 0 5px;
@include transition(height, 0.1s, ease-out);
}
li.folder {
padding: 0;
border-left: $nest-margin solid rgba(0,0,0,0);
}
/** Folder names */
li.title {
cursor: pointer;
margin-left: -$nest-margin;
}
/** Hides closed items */
.closed li:not(.title),
.closed ul li,
.closed ul li > * {
height: 0;
overflow: hidden;
border: 0;
}
/** Controller row */
.cr {
clear: both;
padding-left: 3px;
height: $row-height;
}
/** Name-half (left) */
.property-name {
cursor: default;
float: left;
clear: left;
width: 40%;
overflow: hidden;
text-overflow: ellipsis;
}
/** Controller-half (right) */
.c {
float: left;
width: 60%;
}
/** Controller placement */
.c input[type=text] {
border: 0;
margin-top: 4px;
padding: 3px;
width: 100%;
float: right;
}
/** Shorter number boxes when slider is present. */
.has-slider input[type=text] {
width: 30%;
/*display: none;*/
margin-left: 0;
}
.slider {
float: left;
width: 66%;
margin-left: -5px;
margin-right: 0;
height: 19px;
margin-top: 4px;
}
.slider-fg {
height: 100%;
}
.c input[type=checkbox] {
margin-top: 9px;
}
.c select {
margin-top: 5px;
}
/** Ensure the entire boolean and function row shows a hand */
.cr.function,
.cr.function .property-name, /* Don't know why I need to be this explicit */
.cr.function *,
.cr.boolean,
.cr.boolean * {
cursor: pointer;
}
.selector {
display: none;
position: absolute;
margin-left: -9px;
margin-top: 23px;
}
.c:hover .selector,
.selector.drag {
display: block;
}
li.save-row {
padding: 0;
.button {
display: inline-block;
padding: 0px 6px;
}
}
&.dialogue {
background-color: #222;
width: 460px;
padding: 15px;
font-size: 13px;
line-height: 15px;
}
}
/* TODO Separate style and structure */
#dg-new-constructor {
padding: 10px;
color: #222;
font-family: Monaco, monospace;
font-size: 10px;
border: 0;
resize: none;
box-shadow: inset 1px 1px 1px #888;
word-wrap: break-word;
margin: 12px 0;
display: block;
width: 440px;
overflow-y: scroll;
height: 100px;
position: relative;
}
#dg-local-explain {
display: none;
font-size: 11px;
line-height: 17px;
border-radius: 3px;
background-color: #333;
padding: 8px;
margin-top: 10px;
code {
font-size: 10px;
}
}
#dat-gui-save-locally {
display: none;
}

View File

@ -0,0 +1,21 @@
<div id="dg-save" class="dg dialogue">
Here's the new load parameter for your <code>GUI</code>'s constructor:
<textarea id="dg-new-constructor"></textarea>
<div id="dg-save-locally">
<input id="dg-local-storage" type="checkbox"/> Automatically save
values to <code>localStorage</code> on exit.
<div id="dg-local-explain">The values saved to <code>localStorage</code> will
override those passed to <code>dat.GUI</code>'s constructor. This makes it
easier to work incrementally, but <code>localStorage</code> is fragile,
and your friends may not see the same values you do.
</div>
</div>
</div>

261
src/dat/gui/style.css Normal file
View File

@ -0,0 +1,261 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
.dg {
/** Clear list styles */
/* Auto-place container */
/* Auto-placed GUI's */
/* Line items that don't contain folders. */
/** Folder names */
/** Hides closed items */
/** Controller row */
/** Name-half (left) */
/** Controller-half (right) */
/** Controller placement */
/** Shorter number boxes when slider is present. */
/** Ensure the entire boolean and function row shows a hand */ }
.dg ul {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
clear: both; }
.dg.ac {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 0;
z-index: 0; }
.dg.main {
-webkit-transition: opacity 0.1s linear;
-o-transition: opacity 0.1s linear;
-moz-transition: opacity 0.1s linear;
transition: opacity 0.1s linear;
/*overflow-y: hidden;*/ }
.dg.main.taller-than-window {
overflow-y: auto; }
.dg.a {
float: right;
margin-right: 15px;
overflow-x: hidden; }
.dg.a.has-save {
margin-top: 27px; }
.dg.a .save-row {
position: fixed;
top: 0;
z-index: 1002; }
.dg li:not(.folder) {
cursor: auto;
height: 27px;
line-height: 27px;
overflow: hidden;
padding: 0 4px 0 5px;
-webkit-transition: height 0.1s ease-out;
-o-transition: height 0.1s ease-out;
-moz-transition: height 0.1s ease-out;
transition: height 0.1s ease-out; }
.dg li.folder {
padding: 0;
border-left: 4px solid rgba(0, 0, 0, 0); }
.dg li.title {
cursor: pointer;
margin-left: -4px; }
.dg .closed li:not(.title),
.dg .closed ul li,
.dg .closed ul li > * {
height: 0;
overflow: hidden;
border: 0; }
.dg .cr {
clear: both;
padding-left: 3px;
height: 27px; }
.dg .property-name {
cursor: default;
float: left;
clear: left;
width: 40%;
overflow: hidden;
text-overflow: ellipsis; }
.dg .c {
float: left;
width: 60%; }
.dg .c input[type=text] {
border: 0;
margin-top: 4px;
padding: 3px;
width: 100%;
float: right; }
.dg .has-slider input[type=text] {
width: 30%;
/*display: none;*/
margin-left: 0; }
.dg .slider {
float: left;
width: 66%;
margin-left: -5px;
margin-right: 0;
height: 19px;
margin-top: 4px; }
.dg .slider-fg {
height: 100%; }
.dg .c input[type=checkbox] {
margin-top: 9px; }
.dg .c select {
margin-top: 5px; }
.dg .cr.function,
.dg .cr.function .property-name,
.dg .cr.function *,
.dg .cr.boolean,
.dg .cr.boolean * {
cursor: pointer; }
.dg .selector {
display: none;
position: absolute;
margin-left: -9px;
margin-top: 23px; }
.dg .c:hover .selector,
.dg .selector.drag {
display: block; }
.dg li.save-row {
padding: 0; }
.dg li.save-row .button {
display: inline-block;
padding: 0px 6px; }
.dg.dialogue {
background-color: #222;
width: 460px;
padding: 15px;
font-size: 13px;
line-height: 15px; }
/* TODO Separate style and structure */
#dg-new-constructor {
padding: 10px;
color: #222;
font-family: Monaco, monospace;
font-size: 10px;
border: 0;
resize: none;
box-shadow: inset 1px 1px 1px #888;
word-wrap: break-word;
margin: 12px 0;
display: block;
width: 440px;
overflow-y: scroll;
height: 100px;
position: relative; }
#dg-local-explain {
display: none;
font-size: 11px;
line-height: 17px;
border-radius: 3px;
background-color: #333;
padding: 8px;
margin-top: 10px; }
#dg-local-explain code {
font-size: 10px; }
#dat-gui-save-locally {
display: none; }
/** Main type */
.dg {
color: #eee;
font: 11px 'Lucida Grande', sans-serif;
text-shadow: 0 -1px 0 #111111;
/** Auto place */
/* Controller row, <li> */
/** Controllers */ }
.dg.main {
/** Scrollbar */ }
.dg.main::-webkit-scrollbar {
width: 5px;
background: #1a1a1a; }
.dg.main::-webkit-scrollbar-corner {
height: 0;
display: none; }
.dg.main::-webkit-scrollbar-thumb {
border-radius: 5px;
background: #676767; }
.dg li:not(.folder) {
background: #1a1a1a;
border-bottom: 1px solid #2c2c2c; }
.dg li.save-row {
line-height: 25px;
background: #dad5cb;
border: 0; }
.dg li.save-row select {
margin-left: 5px;
width: 108px; }
.dg li.save-row .button {
margin-left: 5px;
margin-top: 1px;
border-radius: 2px;
font-size: 9px;
line-height: 7px;
padding: 4px 4px 5px 4px;
background: #c5bdad;
color: #fff;
text-shadow: 0 1px 0 #b0a58f;
box-shadow: 0 -1px 0 #b0a58f;
cursor: pointer; }
.dg li.save-row .button.gears {
background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;
height: 7px;
width: 8px; }
.dg li.save-row .button:hover {
background-color: #bab19e;
box-shadow: 0 -1px 0 #b0a58f; }
.dg li.folder {
border-bottom: 0; }
.dg li.title {
padding-left: 16px;
background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;
cursor: pointer;
border-bottom: 1px solid rgba(255, 255, 255, 0.2); }
.dg .closed li.title {
background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); }
.dg .cr.boolean {
border-left: 3px solid #806787; }
.dg .cr.function {
border-left: 3px solid #e61d5f; }
.dg .cr.number {
border-left: 3px solid #2fa1d6; }
.dg .cr.number input[type=text] {
color: #2fa1d6; }
.dg .cr.string {
border-left: 3px solid #1ed36f; }
.dg .cr.string input[type=text] {
color: #1ed36f; }
.dg .cr.function:hover, .dg .cr.boolean:hover {
background: #111; }
.dg .c input[type=text] {
background: #303030;
outline: none; }
.dg .c input[type=text]:hover {
background: #3c3c3c; }
.dg .c input[type=text]:focus {
background: #494949;
color: #fff; }
.dg .c .slider {
background: #303030;
cursor: ew-resize; }
.dg .c .slider-fg {
background: #2fa1d6; }
.dg .c .slider:hover {
background: #3c3c3c; }
.dg .c .slider:hover .slider-fg {
background: #44abda; }

202
src/dat/gui/style.scss Normal file
View File

@ -0,0 +1,202 @@
$background-color: #1a1a1a;
$hover-lighten: 5%;
$border-lighten: 7%;
$active-lighten: 10%;
$number-color: #2FA1D6;
$boolean-color: #806787;
$string-color: #1ed36f;
$function-color: #e61d5f;
$save-row-color: #dad5cb;
$button-color: darken($save-row-color, 10%);
$input-color: lighten($background-color, 8.5%);
@mixin transition($prop, $time, $curve) {
-webkit-transition: $prop $time $curve;
-o-transition: $prop $time $curve;
-moz-transition: $prop $time $curve;
transition: $prop $time $curve;
}
@mixin gradient($a, $b) {
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from($a), to($b));
background: -o-gradient(linear, 0% 0%, 0% 100%, from($a), to($b));
background: -moz-gradient(linear, 0% 0%, 0% 100%, from($a), to($b));
}
@mixin button() {
margin-left: 5px;
margin-top: 1px;
border-radius: 2px;
font-size: 9px;
line-height: 7px;
padding: 4px 4px 5px 4px;
background: $button-color;
color: #fff;
text-shadow: 0 1px 0 darken($button-color, 10%);
box-shadow: 0 -1px 0 darken($button-color, 10%);
cursor: pointer;
}
@mixin gears() {
background: $button-color url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;
height: 7px;
width: 8px;
}
@import "structure";
/** Main type */
.dg {
color: #eee;
font: 11px 'Lucida Grande', sans-serif;
text-shadow: 0 -1px 0 #111;
/** Auto place */
&.main {
/** Scrollbar */
&::-webkit-scrollbar {
width: 5px;
background: $background-color;
}
&::-webkit-scrollbar-corner {
height: 0;
display: none;
}
&::-webkit-scrollbar-thumb {
border-radius: 5px;
background: lighten($background-color, 30%);
}
}
li {
&:not(.folder) {
background: $background-color;
border-bottom: 1px solid lighten($background-color, $border-lighten);
}
&.save-row {
line-height: 25px;
background: $save-row-color;
border: 0;
select {
margin-left: 5px;
width: 108px;
}
.button {
&.gears {
@include gears;
}
@include button;
&:hover {
background-color: darken($button-color, 5%);
box-shadow: 0 -1px 0 darken($button-color, 10%);
}
}
}
&.folder {
border-bottom: 0;
}
&.title {
padding-left: 16px;
background: #000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;
cursor: pointer;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
}
.closed li.title {
background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==);
}
/* Controller row, <li> */
.cr {
&.boolean {
border-left: 3px solid $boolean-color;
}
&.function {
border-left: 3px solid $function-color;
}
&.number {
border-left: 3px solid $number-color;
input[type=text] {
color: $number-color;
}
}
&.string {
border-left: 3px solid $string-color;
input[type=text] {
color: $string-color;
}
}
&.function:hover ,
&.boolean:hover {
background: #111;
}
}
/** Controllers */
.c {
input[type=text] {
background: $input-color;
outline: none;
&:hover {
background: lighten($input-color, $hover-lighten);
}
&:focus {
background: lighten($input-color, $active-lighten);
color: #fff;
}
}
.slider {
background: $input-color;
cursor: ew-resize;
}
.slider-fg {
background: $number-color;
}
.slider:hover {
background: lighten($input-color, $hover-lighten);
.slider-fg {
background: lighten($number-color, $hover-lighten);
}
}
}
}

139
src/dat/utils/common.js Normal file
View File

@ -0,0 +1,139 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
], function() {
var ARR_EACH = Array.prototype.forEach;
var ARR_SLICE = Array.prototype.slice;
/**
* Band-aid methods for things that should be a lot easier in JavaScript.
* Implementation and structure inspired by underscore.js
* http://documentcloud.github.com/underscore/
*/
return {
BREAK: {},
extend: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (!this.isUndefined(obj[key]))
target[key] = obj[key];
}, this);
return target;
},
defaults: function(target) {
this.each(ARR_SLICE.call(arguments, 1), function(obj) {
for (var key in obj)
if (this.isUndefined(target[key]))
target[key] = obj[key];
}, this);
return target;
},
compose: function() {
var toCall = ARR_SLICE.call(arguments);
return function() {
var args = ARR_SLICE.call(arguments);
for (var i = toCall.length -1; i >= 0; i--) {
args = [toCall[i].apply(this, args)];
}
return args[0];
}
},
each: function(obj, itr, scope) {
if (ARR_EACH && obj.forEach === ARR_EACH) {
obj.forEach(itr, scope);
} else if (obj.length === obj.length + 0) { // Is number but not NaN
for (var key = 0, l = obj.length; key < l; key++)
if (key in obj && itr.call(scope, obj[key], key) === this.BREAK)
return;
} else {
for (var key in obj)
if (itr.call(scope, obj[key], key) === this.BREAK)
return;
}
},
defer: function(fnc) {
setTimeout(fnc, 0);
},
toArray: function(obj) {
if (obj.toArray) return obj.toArray();
return ARR_SLICE.call(obj);
},
isUndefined: function(obj) {
return obj === undefined;
},
isNull: function(obj) {
return obj === null;
},
isNaN: function(obj) {
return obj !== obj;
},
isArray: Array.isArray || function(obj) {
return obj.constructor === Array;
},
isObject: function(obj) {
return obj === Object(obj);
},
isNumber: function(obj) {
return obj === obj+0;
},
isString: function(obj) {
return obj === obj+'';
},
isBoolean: function(obj) {
return obj === false || obj === true;
},
isFunction: function(obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
}
};
});

33
src/dat/utils/css.js Normal file
View File

@ -0,0 +1,33 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([],
function() {
return {
load: function (url, doc) {
doc = doc || document;
var link = doc.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
doc.getElementsByTagName('head')[0].appendChild(link);
},
inject: function(css, doc) {
doc = doc || document;
var injected = document.createElement('style');
injected.type = 'text/css';
injected.innerHTML = css;
doc.getElementsByTagName('head')[0].appendChild(injected);
}
}
});

View File

@ -0,0 +1,31 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
define([
], function() {
/**
* requirejs version of Paul Irish's RequestAnimationFrame
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*/
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
};
});

1412
tests/index.html Normal file

File diff suppressed because it is too large Load Diff

9046
tests/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

226
tests/qunit.css Normal file
View File

@ -0,0 +1,226 @@
/**
* QUnit 1.2.0pre - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2011 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
}

1587
tests/qunit.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
#/usr/bin/env python
from optparse import OptionParser
import httplib, urllib
import os, fnmatch, shutil, re
usage = """usage: %prog [options] command
Commands:
build build the script
debug print the header to include js files
clean remove any built files
"""
parser = OptionParser(usage=usage)
parser.add_option('-l', '--level', dest='level', default='SIMPLE_OPTIMIZATIONS',
help='Closure compilation level [WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, \
ADVANCED_OPTIMIZATIONS]')
UTILS = os.path.dirname(os.path.relpath(__file__))
PREFIX = os.path.join(UTILS,'..')
SRC_ROOT= os.path.join(PREFIX,'src')
BUILD_ROOT = os.path.join(PREFIX,'build')
INDEX = os.path.join(PREFIX,'index.html')
BUILD_NAME = 'DAT.GUI'
ALL_JS = ['DAT.GUI.js','DAT.GUI']
LICENSE = """/**
* dat.gui Javascript Controller Library
* http://dataarts.github.com/dat.gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
"""
def flatten(l, ltypes=(list, tuple)):
ltype = type(l)
l = list(l)
i = 0
while i < len(l):
while isinstance(l[i], ltypes):
if not l[i]:
l.pop(i)
i -= 1
break
else:
l[i:i + 1] = l[i]
i += 1
return ltype(l)
def expand(path, globby):
matches = []
path = path.split('.')
path.insert(0,SRC_ROOT)
filename = "%s.%s"%(path[-2],path[-1])
if fnmatch.fnmatch(filename, globby):
tmppath = os.path.join(*(path[:-1]+[filename]))
if os.path.exists(tmppath):
path[-1] = filename
else:
path = path[:-2]+[filename]
path = os.path.join(*path)
if os.path.isdir(path):
for root, dirnames, filenames in os.walk(path):
for filename in fnmatch.filter(filenames, globby):
matches.append(os.path.join(root, filename))
else:
matches.append(path)
return matches
def unique(seq, idfun=None):
"""Ordered uniquify function
if in 2.7 use:
OrderedDict.fromkeys(seq).keys()
"""
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
def source_list(src, globby='*.js'):
def expander(f):
return expand(f,globby)
return unique(flatten(map(expander, src)))
def compile(code):
params = urllib.urlencode([
('js_code', code),
('compilation_level', options.level),
('output_format', 'text'),
('output_info', 'compiled_code'),
])
headers = { 'Content-type': 'application/x-www-form-urlencoded' }
conn = httplib.HTTPConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
data = response.read()
conn.close()
return data
def bytes_to_kb(b,digits=1):
return round(0.0009765625 * b, digits)
def clean():
if os.path.exists(BUILD_ROOT):
shutil.rmtree(BUILD_ROOT)
print('DONE. Removed %s'%(BUILD_ROOT,))
else:
print('DONE. Nothing to clean')
def build(jssrc, csssrc=list([''])):
if not os.path.exists(BUILD_ROOT):
os.makedirs(BUILD_ROOT)
if csssrc:
cssfiles = source_list(csssrc, '*.css')
print('CSS files being compiled: ', cssfiles)
css = '\n'.join([open(f).read() for f in cssfiles])
css = re.sub(r'[ \t\n\r]+',' ',css)
jsfiles = source_list(jssrc, '*.js')
print('JS files being compiled: ', jsfiles)
code = '\n'.join([open(f).read() for f in jsfiles])
if csssrc:
code += """DAT.GUI.inlineCSS = '%s';\n"""%(css,)
outpath = os.path.join(BUILD_ROOT, BUILD_NAME+'.js')
with open(outpath,'w') as f:
f.write(LICENSE)
f.write(code)
compiled = compile(code)
outpathmin = os.path.join(BUILD_ROOT, BUILD_NAME+'.min.js')
with open(outpathmin,'w') as f:
f.write(LICENSE)
f.write(compiled)
size = bytes_to_kb(os.path.getsize(outpath))
sizemin = bytes_to_kb(os.path.getsize(outpathmin))
with open(INDEX,'r') as f:
index = f.read()
with open(INDEX,'w') as f:
index = re.sub(r'<small id=\'buildsize\'>\[[0-9.]+kb\]','<small id=\'buildsize\'>[%skb]'%(size,),index)
index = re.sub(r'<small id=\'buildsizemin\'>\[[0-9.]+kb\]','<small id=\'buildsizemin\'>[%skb]'%(sizemin,),index)
f.write(index)
print('DONE. Built files in %s.'%(BUILD_ROOT,))
def debug(jssrc, csssrc=list([''])):
head = ""
files = source_list(csssrc, '*.css')
for f in files:
f = f.replace(PREFIX+'/','')
head += '<link href="%s" media="screen" rel="stylesheet" type="text/css"/>\n'%(f,)
files = source_list(jssrc, '*.js')
for f in files:
f = f.replace(PREFIX+'/','')
head += '<script type="text/javascript" src="%s"></script>\n'%(f,)
print(head)
if __name__ == '__main__':
global options
(options, args) = parser.parse_args()
if len(args) != 1:
print(parser.usage)
exit(0)
command = args[0]
if command == 'build':
build(ALL_JS)
elif command == 'clean':
clean()
elif command == 'debug':
debug(ALL_JS)

8
utils/build_color.js Normal file
View File

@ -0,0 +1,8 @@
require('./builder.js').build({
"baseUrl": "../src/",
"main": "dat/color/Color",
"out": "../build/dat.color.js",
"minify": false,
"shortcut": "dat.Color",
"paths": {}
});

8
utils/build_gui.js Normal file
View File

@ -0,0 +1,8 @@
require('./builder.js').build({
"baseUrl": "../src/",
"main": "dat/gui/GUI",
"out": "../build/dat.gui.js",
"minify": false,
"shortcut": "dat.GUI",
"paths": {}
});

284
utils/builder.js Normal file
View File

@ -0,0 +1,284 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
var fs = require('fs'),
closure = require('./closure'),
params,
defined,
third_party,
request_counts,
namespaces,
next_load = '',
next_path = '';
exports.build = build;
exports.file_exists = file_exists;
exports.read_file = read_file;
exports.tab = tab;
exports.license = read_file('license.txt');
function build(_params) {
params = _params;
defined = {};
third_party = {};
request_counts = {};
namespaces = {};
var deps = [];
load_module(params.baseUrl + params.main + '.js', params.main);
for (var i in defined) {
if (params.verbose) console.log('Loaded: ' + defined[i].path);
deps.push(defined[i].path);
if (defined[i].module) {
var namespace = i.substr(0, i.lastIndexOf('/'));
namespaces[namespace] = true;
}
}
var to_write = '';
var ensured = {};
for (var name in params.paths) {
var path = params.baseUrl + params.paths[name] + '.js';
var str = read_file(path);
if (str === false) {
console.log('Failed to locate dependency \'' + name + '\' at ' + path);
fail();
}
third_party[name] = str;
to_write += third_party[name] + "\n\n";
if (params.verbose) console.log('Loaded: ' + path);
//deps.push(path);
}
// Ensure namespaces
for (i in namespaces) {
var split = i.split('/');
for (var j = 0; j < split.length; j++) {
var cur = [];
if (j == 0 && !ensured[split[j]]) {
to_write += '/** @namespace */\n';
to_write += 'var ' + split[j] + ' = ' + split[j] + ' || {};\n\n';
ensured[split[j]] = true;
} else {
for (var k = 0; k <= j; k++) {
cur.push(split[k]);
}
var curn = cur.join('.');
if (!ensured[curn]) {
to_write += '/** @namespace */\n';
to_write += curn + ' = ' + curn + ' || {};\n\n';
}
ensured[curn] = true;
}
}
}
var shared_count = 0;
for (i in request_counts) {
var count = request_counts[i];
if (count > 1) {
if (i in defined) {
var new_shared = i.replace(/\//g, '.');
var v = new_shared + ' = ' + defined[i].getClosure() + ';\n';
to_write += v + "\n\n";
defined[i].shared = new_shared;
shared_count++;
}
}
}
to_write += params.shortcut + ' = ' + params.main.replace(/\//g, '.') + ' = ' + defined[params.main].getClosure() + ';';
if (params.verbose) console.log('Exported: ' + params.main + ' to window.' + params.shortcut);
if (params.minify) {
console.log('Compiling minified source ...');
closure.compile(to_write, function(error, code) {
if (error) {
console.log(error);
} else {
write(exports.license + code);
}
if (params.on_compile) {
params.on_compile();
}
});
} else {
write(exports.license + "\n" + to_write);
}
return deps;
}
function define(deps, callback) {
this.name = next_load;
this.path = next_path;
this.shared = false;
defined[this.name] = this;
if (Array.isArray(deps)) {
this.deps = deps;
this.callback = callback.toString();
this.module = true;
// Simple define call, just an object
} else if (typeof deps === 'object') {
var props = [];
for (var i in deps) {
props.push(i + ':' + deps[i].toString())
}
this.callback = '{' + props.join(',') + '}';
this.module = true;
} else {
this.deps = deps;
this.callback = callback;
}
this.getClosure = function() {
if (this.shared) return this.shared;
if (!this.deps || this.text) return this.callback;
var arg_string = '(';
var args = [];
for (var i in this.deps) {
var dep = this.deps[i];
if (dep in defined) {
var closure = defined[dep].getClosure();
if (!defined[dep].shared && !defined[dep].text) {
closure = defined[dep].name.replace(/\//g, '.') + ' = ' + closure;
}
args.push(closure);
}
}
arg_string += args.join(',\n');
arg_string += ')';
return '(' + this.callback + ')' + arg_string;
};
this.recurseDeps = function() {
if (!this.deps) return;
for (var i in this.deps) {
var dep = this.deps[i];
if (dep in params.paths) continue;
var path = params.baseUrl + dep;
// Define module?
if (file_exists(path + '.js')) {
load_module(path + '.js', dep);
// Text module?
} else if (path.match(/text!/) != null) {
load_text(path.replace('text!', ''), dep);
}
// up the request count
if (dep in request_counts) {
request_counts[dep]++
} else {
request_counts[dep] = 1;
}
}
};
this.recurseDeps();
}
function file_exists(path) {
try {
var stats = fs.lstatSync(path)
return stats.isFile();
} catch (e) {
return false;
}
}
function read_file(path) {
try {
return fs.readFileSync(path).toString();
} catch (e) {
return false;
}
}
function load_module(path, name) {
name = name || path;
if (name in defined) return;
next_load = name;
next_path = path;
eval('new ' + read_file(path));
}
function load_text(path, name) {
name = name || path;
if (name in defined) return;
var text = read_file(path);
text = text.replace(/\r/g, "\\r");
text = text.replace(/\n/g, "\\n");
text = text.replace(/"/g, "\\\"");
next_load = name;
next_path = path;
var d = new define([], '"' + text + '"');
d.text = true;
d.module = false;
}
function tab(str, tabs) {
var lines = str.split("\n");
for (var i in lines) {
lines[i] = tabs + lines[i];
}
return lines.join("\n");
}
function write(str) {
fs.writeFile(params.out, str);
console.log('Saved to ' + params.out);
}
function fail() {
console.log('Build failed.');
process.exit(0);
}

108
utils/closure.js Normal file
View File

@ -0,0 +1,108 @@
/// # Google Closure Compiler Service #
/// https://github.com/weaver/scribbles/blob/master/node/google-closure/lib/closure.js
/// Compress javascript with Node.js using the Closure Compiler
/// Service.
var sys = require('sys');
exports.compile = compile;
// Use the Google Closure Compiler Service to compress Javascript
// code.
//
// + code - String of javascript to compress
// + next - Function callback that accepts.
//
// This method will POST the `code` to the compiler service. If an
// error occurs, `next()` will be called with an `Error` object as the
// first argument. Otherwise, the `next()` will be called with `null`
// as the first argument and a String of compressed javascript as the
// second argument.
//
// compile('... javascript ...', function(err, result) {
// if (err) throw err;
//
// ... do something with result ...
// });
//
// Returns nothing.
function compile(code, next) {
try {
var qs = require('querystring'),
http = require('http'),
host = 'closure-compiler.appspot.com',
body = qs.stringify({
js_code: code.toString('utf-8'),
compilation_level: 'SIMPLE_OPTIMIZATIONS',
output_format: 'json',
output_info: 'compiled_code'
}),
client = http.createClient(80, host).on('error', next),
req = client.request('POST', '/compile', {
'Host': host,
'Content-Length': body.length,
'Content-Type': 'application/x-www-form-urlencoded'
});
req.on('error', next).end(body);
req.on('response', function(res) {
if (res.statusCode != 200)
next(new Error('Unexpected HTTP response: ' + res.statusCode));
else
capture(res, 'utf-8', parseResponse);
});
function parseResponse(err, data) {
err ? next(err) : loadJSON(data, function(err, obj) {
var error;
if (err)
next(err);
else if ((error = obj.errors || obj.serverErrors || obj.warnings))
next(new Error('Failed to compile: ' + sys.inspect(error)));
else
next(null, obj.compiledCode);
});
}
} catch (err) {
next(err);
}
}
// Convert a Stream to a String.
//
// + input - Stream object
// + encoding - String input encoding
// + next - Function error/success callback
//
// Returns nothing.
function capture(input, encoding, next) {
var buffer = '';
input.on('data', function(chunk) {
buffer += chunk.toString(encoding);
});
input.on('end', function() {
next(null, buffer);
});
input.on('error', next);
}
// Convert JSON.load() to callback-style.
//
// + data - String value to load
// + next - Function error/success callback
//
// Returns nothing.
function loadJSON(data, next) {
var err, obj;
try {
obj = JSON.parse(data);
} catch (x) {
err = x;
}
next(err, obj);
}

12
utils/license.txt Normal file
View File

@ -0,0 +1,12 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/