diff options
Diffstat (limited to 'src/client/views/nodes/Timeline.tsx')
-rw-r--r-- | src/client/views/nodes/Timeline.tsx | 140 |
1 files changed, 109 insertions, 31 deletions
diff --git a/src/client/views/nodes/Timeline.tsx b/src/client/views/nodes/Timeline.tsx index fd235fad3..1c51dbcad 100644 --- a/src/client/views/nodes/Timeline.tsx +++ b/src/client/views/nodes/Timeline.tsx @@ -1,12 +1,11 @@ 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, IObservableObject } from "mobx"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, NumCast } from "../../../new_fields/Types"; import { SelectionManager } from "../../util/SelectionManager"; import { List } from "../../../new_fields/List"; import { Self } from "../../../new_fields/FieldSymbols"; @@ -16,29 +15,39 @@ import { faCircle, faPlayCircle, faBackward, faForward, faGripLines } from "@for import { DocumentContentsView } from "./DocumentContentsView"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; +import { string } from "prop-types"; export interface FlyoutProps { x?: number; y?: number; display?: string; - time?: number; - duration?: number; + regiondata?:Doc; + regions?:List<Doc>; } @observer export class Timeline extends CollectionSubView(Document) { private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; + private readonly DEFAULT_TICK_SPACING:number = 50; private readonly MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; - - @observable private _tickSpacing = 50; + + @observable private _isMinimized = false; + @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; @observable private _scrubberbox = React.createRef<HTMLDivElement>(); + @observable private _scrubber = React.createRef<HTMLDivElement>(); @observable private _trackbox = React.createRef<HTMLDivElement>(); @observable private _titleContainer = React.createRef<HTMLDivElement>(); @observable private _timelineContainer = React.createRef<HTMLDivElement>(); + @observable private _timeInput = React.createRef<HTMLInputElement>(); + @observable private _durationInput = React.createRef<HTMLInputElement>(); + @observable private _fadeInInput = React.createRef<HTMLInputElement>(); + @observable private _fadeOutInput = React.createRef<HTMLInputElement>(); + + @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; @@ -50,7 +59,7 @@ export class Timeline extends CollectionSubView(Document) { @observable private _infoContainer = React.createRef<HTMLDivElement>(); @observable private _ticks: number[] = []; - @observable private flyoutInfo: FlyoutProps = { x: 0, y: 0, display: "none" }; + @observable private flyoutInfo: FlyoutProps = { x: 0, y: 0, display: "none", regiondata: new Doc(), regions: new List<Doc>()}; private block = false; @@ -80,6 +89,10 @@ export class Timeline extends CollectionSubView(Document) { document.addEventListener("pointerdown", this.closeFlyout); } + @action + changeCurrentBarX = (x: number) => { + this._currentBarX = x; + } @action onFlyoutDown = (e: React.PointerEvent) => { this.flyoutInfo.display = "block"; @@ -169,19 +182,7 @@ export class Timeline extends CollectionSubView(Document) { this._currentBarX = offset; } - @action - toTime = (time: number): string => { - const inSeconds = time / 1000; - let min: (string | number) = Math.floor(inSeconds / 60); - let sec: (string | number) = inSeconds % 60; - - if (Math.floor(sec / 10) === 0) { - sec = "0" + sec; - } - return `${min}:${sec}`; - - } - + @action onPanDown = (e: React.PointerEvent) => { @@ -205,8 +206,6 @@ export class Timeline extends CollectionSubView(Document) { titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; } - - @action onResizeDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -231,7 +230,24 @@ export class Timeline extends CollectionSubView(Document) { } } - @observable private _isMinimized = false; + @action + onTimelineDown = (e:React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.addEventListener("pointermove", this.onTimelineMove); + document.addEventListener("pointerup", () => {document.removeEventListener("pointermove", this.onTimelineMove);}); + } + + @action + onTimelineMove = (e:PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let timelineContainer = this._timelineContainer.current!; + timelineContainer.style.transform = `translate(${timelineContainer.getBoundingClientRect().left + 1}px, ${timelineContainer.getBoundingClientRect().top + 1}px)`; + console.log("mouse move!"); + timelineContainer.style.width = "500px"; + } + @action minimize = (e: React.MouseEvent) => { e.preventDefault(); @@ -246,6 +262,17 @@ export class Timeline extends CollectionSubView(Document) { } } + @action + toTime = (time: number): string => { + const inSeconds = time / 1000; + let min: (string | number) = Math.floor(inSeconds / 60); + let sec: (string | number) = inSeconds % 60; + + if (Math.floor(sec / 10) === 0) { + sec = "0" + sec; + } + return `${min}:${sec}`; + } @action getFlyout = (props: FlyoutProps) => { @@ -265,15 +292,63 @@ export class Timeline extends CollectionSubView(Document) { }), icon: "pinterest" }); ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems }); + + } + + @action + changeTime = (e: React.KeyboardEvent) => { + let time = this._timeInput.current!; + if (e.keyCode === 13){ + if (!Number.isNaN(Number(time.value))){ + this.flyoutInfo.regiondata!.position = Number(time.value) / 1000 * this._tickSpacing; + time.placeholder = time.value +"ms"; + time.value = ""; + } + } + } + + + @action + changeDuration = (e:React.KeyboardEvent) => { + let duration = this._durationInput.current!; + if (e.keyCode === 13){ + if (!Number.isNaN(Number(duration.value))){ + this.flyoutInfo.regiondata!.duration = Number(duration.value) / 1000 * this._tickSpacing; + duration.placeholder = duration.value +"ms"; + duration.value = ""; + } + } + } + + @action + changeFadeIn = (e:React.KeyboardEvent) => { + let fadeIn = this._fadeInInput.current!; + if (e.keyCode === 13){ + if (!Number.isNaN(Number(fadeIn.value))){ + this.flyoutInfo.regiondata!.fadeIn = Number(fadeIn.value); + fadeIn.placeholder = fadeIn.value +"ms"; + fadeIn.value = ""; + } + } } + @action + changeFadeOut = (e:React.KeyboardEvent) => { + let fadeOut = this._fadeOutInput.current!; + if (e.keyCode === 13){ + if (!Number.isNaN(Number(fadeOut.value))){ + this.flyoutInfo.regiondata!.fadeOut = Number(fadeOut.value); + fadeOut.placeholder = fadeOut.value +"ms"; + fadeOut.value = ""; + } + } + } render() { return ( <div> <button className="minimize" onClick={this.minimize}>Minimize</button> - <div className="timeline-container" style={{ height: `${this._containerHeight}px` }} ref={this._timelineContainer} onContextMenu={this.timelineContextMenu}> - <div className="flyout-container" style={{ transform: `translate(${this.flyoutInfo.x}px, ${this.flyoutInfo.y}px)`, display: this.flyoutInfo.display }} onPointerDown={this.onFlyoutDown}> + <div className="flyout-container" style={{left:`${this.flyoutInfo.x}px`, top:`${this.flyoutInfo.y}px`, display: `${this.flyoutInfo.display!}` }} onPointerDown={this.onFlyoutDown}> <FontAwesomeIcon className="flyout" icon="comment-alt" color="grey" /> <div className="text-container"> <p>Time:</p> @@ -282,12 +357,15 @@ export class Timeline extends CollectionSubView(Document) { <p>Fade-out</p> </div> <div className="input-container"> - <input type="text" placeholder={`${Math.round(this.flyoutInfo.time! / this._tickSpacing * 1000)}ms`} /> - <input type="text" placeholder={`${Math.round(this.flyoutInfo.duration! / this._tickSpacing * 1000)}ms`} /> - <input type="text" placeholder={`${Math.round(this.flyoutInfo.time! / this._tickSpacing * 1000)}ms`} /> - <input type="text" placeholder={`${Math.round(this.flyoutInfo.duration! / this._tickSpacing * 1000)}ms`} /> + <input ref = {this._timeInput} type="text" placeholder={`${Math.round(NumCast(this.flyoutInfo.regiondata!.position)/ this._tickSpacing * 1000)}ms`} onKeyDown={this.changeTime} /> + <input ref = {this._durationInput} type="text" placeholder={`${Math.round(NumCast(this.flyoutInfo.regiondata!.duration) / this._tickSpacing * 1000)}ms`} onKeyDown={this.changeDuration}/> + <input ref = {this._fadeInInput} type="text" placeholder={`${Math.round(NumCast(this.flyoutInfo.regiondata!.fadeIn))}ms`} onKeyDown={this.changeFadeIn}/> + <input ref = {this._fadeOutInput} type="text" placeholder={`${Math.round(NumCast(this.flyoutInfo.regiondata!.fadeOut))}ms`} onKeyDown={this.changeFadeOut}/> + </div> + <button onClick={action((e:React.MouseEvent)=>{this.flyoutInfo.regions!.splice(this.flyoutInfo.regions!.indexOf(this.flyoutInfo.regiondata!), 1); this.flyoutInfo.display = "none";})}>delete</button> </div> + <div className="timeline-container" style={{ height: `${this._containerHeight}px` }} ref={this._timelineContainer} onContextMenu={this.timelineContextMenu} > <div className="toolbox"> <div onClick={this.windBackward}> <FontAwesomeIcon icon={faBackward} size="2x" /> </div> <div onClick={this.onPlay}> <FontAwesomeIcon icon={faPlayCircle} size="2x" /> </div> @@ -304,12 +382,12 @@ export class Timeline extends CollectionSubView(Document) { return <div className="tick" style={{ transform: `translate(${element / 1000 * this._tickSpacing}px)`, position: "absolute", pointerEvents: "none" }}> <p>{this.toTime(element)}</p></div>; })} </div> - <div className="scrubber" onPointerDown={this.onScrubberDown} style={{ transform: `translate(${this._currentBarX}px)` }}> + <div className="scrubber" ref={this._scrubber} onPointerDown={this.onScrubberDown} style={{ transform: `translate(${this._currentBarX}px)` }}> <div className="scrubberhead"></div> </div> <div className="trackbox" ref={this._trackbox} onPointerDown={this.onPanDown}> {this._nodes.map(doc => { - return <Track node={(doc as any).value() as Doc} currentBarX={this._currentBarX} setFlyout={this.getFlyout} />; + return <Track node={(doc as any).value() as Doc} currentBarX={this._currentBarX} changeCurrentBarX = {this.changeCurrentBarX} setFlyout={this.getFlyout} />; })} </div> </div> |