dat.GUI 和复杂变量
dat.GUI and Complex Variables
我是 dat.GUI 的新手,在使用更复杂的变量时遇到问题。
我有以下内容:
let complexVariable= {
topLayer:
{
deeperLayer:
{
deepestLayer: 20,
//Other stuff
}
}
}
let gui = new dat.GUI();
gui.add(complexVariable, "topLayer.deeperLayer.deepestLayer", 10, 40);
这给了我以下错误:
Uncaught Error: Object "[object Object]" has no property "topLayer.deeperLayer.deepestLayer"
如有任何帮助,我们将不胜感激。
目前通过查看 source code 似乎不可能。他们使用括号表示法和您传入对象的单个 属性 。
function add(gui, object, property, params) {
if (object[property] === undefined) {
throw new Error(`Object "${object}" has no property "${property}"`);
}
...
所以你告诉 dat.GUI 要做的是找到一个顶层 属性 "topLayer.deeperLayer.deepestLayer" 并且这显然不存在于你的对象上。似乎必须编写更多代码来支持嵌套属性。
dat.gui 必须做类似 if (object[property1][property2][...] === undefined)
的事情,或者在你的情况下 - complexVariable["topLayer"]["deeperLayer"]["deepestLayer"];
很明显这个问题已有 4 年历史了。但我一直在寻找相同的东西,在意识到这是可能的之前我发现了你的问题。以下是 Angular.
中的 E2E 示例
import { AfterViewInit, Component, ViewChild, ViewContainerRef } from '@angular/core';
import { GUI, GUIController, GUIParams } from 'dat.gui';
export type EditorMetadata = Array<IEditorFolder>;
export interface IDatState {
state: EditorMetadata;
instance: GUI;
metadata: EditorMetadata;
}
export interface IEditorFolder {
title: string;
property?: string;
tooltip: string;
elements?: Array<IEditorElement>;
folders?: Array<IEditorFolder>;
folderRef?: GUI;
}
export interface IEditorElement {
title: string;
tooltip: string;
options?: any;
elementRef?: GUIController;
target?: Object;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
@ViewChild('container', { read: ViewContainerRef, static: true })
container: ViewContainerRef;
constructor() { }
ngAfterViewInit(): void {
this.composeEditor(this.container.element.nativeElement, options, foldersMetadata);
}
composeEditor(container: HTMLElement, editorOptions: GUIParams, editorMetadata: EditorMetadata): IDatState {
const
addFolder = (folder: IEditorFolder, parent: GUI): GUI => {
const
{ title, tooltip } = folder,
folderController = parent.addFolder(title);
folderController.domElement.setAttribute('title', tooltip);
return folderController;
},
addElement = (folder: GUI, element: IEditorElement, target: Object): GUIController => {
const
{ title, options, tooltip } = element,
elmController = folder
.add(target, title, options)
.name(title)
.onChange((value) => {
console.log(model);
});
elmController.domElement.setAttribute('title', tooltip);
return elmController;
},
createDat = (options: GUIParams, metadata: EditorMetadata): IDatState => {
const
state: IDatState = {
instance: new GUI(options),
state: JSON.parse(JSON.stringify(metadata)), // Don't touch original metadata, instead clone it.
metadata: metadata, // Return original metadata
};
return state;
},
process = (folders: EditorMetadata, parent: GUI, model: Object): void => {
folders.forEach(folder => {
const target: Object = folder.property ? model[folder.property] : model; // Root level or object nested prop?
folder.folderRef = addFolder(folder, parent);
folder.elements && folder.elements.forEach(element => element.elementRef = addElement(folder.folderRef, element, target));
folder.folders && process(folder.folders, folder.folderRef, target);
});
},
{ state, instance, metadata } = createDat(editorOptions, editorMetadata);
process(state, instance, model);
container.appendChild(instance.domElement);
return { state, instance, metadata };
}
}
const options: GUIParams = {
hideable: false,
autoPlace: false,
closeOnTop: false,
width: 250,
name: 'DAT Sample'
};
const model = {
rtl: true,
renderer: 'geras',
theme: 'dark',
toolbox: 'foundation',
toolboxPosition: 'left',
debug: {
alert: false
}
};
const foldersMetadata: EditorMetadata = [
{
title: 'Options',
tooltip: 'Options AA',
elements: [
{
title: 'rtl',
tooltip: 'RTL',
},
{
title: 'renderer',
tooltip: 'Renderer',
options: ['geras', 'thrasos', 'zelos']
},
{
title: 'theme',
tooltip: 'Theme',
options: ['classic', 'dark', 'deuteranopia', 'tritanopia', 'highcontrast']
},
{
title: 'toolbox',
tooltip: 'Toolbox',
options: ['foundation', 'platform', 'invoice']
},
{
title: 'toolboxPosition',
tooltip: 'Toolbox Position',
options: ['left', 'right', 'top', 'bottom']
},
],
folders: [
{
title: 'Debug',
property: 'debug',
tooltip: 'Debug mode',
elements: [
{
title: 'alert',
tooltip: 'Alert Tooltip',
},
]
}
]
},
];
我是 dat.GUI 的新手,在使用更复杂的变量时遇到问题。
我有以下内容:
let complexVariable= {
topLayer:
{
deeperLayer:
{
deepestLayer: 20,
//Other stuff
}
}
}
let gui = new dat.GUI();
gui.add(complexVariable, "topLayer.deeperLayer.deepestLayer", 10, 40);
这给了我以下错误:
Uncaught Error: Object "[object Object]" has no property "topLayer.deeperLayer.deepestLayer"
如有任何帮助,我们将不胜感激。
目前通过查看 source code 似乎不可能。他们使用括号表示法和您传入对象的单个 属性 。
function add(gui, object, property, params) {
if (object[property] === undefined) {
throw new Error(`Object "${object}" has no property "${property}"`);
}
...
所以你告诉 dat.GUI 要做的是找到一个顶层 属性 "topLayer.deeperLayer.deepestLayer" 并且这显然不存在于你的对象上。似乎必须编写更多代码来支持嵌套属性。
dat.gui 必须做类似 if (object[property1][property2][...] === undefined)
的事情,或者在你的情况下 - complexVariable["topLayer"]["deeperLayer"]["deepestLayer"];
很明显这个问题已有 4 年历史了。但我一直在寻找相同的东西,在意识到这是可能的之前我发现了你的问题。以下是 Angular.
中的 E2E 示例import { AfterViewInit, Component, ViewChild, ViewContainerRef } from '@angular/core';
import { GUI, GUIController, GUIParams } from 'dat.gui';
export type EditorMetadata = Array<IEditorFolder>;
export interface IDatState {
state: EditorMetadata;
instance: GUI;
metadata: EditorMetadata;
}
export interface IEditorFolder {
title: string;
property?: string;
tooltip: string;
elements?: Array<IEditorElement>;
folders?: Array<IEditorFolder>;
folderRef?: GUI;
}
export interface IEditorElement {
title: string;
tooltip: string;
options?: any;
elementRef?: GUIController;
target?: Object;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
@ViewChild('container', { read: ViewContainerRef, static: true })
container: ViewContainerRef;
constructor() { }
ngAfterViewInit(): void {
this.composeEditor(this.container.element.nativeElement, options, foldersMetadata);
}
composeEditor(container: HTMLElement, editorOptions: GUIParams, editorMetadata: EditorMetadata): IDatState {
const
addFolder = (folder: IEditorFolder, parent: GUI): GUI => {
const
{ title, tooltip } = folder,
folderController = parent.addFolder(title);
folderController.domElement.setAttribute('title', tooltip);
return folderController;
},
addElement = (folder: GUI, element: IEditorElement, target: Object): GUIController => {
const
{ title, options, tooltip } = element,
elmController = folder
.add(target, title, options)
.name(title)
.onChange((value) => {
console.log(model);
});
elmController.domElement.setAttribute('title', tooltip);
return elmController;
},
createDat = (options: GUIParams, metadata: EditorMetadata): IDatState => {
const
state: IDatState = {
instance: new GUI(options),
state: JSON.parse(JSON.stringify(metadata)), // Don't touch original metadata, instead clone it.
metadata: metadata, // Return original metadata
};
return state;
},
process = (folders: EditorMetadata, parent: GUI, model: Object): void => {
folders.forEach(folder => {
const target: Object = folder.property ? model[folder.property] : model; // Root level or object nested prop?
folder.folderRef = addFolder(folder, parent);
folder.elements && folder.elements.forEach(element => element.elementRef = addElement(folder.folderRef, element, target));
folder.folders && process(folder.folders, folder.folderRef, target);
});
},
{ state, instance, metadata } = createDat(editorOptions, editorMetadata);
process(state, instance, model);
container.appendChild(instance.domElement);
return { state, instance, metadata };
}
}
const options: GUIParams = {
hideable: false,
autoPlace: false,
closeOnTop: false,
width: 250,
name: 'DAT Sample'
};
const model = {
rtl: true,
renderer: 'geras',
theme: 'dark',
toolbox: 'foundation',
toolboxPosition: 'left',
debug: {
alert: false
}
};
const foldersMetadata: EditorMetadata = [
{
title: 'Options',
tooltip: 'Options AA',
elements: [
{
title: 'rtl',
tooltip: 'RTL',
},
{
title: 'renderer',
tooltip: 'Renderer',
options: ['geras', 'thrasos', 'zelos']
},
{
title: 'theme',
tooltip: 'Theme',
options: ['classic', 'dark', 'deuteranopia', 'tritanopia', 'highcontrast']
},
{
title: 'toolbox',
tooltip: 'Toolbox',
options: ['foundation', 'platform', 'invoice']
},
{
title: 'toolboxPosition',
tooltip: 'Toolbox Position',
options: ['left', 'right', 'top', 'bottom']
},
],
folders: [
{
title: 'Debug',
property: 'debug',
tooltip: 'Debug mode',
elements: [
{
title: 'alert',
tooltip: 'Alert Tooltip',
},
]
}
]
},
];