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',
          },
        ]
      }
    ]
  },
];