From 8fec26f69f287bf7c87c35d59eb5c7d6a72b8cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20P?= Date: Wed, 8 Jul 2026 13:01:48 +0200 Subject: [PATCH] Idiotic instance panel... --- css/app.css | 10 ++++ scenes/ssgp/index.html | 17 ++++++- src/controllers/menu_controller.js | 23 +++++---- src/controllers/node_controller.js | 75 ++++++++++++++++++++++++++++-- src/ontology.js | 25 ++++++++++ src/scene.js | 19 ++++---- src/state.js | 4 ++ src/utils/nodeUtils.js | 1 + 8 files changed, 149 insertions(+), 25 deletions(-) diff --git a/css/app.css b/css/app.css index 615d383..2b76c52 100644 --- a/css/app.css +++ b/css/app.css @@ -57,6 +57,16 @@ input[type="checkbox"] { padding-left: 0; list-style-position: outside; } +#instances li > a { + color: #dee2e6; +} +#instances li > a:hover { + color: var(--bs-nav-link-color); + text-decoration: underline; +} +#instance-panel { + z-index: 999; +} /* Tooltips from https://codepen.io/pure-css/pen/bddggP */ span:after { text-align: left; diff --git a/scenes/ssgp/index.html b/scenes/ssgp/index.html index 47b19d3..a8126c2 100644 --- a/scenes/ssgp/index.html +++ b/scenes/ssgp/index.html @@ -58,7 +58,7 @@ - +
@@ -174,6 +174,21 @@
+ +
+
+

