You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
6.8 KiB
252 lines
6.8 KiB
5 months ago
|
//
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
// list of guis
|
||
|
var guis = [];
|
||
|
|
||
|
// default slider params
|
||
|
var sliderMin = 0;
|
||
|
var sliderMax = 100;
|
||
|
var sliderStep = 1;
|
||
|
|
||
|
// default gui provider
|
||
|
var guiProvider = 'QuickSettings';
|
||
|
|
||
|
const defaultLabel = 'p5.gui';
|
||
|
|
||
|
// Create a GUI using QuickSettings (or DAT.GUI or ...)
|
||
|
// You only need to pass a reference to the sketch in instance mode
|
||
|
|
||
|
// Usually you will call createGui(this, 'label');
|
||
|
p5.prototype.createGui = function(sketch, label, provider) {
|
||
|
|
||
|
// createGui(label) signature
|
||
|
if ((typeof sketch) === 'string') {
|
||
|
return this.createGui(label, sketch, provider);
|
||
|
}
|
||
|
|
||
|
// normally the sketch will just be embedded below the body
|
||
|
let parent = document.body;
|
||
|
|
||
|
if(sketch === undefined) {
|
||
|
// p5js global mode
|
||
|
sketch = window;
|
||
|
label = label || document.title || defaultLabel;
|
||
|
} else {
|
||
|
// p5js instance mode
|
||
|
parent = sketch.canvas.parentElement;
|
||
|
label = label || parent.id || defaultLabel;
|
||
|
}
|
||
|
|
||
|
if(!('color' in sketch)) {
|
||
|
console.error(`${parent.id}: You need to pass the p5 sketch to createGui in instance mode!`);
|
||
|
}
|
||
|
|
||
|
// default gui provider
|
||
|
provider = provider || guiProvider;
|
||
|
|
||
|
var gui;
|
||
|
|
||
|
// create a gui using the provider
|
||
|
if(provider === 'QuickSettings') {
|
||
|
if(QuickSettings) {
|
||
|
console.log('Creating p5.gui powered by QuickSettings.');
|
||
|
gui = new QSGui(label, parent, sketch);
|
||
|
} else {
|
||
|
console.log('QuickSettings not found. Is the script included in your HTML?');
|
||
|
gui = new DummyGui(label, parent, sketch);
|
||
|
}
|
||
|
} else {
|
||
|
console.log('Unknown GUI provider ' + provider);
|
||
|
gui = new DummyGui(label, parent, sketch);
|
||
|
}
|
||
|
|
||
|
// add it to the list of guis
|
||
|
guis.push(gui);
|
||
|
|
||
|
// return it
|
||
|
return gui;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
p5.prototype.removeGui = function(gui) {
|
||
|
// TODO: implement this
|
||
|
};
|
||
|
|
||
|
// update defaults used for creation of sliders
|
||
|
p5.prototype.sliderRange = function(vmin, vmax, vstep) {
|
||
|
sliderMin = vmin;
|
||
|
sliderMax = vmax;
|
||
|
sliderStep = vstep;
|
||
|
};
|
||
|
|
||
|
// extend default behaviour of noLoop()
|
||
|
p5.prototype.noLoop = function() {
|
||
|
this._loop = false;
|
||
|
for(var i = 0; i < guis.length; i++) {
|
||
|
guis[i].noLoop();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// extend default behaviour of loop()
|
||
|
p5.prototype.loop = function() {
|
||
|
for(var i = 0; i < guis.length; i++) {
|
||
|
guis[i].loop();
|
||
|
}
|
||
|
this._loop = true;
|
||
|
this._draw();
|
||
|
};
|
||
|
|
||
|
|
||
|
// interface for quicksettings
|
||
|
function QSGui(label, parent, sketch) {
|
||
|
|
||
|
// hard code the position, it can be changed later
|
||
|
let x = 20;
|
||
|
let y = 20;
|
||
|
|
||
|
var qs = QuickSettings.create(x, y, label, parent);
|
||
|
|
||
|
// proxy all functions of quicksettings
|
||
|
this.prototype = qs;
|
||
|
|
||
|
// addGlobals(global1, global2, ...) to add the selected globals
|
||
|
this.addGlobals = function() {
|
||
|
qs.bindGlobals(arguments);
|
||
|
};
|
||
|
|
||
|
// addObject(object) to add all params of the object
|
||
|
// addObject(object, param1, param2, ...) to add selected params
|
||
|
this.addObject = function() {
|
||
|
// get object
|
||
|
object = arguments[0];
|
||
|
// convert arguments object to array
|
||
|
var params = [];
|
||
|
if(arguments.length > 1) {
|
||
|
params = Array.prototype.slice.call(arguments)
|
||
|
params = params.slice(1);
|
||
|
}
|
||
|
// if no arguments are provided take all keys of the object
|
||
|
if(params.length === 0) {
|
||
|
// won't work in Internet Explorer < 9 (use a polyfill)
|
||
|
params = Object.keys(object);
|
||
|
}
|
||
|
qs.bindParams(object, params);
|
||
|
};
|
||
|
|
||
|
// noLoop() to call draw every time the gui changes when we are not looping
|
||
|
this.noLoop = function() {
|
||
|
qs.setGlobalChangeHandler(sketch._draw);
|
||
|
};
|
||
|
|
||
|
this.loop = function() {
|
||
|
qs.setGlobalChangeHandler(null);
|
||
|
};
|
||
|
|
||
|
// pass through ...
|
||
|
this.show = function() { qs.show(); };
|
||
|
this.hide = function() { qs.hide(); };
|
||
|
this.toggleVisibility = function() { qs.toggleVisibility(); };
|
||
|
this.setPosition = function(x, y) {
|
||
|
qs.setPosition(x, y);
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
// Extend Quicksettings
|
||
|
// so it can magically create a GUI for parameters passed by name
|
||
|
qs.bindParams = function(object, params) {
|
||
|
|
||
|
// iterate over all the arguments
|
||
|
for(var i = 0; i < params.length; i++) {
|
||
|
|
||
|
var arg = params[i];
|
||
|
var val = object[arg];
|
||
|
var typ = typeof val;
|
||
|
|
||
|
//console.log(typ, arg, val);
|
||
|
|
||
|
// don't need to show the sliders for range min, max and step of a property
|
||
|
var sliderConfigRegEx = /^(.*min|.*max|.*step)$/i;
|
||
|
if( sliderConfigRegEx.test(arg)){
|
||
|
continue;
|
||
|
}
|
||
|
switch(typ) {
|
||
|
|
||
|
case 'object':
|
||
|
|
||
|
// color triple ?
|
||
|
if(val instanceof Array && val.length === 3 && typeof val[0] === 'number') {
|
||
|
// create color according to the current color mode of the current sketch
|
||
|
var c = sketch.color(val[0], val[1], val[2]);
|
||
|
// get decimal RGB values
|
||
|
var c2 = c.levels.slice(0,3);
|
||
|
// create HTML color code
|
||
|
var vcolor = '#' + c2.map(function(value) {
|
||
|
return ('0' + value.toString(16)).slice(-2);
|
||
|
}).join('');
|
||
|
this.bindColor(arg, vcolor, object);
|
||
|
} else {
|
||
|
// multiple choice drop down list
|
||
|
this.bindDropDown(arg, val, object);
|
||
|
object[arg] = val[0];
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'number':
|
||
|
|
||
|
// values as defined by magic variables or gui.sliderRange()
|
||
|
var vmin = object[arg + 'Min'] || object[arg + 'min'] || sliderMin;
|
||
|
var vmax = object[arg + 'Max'] || object[arg + 'max'] || sliderMax;
|
||
|
var vstep = object[arg + 'Step'] || object[arg + 'step'] || sliderStep;
|
||
|
|
||
|
// the actual values can still overrule the limits set by magic
|
||
|
var vmin = Math.min(val, vmin);
|
||
|
var vmax = Math.max(val, vmax);
|
||
|
|
||
|
// set the range
|
||
|
this.bindRange(arg, vmin, vmax, val, vstep, object);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'string':
|
||
|
|
||
|
var HEX6 = /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i;
|
||
|
if(HEX6.test(val)) {
|
||
|
// HTML color value (such as #ff0000)
|
||
|
this.bindColor(arg, val, object);
|
||
|
} else {
|
||
|
// String value
|
||
|
this.bindText(arg, val, object);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'boolean':
|
||
|
|
||
|
this.bindBoolean(arg, object[arg], object);
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// bind params that are defined globally
|
||
|
qs.bindGlobals = function(params) {
|
||
|
this.bindParams(window, params);
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
// Just a Dummy object that provides the GUI interface
|
||
|
function DummyGui() {
|
||
|
var f = function() {};
|
||
|
this.addGlobals = f;
|
||
|
this.noLoop = f;
|
||
|
this.addObject = f;
|
||
|
this.show = f;
|
||
|
}
|
||
|
|
||
|
|
||
|
})();
|