mirror of
https://github.com/dataarts/dat.gui.git
synced 2024-12-12 04:08:27 +00:00
755 lines
15 KiB
JavaScript
755 lines
15 KiB
JavaScript
|
/**
|
||
|
* 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
|
||
|
*/
|
||
|
|
||
|
/** @namespace */
|
||
|
var dat = dat || {};
|
||
|
|
||
|
/** @namespace */
|
||
|
dat.color = dat.color || {};
|
||
|
|
||
|
/** @namespace */
|
||
|
dat.utils = dat.utils || {};
|
||
|
|
||
|
dat.utils.common = (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]';
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
})();
|
||
|
|
||
|
|
||
|
dat.color.toString = (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 + ')';
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
})(dat.utils.common);
|
||
|
|
||
|
|
||
|
dat.Color = dat.color.Color = (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;
|
||
|
|
||
|
})(dat.color.interpret = (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;
|
||
|
|
||
|
|
||
|
})(dat.color.toString,
|
||
|
dat.utils.common),
|
||
|
dat.color.math = (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));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
})(),
|
||
|
dat.color.toString,
|
||
|
dat.utils.common);
|