Structured layers menu (WIP)

This commit is contained in:
2026-04-07 10:57:11 +02:00
parent 2df5a71241
commit 9a8f6c7dc5
7 changed files with 135 additions and 63 deletions

View File

@@ -232,18 +232,21 @@ Scene.resetClipping = function () {
}
/**
* @param {Object} marker - The marker object from config
* @param {Object[]} nodes - The flat list of nodes for this scene
*/
Scene.openScene = function(marker) {
Scene.openScene = function(marker, nodes) {
Scene.init();
// TODO: move to init logic
Scene.UI.toggleClipperBar('#clipper', '#clipper-bar');
// Filter nodes with models first
nodes = nodes.filter(n => n.model);
// Load 3D models and create nodes
Scene.loadNodes(marker.nodes);
Scene.loadNodes(nodes);
ATON.setMainPanorama(marker.pano);
// TODO: hardcoded...
AppState.initialRotation = new THREE.Vector3(0, 1.5, 0);
//Scene.showEdges(mainNode);
ATON.setAutoLP(config.scene.autoLP);
AppState.lightProbe = config.scene.autoLP;
@@ -254,7 +257,7 @@ Scene.openScene = function(marker) {
/**
*
* @param {Array} nodes
* @param {Object[]} nodes
*/
Scene.loadNodes = function (nodes) {
nodes.forEach(n => {
@@ -264,7 +267,11 @@ Scene.loadNodes = function (nodes) {
// Apply any transparency before attaching to scene
if (n.opacity) {
node.setMaterial(new THREE.MeshPhongMaterial({transparent: true, opacity: n.opacity, color: '#fff'}));
node.setMaterial(new THREE.MeshPhongMaterial({
transparent: true,
opacity: n.opacity,
color: '#fff'
}));
}
node.attachToRoot();
@@ -275,7 +282,6 @@ Scene.loadNodes = function (nodes) {
AppState.clipping.boundingSphere = node.getBound();
}
AppState.nodes.push({id: n.label, active: true});
});
}

View File

@@ -8,6 +8,7 @@ let AppState = {
root: null,
// {id: String, active: Boolean}
nodes: [],
normalizedNodes: [],
mainNodeId: null,
currentScene: null,
sceneHasAudio: false,

View File

@@ -9,7 +9,7 @@ const UI = {};
UI.domParser = new DOMParser;
UI.contentMenuTabs = `
<!-- Nav tabs -->
<!-- Nav tabs -->
<ul class="nav nav-pills" id="content-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="layer-tab" data-bs-toggle="tab" data-bs-target="#layer" type="button" role="tab" aria-controls="layer" aria-selected="false">
@@ -24,8 +24,8 @@ UI.contentMenuTabs = `
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active p-3" id="layer" role="tabpanel" aria-labelledby="layer-tab" tabindex="0"></div>
<div class="tab-content ps-4 ms-3" style="overflow: auto">
<div class="tab-pane active p-3 ms-3" id="layer" role="tabpanel" aria-labelledby="layer-tab" tabindex="0"></div>
<div class="tab-pane p-3" id="media" role="tabpanel" aria-labelledby="media-tab" tabindex="0"></div>
</div>
`;
@@ -230,7 +230,7 @@ UI.toggleContentMenu = function(triggerId) {
const tabs = this.domParser.parseFromString(UI.contentMenuTabs, 'text/html');
ATON.UI.elSidePanel.appendChild(tabs.querySelector('#content-tabs'));
ATON.UI.elSidePanel.appendChild(tabs.querySelector('.tab-content'));
this.buildLayersMenu(AppState.nodes, ATON.UI.elSidePanel.querySelector('#layer'));
this.buildLayersMenu(AppState.normalizedNodes, ATON.UI.elSidePanel.querySelector('#layer'));
});
}
/**
@@ -240,19 +240,26 @@ UI.toggleContentMenu = function(triggerId) {
*/
UI.buildLayersMenu = function(nodes, sidePanel) {
for(let node of nodes) {
const checkboxStr = `
<div class="form-check form-switch ms-4 mt-2">
<input class="form-check-input" type="checkbox" ${node.active ? 'checked' : ''} role="switch" title="Mostra / nascondi layer">
<label class="form-check-label" for="aoSwitch">${node.id}</label>
</div>
`;
const menuItem = document.createElement('div');
menuItem.className = `form-check form-switch ms-${node.depth} ps-${node.depth} mt-2`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = "form-check-input";
checkbox.checked = node.active;
checkbox.role = 'switch';
checkbox.title = "Mostra / nascondi layer";
let element = this.domParser.parseFromString(checkboxStr, 'text/html');
element = element.querySelector('div.form-check');
menuItem.appendChild(checkbox);
sidePanel.appendChild(element);
const label = document.createElement('label');
label.className = "form-check-label";
label.textContent = node.label;
menuItem.appendChild(label);
sidePanel.appendChild(menuItem);
// Will this ever work??
element.addEventListener('change', event => toggleNode(node.id, event.target.checked));
menuItem.addEventListener('change', event => toggleNode(node.label, event.target.checked));
}
/**
@@ -262,7 +269,7 @@ UI.buildLayersMenu = function(nodes, sidePanel) {
*/
const toggleNode = (id, status) => {
ATON.getSceneNode(id).toggle(status);
AppState.nodes.find(n => n.id === id).active = status;
AppState.normalizedNodes.find(n => n.label === id).active = status;
}
}

42
js/utils/nodeUtils.js Normal file
View File

@@ -0,0 +1,42 @@
/**
* @module
*/
/**
*
* @param {Object} node
* @param {Object[]} flatList
* @param {Number} depth
*/
function traverse(node, flatList, depth = 1) {
const normNode = {label: node.label};
if (node.model) {
normNode.model = node.model;
}
flatList.push({
...normNode,
depth
});
if (node.children) {
depth++;
for(let child of node.children) {
traverse(child, flatList, depth);
}
}
}
/**
* Create a flat list of nodes from
* the nested structure in config
* @param {Array} nodes
* @returns {Object[]} A flat list of nodes
**/
export function normalizeNodes (nodes) {
let flatNodes = [];
for (let node of nodes) {
traverse(node, flatNodes);
}
return flatNodes;
}