comparison src/graph_view.ts @ 15:7ca4ff2088c3

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