Changeset - 5f94c9f5b879
[Not reviewed]
default
0 2 0
drewp@bigasterisk.com - 3 years ago 2022-05-31 07:41:35
drewp@bigasterisk.com
port ui to lit
2 files changed with 156 insertions and 117 deletions:
0 comments (0 inline, 0 general)
light9/effect/sequencer/web/Light9SequencerUi.ts
Show inline comments
 
<dom-module id="light9-sequencer-ui">
 
<template>
 
  <style>
 
   :host {
 
       display: block;
 
   }
 
   td {
 
       white-space: nowrap;
 
       padding: 0 10px;
 
       vertical-align: top;
 
       vertical-align: top;
 
       text-align: start;
 
   }
 
   tr.active { background: #151515; }
 
   .inactive > * { opacity: .5; }
 
   .effectSetting {
 
       display: inline-block;
 
       background: #1b1e21;
 
       margin: 1px 3px;
 
   }
 
   .chart {
 
       height: 40px;
 
       background: #222;
 
       display: inline-flex;
 
       align-items: flex-end;
 
   }
 
   .chart > div {
 
       background: #a4a54f;
 
       width: 8px;
 
       margin: 0 1px;
 
   }
 
   .number {
 
       display: inline-block;
 
       min-width: 4em;
 
   }
 
  </style>
 
  <rdfdb-synced-graph graph="{{graph}}"></rdfdb-synced-graph>
 
import debug from "debug";
 
import { css, html, LitElement } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { getTopGraph } from "../../../web/RdfdbSyncedGraph";
 
import { SyncedGraph } from "../../../web/SyncedGraph";
 

	
 
debug.enable("*");
 
const log = debug("sequencer");
 

	
 
  <h1>Sequencer <a href="stats/">[stats]</a></h1>
 
  
 
  <h2>Song</h2>
 

	
 
  <resource-display graph="{{graph}}" uri="{{report.song}}"></resource-display>
 
  t={{report.roundT}}
 
  
 
  <h3>Notes</h3>
 
interface Note {
 
  note: string;
 
  nonZero: boolean;
 
  rowClass?: string; // added in message handler below
 
  effectClass: string;
 
  effectSettings: { [attr: string]: string };
 
  effectSettingsPairs: EffectSettingsPair[]; // added in message handler below
 
  devicesAffected: number;
 
}
 
interface Report {
 
  song: string;
 
  songUri: NamedNode; // added in message handler below
 
  t: number;
 
  roundT?: number; // added in message handler below
 
  recentFps: number;
 
  recentDeltas: number[];
 
  recentDeltasStyle: string[]; // added in message handler below
 
  songNotes: Note[];
 
}
 
interface EffectSettingsPair {
 
  effectAttr: string;
 
  value: any;
 
}
 
@customElement("light9-sequencer-ui")
 
export class Light9SequencerUi extends LitElement {
 
  static styles = [
 
    css`
 
      :host {
 
        display: block;
 
      }
 
      td {
 
        white-space: nowrap;
 
        padding: 0 10px;
 
        vertical-align: top;
 
        vertical-align: top;
 
        text-align: start;
 
      }
 
      tr.active {
 
        background: #151515;
 
      }
 
      .inactive > * {
 
        opacity: 0.5;
 
      }
 
      .effectSetting {
 
        display: inline-block;
 
        background: #1b1e21;
 
        margin: 1px 3px;
 
      }
 
      .chart {
 
        height: 40px;
 
        background: #222;
 
        display: inline-flex;
 
        align-items: flex-end;
 
      }
 
      .chart > div {
 
        background: #a4a54f;
 
        width: 8px;
 
        margin: 0 1px;
 
      }
 
      .number {
 
        display: inline-block;
 
        min-width: 4em;
 
      }
 
    `,
 
  ];
 
  render() {
 
    return html`
 
      <rdfdb-synced-graph></rdfdb-synced-graph>
 

	
 
  <table>
 
    <tr>
 
      <th>Note</th>
 
      <th>Effect class</th>
 
      <th>Effect settings</th>
 
      <th>Devices affected</th>
 
    </tr>
 
    <template is="dom-repeat" items="{{report.songNotes}}">
 
      <h1>Sequencer <a href="metrics/">[metrics]</a></h1>
 

	
 
      <tr class$="{{item.rowClass}}">
 
        <td>
 
          <resource-display graph="{{graph}}" uri="{{item.note}}"></resource-display>
 
        </td>
 
        <td>
 
          <resource-display graph="{{graph}}" uri="{{item.effectClass}}"></resource-display>
 
        </td>  
 
        <td>
 
          <template is="dom-repeat" items="{{item.effectSettingsPairs}}">
 
            <div>
 
            <span class="effectSetting">
 
              <resource-display graph="{{graph}}" uri="{{item.effectAttr}}"></resource-display>:
 
              <span class="number">{{item.value}}</span>
 
            </span>
 
            </div>
 
          </template>
 
        </td>
 
        <td>
 
          {{item.devicesAffected}}
 
        </td>
 
      </tr>
 
    </template>
 
  </table>
 
      <h2>Song</h2>
 

	
 
      <resource-display uri=${this.report.songUri}"></resource-display>
 
      t=${this.report.roundT}
 

	
 
      <h3>Notes</h3>
 

	
 
      <table>
 
        <tr>
 
          <th>Note</th>
 
          <th>Effect class</th>
 
          <th>Effect settings</th>
 
          <th>Devices affected</th>
 
        </tr>
 
        ${this.report.songNotes.map(
 
          (item: Note) => html`
 
            <tr class$="${item.rowClass}">
 
              <td><resource-display uri="${item.note}"></resource-display></td>
 
              <td><resource-display uri="${item.effectClass}"></resource-display></td>
 
              <td>
 
                ${item.effectSettingsPairs.map(
 
                  (item) => html`
 
                    <div>
 
                      <span class="effectSetting">
 
                        <resource-display uri="${item.effectAttr}"></resource-display>:
 
                        <span class="number">${item.value}</span>
 
                      </span>
 
                    </div>
 
                  `
 
                )}
 
              </td>
 
              <td>${item.devicesAffected}</td>
 
            </tr>
 
          `
 
        )}
 
      </table>
 
    `;
 
  }
 

	
 
</template>
 
<script>
 
 HTMLImports.whenReady(function () {
 
   Polymer({
 
     is: "light9-sequencer-ui",
 
     properties: {
 
       graph: {type: Object, notify: true},
 
       report: {type: Object, notify: true},
 
     },
 
     ready: function() {
 
       var source = new EventSource('updates');
 
       source.addEventListener('message', (e) => {
 
         const report = JSON.parse(e.data);
 
         report.roundT = Math.floor((report.t || 0) * 1000) / 1000;
 
         report.recentFps = Math.floor((report.recentFps || 0) * 10) / 10;
 
         report.recentDeltasStyle = (report.recentDeltas || []).map((dt) => {
 
           const height = Math.min(40, dt / 0.085 * 20);
 
           return `height: ${height}px;`
 
         });
 
  graph!: SyncedGraph;
 
  @property() report!: Report;
 

	
 
  constructor() {
 
    super();
 
    getTopGraph().then((g) => {
 
      var source = new EventSource("./api/updates");
 
      source.addEventListener("message", this.onMessage.bind(this));
 
    });
 
  }
 
  onMessage(ev: MessageEvent) {
 
    const report = JSON.parse(ev.data) as Report;
 
    report.roundT = Math.floor((report.t || 0) * 1000) / 1000;
 
    report.recentFps = Math.floor((report.recentFps || 0) * 10) / 10;
 
    report.recentDeltasStyle = (report.recentDeltas || []).map((dt) => {
 
      const height = Math.min(40, (dt / 0.085) * 20);
 
      return `height: ${height}px;`;
 
    });
 
    report.songUri = this.graph.Uri(report.song);
 

	
 
         const fakeUris = (report.songNotes || []).map((obj) => { return {value: obj.note, orig: obj} });
 
         const s = this.graph.sortedUris(fakeUris);
 
         report.songNotes = s.map((u) => { return u.orig; });
 
         
 
         (report.songNotes || []).forEach((note) => {
 
           note.rowClass = note.nonZero ? 'active' : 'inactive';
 
           note.effectSettingsPairs = [];
 
    const fakeUris = (report.songNotes || []).map((obj) => {
 
      return { value: obj.note, orig: obj };
 
    });
 
    const s = this.graph.sortedUris(fakeUris);
 
    report.songNotes = s.map((u) => {
 
      return u.orig;
 
    });
 

	
 
           const attrs = Object.keys(note.effectSettings);
 
           attrs.sort();
 
           attrs.forEach((attr) => {
 
             note.effectSettingsPairs.push(
 
               {effectAttr: attr, value: note.effectSettings[attr]});
 
           });
 
         });
 
         this.report = report;
 
       });
 
     },
 
   });
 
 });
 
</script>
 
</dom-module>
 
    (report.songNotes || []).forEach((note) => {
 
      note.rowClass = note.nonZero ? "active" : "inactive";
 
      note.effectSettingsPairs = [];
 

	
 
      const attrs = Object.keys(note.effectSettings);
 
      attrs.sort();
 
      attrs.forEach((attr) => {
 
        note.effectSettingsPairs.push({ effectAttr: attr, value: note.effectSettings[attr] } as EffectSettingsPair);
 
      });
 
    });
 
    this.report = report;
 
  }
 
}
light9/effect/sequencer/web/index.html
Show inline comments
 
@@ -5,7 +5,7 @@
 
    <meta charset="utf-8" />
 

	
 
    <link rel="stylesheet" href="./style.css" />
 
    <script type="module" src="./Light9SequencerUi"></script>
 
    <script type="module" src="../effectSequencer/Light9SequencerUi"></script>
 
  </head>
 
  <body>
 
    <light9-sequencer-ui></light9-sequencer-ui>
0 comments (0 inline, 0 general)