Mercurial > code > home > repos > streamed-graph
view src/render/GraphView.ts @ 110:3cdbbd913f1d
table displays now just barely
author | drewp@bigasterisk.com |
---|---|
date | Fri, 18 Mar 2022 23:41:24 -0700 |
parents | cbcd82d21356 |
children | 4822d5621463 |
line wrap: on
line source
import Immutable from "immutable"; import { html, TemplateResult } from "lit"; import { NamedNode, Quad, Store, Term } from "n3"; import { AlignedTable, FreeStatements, Layout, PredRow, SubjRow, } from "../layout/Layout"; import { SuffixLabels } from "../layout/suffixLabels"; import { ViewConfig } from "../layout/ViewConfig"; import { NodeDisplay } from "./NodeDisplay"; type UriSet = Immutable.Set<NamedNode>; export class GraphView { nodeDisplay!: NodeDisplay; constructor( public dataSourceUrls: string[], public graph: Store, public viewConfig?: ViewConfig ) {} async makeTemplate(): Promise<TemplateResult> { const layout = new Layout(this.viewConfig); const lr = layout.plan(this.graph); const labels = new SuffixLabels(); this._addLabelsForAllTerms(this.graph, labels); this.nodeDisplay = new NodeDisplay(labels); let viewTitle = html` (no view)`; if (this.viewConfig?.url) { viewTitle = html` using view <a href="${this.viewConfig?.url}">${this.viewConfig?.label()}</a>`; } return html` <section> <h2> Current graph (<a href="${this.dataSourceUrls[0]}" >${this.dataSourceUrls[0]}</a >)${viewTitle} </h2> <div> <!-- todo: graphs and provenance. These statements are all in the <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.--> </div> ${lr.sections.map(this._renderSection.bind(this))} </section> `; } _addLabelsForAllTerms(graph: Store, labels: SuffixLabels) { graph.forEach( (q: Quad) => { if (q.subject.termType === "NamedNode") { labels.planDisplayForNode(q.subject); } if (q.predicate.termType === "NamedNode") { labels.planDisplayForNode(q.predicate); } if (q.object.termType === "NamedNode") { labels.planDisplayForNode(q.object); } if (q.object.termType === "Literal" && q.object.datatype) { labels.planDisplayForNode(q.object.datatype); } }, null, null, null, null ); } _renderSection(section: AlignedTable | FreeStatements) { if ((section as any).columnHeaders) { return this._renderAlignedTable(section as AlignedTable); } else { return this._renderFreeStatements(section as FreeStatements); } } _renderAlignedTable(section: AlignedTable): TemplateResult { const heads = section.columnHeaders.map((ch) => { return html`<th>${this.nodeDisplay.render(ch.pred)}</th>`; }); const cells = []; for (let rowIndex in section.rows) { const headerCol = html`<th>${this.nodeDisplay.render(section.rowHeaders[rowIndex])}</th>`; const bodyCols = [] for (let cellObjs of section.rows[rowIndex]) { const display = cellObjs.map( (t) => html`<div>${this.nodeDisplay.render(t)}</div>` ); bodyCols.push(html`<td>${display}</td>`); } cells.push(html`<tr>${headerCol}${bodyCols}</tr>`); } return html` <pre> {JSON.stringify(section.rows,null,' ')}</pre> <div class="typeBlockScroll"> <table class="typeBlock"> <thead> <th>Subject</th> ${heads} </thead> <tbody> ${cells} </tbody> </table> </div> `; } _renderFreeStatements(section: FreeStatements): TemplateResult { const subjects: NamedNode[] = []; let subjPreds = Immutable.Map<NamedNode, UriSet>(); return html`<div class="spoGrid"> grid has rowcount ${section.subjRows.length} ${section.subjRows.map(this._subjPredObjsBlock.bind(this))} </div>`; } _subjPredObjsBlock(row: SubjRow): TemplateResult { return html` <div class="subject"> ${this.nodeDisplay.render(row.subj)} <!-- todo: special section for uri/type-and-icon/label/comment --> <div>${row.predRows.map(this._predObjsBlock.bind(this))}</div> </div> `; } _predObjsBlock(row: PredRow): TemplateResult { return html` <div class="predicate"> ${this.nodeDisplay.render(row.pred)} <div>${row.objs.map(this._objCell.bind(this))}</div> </div> `; } _objCell(obj: Term): TemplateResult { return html` <div class="object"> ${this.nodeDisplay.render(obj)} <!-- indicate what source or graph said this stmt --> </div> `; } _drawObj(obj: Term): TemplateResult { return html` <div>${this.nodeDisplay.render(obj)}</div> `; } _drawColumnHead(pred: NamedNode): TemplateResult { return html` <th>${this.nodeDisplay.render(pred)}</th> `; } // _thead(layout: MultiSubjsTypeBlockLayout): TemplateResult { // return html` // <thead> // <tr> // <th></th> // ${layout.preds.map(this._drawColumnHead.bind(this))} // </tr> // </thead> // `; // } // _msbCell(layout: MultiSubjsTypeBlockLayout, subj: NamedNode) { // return (pred: NamedNode): TemplateResult => { // const objs = layout.graphCells.get(layout.makeCellKey(subj, pred)); // if (!objs || !objs.size) { // return html` <td></td> `; // } // const objsList = Array.from(objs); // objsList.sort(); // return html` <td>${objsList.map(this._drawObj.bind(this))}</td> `; // }; // } // _instanceRow(layout: MultiSubjsTypeBlockLayout) { // return (subj: NamedNode): TemplateResult => { // return html` // <tr> // <td>${this.nodeDisplay.render(subj)}</td> // ${layout.preds.map(this._msbCell(layout, subj))} // </tr> // `; // }; // } // _multiSubjsTypeBlock(byType: TypeToSubjs, table: TableDesc) { // const layout = new MultiSubjsTypeBlockLayout(this.graph, byType, table); // let typeNames = [html`${this.nodeDisplay.render(table.primary)}`]; // if (table.joins) { // typeNames.push(html` joined with [`); // for (let j of table.joins) { // typeNames.push(html`${this.nodeDisplay.render(j)}`); // } // typeNames.push(html`]`); // } // return html` // <div>[icon] Resources of type ${typeNames}</div> // <div class="typeBlockScroll"> // <table class="typeBlock"> // ${this._thead(layout)} ${layout.subjs.map(this._instanceRow(layout))} // </table> // </div> // `; // } }