lil-gui 是一个可以在运行时修改 JavaScript 对象属性的界面库。相信用过 three.js 的同学对它一定不会陌生,three.js 的很多示例都用到了这个轻量的界面库修改三维场景的属性。我也是因为接触到 three.js 才打算学习一下这个库的。
下面通过一组例子总结 lil-gui 的基本用法
用这个库之前,需要实例化它的对象
const gui = new GUI();
1、属性类型和界面控件的对应关系
const obj = {
myBoolean: true,
myString: 'lil-gui',
myNumber: 1,
myFunction: function() { alert( 'hi' ) }
}
gui.add( obj, 'myBoolean' ); // checkbox
gui.add( obj, 'myString' ); // text field
gui.add( obj, 'myNumber' ); // number field
gui.add( obj, 'myFunction' ); // button
上面的例子用到了 gui.add 方法,该方法的函数签名如下所示:
gui.add(object, property, [$1], [max], [step])
object: 目标对象
property:目标对象上要修改的属性
$1:数值属性的最小值或可选值列表
max: 数值属性的最大值
step:数值属性的步进
lil-gui 会根据要修改属性的数据类型选择合适的界面控件,主要数据类型对应的控件
- 布尔值:checkbox
- 字符串:text field
- 数值:number field
- 函数:button
2、指定最大值、最小值和步进量
const obj = { hasMin: 0, hasMax: 100, hasStep: 60 }
gui.add( obj, 'hasMin' ).min( 0 );
gui.add( obj, 'hasMax' ).max( 100 );
gui.add( obj, 'hasStep' ).step( 10 ); // 四舍五入到10的倍数
3、为数值属性提供滑块
同时设置数值的最大值和最小值,lil-gui会提供一个滑块
const obj = { number1: 1, number2: 40 }
gui.add( obj, 'number1', 0, 1, 0.1); // min, max, step
gui.add( obj, 'number2', 0, 100, 10 ); // min, max, step
4、为属性提供可选值的下拉列表
下拉列表中的可选值可以用数组或者对象组织。用对象组织时,界面上显示的是对象中的键值。
const obj = { size: 'Large', speed: 1 };
gui.add( obj, 'size', [ 'Small', 'Medium', 'Large' ] );
gui.add( obj, 'speed', { Slow: 0.1, Normal: 1, Fast: 5 } );
4、修改颜色属性
lil-gui 可以识别 CSS字符串 或 十六进制 数值表示的颜色,通过 addColor() 方法创建颜色选择器
const obj = {
color1: '#AA00FF',
color2: '#a0f',
color3: 'rgb(170, 0, 255)',
color4: 0xaa00ff
}
gui.addColor( obj, 'color1' );
gui.addColor( obj, 'color2' );
gui.addColor( obj, 'color3' );
gui.addColor( obj, 'color4' );
5、通过分量指定颜色初始值
可以通过 对象 或 数组 两种形式指定颜色初始值
const obj = {
colorObject: { r: 0.39215686274509803, g: 0.18823529411764706, b: 0.49411764705882355 },
colorArray: [ 0.25098039215686274, 0.12549019607843137, 0.3137254901960784 ]
}
gui.addColor( obj, 'colorObject' );
gui.addColor( obj, 'colorArray' );
6、修改颜色分量的范围
默认颜色分量在 [ 0, 1 ] 区间内,可以设置 addColor 方法的第三个参数将颜色分量扩展到 [ 0, 255 ]
// 指定0-255范围的颜色值
const obj = {
colorObject: { r: 170, g: 0, b: 255 },
colorArray: [ 170, 0, 255 ]
};
gui.addColor( obj, 'colorObject', 255 );
gui.addColor( obj, 'colorArray', 255 );
addColor 方法的函数签名如下所示
addColor( object, property, rgbScale=1 )
object:目标对象
property:目标对象中作为颜色的属性名称
rgbScale:颜色通道的最大值,默认为1
7、为属性分组
const obj = {
scale: 0.5,
x: 1,
y: 2,
z: 3
};
// top level controller
gui.add(obj, 'scale', 0, 1);
// nested controllers
const folder = gui.addFolder('Position');
folder.add(obj, 'x');
folder.add(obj, 'y');
folder.add(obj, 'z');
在界面上,将 obj 对象的 x、y、z 属性在界面上组织成名称为 Position 的可折叠分组
8、属性变化监听事件
有两种属性变化监听事件:onChange 和 onFinishChange 。它们的区别是 onChange 修改立即触发;onFinishChange 修改并失去焦点后触发。
onChange :
const params = {
foo: 'foo'
};
// 链式调用
gui.add(params, 'foo').onChange(value => {
// 修改后的新值
console.log(value);
});
onFinishChange :
// 修改属性,界面控件失去焦点时才触发
const params = {
foo: 'foo'
};
gui.add(params, 'foo').onFinishChange(value => {
// 修改后的新值
console.log(value);
});
9、全局的属性变化监听事件
除了针对对象上具体属性的监听方式外,lil-gui 还提供全局的监听方式。任何属性的变化都会触发它们。
全局 onChange :
gui.onChange(event => {
/*
// event.object // object that was modified
// event.property // string, name of property
// event.value // new value of controller
// event.controller // controller that was modified
*/
console.log(event.object);
console.log(event.property);
console.log(event.value);
console.log(event.controller);
});
const params1 = {
foo: 'foo'
};
gui.add(params1, 'foo');
const params2 = {
bar: 'bar'
};
gui.add(params2, 'bar');
全局 onFinishChange :
gui.onFinishChange(event => {
console.log(event.object);
console.log(event.property);
console.log(event.value);
console.log(event.controller);
// event.object // object that was modified
// event.property // string, name of property
// event.value // new value of controller
// event.controller // controller that was modified
});
const params1 = {
foo: 'foo'
};
gui.add(params1, 'foo');
const params2 = {
bar: 'bar'
};
gui.add(params2, 'bar');
10、界面外部修改属性值的情况
通过界面外的方式修改了属性值,lil-gui并不会做出响应。这时可以用 listen 方法监听属性值在界面外的变化,并在界面上更新
const params = {
feedback: 0,
};
gui.add( params, 'feedback', -1, 1 ).listen();
document.getElementById('test').onclick = function () {
params.feedback = 0.5;
};
11、保存界面上的属性值
gui.save 将当前界面上的属性值保存到一个对象中,以 JSON 对象的形式存储
let preset = {};
const obj = {
value1: 'original',
value2: 1996,
savePreset() {
// 保存当前值到一个对象中
preset = gui.save();
loadButton.enable();
},
loadPreset() {
// gui.load 将通过 gui.save保存的对象重新加载到界面上
gui.load(preset);
}
}
gui.add(obj, 'value1');
gui.add(obj, 'value2');
gui.add(obj, 'savePreset');
const loadButton = gui.add(obj, 'loadPreset');
loadButton.disable();
12、处理属性名称冲突
界面上有相同的属性名时,用 gui.save 会报名称冲突的错误。这时可以用 name 方法改名可以避免这个问题
const position = {
x: 1
};
const rotation = {
x: 2
};
// gui.add( position, 'x' );
// gui.add( rotation, 'x' );
// 避免两个对象中的 x 同名
gui.add(position, 'x').name('position.x');
gui.add(rotation, 'x').name('rotation.x');
const obj = {
savePreset() {
preset = gui.save();
loadButton.enable();
},
loadPreset() {
gui.load(preset);
}
};
let preset = {};
gui.add(obj, 'savePreset');
const loadButton = gui.add(obj, 'loadPreset');
loadButton.disable();
13、改变面板的位置
默认情况下面板是位于页面右上角的,实际应用中可能由于界面元素冲突需要调整面板的位置。
在实例化的时候设置 autoPlace 属性为 false,然后指定 CSS 进行修改即可
const gui = new lil.GUI({
autoPlace: false
});
const guiWrapper = document.createElement("div");
guiWrapper.style.position = "absolute";
guiWrapper.style.left = "15px";
guiWrapper.style.top = "0";
guiWrapper.style.zIndex = 1001;
guiWrapper.appendChild(gui.domElement);
document.body.appendChild(guiWrapper);
14、添加多行文本框(textarea)
lil-gui 的核心库不支持多行文本框,但是官网提供了解决方案。Multiline Controller,然后像下面这样使用就行。
const obj = {
text: 'one\ntwo\nthree'
};
gui.addMultiline( obj, 'text');