WebVOWL_work

Redesign right panel with Ontology and Selected Node sections Replace

6/9/2026 8:55:37 AM

Changes

src/app/js/sidebar.js 389(+111 -278)

src/index.html 59(+6 -53)

Details

diff --git a/src/app/css/toolstyle.css b/src/app/css/toolstyle.css
index 9caec37..2bddc81 100644
--- a/src/app/css/toolstyle.css
+++ b/src/app/css/toolstyle.css
@@ -965,15 +965,67 @@ main {
     width: auto;
     box-sizing: border-box;
     height: 100%;
+    overflow-y: auto;
+    padding: 8px;
 }
 
-#generalDetails span #about {
-    border-bottom: solid 1px #34495e;
-    display: block;
-    padding: 10px;
-    text-align: center;
-    word-wrap: break-word;
+.panel-language {
+    padding: 6px 0 10px;
+    color: #ecf0f1;
+    font-size: 0.85em;
+}
+
+.panel-section-title {
+    color: #aac;
+    font-size: 0.8em;
+    font-weight: bold;
+    text-transform: uppercase;
+    letter-spacing: 0.08em;
+    margin: 12px 0 4px;
+    padding-bottom: 4px;
+    border-bottom: 1px solid #34495e;
+}
+
+.annotation-panel {
+    margin-bottom: 8px;
+}
+
+.annotation-row {
+    display: flex;
+    font-size: 0.82em;
+    line-height: 1.4;
+    padding: 2px 0;
+    border-bottom: 1px solid #1e2a35;
+    word-break: break-word;
+}
+
+.annotation-name {
+    flex: 0 0 38%;
+    color: #8ab;
+    padding-right: 6px;
+    font-weight: 600;
+}
+
+.annotation-value {
+    flex: 1;
+    color: #ecf0f1;
+    font-weight: 100;
+}
+
+.annotation-value a {
     color: #69c;
+    text-decoration: none;
+}
+
+.annotation-value a:hover {
+    text-decoration: underline;
+}
+
+.no-selection-hint {
+    color: #8ab;
+    font-size: 0.82em;
+    font-style: italic;
+    padding: 4px 0;
 }
 
 #generalDetails h4 {

src/app/js/sidebar.js 389(+111 -278)

