comparison web/ascoltami/Light9AscoltamiTimeline.ts @ 2439:06da5db2fafe

rewrite ascoltami to use the graph for more playback data
author drewp@bigasterisk.com
date Thu, 30 May 2024 01:08:07 -0700
parents
children e7e03c203c99
comparison
equal deleted inserted replaced
2438:f2b3cfcc23d3 2439:06da5db2fafe
1 import { css, html, LitElement, PropertyValueMap } from "lit";
2 import { customElement, property, state } from "lit/decorators.js";
3 import Sylvester from "sylvester";
4 import { Zoom } from "../light9-timeline-audio";
5 import { PlainViewState } from "../Light9CursorCanvas";
6 import { getTopGraph } from "../RdfdbSyncedGraph";
7 import { show } from "../show_specific";
8 import { SyncedGraph } from "../SyncedGraph";
9 import { PlayerState } from "./PlayerState";
10 export { Light9TimelineAudio } from "../light9-timeline-audio";
11 export { Light9CursorCanvas } from "../Light9CursorCanvas";
12 export { RdfdbSyncedGraph } from "../RdfdbSyncedGraph";
13 export { ResourceDisplay } from "../ResourceDisplay";
14
15 const $V = Sylvester.Vector.create;
16
17 async function postJson(url: string, jsBody: Object) {
18 return fetch(url, {
19 method: "POST",
20 headers: { "Content-Type": "applcation/json" },
21 body: JSON.stringify(jsBody),
22 });
23 }
24
25 @customElement("light9-ascoltami-timeline")
26 export class Light9AscoltamiTimeline extends LitElement {
27 static styles = [
28 css`
29 .timeRow {
30 margin: 14px;
31 position: relative;
32 }
33 #overview {
34 height: 60px;
35 }
36 #zoomed {
37 margin-top: 40px;
38 height: 80px;
39 }
40 #cursor {
41 position: absolute;
42 left: 0;
43 top: 0;
44 width: 100%;
45 height: 100%;
46 }
47 `,
48 ];
49 graph!: SyncedGraph;
50 @property() playerState: PlayerState = {
51 duration: null,
52 endOfSong: null,
53 pausedSongTime: null,
54 playing: null,
55 song: null,
56 wallStartTime: null,
57 };
58 @property() playerTime: number = 0;
59 @state() zoom: Zoom;
60 @state() overviewZoom: Zoom;
61 @state() viewState: PlainViewState | null = null;
62 constructor() {
63 super();
64 getTopGraph().then((g) => {
65 this.graph = g;
66 });
67 this.zoom = this.overviewZoom = { duration: null, t1: 0, t2: 1 };
68 }
69 protected willUpdate(_changedProperties: PropertyValueMap<this>): void {
70 super.willUpdate(_changedProperties);
71 if ((_changedProperties.has("playerState") || _changedProperties.has("playerTime")) && this.playerState !== null) {
72 const duration = this.playerState.duration;
73 const t = this.playerTime;
74 if (duration !== null) {
75 const timeRow = this.shadowRoot!.querySelector(".timeRow") as HTMLDivElement;
76 if (timeRow != null) {
77 this.updateZooms(duration, t, timeRow);
78 }
79 }
80 }
81 }
82
83 updateZooms(duration: number, t: number, timeRow: HTMLDivElement) {
84 this.overviewZoom = { duration: duration, t1: 0, t2: duration };
85 const t1 = t - 2;
86 const t2 = t + 20;
87 this.zoom = { duration: duration, t1, t2 };
88 const w = timeRow.offsetWidth;
89 this.viewState = {
90 zoomSpec: { t1: () => t1, t2: () => t2 },
91 cursor: { t: () => t },
92 audioY: () => 0,
93 audioH: () => 60,
94 zoomedTimeY: () => 60,
95 zoomedTimeH: () => 40,
96 fullZoomX: (sec: number) => (sec / duration) * w,
97 zoomInX: (sec: number) => ((sec - t1) / (t2 - t1)) * w,
98 mouse: { pos: () => $V([0, 0]) },
99 };
100 }
101
102 render() {
103 const song = this.playerState?.song;
104 if (!song) return html`(spectrogram)`;
105 return html`
106 <div class="timeRow">
107 <div id="timeSlider"></div>
108 <light9-timeline-audio id="overview" .show=${show} .song=${song} .zoom=${this.overviewZoom}> </light9-timeline-audio>
109 <light9-timeline-audio id="zoomed" .show=${show} .song=${song} .zoom=${this.zoom}></light9-timeline-audio>
110 <light9-cursor-canvas id="cursor" .viewState=${this.viewState}></light9-cursor-canvas>
111 </div>
112 `;
113 }
114 }