Structured layers menu (WIP)
This commit is contained in:
24
config.js
24
config.js
@@ -44,15 +44,13 @@ export const config = {
|
||||
uri : `${BASE_URI}/scenes/ssgp/`,
|
||||
popup: theater2Popup,
|
||||
coords: [45.4401, 12.3408],
|
||||
nodes: {
|
||||
groups: [
|
||||
nodes: [
|
||||
{
|
||||
label: 'Teatro',
|
||||
layers: [
|
||||
children: [
|
||||
{
|
||||
label: 'Struttura complessiva',
|
||||
model: 'models/ssgp/Teatro_SSGP_Full_ConSottrazioni.glb',
|
||||
//isMain: true,
|
||||
},
|
||||
{
|
||||
label: 'Involucro',
|
||||
@@ -64,11 +62,14 @@ export const config = {
|
||||
},
|
||||
{
|
||||
label: 'Sala / Auditorium',
|
||||
layers: [
|
||||
children: [
|
||||
{
|
||||
label: 'Peplano / Platea',
|
||||
model: 'models/ssgp/Teatro_SSGP_Platea_peplano.glb',
|
||||
},
|
||||
{
|
||||
label: 'Ordini di palchi',
|
||||
children: [
|
||||
{
|
||||
label: 'Ordine 1',
|
||||
model: 'models/ssgp/Teatro_SSGP_Ordine1.glb',
|
||||
@@ -89,6 +90,8 @@ export const config = {
|
||||
label: 'Ordine 5',
|
||||
model: 'models/ssgp/Teatro_SSGP_Ordine5.glb',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Parapetto',
|
||||
model: 'models/ssgp/Teatro_SSGP_parapetto_scala_piani.glb',
|
||||
@@ -101,7 +104,7 @@ export const config = {
|
||||
},
|
||||
{
|
||||
label: 'Scena',
|
||||
layers: [
|
||||
children: [
|
||||
{
|
||||
label: 'Palcoscenico',
|
||||
model: 'models/ssgp/Teatro_SSGP_Palcoscenico.glb',
|
||||
@@ -122,11 +125,11 @@ export const config = {
|
||||
},
|
||||
{
|
||||
label: 'Spazi tecnici',
|
||||
layers: [
|
||||
children: [
|
||||
{
|
||||
label: 'Spazio tecnico superiore',
|
||||
model: 'models/ssgp/Teatro_SSGP_Layer_Spazio_tecnico_sup_soffitta.glb',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
label: 'Graticcia',
|
||||
model: 'models/ssgp/Teatro_SSGP_Graticcia.glb',
|
||||
@@ -141,9 +144,11 @@ export const config = {
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Orchestra',
|
||||
layers: [
|
||||
children: [
|
||||
{
|
||||
label: 'Fossa orchestra',
|
||||
model: 'models/ssgp/Teatro_SSGP_Fossa_orchestra.glb',
|
||||
@@ -151,7 +156,6 @@ export const config = {
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
pano: `pano/gradient.jpg`,
|
||||
}
|
||||
],
|
||||
|
||||
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,
|
||||
|
||||
35
js/ui.js
35
js/ui.js
@@ -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;
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
import Scene from "../../js/scene.js";
|
||||
import { config } from "../../config.js";
|
||||
import AppState from "../../js/state.js";
|
||||
import { normalizeNodes } from "../../js/utils/nodeUtils.js";
|
||||
|
||||
AppState.currentScene = 'salvador';
|
||||
AppState.sceneHasAudio = true;
|
||||
const marker = config.markers.find(m => m.id === 'salvador');
|
||||
AppState.normalizedNodes = normalizeNodes(marker.nodes);
|
||||
|
||||
AppState.normalizedNodes.forEach(node => node.active = true);
|
||||
|
||||
Scene.openScene(marker, AppState.normalizedNodes);
|
||||
|
||||
Scene.openScene(config.markers.find(m => m.id === 'salvador'));
|
||||
Scene.UI.pauseAudio('[data-bs-dismiss="modal"]');
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import Scene from "../../js/scene.js";
|
||||
import { config } from "../../config.js";
|
||||
import AppState from "../../js/state.js";
|
||||
import { normalizeNodes } from "../../js/utils/nodeUtils.js";
|
||||
|
||||
AppState.currentScene = 'ssgp';
|
||||
Scene.openScene(config.markers.find(m => m.id === 'ssgp'));
|
||||
const marker = config.markers.find(m => m.id === 'ssgp');
|
||||
AppState.normalizedNodes = normalizeNodes(marker.nodes);
|
||||
|
||||
AppState.normalizedNodes.forEach(node => node.active = true);
|
||||
|
||||
Scene.openScene(marker, AppState.normalizedNodes);
|
||||
|
||||
Reference in New Issue
Block a user