Files
@ 90792e984249
Branch filter:
Location: light9/web/timeline/viewstate.ts
90792e984249
3.9 KiB
video/MP2T
isolate import warnings to one file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | import * as ko from "knockout";
import * as d3 from "d3";
import debug from "debug";
const log = debug("viewstate");
export class ViewState {
zoomSpec: {
duration: ko.Observable<number>; // current song duration
t1: ko.Observable<number>;
t2: ko.Observable<number>;
};
cursor: { t: ko.Observable<number> };
mouse: { pos: ko.Observable<Vector> };
width: ko.Observable<number>;
coveredByDiagramTop: ko.Observable<number>;
audioY: ko.Observable<number>;
audioH: ko.Observable<number>;
zoomedTimeY: ko.Observable<number>;
zoomedTimeH: ko.Observable<number>;
rowsY: ko.Observable<number>;
fullZoomX: d3.ScaleLinear<number, number>;
zoomInX: d3.ScaleLinear<number, number>;
zoomAnimSec: number;
constructor() {
// caller updates all these observables
this.zoomSpec = {
duration: ko.observable(100), // current song duration
t1: ko.observable(0),
t2: ko.observable(100),
};
this.cursor = { t: ko.observable(20) }; // songTime
this.mouse = { pos: ko.observable($V([0, 0])) };
this.width = ko.observable(500);
this.coveredByDiagramTop = ko.observable(0); // page coords
// all these are relative to #coveredByDiagram:
this.audioY = ko.observable(0);
this.audioH = ko.observable(0);
this.zoomedTimeY = ko.observable(0);
this.zoomedTimeH = ko.observable(0);
this.rowsY = ko.observable(0);
this.fullZoomX = d3.scaleLinear();
this.zoomInX = d3.scaleLinear();
this.zoomAnimSec = 0.1;
ko.computed(this.maintainZoomLimitsAndScales.bind(this));
}
setWidth(w: any) {
this.width(w);
this.maintainZoomLimitsAndScales(); // before other handlers run
}
maintainZoomLimitsAndScales() {
// not for cursor updates
if (this.zoomSpec.t1() < 0) {
this.zoomSpec.t1(0);
}
if (this.zoomSpec.duration() && this.zoomSpec.t2() > this.zoomSpec.duration()) {
this.zoomSpec.t2(this.zoomSpec.duration());
}
const rightPad = 5; // don't let time adjuster fall off right edge
this.fullZoomX.domain([0, this.zoomSpec.duration()]);
this.fullZoomX.range([0, this.width() - rightPad]);
this.zoomInX.domain([this.zoomSpec.t1(), this.zoomSpec.t2()]);
this.zoomInX.range([0, this.width() - rightPad]);
}
latestMouseTime(): number {
return this.zoomInX.invert(this.mouse.pos().e(1));
}
onMouseWheel(deltaY: any) {
const zs = this.zoomSpec;
const center = this.latestMouseTime();
const left = center - zs.t1();
const right = zs.t2() - center;
const scale = Math.pow(1.005, deltaY);
zs.t1(center - left * scale);
zs.t2(center + right * scale);
log("view to", ko.toJSON(this));
}
frameCursor() {
const zs = this.zoomSpec;
const visSeconds = zs.t2() - zs.t1();
const margin = visSeconds * 0.4;
// buggy: really needs t1/t2 to limit their ranges
if (this.cursor.t() < zs.t1() || this.cursor.t() > zs.t2() - visSeconds * 0.6) {
const newCenter = this.cursor.t() + margin;
this.animatedZoom(newCenter - visSeconds / 2, newCenter + visSeconds / 2, this.zoomAnimSec);
}
}
frameToEnd() {
this.animatedZoom(this.cursor.t() - 2, this.zoomSpec.duration(), this.zoomAnimSec);
}
frameAll() {
this.animatedZoom(0, this.zoomSpec.duration(), this.zoomAnimSec);
}
animatedZoom(newT1: number, newT2: number, secs: number) {
const fps = 30;
const oldT1 = this.zoomSpec.t1();
const oldT2 = this.zoomSpec.t2();
let lastTime = 0;
for (let step = 0; step < secs * fps; step++) {
const frac = step / (secs * fps);
((frac) => {
const gotoStep = () => {
this.zoomSpec.t1((1 - frac) * oldT1 + frac * newT1);
return this.zoomSpec.t2((1 - frac) * oldT2 + frac * newT2);
};
const delay = frac * secs * 1000;
setTimeout(gotoStep, delay);
lastTime = delay;
})(frac);
}
setTimeout(() => {
this.zoomSpec.t1(newT1);
return this.zoomSpec.t2(newT2);
}, lastTime + 10);
}
}
|