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
|
import * as React from "react";
import * as ReactDOM from "react-dom";
import "./Timeline.scss";
import { CollectionSubView } from "../collections/CollectionSubView";
import { Document, listSpec, createSchema, makeInterface, defaultSpec } from "../../../new_fields/Schema";
import { observer} from "mobx-react";
import { Track } from "./Track";
import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, Reaction } from "mobx";
import { Cast } from "../../../new_fields/Types";
import { SelectionManager } from "../../util/SelectionManager";
import { List } from "../../../new_fields/List";
import { Self } from "../../../new_fields/FieldSymbols";
import { Doc } from "../../../new_fields/Doc";
@observer
export class Timeline extends CollectionSubView(Document){
@observable private _scrubberbox = React.createRef<HTMLDivElement>()
@observable private _currentBarX:number = 0;
@observable private _windSpeed:number = 1;
@observable private _isPlaying:boolean = false;
@observable private _boxLength:number = 0;
@observable private _nodes:List<Doc> = new List<Doc>();
private _reactionDisposers: IReactionDisposer[] = [];
@action
componentDidMount(){
let scrubber = this._scrubberbox.current!;
this._boxLength = scrubber.getBoundingClientRect().width;
let children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc));
if (!children) {
return;
}
let childrenList = ((children[Self] as any).__fields) as List<Doc>;
this._nodes = childrenList;
}
componentWillUnmount(){
}
@action
onPlay = async (e: React.MouseEvent) => {
if (this._isPlaying) {
this._isPlaying = false;
} else {
this._isPlaying = true;
this.changeCurrentX();
}
}
@action
changeCurrentX = () => {
if (this._currentBarX >= this._boxLength && this._isPlaying) {
this._currentBarX = 0;
}
if (this._currentBarX <= this._boxLength && this._isPlaying) {
this._currentBarX = this._currentBarX + this._windSpeed;
setTimeout(this.changeCurrentX, 15);
}
}
@action
windForward = (e: React.MouseEvent) => {
if (this._windSpeed < 64) { //max speed is 32
this._windSpeed = this._windSpeed * 2;
}
}
@action
windBackward = (e: React.MouseEvent) => {
if (this._windSpeed > 1 / 16) { // min speed is 1/8
this._windSpeed = this._windSpeed / 2;
}
}
@action
onScrubberDown = (e:React.PointerEvent) => {
let scrubberbox = this._scrubberbox.current!;
let left = scrubberbox.getBoundingClientRect().left;
let offsetX = Math.round(e.clientX - left);
this._currentBarX = offsetX;
}
render(){
return (
<div className="timeline-container">
<div className="toolbox">
<button onClick={this.windBackward}> {"<"} </button>
<button onClick={this.onPlay}> Play </button>
<button onClick={this.windForward}> {">"} </button>
</div>
<div className="scrubberbox" onPointerDown={this.onScrubberDown} ref ={this._scrubberbox}>
<div className="scrubber" style={{transform:`translate(${this._currentBarX}px)`}}></div>
</div>
<div className="trackbox">
{this._nodes.map(doc => {return <Track {...this.props}/>})}
</div>
</div>
);
}
}
|