Structured layers menu (WIP)
This commit is contained in:
18
js/scene.js
18
js/scene.js
@@ -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});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ let AppState = {
|
||||
root: null,
|
||||
// {id: String, active: Boolean}
|
||||
nodes: [],
|
||||
normalizedNodes: [],
|
||||
mainNodeId: null,
|
||||
currentScene: null,
|
||||
sceneHasAudio: false,
|
||||
|
||||
37
js/ui.js
37
js/ui.js
@@ -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
42
js/utils/nodeUtils.js
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user