comparison src/graph_view.ts @ 79:0c188ed3bcd8

starting lit upgrade. total mess right now
author drewp@bigasterisk.com
date Wed, 17 Nov 2021 13:01:08 -0800
parents 58676ebdce0f
children 067d66a45a51
comparison
equal deleted inserted replaced
78:ea9c9db282d6 79:0c188ed3bcd8
1 import { html, TemplateResult } from 'lit-html'; 1 // import { html, TemplateResult } from 'lit-html';
2 import { DataFactory, Literal, N3Store, NamedNode, Quad, Quad_Object, Term, Util } from 'n3'; 2 // import { DataFactory, Literal, N3Store, NamedNode, Quad, Quad_Object, Term, Util } from 'n3';
3 3
4 import { SuffixLabels } from './suffixLabels'; 4 // import { SuffixLabels } from './suffixLabels';
5 5
6 const { namedNode } = DataFactory; 6 // const { namedNode } = DataFactory;
7 7
8 // import ns from 'n3/src/IRIs'; 8 // // import ns from 'n3/src/IRIs';
9 // const { rdf } = ns; 9 // // const { rdf } = ns;
10 const rdf = { 10 // const rdf = {
11 type: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type") 11 // type: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
12 }; 12 // };
13 13
14 type TypeToSubjs = Map<NamedNode, Set<NamedNode>>; 14 // type TypeToSubjs = Map<NamedNode, Set<NamedNode>>;
15 // When there are multiple types, an arbitrary one is used. 15 // // When there are multiple types, an arbitrary one is used.
16 function groupByRdfType( 16 // function groupByRdfType(
17 graph: N3Store 17 // graph: N3Store
18 ): { byType: TypeToSubjs; untyped: Set<NamedNode> } { 18 // ): { byType: TypeToSubjs; untyped: Set<NamedNode> } {
19 const rdfType = rdf.type; 19 // const rdfType = rdf.type;
20 const byType: TypeToSubjs = new Map(); 20 // const byType: TypeToSubjs = new Map();
21 const untyped: Set<NamedNode> = new Set(); // subjs 21 // const untyped: Set<NamedNode> = new Set(); // subjs
22 const internSubjs = new Map<string, NamedNode>(); 22 // const internSubjs = new Map<string, NamedNode>();
23 graph.forEach( 23 // graph.forEach(
24 q => { 24 // q => {
25 if (!Util.isNamedNode(q.subject)) { 25 // if (!Util.isNamedNode(q.subject)) {
26 throw new Error("unsupported " + q.subject.value); 26 // throw new Error("unsupported " + q.subject.value);
27 } 27 // }
28 const subj = q.subject as NamedNode; 28 // const subj = q.subject as NamedNode;
29 29
30 let subjType: NamedNode | null = null; 30 // let subjType: NamedNode | null = null;
31 31
32 graph.forObjects( 32 // graph.forObjects(
33 (o: Quad_Object) => { 33 // (o: Quad_Object) => {
34 subjType = o as NamedNode; 34 // subjType = o as NamedNode;
35 }, 35 // },
36 subj, 36 // subj,
37 rdfType, 37 // rdfType,
38 null 38 // null
39 ); 39 // );
40 40
41 if (subjType !== null) { 41 // if (subjType !== null) {
42 // (subj, rdf:type, subjType) in graph 42 // // (subj, rdf:type, subjType) in graph
43 if (!byType.has(subjType)) { 43 // if (!byType.has(subjType)) {
44 byType.set(subjType, new Set()); 44 // byType.set(subjType, new Set());
45 } 45 // }
46 (byType.get(subjType) as Set<NamedNode>).add(subj); 46 // (byType.get(subjType) as Set<NamedNode>).add(subj);
47 } else { 47 // } else {
48 // no rdf:type stmt in graph 48 // // no rdf:type stmt in graph
49 if (!internSubjs.has(subj.value)) { 49 // if (!internSubjs.has(subj.value)) {
50 internSubjs.set(subj.value, subj); 50 // internSubjs.set(subj.value, subj);
51 } 51 // }
52 const intSubj: NamedNode = internSubjs.get( 52 // const intSubj: NamedNode = internSubjs.get(
53 subj.value as string 53 // subj.value as string
54 ) as NamedNode; 54 // ) as NamedNode;
55 untyped.add(intSubj); 55 // untyped.add(intSubj);
56 } 56 // }
57 }, 57 // },
58 null, 58 // null,
59 null, 59 // null,
60 null, 60 // null,
61 null 61 // null
62 ); 62 // );
63 return { byType: byType, untyped: untyped }; 63 // return { byType: byType, untyped: untyped };
64 } 64 // }
65 65
66 class NodeDisplay { 66 // class NodeDisplay {
67 labels: SuffixLabels; 67 // labels: SuffixLabels;
68 constructor(labels: SuffixLabels) { 68 // constructor(labels: SuffixLabels) {
69 this.labels = labels; 69 // this.labels = labels;
70 } 70 // }
71 getHtml(n: Term | NamedNode): TemplateResult { 71 // getHtml(n: Term | NamedNode): TemplateResult {
72 if (Util.isLiteral(n)) { 72 // if (Util.isLiteral(n)) {
73 n = n as Literal; 73 // n = n as Literal;
74 let dtPart: any = ""; 74 // let dtPart: any = "";
75 if (n.datatype) { 75 // if (n.datatype) {
76 dtPart = html` 76 // dtPart = html`
77 ^^<span class="literalType"> 77 // ^^<span class="literalType">
78 ${this.getHtml(n.datatype)} 78 // ${this.getHtml(n.datatype)}
79 </span> 79 // </span>
80 `; 80 // `;
81 } 81 // }
82 return html` 82 // return html`
83 <span class="literal">${n.value}${dtPart}</span> 83 // <span class="literal">${n.value}${dtPart}</span>
84 `; 84 // `;
85 } 85 // }
86 86
87 if (Util.isNamedNode(n)) { 87 // if (Util.isNamedNode(n)) {
88 n = n as NamedNode; 88 // n = n as NamedNode;
89 let shortened = false; 89 // let shortened = false;
90 let uriValue: string = n.value; 90 // let uriValue: string = n.value;
91 for (let [long, short] of [ 91 // for (let [long, short] of [
92 ["http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:"], 92 // ["http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:"],
93 ["http://www.w3.org/2000/01/rdf-schema#", "rdfs:"], 93 // ["http://www.w3.org/2000/01/rdf-schema#", "rdfs:"],
94 ["http://purl.org/dc/elements/1.1/", "dc:"], 94 // ["http://purl.org/dc/elements/1.1/", "dc:"],
95 ["http://www.w3.org/2001/XMLSchema#", "xsd:"] 95 // ["http://www.w3.org/2001/XMLSchema#", "xsd:"]
96 ]) { 96 // ]) {
97 if (uriValue.startsWith(long)) { 97 // if (uriValue.startsWith(long)) {
98 uriValue = short + uriValue.substr(long.length); 98 // uriValue = short + uriValue.substr(long.length);
99 shortened = true; 99 // shortened = true;
100 break; 100 // break;
101 } 101 // }
102 } 102 // }
103 if (!shortened) { 103 // if (!shortened) {
104 let dn: string | undefined = this.labels.getLabelForNode(uriValue); 104 // let dn: string | undefined = this.labels.getLabelForNode(uriValue);
105 if (dn === undefined) { 105 // if (dn === undefined) {
106 throw new Error(`dn=${dn}`); 106 // throw new Error(`dn=${dn}`);
107 } 107 // }
108 uriValue = dn; 108 // uriValue = dn;
109 } 109 // }
110 110
111 return html` 111 // return html`
112 <a class="graphUri" href="${n.value}">${uriValue}</a> 112 // <a class="graphUri" href="${n.value}">${uriValue}</a>
113 `; 113 // `;
114 } 114 // }
115 115
116 return html` 116 // return html`
117 [${n.termType} ${n.value}] 117 // [${n.termType} ${n.value}]
118 `; 118 // `;
119 } 119 // }
120 } 120 // }
121 121
122 export class GraphView { 122 // export class GraphView {
123 url: string; 123 // url: string;
124 graph: N3Store; 124 // graph: N3Store;
125 nodeDisplay: NodeDisplay; 125 // nodeDisplay: NodeDisplay;
126 constructor(url: string, graph: N3Store) { 126 // constructor(url: string, graph: N3Store) {
127 this.url = url; 127 // this.url = url;
128 this.graph = graph; 128 // this.graph = graph;
129 129
130 const labels = new SuffixLabels(); 130 // const labels = new SuffixLabels();
131 this._addLabelsForAllTerms(labels); 131 // this._addLabelsForAllTerms(labels);
132 this.nodeDisplay = new NodeDisplay(labels); 132 // this.nodeDisplay = new NodeDisplay(labels);
133 } 133 // }
134 134
135 _addLabelsForAllTerms(labels: SuffixLabels) { 135 // _addLabelsForAllTerms(labels: SuffixLabels) {
136 return this.graph.forEach( 136 // return this.graph.forEach(
137 (q: Quad) => { 137 // (q: Quad) => {
138 if (q.subject.termType === "NamedNode") { 138 // if (q.subject.termType === "NamedNode") {
139 labels.planDisplayForNode(q.subject); 139 // labels.planDisplayForNode(q.subject);
140 } 140 // }
141 if (q.predicate.termType === "NamedNode") { 141 // if (q.predicate.termType === "NamedNode") {
142 labels.planDisplayForNode(q.predicate); 142 // labels.planDisplayForNode(q.predicate);
143 } 143 // }
144 if (q.object.termType === "NamedNode") { 144 // if (q.object.termType === "NamedNode") {
145 labels.planDisplayForNode(q.object); 145 // labels.planDisplayForNode(q.object);
146 } 146 // }
147 if (q.object.termType === "Literal" && q.object.datatype) { 147 // if (q.object.termType === "Literal" && q.object.datatype) {
148 labels.planDisplayForNode(q.object.datatype); 148 // labels.planDisplayForNode(q.object.datatype);
149 } 149 // }
150 }, 150 // },
151 null, 151 // null,
152 null, 152 // null,
153 null, 153 // null,
154 null 154 // null
155 ); 155 // );
156 } 156 // }
157 157
158 _subjBlock(subj: NamedNode) { 158 // _subjBlock(subj: NamedNode) {
159 const predsSet: Set<NamedNode> = new Set(); 159 // const predsSet: Set<NamedNode> = new Set();
160 this.graph.forEach( 160 // this.graph.forEach(
161 (q: Quad) => { 161 // (q: Quad) => {
162 predsSet.add(q.predicate as NamedNode); 162 // predsSet.add(q.predicate as NamedNode);
163 }, 163 // },
164 subj, 164 // subj,
165 null, 165 // null,
166 null, 166 // null,
167 null 167 // null
168 ); 168 // );
169 const preds = Array.from(predsSet.values()); 169 // const preds = Array.from(predsSet.values());
170 preds.sort(); 170 // preds.sort();
171 return html` 171 // return html`
172 <div class="subject"> 172 // <div class="subject">
173 ${this.nodeDisplay.getHtml(subj)} 173 // ${this.nodeDisplay.getHtml(subj)}
174 <!-- todo: special section for uri/type-and-icon/label/comment --> 174 // <!-- todo: special section for uri/type-and-icon/label/comment -->
175 <div> 175 // <div>
176 ${preds.map(p => { 176 // ${preds.map(p => {
177 return this._predBlock(subj, p); 177 // return this._predBlock(subj, p);
178 })} 178 // })}
179 </div> 179 // </div>
180 </div> 180 // </div>
181 `; 181 // `;
182 } 182 // }
183 183
184 _objBlock(obj: Term) { 184 // _objBlock(obj: Term) {
185 return html` 185 // return html`
186 <div class="object"> 186 // <div class="object">
187 ${this.nodeDisplay.getHtml(obj)} 187 // ${this.nodeDisplay.getHtml(obj)}
188 <!-- indicate what source or graph said this stmt --> 188 // <!-- indicate what source or graph said this stmt -->
189 </div> 189 // </div>
190 `; 190 // `;
191 } 191 // }
192 192
193 _predBlock(subj: NamedNode, pred: NamedNode) { 193 // _predBlock(subj: NamedNode, pred: NamedNode) {
194 const objsSet = new Set<Term>(); 194 // const objsSet = new Set<Term>();
195 this.graph.forEach( 195 // this.graph.forEach(
196 (q: Quad) => { 196 // (q: Quad) => {
197 objsSet.add(q.object); 197 // objsSet.add(q.object);
198 }, 198 // },
199 subj, 199 // subj,
200 pred, 200 // pred,
201 null, 201 // null,
202 null 202 // null
203 ); 203 // );
204 const objs = Array.from(objsSet.values()); 204 // const objs = Array.from(objsSet.values());
205 objs.sort(); 205 // objs.sort();
206 return html` 206 // return html`
207 <div class="predicate"> 207 // <div class="predicate">
208 ${this.nodeDisplay.getHtml(pred)} 208 // ${this.nodeDisplay.getHtml(pred)}
209 <div> 209 // <div>
210 ${objs.map(this._objBlock.bind(this))} 210 // ${objs.map(this._objBlock.bind(this))}
211 </div> 211 // </div>
212 </div> 212 // </div>
213 `; 213 // `;
214 } 214 // }
215 215
216 byTypeBlock(byType: TypeToSubjs, typeUri: NamedNode) { 216 // byTypeBlock(byType: TypeToSubjs, typeUri: NamedNode) {
217 const subjSet = byType.get(typeUri); 217 // const subjSet = byType.get(typeUri);
218 const subjs: Array<NamedNode> = subjSet ? Array.from(subjSet) : []; 218 // const subjs: Array<NamedNode> = subjSet ? Array.from(subjSet) : [];
219 subjs.sort(); 219 // subjs.sort();
220 220
221 const graphCells = new Map<string, Set<Term>>(); // [subj, pred] : objs 221 // const graphCells = new Map<string, Set<Term>>(); // [subj, pred] : objs
222 const makeCellKey = (subj: NamedNode, pred: NamedNode) => 222 // const makeCellKey = (subj: NamedNode, pred: NamedNode) =>
223 subj.value + "|||" + pred.value; 223 // subj.value + "|||" + pred.value;
224 const preds = new Set<NamedNode>(); 224 // const preds = new Set<NamedNode>();
225 225
226 subjs.forEach((subj: NamedNode) => { 226 // subjs.forEach((subj: NamedNode) => {
227 this.graph.forEach( 227 // this.graph.forEach(
228 (q: Quad) => { 228 // (q: Quad) => {
229 if (!Util.isNamedNode(q.predicate)) { 229 // if (!Util.isNamedNode(q.predicate)) {
230 throw new Error(); 230 // throw new Error();
231 } 231 // }
232 preds.add(q.predicate as NamedNode); 232 // preds.add(q.predicate as NamedNode);
233 const cellKey = makeCellKey(subj, q.predicate as NamedNode); 233 // const cellKey = makeCellKey(subj, q.predicate as NamedNode);
234 if (!graphCells.has(cellKey)) { 234 // if (!graphCells.has(cellKey)) {
235 graphCells.set(cellKey, new Set<Term>()); 235 // graphCells.set(cellKey, new Set<Term>());
236 } 236 // }
237 graphCells.get(cellKey)!.add(q.object); 237 // graphCells.get(cellKey)!.add(q.object);
238 }, 238 // },
239 subj, 239 // subj,
240 null, 240 // null,
241 null, 241 // null,
242 null 242 // null
243 ); 243 // );
244 }); 244 // });
245 const predsList = Array.from(preds); 245 // const predsList = Array.from(preds);
246 predsList.splice(predsList.indexOf(rdf.type), 1); 246 // predsList.splice(predsList.indexOf(rdf.type), 1);
247 // also pull out label, which should be used on 1st column 247 // // also pull out label, which should be used on 1st column
248 predsList.sort(); 248 // predsList.sort();
249 249
250 const thead = () => { 250 // const thead = () => {
251 const predColumnHead = (pred: NamedNode) => { 251 // const predColumnHead = (pred: NamedNode) => {
252 return html` 252 // return html`
253 <th>${this.nodeDisplay.getHtml(pred)}</th> 253 // <th>${this.nodeDisplay.getHtml(pred)}</th>
254 `; 254 // `;
255 }; 255 // };
256 return html` 256 // return html`
257 <thead> 257 // <thead>
258 <tr> 258 // <tr>
259 <th></th> 259 // <th></th>
260 ${predsList.map(predColumnHead)} 260 // ${predsList.map(predColumnHead)}
261 </tr> 261 // </tr>
262 </thead> 262 // </thead>
263 `; 263 // `;
264 }; 264 // };
265 265
266 const instanceRow = (subj: NamedNode) => { 266 // const instanceRow = (subj: NamedNode) => {
267 const cell = (pred: NamedNode) => { 267 // const cell = (pred: NamedNode) => {
268 const objs = graphCells.get(subj + "|||" + pred); 268 // const objs = graphCells.get(subj + "|||" + pred);
269 if (!objs) { 269 // if (!objs) {
270 return html` 270 // return html`
271 <td></td> 271 // <td></td>
272 `; 272 // `;
273 } 273 // }
274 const objsList = Array.from(objs); 274 // const objsList = Array.from(objs);
275 objsList.sort(); 275 // objsList.sort();
276 const draw = (obj: Term) => { 276 // const draw = (obj: Term) => {
277 return html` 277 // return html`
278 <div>${this.nodeDisplay.getHtml(obj)}</div> 278 // <div>${this.nodeDisplay.getHtml(obj)}</div>
279 `; 279 // `;
280 }; 280 // };
281 return html` 281 // return html`
282 <td>${objsList.map(draw)}</td> 282 // <td>${objsList.map(draw)}</td>
283 `; 283 // `;
284 }; 284 // };
285 285
286 return html` 286 // return html`
287 <tr> 287 // <tr>
288 <td>${this.nodeDisplay.getHtml(subj)}</td> 288 // <td>${this.nodeDisplay.getHtml(subj)}</td>
289 ${predsList.map(cell)} 289 // ${predsList.map(cell)}
290 </tr> 290 // </tr>
291 `; 291 // `;
292 }; 292 // };
293 293
294 return html` 294 // return html`
295 <div>[icon] ${this.nodeDisplay.getHtml(typeUri)} resources</div> 295 // <div>[icon] ${this.nodeDisplay.getHtml(typeUri)} resources</div>
296 <div class="typeBlockScroll"> 296 // <div class="typeBlockScroll">
297 <table class="typeBlock"> 297 // <table class="typeBlock">
298 ${thead()} ${subjs.map(instanceRow)} 298 // ${thead()} ${subjs.map(instanceRow)}
299 </table> 299 // </table>
300 </div> 300 // </div>
301 `; 301 // `;
302 } 302 // }
303 303
304 makeTemplate(): TemplateResult { 304 // makeTemplate(): TemplateResult {
305 const { byType, untyped } = groupByRdfType(this.graph); 305 // const { byType, untyped } = groupByRdfType(this.graph);
306 const typedSubjs = Array.from(byType.keys()); 306 // const typedSubjs = Array.from(byType.keys());
307 typedSubjs.sort(); 307 // typedSubjs.sort();
308 308
309 const untypedSubjs = Array.from(untyped.values()); 309 // const untypedSubjs = Array.from(untyped.values());
310 untypedSubjs.sort(); 310 // untypedSubjs.sort();
311 311
312 return html` 312 // return html`
313 <section> 313 // <section>
314 <h2>Current graph (<a href="${this.url}">${this.url}</a>)</h2> 314 // <h2>Current graph (<a href="${this.url}">${this.url}</a>)</h2>
315 <div> 315 // <div>
316 <!-- todo: graphs and provenance. 316 // <!-- todo: graphs and provenance.
317 These statements are all in the 317 // These statements are all in the
318 <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.--> 318 // <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
319 </div> 319 // </div>
320 ${typedSubjs.map((t: NamedNode) => this.byTypeBlock(byType, t))} 320 // ${typedSubjs.map((t: NamedNode) => this.byTypeBlock(byType, t))}
321 <div class="spoGrid"> 321 // <div class="spoGrid">
322 ${untypedSubjs.map(this._subjBlock.bind(this))} 322 // ${untypedSubjs.map(this._subjBlock.bind(this))}
323 </div> 323 // </div>
324 </section> 324 // </section>
325 `; 325 // `;
326 } 326 // }
327 } 327 // }