diff src/graph_view.js @ 3:a7ba8627a7b6

still trying to make imports work. add other files too
author drewp@bigasterisk.com
date Wed, 04 Dec 2019 00:09:15 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/graph_view.js	Wed Dec 04 00:09:15 2019 -0800
@@ -0,0 +1,202 @@
+// from /my/site/homepage/www/rdf/browse/graphView.js
+
+
+import { SuffixLabels } from './suffixLabels.js';
+
+const groupByRdfType = (graph) => {
+    const env = graph.store.rdf;
+    const rdfType = env.createNamedNode('rdf:type');
+    const byType = new Map(); // type : subjs
+    const untyped = new Set(); // subjs
+    graph.quadStore.quads({}, (q) => {
+        let subjType = null;
+        graph.quadStore.quads({subject: q.subject,
+                               predicate: rdfType},
+                              (q2) => { subjType = q2.object; });
+        if (subjType){
+            subjType = subjType.toString();
+            if (!byType.has(subjType)) {
+                byType.set(subjType, new Set());
+            }
+            byType.get(subjType).add(q.subject.toString());
+        } else {
+            untyped.add(q.subject.toString());
+        }
+
+    });
+    return {byType: byType, untyped: untyped};
+};
+
+const graphView = (graph) => {
+    const env = graph.store.rdf;
+
+    const labels = new SuffixLabels();
+    graph.quadStore.quads({}, (q) => {
+        if (q.subject.interfaceName == "NamedNode") { labels.planDisplayForNode(q.subject); }
+        if (q.predicate.interfaceName == "NamedNode") { labels.planDisplayForNode(q.predicate); }
+        if (q.object.interfaceName == "NamedNode") { labels.planDisplayForNode(q.object); }
+        if (q.object.interfaceName == "Literal" && q.object.datatype) { labels.planDisplayForNode(env.createNamedNode(q.object.datatype)); }
+    });
+
+    const rdfNode = (n) => {
+        if (n.interfaceName == "Literal") {
+            let dtPart = "";
+            if (n.datatype) {
+                dtPart = html`
+        ^^<span class="literalType">
+          ${rdfNode(env.createNamedNode(n.datatype))}
+        </span>`;
+            }
+            return html`<span class="literal">${n.nominalValue}${dtPart}</span>`;
+        }
+        if (n.interfaceName == "NamedNode") {
+            let dn = labels.getLabelForNode(n);
+            if (dn.match(/XMLSchema#.*/)) { dn = dn.replace('XMLSchema#', 'xsd:'); }
+            if (dn.match(/rdf-schema#.*/)) { dn = dn.replace('rdf-schema#', 'rdfs:'); }
+            return html`<a class="graphUri" href="${n.toString()}">${dn}</a>`;
+        }
+
+        return html`[${n.interfaceName} ${n.toNT()}]`;
+    }
+
+    const objBlock = (obj) => {
+        return html`
+        <div class="object">
+          ${rdfNode(obj)} <!-- indicate what source or graph said this stmt -->
+        </div>
+    `;
+    };
+
+    /// bunch of table rows
+    const predBlock = (subj, pred) => {
+        const objsSet = new Set();
+        graph.quadStore.quads({ subject: subj, predicate: pred }, (q) => {
+
+            if (q.object.length) {
+                console.log(q.object)
+            }
+            objsSet.add(q.object);
+        });
+        const objs = Array.from(objsSet.values());
+        objs.sort();
+        return html`
+      <div class="predicate">${rdfNode(pred)}
+        <div>
+          ${objs.map(objBlock)}
+        </div>
+      </div>
+    `;
+    };
+
+    const {byType, untyped} = groupByRdfType(graph);
+    const typedSubjs = Array.from(byType.keys());
+    typedSubjs.sort();
+
+    const untypedSubjs = Array.from(untyped.values());
+    untypedSubjs.sort();
+
+    const subjBlock = (subj) => {
+        const subjNode = env.createNamedNode(subj);
+        const predsSet = new Set();
+        graph.quadStore.quads({ subject: subjNode }, (q) => {
+            predsSet.add(q.predicate);
+        });
+        const preds = Array.from(predsSet.values());
+        preds.sort();
+        return html`
+      <div class="subject">${rdfNode(subjNode)}
+        <!-- todo: special section for uri/type-and-icon/label/comment -->
+        <div>
+          ${preds.map((p) => { return predBlock(subjNode, p); })}
+        </div>
+      </div>
+    `;
+    };
+    const byTypeBlock = (typeUri) => {
+        const subjs = Array.from(byType.get(typeUri));
+        subjs.sort();
+
+        const graphCells = new Map(); // [subj, pred] : objs
+        const preds = new Set();
+
+        subjs.forEach((subj) => {
+            graph.quadStore.quads({subject: env.createNamedNode(subj)}, (q) => {
+                preds.add(q.predicate.toString());
+                const cellKey = subj + '|||' + q.predicate.toString();
+                if (!graphCells.has(cellKey)) {
+                    graphCells.set(cellKey, new Set());
+                }
+                graphCells.get(cellKey).add(q.object);
+            });
+        });
+        const predsList = Array.from(preds);
+        predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1);
+        // also pull out label, which should be used on 1st column
+        predsList.sort();
+
+        const thead = () => {
+            const predColumnHead = (pred) => {
+                return html`<th>${rdfNode(env.createNamedNode(pred))}</th>`;
+            };
+            return html`
+              <thead>
+                <tr>
+                  <th></th>
+                  ${predsList.map(predColumnHead)}
+                </tr>
+              </thead>`;
+        };
+
+        const instanceRow = (subj) => {
+            const cell = (pred) => {
+                const objs = graphCells.get(subj + '|||' + pred);
+                if (!objs) {
+                    return html`<td></td>`;
+                }
+                const objsList = Array.from(objs);
+                objsList.sort();
+                const draw = (obj) => {
+                    return html`<div>${rdfNode(obj)}</div>`
+                };
+                return html`<td>${objsList.map(draw)}</td>`;
+            };
+
+            return html`
+              <tr>
+                <td>${rdfNode(env.createNamedNode(subj))}</td>
+                ${predsList.map(cell)}
+              </tr>
+            `;
+        };
+
+        return html`
+          <div>[icon] ${rdfNode(env.createNamedNode(typeUri))} resources</div>
+<div class="typeBlockScroll">
+          <table class="typeBlock">
+            ${thead()}
+            ${subjs.map(instanceRow)}
+          </table>
+</div>
+        `;
+    };
+
+    return html`
+      <link rel="stylesheet" href="/rdf/browse/style.css">
+
+      <section>
+        <h2>
+          Current graph (<a href="${graph.events.url}">${graph.events.url}</a>)
+        </h2>
+        <div>
+         <!-- todo: graphs and provenance.
+          These statements are all in the
+          <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
+        </div>
+        ${typedSubjs.map(byTypeBlock)}
+        <div class="spoGrid">
+          ${untypedSubjs.map(subjBlock)}
+        </div>
+      </section>
+    `;
+}
+export { graphView }