diff --git a/src/app/js/sidebar.js b/src/app/js/sidebar.js
index 1265ea5..e36a681 100644
--- a/src/app/js/sidebar.js
+++ b/src/app/js/sidebar.js
@@ -58,35 +58,8 @@ module.exports = function ( graph ){
   }
   
   sidebar.clearOntologyInformation = function (){
-    
-    d3.select("#title").text("No title available");
-    d3.select("#about").attr("href", "#").attr("target", "_blank").text("not given");
-    d3.select("#version").text("--");
-    d3.select("#authors").text("--");
-    d3.select("#description").text("No description available.");
-    var container = d3.select("#ontology-metadata");
-    container.selectAll("*").remove();
-    d3.select("#classCount")
-      .text("0");
-    d3.select("#objectPropertyCount")
-      .text("0");
-    d3.select("#datatypePropertyCount")
-      .text("0");
-    d3.select("#individualCount")
-      .text("0");
-    d3.select("#nodeCount")
-      .text("0");
-    d3.select("#edgeCount")
-      .text("0");
-    
-    // clear selectedNode info
-    var isTriggerActive = d3.select("#selection-details-trigger").classed("accordion-trigger-active");
-    if ( isTriggerActive ) {
-      // close accordion
-      d3.select("#selection-details-trigger").node().click();
-    }
-    showSelectionAdvice();
-    
+    d3.select("#ontology-panel").selectAll("*").remove();
+    clearSelectedNodePanel();
   };
   
   /**
@@ -97,14 +70,35 @@ module.exports = function ( graph ){
   sidebar.updateOntologyInformation = function ( data, statistics ){
     data = data || {};
     ontologyInfo = data.header || {};
-    
-    updateGraphInformation();
-    displayGraphStatistics(undefined, statistics);
-    displayMetadata(ontologyInfo.other);
-    
-    // Reset the sidebar selection
+
+    var panel = d3.select("#ontology-panel");
+    panel.selectAll("*").remove();
+
+    renderPair(panel, "IRI", ontologyInfo.iri, ontologyInfo.iri);
+    var title = languageTools.textInLanguage(ontologyInfo.title, graph.language());
+    renderPair(panel, "Title", title);
+    renderPair(panel, "Version", ontologyInfo.version);
+    var authors = ontologyInfo.author;
+    if ( authors instanceof Array ) authors = authors.join(", ");
+    renderPair(panel, "Author", authors);
+    var description = languageTools.textInLanguage(ontologyInfo.description, graph.language());
+    renderPair(panel, "Description", description);
+
+    var other = ontologyInfo.other || {};
+    for ( var key in other ) {
+      if ( other.hasOwnProperty(key) ) {
+        var ann = other[key][0];
+        if ( ann ) {
+          renderPair(panel, ann.identifier, ann.value, ann.type === "iri" ? ann.value : undefined);
+        }
+      }
+    }
+
+    if ( panel.selectAll(".annotation-row").size() === 0 ) {
+      panel.append("p").classed("no-selection-hint", true).text("No ontology information available.");
+    }
+
     sidebar.updateSelectionInformation(undefined);
-    
     setLanguages(ontologyInfo.languages);
   };
   
@@ -162,76 +156,18 @@ module.exports = function ( graph ){
     return false;
   }
   
-  function updateGraphInformation(){
-    var title = languageTools.textInLanguage(ontologyInfo.title, graph.language());
-    d3.select("#title").text(title || "No title available");
-    d3.select("#about").attr("href", ontologyInfo.iri).attr("target", "_blank").text(ontologyInfo.iri);
-    d3.select("#version").text(ontologyInfo.version || "--");
-    var authors = ontologyInfo.author;
-    if ( typeof authors === "string" ) {
-      // Stay compatible with author info as strings after change in january 2015
-      d3.select("#authors").text(authors);
-    } else if ( authors instanceof Array ) {
-      d3.select("#authors").text(authors.join(", "));
-    } else {
-      d3.select("#authors").text("--");
-    }
-    
-    var description = languageTools.textInLanguage(ontologyInfo.description, graph.language());
-    d3.select("#description").text(description || "No description available.");
+  function renderPair( container, name, value, iri ){
+    if ( !value && value !== 0 ) return;
+    var row = container.append("div").classed("annotation-row", true);
+    row.append("span").classed("annotation-name", true).text(name);
+    var valSpan = row.append("span").classed("annotation-value", true);
+    appendIriLabel(valSpan, value, iri);
   }
-  
-  function displayGraphStatistics( deliveredMetrics, statistics ){
-    // Metrics are optional and may be undefined
-    deliveredMetrics = deliveredMetrics || {};
-    
-    d3.select("#classCount")
-      .text(deliveredMetrics.classCount || statistics.classCount());
-    d3.select("#objectPropertyCount")
-      .text(deliveredMetrics.objectPropertyCount || statistics.objectPropertyCount());
-    d3.select("#datatypePropertyCount")
-      .text(deliveredMetrics.datatypePropertyCount || statistics.datatypePropertyCount());
-    d3.select("#individualCount")
-      .text(deliveredMetrics.totalIndividualCount || statistics.totalIndividualCount());
-    d3.select("#nodeCount")
-      .text(statistics.nodeCount());
-    d3.select("#edgeCount")
-      .text(statistics.edgeCount());
-  }
-  
-  function displayMetadata( metadata ){
-    var container = d3.select("#ontology-metadata");
-    container.selectAll("*").remove();
-    
-    listAnnotations(container, metadata);
-    
-    if ( container.selectAll(".annotation").size() <= 0 ) {
-      container.append("p").text("No annotations available.");
-    }
-  }
-  
-  function listAnnotations( container, annotationObject ){
-    annotationObject = annotationObject || {};  //todo
-    
-    // Collect the annotations in an array for simpler processing
-    var annotations = [];
-    for ( var annotation in annotationObject ) {
-      if ( annotationObject.hasOwnProperty(annotation) ) {
-        annotations.push(annotationObject[annotation][0]);
-      }
-    }
-    
-    container.selectAll(".annotation").remove();
-    container.selectAll(".annotation").data(annotations).enter().append("p")
-      .classed("annotation", true)
-      .classed("statisticDetails", true)
-      .text(function ( d ){
-        return d.identifier + ":";
-      })
-      .append("span")
-      .each(function ( d ){
-        appendIriLabel(d3.select(this), d.value, d.type === "iri" ? d.value : undefined);
-      });
+
+  function clearSelectedNodePanel(){
+    var panel = d3.select("#selected-node-panel");
+    panel.selectAll("*").remove();
+    panel.append("p").classed("no-selection-hint", true).text("Select an element in the visualization.");
   }
   
   /**
@@ -240,106 +176,78 @@ module.exports = function ( graph ){
    */
   sidebar.updateSelectionInformation = function ( selectedElement ){
     lastSelectedElement = selectedElement;
-    
-    // Click event was prevented when dragging
+
     if ( d3.event && d3.event.defaultPrevented ) {
       return;
     }
-    
-    var isTriggerActive = d3.select("#selection-details-trigger").classed("accordion-trigger-active");
-    if ( selectedElement && !isTriggerActive ) {
-      d3.select("#selection-details-trigger").node().click();
-    } else if ( !selectedElement && isTriggerActive ) {
-      showSelectionAdvice();
+
+    if ( !selectedElement ) {
+      clearSelectedNodePanel();
       return;
     }
-    
+
     if ( elementTools.isProperty(selectedElement) ) {
       displayPropertyInformation(selectedElement);
     } else if ( elementTools.isNode(selectedElement) ) {
       displayNodeInformation(selectedElement);
     }
   };
-  
-  function showSelectionAdvice(){
-    setSelectionInformationVisibility(false, false, true);
-  }
-  
-  function setSelectionInformationVisibility( showClasses, showProperties, showAdvice ){
-    d3.select("#classSelectionInformation").classed("hidden", !showClasses);
-    d3.select("#propertySelectionInformation").classed("hidden", !showProperties);
-    d3.select("#noSelectionInformation").classed("hidden", !showAdvice);
-  }
-  
+
   function displayPropertyInformation( property ){
-    showPropertyInformations();
-    
-    setIriLabel(d3.select("#propname"), property.labelForCurrentLanguage(), property.iri());
-    d3.select("#typeProp").text(property.type());
-    
-    if ( property.inverse() !== undefined ) {
-      d3.select("#inverse").classed("hidden", false);
-      setIriLabel(d3.select("#inverse span"), property.inverse().labelForCurrentLanguage(), property.inverse().iri());
-    } else {
-      d3.select("#inverse").classed("hidden", true);
-    }
-    
-    var equivalentIriSpan = d3.select("#propEquivUri");
-    listNodeArray(equivalentIriSpan, property.equivalents());
-    
-    listNodeArray(d3.select("#subproperties"), property.subproperties());
-    listNodeArray(d3.select("#superproperties"), property.superproperties());
-    
+    var panel = d3.select("#selected-node-panel");
+    panel.selectAll("*").remove();
+
+    renderPair(panel, "IRI", property.iri(), property.iri());
+    renderPair(panel, "Label", property.labelForCurrentLanguage());
+    renderPair(panel, "Type", property.type());
+
+    if ( property.domain() ) renderPair(panel, "Domain", property.domain().labelForCurrentLanguage(), property.domain().iri());
+    if ( property.range() )  renderPair(panel, "Range",  property.range().labelForCurrentLanguage(),  property.range().iri());
+    if ( property.inverse() ) renderPair(panel, "Inverse", property.inverse().labelForCurrentLanguage(), property.inverse().iri());
+
+    renderNodeArrayPairs(panel, "Equivalent", property.equivalents());
+    renderNodeArrayPairs(panel, "Subproperty", property.subproperties());
+    renderNodeArrayPairs(panel, "Superproperty", property.superproperties());
+
     if ( property.minCardinality() !== undefined ) {
-      d3.select("#infoCardinality").classed("hidden", true);
-      d3.select("#minCardinality").classed("hidden", false);
-      d3.select("#minCardinality span").text(property.minCardinality());
-      d3.select("#maxCardinality").classed("hidden", false);
-      
-      if ( property.maxCardinality() !== undefined ) {
-        d3.select("#maxCardinality span").text(property.maxCardinality());
-      } else {
-        d3.select("#maxCardinality span").text("*");
-      }
-      
+      renderPair(panel, "Min. cardinality", property.minCardinality());
+      renderPair(panel, "Max. cardinality", property.maxCardinality() !== undefined ? property.maxCardinality() : "*");
     } else if ( property.cardinality() !== undefined ) {
-      d3.select("#minCardinality").classed("hidden", true);
-      d3.select("#maxCardinality").classed("hidden", true);
-      d3.select("#infoCardinality").classed("hidden", false);
-      d3.select("#infoCardinality span").text(property.cardinality());
-    } else {
-      d3.select("#infoCardinality").classed("hidden", true);
-      d3.select("#minCardinality").classed("hidden", true);
-      d3.select("#maxCardinality").classed("hidden", true);
+      renderPair(panel, "Cardinality", property.cardinality());
     }
-    
-    setIriLabel(d3.select("#domain"), property.domain().labelForCurrentLanguage(), property.domain().iri());
-    setIriLabel(d3.select("#range"), property.range().labelForCurrentLanguage(), property.range().iri());
-    
-    displayAttributes(property.attributes(), d3.select("#propAttributes"));
-    
-    setTextAndVisibility(d3.select("#propDescription"), property.descriptionForCurrentLanguage());
-    setTextAndVisibility(d3.select("#propComment"), property.commentForCurrentLanguage());
-    
-    listAnnotations(d3.select("#propertySelectionInformation"), property.annotations());
+
+    var attrs = getAttributes(property.attributes());
+    if ( attrs ) renderPair(panel, "Characteristics", attrs);
+
+    renderPair(panel, "Description", property.descriptionForCurrentLanguage());
+    renderPair(panel, "Comment", property.commentForCurrentLanguage());
+
+    renderAnnotationPairs(panel, property.annotations());
   }
   
-  function showPropertyInformations(){
-    setSelectionInformationVisibility(false, true, false);
+  function getAttributes( attributes ){
+    if ( !attributes || attributes.length === 0 ) return null;
+    var filtered = attributes.filter(function ( a ){ return a !== "object" && a !== "datatype" && a !== "rdf"; });
+    return filtered.length > 0 ? filtered.join(", ") : null;
   }
-  
-  function setIriLabel( element, name, iri ){
-    var parent = d3.select(element.node().parentNode);
-    
-    if ( name ) {
-      element.selectAll("*").remove();
-      appendIriLabel(element, name, iri);
-      parent.classed("hidden", false);
-    } else {
-      parent.classed("hidden", true);
+
+  function renderNodeArrayPairs( panel, label, nodes ){
+    if ( !nodes || nodes.length === 0 ) return;
+    nodes.forEach(function ( el ){
+      renderPair(panel, label, el.labelForCurrentLanguage(), el.iri());
+    });
+  }
+
+  function renderAnnotationPairs( panel, annotationObject ){
+    annotationObject = annotationObject || {};
+    for ( var key in annotationObject ) {
+      if ( annotationObject.hasOwnProperty(key) ) {
+        var ann = annotationObject[key][0];
+        if ( ann ) renderPair(panel, ann.identifier, ann.value, ann.type === "iri" ? ann.value : undefined);
+      }
     }
   }
-  
+
   function appendIriLabel( element, name, iri ){
     var tag;
     
@@ -354,100 +262,25 @@ module.exports = function ( graph ){
     tag.text(name);
   }
   
-  function displayAttributes( attributes, textSpan ){
-    var spanParent = d3.select(textSpan.node().parentNode);
-    
-    if ( attributes && attributes.length > 0 ) {
-      // Remove redundant redundant attributes for sidebar
-      removeElementFromArray("object", attributes);
-      removeElementFromArray("datatype", attributes);
-      removeElementFromArray("rdf", attributes);
-    }
-    
-    if ( attributes && attributes.length > 0 ) {
-      textSpan.text(attributes.join(", "));
-      
-      spanParent.classed("hidden", false);
-    } else {
-      spanParent.classed("hidden", true);
-    }
-  }
-  
-  function removeElementFromArray( element, array ){
-    var index = array.indexOf(element);
-    if ( index > -1 ) {
-      array.splice(index, 1);
-    }
-  }
-  
   function displayNodeInformation( node ){
-    showClassInformations();
-    
-    setIriLabel(d3.select("#name"), node.labelForCurrentLanguage(), node.iri());
-    
-    /* Equivalent stuff. */
-    var equivalentIriSpan = d3.select("#classEquivUri");
-    listNodeArray(equivalentIriSpan, node.equivalents());
-    
-    d3.select("#typeNode").text(node.type());
-    listNodeArray(d3.select("#individuals"), node.individuals());
-    
-    /* Disjoint stuff. */
-    var disjointNodes = d3.select("#disjointNodes");
-    var disjointNodesParent = d3.select(disjointNodes.node().parentNode);
-    
-    if ( node.disjointWith() !== undefined ) {
-      disjointNodes.selectAll("*").remove();
-      
-      node.disjointWith().forEach(function ( element, index ){
-        if ( index > 0 ) {
-          disjointNodes.append("span").text(", ");
-        }
-        appendIriLabel(disjointNodes, element.labelForCurrentLanguage(), element.iri());
-      });
-      
-      disjointNodesParent.classed("hidden", false);
-    } else {
-      disjointNodesParent.classed("hidden", true);
-    }
-    
-    displayAttributes(node.attributes(), d3.select("#classAttributes"));
-    
-    setTextAndVisibility(d3.select("#nodeDescription"), node.descriptionForCurrentLanguage());
-    setTextAndVisibility(d3.select("#nodeComment"), node.commentForCurrentLanguage());
-    
-    listAnnotations(d3.select("#classSelectionInformation"), node.annotations());
-  }
-  
-  function showClassInformations(){
-    setSelectionInformationVisibility(true, false, false);
-  }
-  
-  function listNodeArray( textSpan, nodes ){
-    var spanParent = d3.select(textSpan.node().parentNode);
-    
-    if ( nodes && nodes.length ) {
-      textSpan.selectAll("*").remove();
-      nodes.forEach(function ( element, index ){
-        if ( index > 0 ) {
-          textSpan.append("span").text(", ");
-        }
-        appendIriLabel(textSpan, element.labelForCurrentLanguage(), element.iri());
-      });
-      
-      spanParent.classed("hidden", false);
-    } else {
-      spanParent.classed("hidden", true);
-    }
-  }
-  
-  function setTextAndVisibility( label, value ){
-    var parentNode = d3.select(label.node().parentNode);
-    var hasValue = !!value;
-    if ( value ) {
-      label.text(value);
-    }
-    parentNode.classed("hidden", !hasValue);
+    var panel = d3.select("#selected-node-panel");
+    panel.selectAll("*").remove();
+
+    renderPair(panel, "IRI", node.iri(), node.iri());
+    renderPair(panel, "Label", node.labelForCurrentLanguage());
+    renderPair(panel, "Type", node.type());
+
+    renderNodeArrayPairs(panel, "Equivalent", node.equivalents());
+    renderNodeArrayPairs(panel, "Disjoint with", node.disjointWith());
+    renderNodeArrayPairs(panel, "Individual", node.individuals());
+
+    var attrs = getAttributes(node.attributes());
+    if ( attrs ) renderPair(panel, "Characteristics", attrs);
+
+    renderPair(panel, "Description", node.descriptionForCurrentLanguage());
+    renderPair(panel, "Comment", node.commentForCurrentLanguage());
+
+    renderAnnotationPairs(panel, node.annotations());
   }
   
   /** Collapsible Sidebar functions; **/

src/index.html 59(+6 -53)

diff --git a/src/index.html b/src/index.html
index 20f2ee8..6167b33 100644
--- a/src/index.html
+++ b/src/index.html
@@ -444,61 +444,14 @@
 
         </section>
         <section id="generalDetails" class="hidden">
-            <h1 id="title"></h1>
-            <span><a id="about" href=""></a></span>
-            <h5>Version: <span id="version"></span></h5>
-            <h5>Author(s): <span id="authors"></span></h5>
-            <h5>
+            <div class="panel-language">
                 <label>Language: <select id="language" name="language" size="1"></select></label>
-            </h5>
-            <h3 class="accordion-trigger noselect accordion-trigger-active">Description</h3>
-            <div class="accordion-container scrollable">
-                <p id="description"></p>
             </div>
-            <h3 class="accordion-trigger noselect">Metadata</h3>
-            <div id="ontology-metadata" class="accordion-container"></div>
-            <h3 class="accordion-trigger noselect">Statistics</h3>
-            <div class="accordion-container">
-                <p class="statisticDetails">Classes: <span id="classCount"></span></p>
-                <p class="statisticDetails">Object prop.: <span id="objectPropertyCount"></span></p>
-                <p class="statisticDetails">Datatype prop.: <span id="datatypePropertyCount"></span></p>
-                <div class="small-whitespace-separator"></div>
-                <p class="statisticDetails">Individuals: <span id="individualCount"></span></p>
-                <div class="small-whitespace-separator"></div>
-                <p class="statisticDetails">Nodes: <span id="nodeCount"></span></p>
-                <p class="statisticDetails">Edges: <span id="edgeCount"></span></p>
-            </div>
-            <h3 class="accordion-trigger noselect" id="selection-details-trigger">Selection Details</h3>
-            <div class="accordion-container" id="selection-details">
-                <div id="classSelectionInformation" class="hidden">
-                    <p class="propDetails">Name: <span id="name"></span></p>
-                    <p class="propDetails">Type: <span id="typeNode"></span></p>
-                    <p class="propDetails">Equiv.: <span id="classEquivUri"></span></p>
-                    <p class="propDetails">Disjoint: <span id="disjointNodes"></span></p>
-                    <p class="propDetails">Charac.: <span id="classAttributes"></span></p>
-                    <p class="propDetails">Individuals: <span id="individuals"></span></p>
-                    <p class="propDetails">Description: <span id="nodeDescription"></span></p>
-                    <p class="propDetails">Comment: <span id="nodeComment"></span></p>
-                </div>
-                <div id="propertySelectionInformation" class="hidden">
-                    <p class="propDetails">Name: <span id="propname"></span></p>
-                    <p class="propDetails">Type: <span id="typeProp"></span></p>
-                    <p id="inverse" class="propDetails">Inverse: <span></span></p>
-                    <p class="propDetails">Domain: <span id="domain"></span></p>
-                    <p class="propDetails">Range: <span id="range"></span></p>
-                    <p class="propDetails">Subprop.: <span id="subproperties"></span></p>
-                    <p class="propDetails">Superprop.: <span id="superproperties"></span></p>
-                    <p class="propDetails">Equiv.: <span id="propEquivUri"></span></p>
-                    <p id="infoCardinality" class="propDetails">Cardinality: <span></span></p>
-                    <p id="minCardinality" class="propDetails">Min. cardinality: <span></span></p>
-                    <p id="maxCardinality" class="propDetails">Max. cardinality: <span></span></p>
-                    <p class="propDetails">Charac.: <span id="propAttributes"></span></p>
-                    <p class="propDetails">Description: <span id="propDescription"></span></p>
-                    <p class="propDetails">Comment: <span id="propComment"></span></p>
-                </div>
-                <div id="noSelectionInformation">
-                    <p><span>Select an element in the visualization.</span></p>
-                </div>
+            <h3 class="panel-section-title">Ontology</h3>
+            <div id="ontology-panel" class="annotation-panel"></div>
+            <h3 class="panel-section-title">Selected Node</h3>
+            <div id="selected-node-panel" class="annotation-panel">
+                <p class="no-selection-hint">Select an element in the visualization.</p>
             </div>
         </section>
     </aside>