Mercurial > code > home > repos > streamed-graph
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 } |