@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
119 lines (117 loc) • 4.06 kB
JavaScript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import { Object3D } from 'three';
import { isBufferGeometry, isInterleavedBufferAttribute, isVector3 } from '../../utils/predicates';
import Panel from '../Panel';
class OutlinerPropertyView extends Panel {
_object = null;
constructor(parentGui, instance) {
super(parentGui, instance, 'Properties');
this._folders = [];
this.gui.domElement.style.overflow = 'auto';
this.gui.domElement.style.maxHeight = '200px';
this.gui.open(true);
this.populateProperties(new Object3D());
}
createControllers(obj, gui) {
if (obj == null) {
return;
}
const notify = () => this.instance.notifyChange();
const entries = Object.entries(obj);
entries.forEach(([name, value]) => {
if (!name.startsWith('___outliner')) {
switch (typeof value) {
case 'string':
case 'number':
case 'bigint':
case 'boolean':
if (value != null) {
this._controllers.push(gui.add(obj, name).onChange(notify));
}
break;
}
}
});
}
/**
* @param obj - The object to update.
*/
updateObject(obj) {
obj.updateMatrixWorld(true);
obj.updateWorldMatrix(true, true);
this.notify();
}
goToObject() {
if (this._object != null) {
const pov = this.instance.view.goTo(this._object);
this.updateControlsWithDefaultView(pov);
}
}
updateControlsWithDefaultView(defaultView) {
const controls = this.instance.view.controls;
if (defaultView && controls && 'target' in controls && isVector3(controls.target)) {
controls.target.copy(defaultView.target);
}
}
populateProperties(obj) {
while (this._controllers.length > 0) {
this._controllers.pop()?.destroy();
}
while (this._folders.length > 0) {
this._folders.pop()?.destroy();
}
this._object = obj;
this.addController(this, 'goToObject');
this.createControllers(obj, this.gui);
const position = this.gui.addFolder('Position');
position.close();
this._folders.push(position);
const update = () => this.updateObject(obj);
function bindVector(gui, v, key) {
return gui.add(v, key).step(0.01);
}
this._controllers.push(bindVector(position, obj.position, 'x').onChange(update));
this._controllers.push(bindVector(position, obj.position, 'y').onChange(update));
this._controllers.push(bindVector(position, obj.position, 'z').onChange(update));
const scale = this.gui.addFolder('Scale');
scale.close();
this._folders.push(scale);
this._controllers.push(bindVector(scale, obj.scale, 'x').onChange(update));
this._controllers.push(bindVector(scale, obj.scale, 'y').onChange(update));
this._controllers.push(bindVector(scale, obj.scale, 'z').onChange(update));
if ('material' in obj && obj.material != null) {
const material = this.gui.addFolder('Material');
this._folders.push(material);
material.close();
this.createControllers(obj.material, material);
}
if ('geometry' in obj && isBufferGeometry(obj.geometry)) {
const geometry = this.gui.addFolder('Geometry');
this._folders.push(geometry);
geometry.close();
this.createControllers(obj.geometry, geometry);
if (obj.geometry.attributes != null) {
const attrs = obj.geometry.attributes;
const attributes = geometry.addFolder('Attributes');
Object.keys(attrs).forEach(p => {
const attrValue = attrs[p];
if (p && attrValue != null) {
const attr = attributes.addFolder(p);
attr.close();
attr.add(attrValue, 'normalized');
attr.add(attrValue, 'count');
attr.add(attrValue, 'itemSize');
if (!isInterleavedBufferAttribute(attrValue)) {
attr.add(attrValue, 'usage');
}
}
});
}
}
}
}
export default OutlinerPropertyView;