+
+
+
+
    +
    +
    +

    Sono inesorabilmente vuoto...

    +
    +
    +
    +
    diff --git a/src/controllers/menu_controller.js b/src/controllers/menu_controller.js index cfe911e..2d9e75b 100644 --- a/src/controllers/menu_controller.js +++ b/src/controllers/menu_controller.js @@ -14,6 +14,7 @@ export default class extends Controller { async connect() { console.log('#menu controller connected'); this.ontologyObject = await loadOntology(ontologyJsonPath); + AppState.ontology = this.ontologyObject; } /** * Open settings panel @@ -240,7 +241,6 @@ export default class extends Controller { tab.appendChild(content); const classesTab = content.querySelector('#classes'); - const instancesTab = content.querySelector('#instances'); for (let domain of domains) { const heading = document.createElement('span'); @@ -266,17 +266,20 @@ export default class extends Controller { classesTab.appendChild(domainList); } + const instancesTab = content.querySelector('#instances'); + const navList = instancesTab.querySelector('ul'); const sortedItLabels = ontology.getInstanceLabels().map(l => l.it).sort(); for (let label of sortedItLabels) { - const instanceItem = document.createElement('div'); - instanceItem.className = 'border-bottom ps-3 py-2 c-hand'; - instanceItem.textContent = label; - instanceItem.setAttribute('data-controller', 'node'); - instanceItem.setAttribute('data-node-id-value', label); - instanceItem.setAttribute('data-action', 'click->node#transition'); + const instanceItem = document.createElement('li'); + instanceItem.className = 'nav-item border-bottom ps-3 py-2 c-hand'; + instanceItem.innerHTML = html` + ${label} + `; + instanceItem.setAttribute('data-node-id-param', label); + instanceItem.setAttribute('data-action', 'click->node#open'); - instancesTab.appendChild(instanceItem); + navList.appendChild(instanceItem); } } @@ -299,7 +302,9 @@ export default class extends Controller { const content = html`
    -
    +
    + +
    `; diff --git a/src/controllers/node_controller.js b/src/controllers/node_controller.js index f5b8517..161c4b7 100644 --- a/src/controllers/node_controller.js +++ b/src/controllers/node_controller.js @@ -1,13 +1,16 @@ // Global ATON import { Controller } from "@hotwired/stimulus" import AppState from "../state.js"; +import { createSemanticNode } from "../scene.js"; +import { Ontology } from "../ontology.js"; +const html = String.raw; /** * Handle events for the clipper toolbar, * related to the clipping module */ export default class extends Controller { - static targets = ['instance', 'node']; + static targets = ['instance', 'node', 'panel']; static values = { id: String, }; @@ -17,13 +20,75 @@ export default class extends Controller { } /** - * Transition to this ATON node (request POV) + * Transition to ATON node (request POV) + * if instance is architectural and + * open the instance panel */ - transition() { - const node = ATON.getSceneNode(this.idValue); + open({ params: {id} }) { + const node = ATON.getSceneNode(id); + const normNode = AppState.normalizedNodes.find(n => n.id === id); if (node) ATON.Nav.requestPOVbyNode(node); + if (normNode) this.addSemanticNode(normNode); + + const ontology = new Ontology; + ontology.data = AppState.ontology; + + const instance = ontology.getInstanceByLabel(id, 'it'); + if (instance) this.openInstancePanel(instance); } -} + /** + * Attaches a semantic node to + * an existing scene node using + * its 3D model for the semantic shape + * @param {import("../state.js").NormalizedSceneNode} normNode + */ + addSemanticNode(normNode) { + if (!AppState.semanticNodes.get(normNode.label)) { + createSemanticNode(normNode.model, normNode.label); + AppState.semanticNodes.set(normNode.label, normNode.content); + } + } + /** + * Populates an instance panel based on the + * instance data and opens it + * @param {Object} instance + */ + openInstancePanel(instance) { + const properties = instance.literalProperties; + // Populate left side properties column + /** + * @type {HTMLDivElement} + */ + const panel = this.panelTarget; + const list = panel.querySelector('#properties'); + list.innerHTML = ''; + + panel.querySelector('h1').textContent = instance.label.it; + + for (const prop of properties) { + // Include only DC properties (OK?) + const schema = prop.property.split(':')[0]; + if (schema === 'dcterms' && Object.keys(prop.propertyLabel).length !== 0) { + const item = document.createElement('li'); + item.className = 'py-2'; + + item.innerHTML = html` + ${prop.propertyLabel.it ?? prop.propertyLabel.en} +
    + ${prop.value.value} + `; + + list.appendChild(item); + } + } + + panel.classList.remove('d-none'); + } + + closeInstancePanel() { + + } +} diff --git a/src/ontology.js b/src/ontology.js index 6afe7c4..db2b9cf 100644 --- a/src/ontology.js +++ b/src/ontology.js @@ -19,6 +19,31 @@ export class Ontology { return this.#data.instancesById[id]; } + /** + * @todo Revise loop approach... + * @param {String} label + * @param {String} lang The language identifier, either 'en' or 'it' + * @returns {Object} The instance object as per onto JSON... (document it!!) + */ + getInstanceByLabel(label, lang) { + if (!['en','it'].includes(lang)) { + throw new Error(`Invalid language string provided: '${lang}'`); + } + + let instance = {}; + + for (const key of Object.keys(this.#data.instancesById)) { + const currentInstance = this.#data.instancesById[key]; + const currentLabel = currentInstance.label[lang]; + if (currentLabel === label) { + instance = currentInstance; + break; + } + } + + return instance; + } + /** * @returns {Array<{en: string, it: string}>} The bloody array of label objects */ diff --git a/src/scene.js b/src/scene.js index 44052cc..c906b39 100644 --- a/src/scene.js +++ b/src/scene.js @@ -107,12 +107,6 @@ function loadNodes(nodes) { AppState.clipping.boundingSphere = node.getBound(); } - if (n.isSemantic) { - createSemanticNode(n.model, n.label); - AppState.semanticNodes.set(n.label, n.content); - //ATON.getSemanticRoot().attach(semNode); - } - AppState.nodes.push({ id: n.label, active: n.isInvisible ? false: true, @@ -130,14 +124,19 @@ function loadNodes(nodes) { * @param {string} id The original scene node ID (3D object) * @returns {ATON.SceneNode} */ -function createSemanticNode(model, id) { +export function createSemanticNode(model, id) { // Default/highlight materials for semantic node let matSemDef = new THREE.MeshStandardMaterial({ - color: '#f7e6af', + color: '#81eb81', transparent: true, - opacity: 0.2, + opacity: 0.4, }); - let matSemHL = ATON.MatHub.materials.semanticShapeHL; + let matSemHL = new THREE.MeshStandardMaterial({ + color: '#e9757b', + transparent: true, + opacity: 0.5, + }); + const semNode = ATON.createSemanticNode(id) .setCloneOnLoadHit(false) diff --git a/src/state.js b/src/state.js index 973615c..4f55810 100644 --- a/src/state.js +++ b/src/state.js @@ -23,6 +23,10 @@ let AppState = { * @type {NormalizedSceneNode[]} normalizedNodes */ normalizedNodes: [], + /** + * The loaded ontology object + */ + ontology: {}, treeNodes: {}, semanticNodes: new Map, mainNodeId: null, diff --git a/src/utils/nodeUtils.js b/src/utils/nodeUtils.js index 46b24cc..e3adc6e 100644 --- a/src/utils/nodeUtils.js +++ b/src/utils/nodeUtils.js @@ -20,6 +20,7 @@ * @property {Boolean} isMain * @property {Number|null} opacity * @property {Boolean} active + * @property {String} content */ /**