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