Mercurial > code > home > repos > streamed-graph
annotate src/layout/Layout.ts @ 106:2468f2227d22
make src/layout/ and src/render/ separation
author | drewp@bigasterisk.com |
---|---|
date | Sun, 13 Mar 2022 22:00:30 -0700 |
parents | src/Layout.ts@1aea03d306af |
children | 5e6840229a05 |
rev | line source |
---|---|
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
1 // Organize graph data into tables (column orders, etc) for the view layer. |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
2 |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
3 import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x) |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
4 import { NamedNode, Quad, Store, Term } from "n3"; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
5 import { rdf } from "./namespaces"; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
6 import { TableDesc, ViewConfig } from "./ViewConfig"; |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
7 |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
8 type UriSet = Immutable.Set<NamedNode>; |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
9 export type TypeToSubjs = Immutable.Map<NamedNode, UriSet>; |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
10 |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
11 // https://github.com/rdfjs/N3.js/issues/265 |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
12 (NamedNode.prototype as any).hashCode = () => 0; |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
13 |
103 | 14 interface ColumnHeader { |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
15 rdfType: NamedNode; |
103 | 16 pred: NamedNode; |
17 } | |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
18 export interface AlignedTable { |
103 | 19 columnHeaders: ColumnHeader[]; |
20 rows: (Term | null)[][]; // each row is 1 wider than columnHeaders since the 1st element is the subject for that row | |
21 } | |
22 interface FreeStatements { | |
23 statements: Quad[]; | |
24 } | |
25 export interface LayoutResult { | |
26 sections: (AlignedTable | FreeStatements)[]; | |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
27 } |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
28 |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
29 class AlignedTableBuilder { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
30 columnPreds = Immutable.List<NamedNode>(); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
31 subjRowIndices = Immutable.Map<NamedNode, number>(); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
32 rows: (Term | null)[][] = []; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
33 constructor( |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
34 public rdfType: NamedNode /* plus join types, sort instructions */ |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
35 ) {} |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
36 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
37 addQuad(q: Quad) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
38 const pred = q.predicate as NamedNode; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
39 const omittedColumn = pred.equals(rdf.type); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
40 if (!this.columnPreds.contains(pred) && !omittedColumn) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
41 this.columnPreds = this.columnPreds.push(pred); // this is putting cols in random order |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
42 this.rows.forEach((r) => r.push(null)); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
43 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
44 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
45 const predIndex = omittedColumn ? null : this.columnPreds.indexOf(pred); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
46 let rowIndex = this.subjRowIndices.get(q.subject as NamedNode); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
47 if (rowIndex === undefined) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
48 const newRow = new Array(1 + this.columnPreds.size).fill(null); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
49 newRow[0] = q.subject; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
50 this.rows.push(newRow); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
51 rowIndex = this.rows.length - 1; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
52 this.subjRowIndices = this.subjRowIndices.set( |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
53 q.subject as NamedNode, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
54 rowIndex |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
55 ); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
56 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
57 if (predIndex !== null) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
58 this.rows[rowIndex][1 + predIndex] = q.object; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
59 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
60 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
61 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
62 value(): AlignedTable { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
63 this.rows.sort((a, b) => { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
64 const uriA = (a[0] as NamedNode).value, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
65 uriB = (b[0] as NamedNode).value; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
66 return uriA.localeCompare(uriB); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
67 }); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
68 const headers = this.columnPreds |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
69 .map((pred) => { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
70 return { rdfType: this.rdfType, pred: pred }; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
71 }) |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
72 .toArray(); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
73 return { columnHeaders: headers, rows: this.rows }; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
74 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
75 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
76 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
77 function findTypesNeededForTables(viewConfig?: ViewConfig): UriSet { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
78 const typesToGather: NamedNode[] = []; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
79 if (viewConfig) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
80 viewConfig.tables.forEach((t: TableDesc) => { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
81 typesToGather.push(t.primary); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
82 }); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
83 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
84 return Immutable.Set(typesToGather); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
85 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
86 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
87 function findSubjectsWithTypes(graph: Store, typesToGatherSet: UriSet): UriSet { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
88 const subjectsToGather: NamedNode[] = []; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
89 graph.forEach( |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
90 (q: Quad) => { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
91 if (typesToGatherSet.contains(q.object as NamedNode)) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
92 subjectsToGather.push(q.subject as NamedNode); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
93 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
94 }, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
95 null, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
96 rdf.type, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
97 null, |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
98 null |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
99 ); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
100 return Immutable.Set(subjectsToGather); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
101 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
102 |
103 | 103 export class Layout { |
104 constructor(public viewConfig?: ViewConfig) {} | |
105 plan(graph: Store): LayoutResult { | |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
106 const typesToGatherSet = findTypesNeededForTables(this.viewConfig); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
107 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
108 const subjectsToGatherSet = findSubjectsWithTypes(graph, typesToGatherSet); |
103 | 109 const ungrouped: Quad[] = []; |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
110 const vc = this.viewConfig; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
111 const table = |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
112 vc && vc.tables.length > 0 |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
113 ? new AlignedTableBuilder(vc.tables[0].primary) |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
114 : null; |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
115 |
103 | 116 graph.forEach( |
117 (q: Quad) => { | |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
118 if (!subjectsToGatherSet.contains(q.subject as NamedNode) || !table) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
119 ungrouped.push(q); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
120 } else { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
121 table.addQuad(q); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
122 } |
103 | 123 }, |
124 null, | |
125 null, | |
126 null, | |
127 null | |
128 ); | |
104
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
129 const res: LayoutResult = { sections: [] }; |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
130 if (table) { |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
131 res.sections.push(table.value()); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
132 } |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
133 res.sections.push({ statements: ungrouped }); |
1aea03d306af
WIP Layout. tests are passing but they're a little wrong
drewp@bigasterisk.com
parents:
103
diff
changeset
|
134 return res; |
103 | 135 } |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
136 } |
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
137 |
103 | 138 // interface ISP { |
139 // subj: NamedNode; | |
140 // pred: NamedNode; | |
141 // } | |
142 // const SP = Immutable.Record<ISP>({ | |
143 // subj: new NamedNode(""), | |
144 // pred: new NamedNode(""), | |
145 // }); | |
146 | |
147 // // One table of rows with a common rdf:type. | |
148 // export class MultiSubjsTypeBlockLayout { | |
149 // subjs: NamedNode[]; | |
150 // preds: NamedNode[]; | |
151 // graphCells: Immutable.Map<ISP, Immutable.Set<Term>>; | |
152 // constructor(graph: Store, byType: TypeToSubjs, table: TableDesc) { | |
153 // const subjSet = byType.get(table.primary); | |
154 // this.subjs = subjSet ? Array.from(subjSet) : []; | |
155 // this.subjs.sort(); | |
156 | |
157 // let preds = Immutable.Set<NamedNode>(); | |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
158 |
103 | 159 // this.graphCells = Immutable.Map<ISP, Immutable.Set<Term>>().withMutations( |
160 // (mutGraphCells) => { | |
161 // this.subjs.forEach((subj: NamedNode) => { | |
162 // graph.forEach( | |
163 // (q: Quad) => { | |
164 // if (!Util.isNamedNode(q.predicate)) { | |
165 // throw new Error(); | |
166 // } | |
88
ac7ad087d474
graph view rewrites and fixes for the multi-subject table
drewp@bigasterisk.com
parents:
diff
changeset
|
167 |
103 | 168 // const pred = q.predicate as NamedNode; |
169 // if (pred.equals(rdf.type)) { | |
170 // // the whole block is labeled with the type | |
171 // return; | |
172 // } | |
173 // preds = preds.add(pred); | |
174 // const cellKey = this.makeCellKey(subj, pred); | |
175 // mutGraphCells.set( | |
176 // cellKey, | |
177 // mutGraphCells.get(cellKey, Immutable.Set<Term>()).add(q.object) | |
178 // ); | |
179 // }, | |
180 // subj, | |
181 // null, | |
182 // null, | |
183 // null | |
184 // ); | |
185 // }); | |
186 // } | |
187 // ); | |
188 // this.preds = Array.from(preds); | |
189 // this.preds.splice(this.preds.indexOf(rdf.type), 1); | |
190 // // also pull out label, which should be used on 1st column | |
191 // this.preds.sort(); | |
192 // } | |
193 | |
194 // makeCellKey(subj: NamedNode, pred: NamedNode): ISP { | |
195 // return SP({ | |
196 // subj: subj, | |
197 // pred: pred, | |
198 // }); | |
199 // } | |
200 // } |