diff src/render/StreamedGraph.ts @ 107:042bd3361339

renames
author drewp@bigasterisk.com
date Sun, 13 Mar 2022 22:02:30 -0700
parents src/render/element.ts@2468f2227d22
children 5e6840229a05
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/render/StreamedGraph.ts	Sun Mar 13 22:02:30 2022 -0700
@@ -0,0 +1,150 @@
+import { LitElement, html, render, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators.js";
+
+import { Store } from "n3";
+
+import { GraphView } from "./GraphView";
+import { StreamedGraphClient } from "../layout/StreamedGraphClient";
+import { style, addFontToRootPage } from "./style";
+
+// export * from "./graph_queries";
+
+export interface VersionedGraph {
+  version: number;
+  store: Store;
+}
+
+@customElement("streamed-graph")
+export class StreamedGraph extends LitElement {
+  @property({ type: String })
+  url: string = "";
+  @property({ type: String })
+  view: string = "";
+  @property({ type: Object })
+  graph!: VersionedGraph;
+
+  @property({ type: Boolean })
+  expanded: boolean = false;
+
+  @property({ type: String })
+  status: string = "";
+
+  sg!: StreamedGraphClient;
+  graphViewDirty = true;
+
+  static styles = style;
+
+  render() {
+    const expandAction = this.expanded ? "-" : "+";
+    return html`
+      <div id="ui">
+        <span class="expander"
+          ><button @click="${this.toggleExpand}">${expandAction}</button></span
+        >
+        StreamedGraph <a href="${this.url}">[source]</a>: ${this.status}
+      </div>
+      <div id="graphView"></div>
+    `;
+  }
+
+  connectedCallback() {
+    super.connectedCallback();
+    addFontToRootPage();
+    const emptyStore = new Store();
+    this.graph = { version: -1, store: emptyStore };
+
+    this._onUrl(this.url); // todo: watch for changes and rebuild
+    if (this.expanded) {
+      this.redrawGraph();
+    }
+  }
+
+  toggleExpand() {
+    this.expanded = !this.expanded;
+    if (this.expanded) {
+      this.redrawGraph();
+    } else {
+      this.graphViewDirty = false;
+      this._graphAreaClose();
+    }
+  }
+
+  redrawGraph() {
+    this.graphViewDirty = true;
+    const rl: ()=>Promise<void> = this._redrawLater.bind(this)
+    requestAnimationFrame(rl);
+  }
+
+  _onUrl(url: string) {
+    if (this.sg) {
+      this.sg.close();
+    }
+    this.sg = new StreamedGraphClient(
+      url,
+      this.onGraphChanged.bind(this),
+      (st) => {
+        this.status = st;
+      },
+      [], //window.NS,
+      []
+    );
+  }
+
+  onGraphChanged() {
+    this.graph = {
+      version: this.graph.version + 1,
+      store: this.sg.store,
+    };
+    if (this.expanded) {
+      this.redrawGraph();
+    }
+    this.dispatchEvent(
+      new CustomEvent("graph-changed", { detail: { graph: this.graph } })
+    );
+  }
+
+  async _redrawLater() {
+    if (!this.graphViewDirty) return;
+
+    if ((this.graph as VersionedGraph).store && this.graph.store) {
+      await this._graphAreaShowGraph(
+        new GraphView(this.url, this.view, this.graph.store)
+      );
+      this.graphViewDirty = false;
+    } else {
+      this._graphAreaShowPending();
+    }
+  }
+
+  _graphAreaClose() {
+    this._setGraphArea(html``);
+  }
+
+  _graphAreaShowPending() {
+    this._setGraphArea(html` <span>waiting for data...</span> `);
+  }
+
+  async _graphAreaShowGraph(graphView: GraphView) {
+    this._setGraphArea(await graphView.makeTemplate());
+  }
+
+  _setGraphArea(tmpl: TemplateResult) {
+    const el = this.shadowRoot?.getElementById("graphView");
+    if (!el) {
+      return;
+    }
+    render(tmpl, el);
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    "streamed-graph": StreamedGraph;
+  }
+}
+
+// // allow child nodes to combine a few graphs and statics
+// //<streamed-graph id="timebankGraph"  graph="{{graph}}" expanded="true">
+// //  <member-graph url="graph/timebank/events"></member-graph>
+// //  <member-graph url="/some/static.n3"></member-graph>
+// //</streamed-graph>