Files @ cc69faa87c27
Branch filter:

Location: light9/web/fade/Light9EffectFader.ts

drewp@bigasterisk.com
tear up and rewrite ascoltami to emit player state into the graph. web ui works but displays nothing but songs
import debug from "debug";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { NamedNode, Quad } from "n3";
import { getTopGraph } from "../RdfdbSyncedGraph";
import { showRoot } from "../show_specific";
import { SyncedGraph } from "../SyncedGraph";
import { Patch } from "../patch";
import { Literal } from "n3";
export { Light9Fader } from "./Light9Fader";

const log = debug("efffader")

//////////////////////////////////////
const RETURN_URI = new NamedNode("");
const RETURN_FLOAT = 1;
function get2Step<T extends NamedNode | number>(returnWhat: T, graph: SyncedGraph, subj1: NamedNode, pred1: NamedNode, pred2: NamedNode): T | undefined {
  // ?subj1 ?pred1 ?x . ?x ?pred2 ?returned .
  let x: NamedNode;
  try {
    x = graph.uriValue(subj1, pred1);
  } catch (e) {
    return undefined;
  }
  try {
    if (typeof returnWhat === "object" && (returnWhat as NamedNode).termType == "NamedNode") {
      return graph.uriValue(x, pred2) as T;
    } else if (typeof returnWhat === "number") {
      return graph.floatValue(x, pred2) as T;
    }
  } catch (e) {
    return undefined;
  }
}
function set2Step(
  graph: SyncedGraph, //
  subj1: NamedNode,
  pred1: NamedNode,
  baseName: string,
  pred2: NamedNode,
  newObjLiteral: Literal
) { }

function maybeUriValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): NamedNode | undefined {
  try {
    return graph.uriValue(s, p);
  } catch (e) {
    return undefined;
  }
}
function maybeStringValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): string | undefined {
  try {
    return graph.stringValue(s, p);
  } catch (e) {
    return undefined;
  }
}
function maybeFloatValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): number | undefined {
  try {
    return graph.floatValue(s, p);
  } catch (e) {
    return undefined;
  }
}

//////////////////////////////////////
class EffectFader {
  constructor(public uri: NamedNode) { }
  column: string = "unset";
  effect?: NamedNode;
  effectAttr?: NamedNode; // :strength
  setting?: NamedNode; // we assume fader always has exactly one setting
  value?: number;
}

@customElement("light9-effect-fader")
export class Light9EffectFader extends LitElement {
  static styles = [
    css`
      :host {
        display: inline-block;
        border: 2px gray outset;
        background: #272727;
      }
      light9-fader {
        margin: 0px;
        width: 100%;
      }
    `,
  ];
  render() {
    if (this.conf === undefined || this.conf.value === undefined) {
      return html`...`;
    }
    return html`
      <div><resource-display .uri=${this.uri}></resource-display>
      <light9-fader .value=${this.conf.value} @change=${this.onSliderInput}></light9-fader>
      <div>${this.conf.value.toPrecision(3)}</div>
      <div>effect <edit-choice nounlink .uri=${this.conf.effect} @edited=${this.onEffectChange}></edit-choice></div>
      <div>attr <edit-choice nounlink .uri=${this.conf.effectAttr} @edited=${this.onEffectAttrChange}></edit-choice></div>
    `;
  }

  graph?: SyncedGraph;
  ctx: NamedNode = new NamedNode(showRoot + "/fade");
  @property() uri!: NamedNode;
  @state() conf?: EffectFader; // compiled from graph

  constructor() {
    super();
    getTopGraph().then((g) => {
      this.graph = g;
      this.graph.runHandler(this.compile.bind(this, this.graph), `fader config ${this.uri.value}`);
    });
  }

  private compile(graph: SyncedGraph) {
    const U = graph.U();
    this.conf = undefined;

    const conf = new EffectFader(this.uri);

    if (!graph.contains(this.uri, U("rdf:type"), U(":Fader"))) {
      // not loaded yet, perhaps
      return;
    }

    conf.column = maybeStringValue(graph, this.uri, U(":column")) || "unset";
    conf.effect = maybeUriValue(graph, this.uri, U(":effect"));
    conf.effectAttr = get2Step(RETURN_URI, graph, this.uri, U(":setting"), U(":effectAttr"));

    this.conf = conf;
    graph.runHandler(this.compileValue.bind(this, graph, this.conf), `fader config.value ${this.uri.value}`);
  }

  private compileValue(graph: SyncedGraph, conf: EffectFader) {
    // external graph change -> conf.value
    const U = graph.U();
    conf.value = get2Step(RETURN_FLOAT, graph, this.uri, U(":setting"), U(":value"));
    // since conf attrs aren't watched as property:
    this.requestUpdate()
  }

  onSliderInput(ev: CustomEvent) {
    // slider user input -> graph
    if (this.conf === undefined) return;
    this.conf.value = ev.detail.value
    this.writeValueToGraph()
  }

  writeValueToGraph() {
    // this.value -> graph
    if (this.graph === undefined) {
      return;
    }
    const U = this.graph.U();
    if (this.conf === undefined) {
      return;
    }
    if (this.conf.value === undefined) {
      log(`value of ${this.uri} is undefined`)
      return;
    }
    log('writeValueToGraph', this.conf.value)
    const valueTerm = this.graph.LiteralRoundedFloat(this.conf.value);
    const settingNode = this.graph.uriValue(this.uri, U(":setting"));
    this.graph.patchObject(settingNode, this.graph.Uri(":value"), valueTerm, this.ctx);

  }

  onEffectChange(ev: CustomEvent) {
    if (this.graph === undefined) {
      return;
    }
    const { newValue } = ev.detail;
    this.graph.patchObject(this.uri, this.graph.Uri(":effect"), newValue, this.ctx);
  }

  onEffectAttrChange(ev: CustomEvent) {
    if (this.graph === undefined) {
      return;
    }
    // const { newValue } = ev.detail;
    // if (this.setting === undefined) {
    //   this.setting = this.graph.nextNumberedResource(this.graph.Uri(":fade_set"));
    //   this.graph.patchObject(this.uri, this.graph.Uri(":setting"), this.setting, this.ctx);
    // }
    // this.graph.patchObject(this.setting, this.graph.Uri(":effectAttr"), newValue, this.ctx);
  }
}