comparison src/graph_view.ts @ 8:6fefd287aff9

closer- element now holds a changing graph, but can't draw it yet
author drewp@bigasterisk.com
date Thu, 05 Dec 2019 01:32:13 -0800
parents
children 26d3e4860adc
comparison
equal deleted inserted replaced
7:daf08d794660 8:6fefd287aff9
1 // from /my/site/homepage/www/rdf/browse/graphView.js
2
3 import { html } from 'lit-html';
4 import { SuffixLabels } from './suffixLabels.js';
5 import { Store, Quad, DataFactory } from "n3"
6 const { namedNode, literal, quad } = DataFactory;
7
8 const groupByRdfType = (graph: Store) => {
9 const env = graph.store.rdf;
10 const rdfType = env.createNamedNode('rdf:type');
11 const byType = new Map(); // type : subjs
12 const untyped = new Set(); // subjs
13 graph.quadStore.quads({}, (q) => {
14 let subjType = null;
15 graph.quadStore.quads({
16 subject: q.subject,
17 predicate: rdfType
18 },
19 (q2) => { subjType = q2.object; });
20 if (subjType) {
21 subjType = subjType.toString();
22 if (!byType.has(subjType)) {
23 byType.set(subjType, new Set());
24 }
25 byType.get(subjType).add(q.subject.toString());
26 } else {
27 untyped.add(q.subject.toString());
28 }
29
30 });
31 return { byType: byType, untyped: untyped };
32 };
33
34 const graphView = (graph: Store) => {
35 const env = graph.store.rdf;
36
37 const labels = new SuffixLabels();
38 graph.quadStore.quads({}, (q) => {
39 if (q.subject.interfaceName == "NamedNode") { labels.planDisplayForNode(q.subject); }
40 if (q.predicate.interfaceName == "NamedNode") { labels.planDisplayForNode(q.predicate); }
41 if (q.object.interfaceName == "NamedNode") { labels.planDisplayForNode(q.object); }
42 if (q.object.interfaceName == "Literal" && q.object.datatype) { labels.planDisplayForNode(env.createNamedNode(q.object.datatype)); }
43 });
44
45 const rdfNode = (n) => {
46 if (n.interfaceName == "Literal") {
47 let dtPart: any = "";
48 if (n.datatype) {
49 dtPart = html`
50 ^^<span class="literalType">
51 ${rdfNode(env.createNamedNode(n.datatype))}
52 </span>`;
53 }
54 return html`<span class="literal">${n.nominalValue}${dtPart}</span>`;
55 }
56 if (n.interfaceName == "NamedNode") {
57 let dn = labels.getLabelForNode(n);
58 if (dn.match(/XMLSchema#.*/)) { dn = dn.replace('XMLSchema#', 'xsd:'); }
59 if (dn.match(/rdf-schema#.*/)) { dn = dn.replace('rdf-schema#', 'rdfs:'); }
60 return html`<a class="graphUri" href="${n.toString()}">${dn}</a>`;
61 }
62
63 return html`[${n.interfaceName} ${n.toNT()}]`;
64 }
65
66 const objBlock = (obj) => {
67 return html`
68 <div class="object">
69 ${rdfNode(obj)} <!-- indicate what source or graph said this stmt -->
70 </div>
71 `;
72 };
73
74 /// bunch of table rows
75 const predBlock = (subj, pred) => {
76 const objsSet = new Set();
77 graph.quadStore.quads({ subject: subj, predicate: pred }, (q) => {
78
79 if (q.object.length) {
80 console.log(q.object)
81 }
82 objsSet.add(q.object);
83 });
84 const objs = Array.from(objsSet.values());
85 objs.sort();
86 return html`
87 <div class="predicate">${rdfNode(pred)}
88 <div>
89 ${objs.map(objBlock)}
90 </div>
91 </div>
92 `;
93 };
94
95 const { byType, untyped } = groupByRdfType(graph);
96 const typedSubjs = Array.from(byType.keys());
97 typedSubjs.sort();
98
99 const untypedSubjs = Array.from(untyped.values());
100 untypedSubjs.sort();
101
102 const subjBlock = (subj) => {
103 const subjNode = env.createNamedNode(subj);
104 const predsSet = new Set();
105 graph.quadStore.quads({ subject: subjNode }, (q) => {
106 predsSet.add(q.predicate);
107 });
108 const preds = Array.from(predsSet.values());
109 preds.sort();
110 return html`
111 <div class="subject">${rdfNode(subjNode)}
112 <!-- todo: special section for uri/type-and-icon/label/comment -->
113 <div>
114 ${preds.map((p) => { return predBlock(subjNode, p); })}
115 </div>
116 </div>
117 `;
118 };
119 const byTypeBlock = (typeUri) => {
120 const subjs = Array.from(byType.get(typeUri));
121 subjs.sort();
122
123 const graphCells = new Map(); // [subj, pred] : objs
124 const preds = new Set();
125
126 subjs.forEach((subj) => {
127 graph.quadStore.quads({ subject: env.createNamedNode(subj) }, (q) => {
128 preds.add(q.predicate.toString());
129 const cellKey = subj + '|||' + q.predicate.toString();
130 if (!graphCells.has(cellKey)) {
131 graphCells.set(cellKey, new Set());
132 }
133 graphCells.get(cellKey).add(q.object);
134 });
135 });
136 const predsList = Array.from(preds);
137 predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1);
138 // also pull out label, which should be used on 1st column
139 predsList.sort();
140
141 const thead = () => {
142 const predColumnHead = (pred) => {
143 return html`<th>${rdfNode(env.createNamedNode(pred))}</th>`;
144 };
145 return html`
146 <thead>
147 <tr>
148 <th></th>
149 ${predsList.map(predColumnHead)}
150 </tr>
151 </thead>`;
152 };
153
154 const instanceRow = (subj) => {
155 const cell = (pred) => {
156 const objs = graphCells.get(subj + '|||' + pred);
157 if (!objs) {
158 return html`<td></td>`;
159 }
160 const objsList = Array.from(objs);
161 objsList.sort();
162 const draw = (obj) => {
163 return html`<div>${rdfNode(obj)}</div>`
164 };
165 return html`<td>${objsList.map(draw)}</td>`;
166 };
167
168 return html`
169 <tr>
170 <td>${rdfNode(env.createNamedNode(subj))}</td>
171 ${predsList.map(cell)}
172 </tr>
173 `;
174 };
175
176 return html`
177 <div>[icon] ${rdfNode(env.createNamedNode(typeUri))} resources</div>
178 <div class="typeBlockScroll">
179 <table class="typeBlock">
180 ${thead()}
181 ${subjs.map(instanceRow)}
182 </table>
183 </div>
184 `;
185 };
186
187 return html`
188 <link rel="stylesheet" href="/rdf/browse/style.css">
189
190 <section>
191 <h2>
192 Current graph (<a href="${graph.events.url}">${graph.events.url}</a>)
193 </h2>
194 <div>
195 <!-- todo: graphs and provenance.
196 These statements are all in the
197 <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
198 </div>
199 ${typedSubjs.map(byTypeBlock)}
200 <div class="spoGrid">
201 ${untypedSubjs.map(subjBlock)}
202 </div>
203 </section>
204 `;
205 }
206 export { graphView }