aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/Keyframe.scss4
-rw-r--r--src/client/views/nodes/Keyframe.tsx364
-rw-r--r--src/client/views/nodes/Timeline.scss13
-rw-r--r--src/client/views/nodes/Timeline.tsx265
-rw-r--r--src/client/views/nodes/Track.tsx257
5 files changed, 473 insertions, 430 deletions
diff --git a/src/client/views/nodes/Keyframe.scss b/src/client/views/nodes/Keyframe.scss
index 2410dceaf..44850cd64 100644
--- a/src/client/views/nodes/Keyframe.scss
+++ b/src/client/views/nodes/Keyframe.scss
@@ -82,4 +82,8 @@
position:absolute;
}
+
}
+
+
+
diff --git a/src/client/views/nodes/Keyframe.tsx b/src/client/views/nodes/Keyframe.tsx
index 76955da99..ed1f3b03a 100644
--- a/src/client/views/nodes/Keyframe.tsx
+++ b/src/client/views/nodes/Keyframe.tsx
@@ -1,87 +1,81 @@
import * as React from "react";
-import * as ReactDOM from "react-dom";
import "./Keyframe.scss";
-import "./../globalCssVariables.scss";
-import { observer } from "mobx-react";
-import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS } from "mobx";
+import "./Timeline.scss";
+import "./../globalCssVariables.scss";
+import { observer, Observer } from "mobx-react";
+import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, isComputedProp } from "mobx";
import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { auto } from "async";
import { Cast, FieldValue, StrCast, NumCast } from "../../../new_fields/Types";
-import { StandardLonghandProperties } from "csstype";
-import { runInThisContext } from "vm";
-import { DateField } from "../../../new_fields/DateField";
-import { DocumentManager } from "../../util/DocumentManager";
-import { DocumentView } from "./DocumentView";
-import { anchorPoints, Flyout } from "../TemplateMenu";
-import { LinkMenu } from "./LinkMenu";
-import { faCircle } from "@fortawesome/free-solid-svg-icons";
-import { node, number } from "prop-types";
import { List } from "../../../new_fields/List";
import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema";
-import { CollectionBaseView } from "../collections/CollectionBaseView";
-import { notDeepEqual } from "assert";
-import { DocUtils, Docs } from "../../documents/Documents";
-import { DragLinksAsDocuments } from "../../util/DragManager";
-
-
-
+enum Direction {
+ left = "left",
+ right = "right"
+}
interface IProp {
node: Doc;
- keyframedata: Doc;
+ RegionData: Doc;
+ // routine: (innerFunc: () => void, args: any) => void;
}
-const KeyDataSchema = createSchema({});
-
-const TimeAndKeyDataSchema = createSchema({
+const KeyframeDataSchema = createSchema({
time: defaultSpec("number", 0),
key: Doc
});
-
-type KeyData = makeInterface<[typeof KeyDataSchema]>;
-type TimeAndKey = makeInterface<[typeof TimeAndKeyDataSchema]>;
-const KeyData = makeInterface(KeyDataSchema);
-const TimeAndKey = makeInterface(TimeAndKeyDataSchema);
+type KeyframeData = makeInterface<[typeof KeyframeDataSchema]>;
+const KeyframeData = makeInterface(KeyframeDataSchema);
-const KeyframeDataSchema = createSchema({
+const RegionDataSchema = createSchema({
position: defaultSpec("number", 0),
duration: defaultSpec("number", 0),
- kfs: listSpec(Doc)
-});
-
-type KeyframeData = makeInterface<[typeof KeyframeDataSchema]>;
-export const KeyframeData = makeInterface(KeyframeDataSchema);
-
+ keyframes: listSpec(Doc)
+});
+type RegionData = makeInterface<[typeof RegionDataSchema]>;
+export const RegionData = makeInterface(RegionDataSchema);
-@observer
-export class Keyframe extends React.Component<IProp> {
+interface FlyoutInfo {
+ position: number;
+ fadeIn: number;
+ fadeOut: number;
+}
- @observable private _display:string = "none";
- @observable private _duration:number = 200;
- @observable private _bar = React.createRef<HTMLDivElement>();
- @observable private _keyframes:number[] = [];
+const FlyoutObj = {
+ position: 0,
+ fadeIn: 0,
+ fadeOut: 1
+};
- private _reactionDisposers: IReactionDisposer[] = [];
- private _selectionManagerChanged?: IReactionDisposer;
+export var FlyoutInfoContext = React.createContext<FlyoutInfo>(FlyoutObj);
+@observer
+export class Keyframe extends React.Component<IProp> {
+ @observable private _display: string = "none";
+ @observable private _bar = React.createRef<HTMLDivElement>();
+ @observable private _keyframes: number[] = [];
+ @observable private position: number = 0;
+ @observable private fadein: number = 0;
+ @observable private fadeout: number = 0;
@action
componentDidMount() {
-
+
// need edge case here when keyframe data already exists when loading.....................;
- // let keyframes = Cast(this.props.node.keyframes, listSpec(Doc)) as List<Doc>;
- // if keyframes.indexOf()
+ this.fadein = 100;
+ FlyoutInfoContext = React.createContext<FlyoutInfo>({position: this.position,
+ fadeIn: this.fadein,
+ fadeOut: this.fadeout});
}
componentWillUnmount() {
-
+
}
-
+
// @action
// onPointerEnter = (e: React.PointerEvent) => {
// e.preventDefault();
@@ -96,138 +90,168 @@ export class Keyframe extends React.Component<IProp> {
// //this._display = "none";
// }
+
+ @computed
+ private get regiondata() {
+ let index = this.regions.indexOf(this.props.RegionData);
+ return RegionData(this.regions[index] as Doc);
+ }
+
@computed
- private get keyframes() {
- return Cast(this.props.node.keyframes, listSpec(Doc)) as List<Doc>;
+ private get regions() {
+ return Cast(this.props.node.regions, listSpec(Doc)) as List<Doc>;
}
- @action
+
+
+ @action
makeKeyData = (kfpos: number) => { //Kfpos is mouse offsetX, representing time
- let hasData = false;
- this.kfd.kfs!.forEach(TK => { //TK is TimeAndKey
- TK = TK as Doc;
- if (TK.time === kfpos){
- hasData = true;
+ let hasData = false;
+ this.regiondata.keyframes!.forEach(TK => { //TK is TimeAndKey
+ TK = TK as Doc;
+ if (TK.time === kfpos) {
+ hasData = true;
}
- });
- if (!hasData){
- let TK:Doc = new Doc();
- TK.time = kfpos;
- TK.key = Doc.MakeCopy(this.props.node);
- this.kfd.kfs!.push(TK);
- }
-
+ });
+ if (!hasData) {
+ let TK: Doc = new Doc();
+ TK.time = kfpos;
+ TK.key = Doc.MakeCopy(this.props.node);
+ this.regiondata.keyframes!.push(TK);
+ }
+
}
- @computed
- private get kfd(){
- let index = this.keyframes.indexOf(this.props.keyframedata);
- return KeyframeData(this.keyframes[index] as Doc);
- }
- @action
+ @action
onBarPointerDown = (e: React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onBarPointerMove);
- document.addEventListener("pointerup", (e:PointerEvent) => {
- document.removeEventListener("pointermove", this.onBarPointerMove);
- });
- }
-
- @action
- onBarPointerMove = (e:PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- if (this.kfd.position >= 0){
- let futureX = this.kfd.position + e.movementX;
- if (futureX <= 0){
- this.kfd.position = 0;
- } else{
- this.kfd.position += e.movementX;
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onBarPointerMove);
+ document.addEventListener("pointerup", (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.onBarPointerMove);
+ });
+ }
+
+ @action
+ onBarPointerMove = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let left = this.findAdjacentRegion(Direction.left);
+ let right = this.findAdjacentRegion(Direction.right);
+ let futureX = this.regiondata.position + e.movementX;
+ if (futureX <= 0) {
+ this.regiondata.position = 0;
+ } else if ((left && left.position + left.duration >= futureX)) {
+ this.regiondata.position = left.position + left.duration;
+ } else if ((right && right.position <= futureX + this.regiondata.duration)) {
+ this.regiondata.position = right.position - this.regiondata.duration;
+ } else {
+ this.regiondata.position = futureX;
+ }
+
+ }
+
+ @action
+ findAdjacentRegion = (dir: Direction): (RegionData | undefined) => {
+ let leftMost: (RegionData | undefined) = undefined;
+ let rightMost: (RegionData | undefined) = undefined;
+ this.regions.forEach(region => {
+ let neighbor = RegionData(region as Doc);
+ if (this.regiondata.position > neighbor.position) {
+ if (!leftMost || neighbor.position > leftMost.position) {
+ leftMost = neighbor;
+ }
+ } else if (this.regiondata.position < neighbor.position) {
+ if (!rightMost || neighbor.position < rightMost.position) {
+ rightMost = neighbor;
+ }
}
+ });
+ if (dir === Direction.left) {
+ return leftMost;
+ } else if (dir === Direction.right) {
+ return rightMost;
}
}
- @action
- onResizeLeft = (e:React.PointerEvent)=>{
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onDragResizeLeft);
- document.addEventListener("pointerup", ()=>{
+ @action
+ onResizeLeft = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onDragResizeLeft);
+ document.addEventListener("pointerup", () => {
document.removeEventListener("pointermove", this.onDragResizeLeft);
- });
+ });
}
- @action
- onResizeRight = (e:React.PointerEvent)=> {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onDragResizeRight);
- document.addEventListener("pointerup", ()=>{
+ @action
+ onResizeRight = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onDragResizeRight);
+ document.addEventListener("pointerup", () => {
document.removeEventListener("pointermove", this.onDragResizeRight);
- });
- }
-
- @action
- onDragResizeLeft = (e:PointerEvent)=>{
- e.preventDefault();
- e.stopPropagation();
- let bar = this._bar.current!;
- let barX = bar.getBoundingClientRect().left;
- let offset = e.clientX - barX;
- this._duration -= offset;
- this.kfd.position += offset;
- this.kfd.kfs!.forEach(kf => {
- kf = kf as Doc;
- kf.time = NumCast(kf.time) + offset;
- });
+ });
+ }
+
+ @action
+ onDragResizeLeft = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let bar = this._bar.current!;
+ let barX = bar.getBoundingClientRect().left;
+ let offset = e.clientX - barX;
+ this.regiondata.duration -= offset;
+ this.regiondata.position += offset;
+ this.regiondata.keyframes!.forEach(kf => {
+ kf = kf as Doc;
+ kf.time = NumCast(kf.time) + offset;
+ });
this._keyframes.forEach(num => {
- num += offset;
- });
- }
-
-
- @action
- onDragResizeRight = (e:PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- let bar = this._bar.current!;
- let barX = bar.getBoundingClientRect().right;
- let offset = e.clientX - barX;
- console.log(offset);
- this._duration += offset;
- this.kfd.duration = this._duration;
- }
-
- createDivider = (type?: string):JSX.Element => {
- if (type === "left"){
- return <div className="divider" style={{right:"0px"}}></div>;
- } else if (type === "right"){
- return <div className="divider" style={{left:"0px"}}> </div>;
+ num -= offset;
+ });
+ }
+
+
+ @action
+ onDragResizeRight = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let bar = this._bar.current!;
+ let barX = bar.getBoundingClientRect().right;
+ let offset = e.clientX - barX;
+ console.log(offset);
+ this.regiondata.duration += offset;
+ }
+
+ createDivider = (type?: string): JSX.Element => {
+ if (type === "left") {
+ return <div className="divider" style={{ right: "0px" }}></div>;
+ } else if (type === "right") {
+ return <div className="divider" style={{ left: "0px" }}> </div>;
}
- return <div className="divider"></div>;
+ return <div className="divider"></div>;
}
@action
createKeyframe = (e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
+ e.preventDefault();
+ e.stopPropagation();
let mouse = e.nativeEvent;
- let position = NumCast(this.props.keyframedata.position);
- this._keyframes.push(mouse.offsetX);
- this.makeKeyData(position + mouse.offsetX);
-
+ let position = NumCast(this.regiondata.position);
+ this._keyframes.push(mouse.offsetX);
+ this.makeKeyData(position + mouse.offsetX);
}
- @action
+ @action
onMenuHover = (e: React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- if (this._display === "none"){
- this._display = "grid";
+ e.preventDefault();
+ e.stopPropagation();
+ if (this._display === "none") {
+ this._display = "grid";
} else {
- this._display = "none";
+ this._display = "none";
}
}
@@ -236,18 +260,26 @@ export class Keyframe extends React.Component<IProp> {
render() {
return (
<div>
- <div className="bar" ref={this._bar} style={{ transform: `translate(${this.props.keyframedata.position}px)`, width:`${this._duration}px`}} onPointerDown={this.onBarPointerDown} onDoubleClick={this.createKeyframe}>
- <div className="leftResize" onPointerDown={this.onResizeLeft} ></div>
- <div className="rightResize" onPointerDown={this.onResizeRight}></div>
- <div className="fadeLeft" style={{width:`${20}px`}}>{this.createDivider("left")}</div>
- <div className="fadeRight" style={{width:`${20}px`}}>{this.createDivider("right")}</div>
- {this._keyframes.map(kf => {return <div className="keyframe" style={{left: `${kf}px`}}>
- {this.createDivider()}
- <div className="keyframeCircle"></div>
- </div>;})}
- {this.createDivider("left")}
- {this.createDivider("right")}
- </div>
+ <FlyoutInfoContext.Provider value={{
+ position: this.position,
+ fadeOut: this.fadeout,
+ fadeIn: this.fadein
+ }}>
+ <div className="bar" ref={this._bar} style={{ transform: `translate(${this.regiondata.position}px)`, width: `${this.regiondata.duration}px` }} onPointerDown={this.onBarPointerDown} onDoubleClick={this.createKeyframe}>
+ <div className="leftResize" onPointerDown={this.onResizeLeft} ></div>
+ <div className="rightResize" onPointerDown={this.onResizeRight}></div>
+ <div className="fadeLeft" style={{ width: `${20}px` }}>{this.createDivider("left")}</div>
+ <div className="fadeRight" style={{ width: `${20}px` }}>{this.createDivider("right")}</div>
+ {this._keyframes.map(kf => {
+ return <div className="keyframe" style={{ left: `${kf}px` }}>
+ {this.createDivider()}
+ <div className="keyframeCircle"></div>
+ </div>;
+ })}
+ {this.createDivider("left")}
+ {this.createDivider("right")}
+ </div>
+ </FlyoutInfoContext.Provider>
</div>
);
}
diff --git a/src/client/views/nodes/Timeline.scss b/src/client/views/nodes/Timeline.scss
index d89fce7fc..d59ed1323 100644
--- a/src/client/views/nodes/Timeline.scss
+++ b/src/client/views/nodes/Timeline.scss
@@ -1,5 +1,18 @@
@import "./../globalCssVariables.scss";
+.flyout{
+ position: absolute;
+ z-index: 9999;
+ background-color: black;
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
+ min-width: 150px;
+ color: black;
+ top: 100px;
+
+ padding: 10px;
+ border-radius: 3px;
+}
+
.timeline-container{
width:100%;
height:300px;
diff --git a/src/client/views/nodes/Timeline.tsx b/src/client/views/nodes/Timeline.tsx
index e6b57ec75..02c2a530d 100644
--- a/src/client/views/nodes/Timeline.tsx
+++ b/src/client/views/nodes/Timeline.tsx
@@ -1,9 +1,9 @@
-import * as React from "react";
-import * as ReactDOM from "react-dom";
-import "./Timeline.scss";
+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 { 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";
@@ -14,35 +14,37 @@ import { Doc, DocListCast } from "../../../new_fields/Doc";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCircle, faPlayCircle, faBackward, faForward, faGripLines } from "@fortawesome/free-solid-svg-icons";
import { DocumentContentsView } from "./DocumentContentsView";
+import { FlyoutInfoContext } from "./Keyframe";
@observer
-export class Timeline extends CollectionSubView(Document){
- private readonly DEFAULT_CONTAINER_HEIGHT:number = 300;
- private readonly MIN_CONTAINER_HEIGHT:number = 205;
- private readonly MAX_CONTAINER_HEIGHT:number = 800;
+export class Timeline extends CollectionSubView(Document) {
+ private readonly DEFAULT_CONTAINER_HEIGHT: number = 300;
+ private readonly MIN_CONTAINER_HEIGHT: number = 205;
+ private readonly MAX_CONTAINER_HEIGHT: number = 800;
@observable private _scrubberbox = React.createRef<HTMLDivElement>();
- @observable private _trackbox = React.createRef<HTMLDivElement>();
- @observable private _titleContainer = 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 _containerHeight:number = this.DEFAULT_CONTAINER_HEIGHT;
- @observable private _nodes:List<Doc> = new List<Doc>();
+ @observable private _trackbox = React.createRef<HTMLDivElement>();
+ @observable private _titleContainer = 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 _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT;
+ @observable private _nodes: List<Doc> = new List<Doc>();
@observable private _time = 100000; //DEFAULT
- @observable private _infoContainer = React.createRef<HTMLDivElement>();
- @observable private _ticks: number[] = [];
+ @observable private _infoContainer = React.createRef<HTMLDivElement>();
+ @observable private _ticks: number[] = [];
+
@action
- componentDidMount(){
- let scrubber = this._scrubberbox.current!;
- this._boxLength = scrubber.getBoundingClientRect().width;
+ 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;
@@ -50,26 +52,26 @@ export class Timeline extends CollectionSubView(Document){
let childrenList = ((children[Self] as any).__fields) as List<Doc>;
this._nodes = (childrenList) as List<Doc>;
- reaction( () => this._time, time => {
- let infoContainer = this._infoContainer.current!;
- let trackbox = this._trackbox.current!;
- this._boxLength = infoContainer.scrollWidth;
- trackbox.style.width = `${this._boxLength}`;
- });
+ reaction(() => this._time, time => {
+ let infoContainer = this._infoContainer.current!;
+ let trackbox = this._trackbox.current!;
+ this._boxLength = infoContainer.scrollWidth;
+ trackbox.style.width = `${this._boxLength}`;
+ });
//check if this is a video frame
- for (let i = 0; i < this._time; ) {
- this._ticks.push(i);
- i += 1000;
- }
+ for (let i = 0; i < this._time;) {
+ this._ticks.push(i);
+ i += 1000;
+ }
}
@action
- componentDidUpdate(){
- this._time = 100001;
+ componentDidUpdate() {
+ this._time = 100001;
}
- componentWillUnmount(){
-
+ componentWillUnmount() {
+
}
//for playing
@@ -84,7 +86,7 @@ export class Timeline extends CollectionSubView(Document){
}
@action
- changeCurrentX = () => {
+ changeCurrentX = () => {
if (this._currentBarX === this._boxLength && this._isPlaying) {
this._currentBarX = 0;
}
@@ -109,141 +111,166 @@ export class Timeline extends CollectionSubView(Document){
}
//for scrubber action
- @action
- onScrubberDown = (e:React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onScrubberMove);
+ @action
+ onScrubberDown = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onScrubberMove);
document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onScrubberMove);
- });
- }
+ document.removeEventListener("pointermove", this.onScrubberMove);
+ });
+ }
- @action
+ @action
onScrubberMove = (e: PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
+ e.preventDefault();
+ e.stopPropagation();
let scrubberbox = this._scrubberbox.current!;
let left = scrubberbox.getBoundingClientRect().left;
let offsetX = Math.round(e.clientX - left);
- this._currentBarX = offsetX;
+ this._currentBarX = offsetX;
}
- @action
- onScrubberClick = (e:React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- let scrubberbox = this._scrubberbox.current!;
- let offset = scrubberbox.scrollLeft + e.clientX - scrubberbox.getBoundingClientRect().left;
- this._currentBarX = offset;
+ @action
+ onScrubberClick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let scrubberbox = this._scrubberbox.current!;
+ let offset = scrubberbox.scrollLeft + e.clientX - scrubberbox.getBoundingClientRect().left;
+ 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;
+ 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;
+ if (Math.floor(sec / 10) === 0) {
+ sec = "0" + sec;
}
- return `${min}:${sec}`;
-
+ return `${min}:${sec}`;
+
}
- @action
- onPanDown = (e:React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onPanMove);
+ @action
+ onPanDown = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onPanMove);
document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onPanMove);
+ document.removeEventListener("pointermove", this.onPanMove);
});
}
- @action
- onPanMove = (e:PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- let infoContainer = this._infoContainer.current!;
- let trackbox = this._trackbox.current!;
- let titleContainer = this._titleContainer.current!;
- infoContainer.scrollLeft = infoContainer.scrollLeft - e.movementX;
- trackbox.scrollTop = trackbox.scrollTop - e.movementY;
- titleContainer.scrollTop = titleContainer.scrollTop - e.movementY;
+ @action
+ onPanMove = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let infoContainer = this._infoContainer.current!;
+ let trackbox = this._trackbox.current!;
+ let titleContainer = this._titleContainer.current!;
+ infoContainer.scrollLeft = infoContainer.scrollLeft - e.movementX;
+ trackbox.scrollTop = trackbox.scrollTop - e.movementY;
+ titleContainer.scrollTop = titleContainer.scrollTop - e.movementY;
}
- @action
- onResizeDown = (e:React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onResizeMove);
+ @action
+ onResizeDown = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.addEventListener("pointermove", this.onResizeMove);
document.addEventListener("pointerup", () => {
document.removeEventListener("pointermove", this.onResizeMove);
- });
+ });
}
- @action
- onResizeMove = (e:PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- let offset = e.clientY - this._containerHeight;
- if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT ){
+ @action
+ onResizeMove = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ let offset = e.clientY - this._containerHeight;
+ if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT) {
this._containerHeight = this.MIN_CONTAINER_HEIGHT;
- } else if (this._containerHeight + offset >= this.MAX_CONTAINER_HEIGHT){
- this._containerHeight = this.MAX_CONTAINER_HEIGHT;
+ } else if (this._containerHeight + offset >= this.MAX_CONTAINER_HEIGHT) {
+ this._containerHeight = this.MAX_CONTAINER_HEIGHT;
} else {
- this._containerHeight += offset;
+ this._containerHeight += offset;
}
}
- @action
- minimize = (e:React.MouseEvent) => {
- this._containerHeight = 0;
+ @action
+ minimize = (e: React.MouseEvent) => {
+ this._containerHeight = 0;
+ }
+
+ renderFlyout = ():JSX.Element => {
+ // console.log("rendered");
+
+ // let data = React.useContext(FlyoutInfoContext);
+ return (
+ <div style ={{height:"100px", width:"100px", backgroundColor:"yellow", position:"absolute"}}>
+ <p>
+ {/* {data.fadeIn} */}
+ </p>
+ </div>
+ );
}
+
- render(){
+
+ render() {
return (
- <div className="timeline-container" style={{height:`${this._containerHeight}px`}}>
+ <div className="timeline-container" style={{ height: `${this._containerHeight}px` }}>
<div className="toolbox">
- <div onClick={this.windBackward}> <FontAwesomeIcon icon={faBackward} size="2x"/> </div>
- <div onClick={this.onPlay}> <FontAwesomeIcon icon={faPlayCircle} size="2x"/> </div>
- <div onClick={this.windForward}> <FontAwesomeIcon icon={faForward} size="2x"/> </div>
+ <div onClick={this.windBackward}> <FontAwesomeIcon icon={faBackward} size="2x" /> </div>
+ <div onClick={this.onPlay}> <FontAwesomeIcon icon={faPlayCircle} size="2x" /> </div>
+ <div onClick={this.windForward}> <FontAwesomeIcon icon={faForward} size="2x" /> </div>
{/* <div>
<p>Timeline Overview</p>
<div className="overview"></div>
</div> */}
- </div>
- <div className="info-container" ref ={this._infoContainer}>
- <div className="scrubberbox" ref ={this._scrubberbox} onClick={this.onScrubberClick}>
+ </div>
+ <div className="info-container" ref={this._infoContainer}>
+
+ <div className="scrubberbox" ref={this._scrubberbox} onClick={this.onScrubberClick}>
{this._ticks.map(element => {
- return <div className="tick" style={{transform:`translate(${element / 20}px)`, position:"absolute", pointerEvents:"none"}}> <p>{this.toTime(element)}</p></div>;
+ return <div className="tick" style={{ transform: `translate(${element / 20}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" onPointerDown={this.onScrubberDown} style={{ transform: `translate(${this._currentBarX}px)` }}>
<div className="scrubberhead"></div>
</div>
- <div className="trackbox" ref={this._trackbox} onPointerDown={this.onPanDown}>
+ <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}/>;
+ return <Track node={(doc as any).value() as Doc} currentBarX={this._currentBarX} />;
})}
- </div>
- </div>
+ </div>
+ </div>
<div className="title-container" ref={this._titleContainer}>
- {this._nodes.map(doc => {return <div className="datapane">
- <p>{((doc as any).value() as Doc).title}</p>
- </div>;})}
+ {this._nodes.map(doc => {
+ return <div className="datapane">
+ <p>{((doc as any).value() as Doc).title}</p>
+ </div>;
+ })}
</div>
- <div onPointerDown ={this.onResizeDown}>
- <FontAwesomeIcon className="resize" icon={faGripLines} />
- </div>
-
+ <div onPointerDown={this.onResizeDown}>
+ <FontAwesomeIcon className="resize" icon={faGripLines} />
+ </div>
+ <FlyoutInfoContext.Consumer>
+ {value => (
+ <div style ={{height:"100px", width:"100px", backgroundColor:"yellow", position:"absolute"}}>
+ <p>
+ {value.fadeIn}
+ </p>
+ </div>)}
+ </FlyoutInfoContext.Consumer>
</div>
- );
+ );
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/Track.tsx b/src/client/views/nodes/Track.tsx
index c7154fbb3..957128040 100644
--- a/src/client/views/nodes/Track.tsx
+++ b/src/client/views/nodes/Track.tsx
@@ -1,50 +1,17 @@
import * as React from "react";
-import * as ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, IObservableObject } from "mobx";
import "./Track.scss";
-import { CollectionViewProps } from "../collections/CollectionBaseView";
-import { CollectionSubView, SubCollectionViewProps } from "../collections/CollectionSubView";
-import { DocumentViewProps, DocumentView } from "./DocumentView";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc";
import { Document, listSpec, createSchema, makeInterface, defaultSpec } from "../../../new_fields/Schema";
import { FieldValue, Cast, NumCast, BoolCast } from "../../../new_fields/Types";
-import { emptyStatement, thisExpression, react } from "babel-types";
-import { DocumentManager } from "../../util/DocumentManager";
-import { SelectionManager } from "../../util/SelectionManager";
import { List } from "../../../new_fields/List";
-import { Self } from "../../../new_fields/FieldSymbols";
-import { list } from "serializr";
-import { arrays, Dictionary } from "typescript-collections";
-import { forEach } from "typescript-collections/dist/lib/arrays";
-import { CompileScript } from "../../util/Scripting";
-import { FieldView } from "./FieldView";
-import { promises } from "fs";
-import { Tapable } from "tapable";
-import { Keyframe, KeyframeData } from "./Keyframe";
-import { timingSafeEqual } from "crypto";
-import { node } from "prop-types";
-
-const PositionSchema = createSchema({
- x: defaultSpec("number", 0),
- y: defaultSpec("number", 0)
-});
-
-type Position = makeInterface<[typeof PositionSchema]>;
-const Position = makeInterface(PositionSchema);
-const TimeAndPositionSchema = createSchema({
- time: defaultSpec("number", 0),
- position: Doc
-});
-
-type TimeAndPosition = makeInterface<[typeof TimeAndPositionSchema]>;
-const TimeAndPosition = makeInterface(TimeAndPositionSchema);
-
-
-interface IProp{
- node: Doc;
- currentBarX: number;
+import { Keyframe, RegionData } from "./Keyframe";
+
+interface IProp {
+ node: Doc;
+ currentBarX: number;
+ // setPosition: (position: number) => any;
}
@observer
@@ -57,54 +24,88 @@ export class Track extends React.Component<IProp> {
@observable private _keys = ["x", "y", "width", "height", "panX", "panY", "scale"];
- @computed
- private get keyframes(){
- return Cast(this.props.node.keyframes, listSpec(Doc)) as List<Doc> ;
+ componentWillMount() {
+ this.props.node.regions = new List<Doc>();
+ console.log((Cast(this.props.node.regions, listSpec(Doc)) as List<Doc>).length);
}
+ @action
+ componentDidMount() {
+ this.props.node.hidden = true;
+ this.props.node.opacity = 0;
+ reaction(() => this.props.currentBarX, () => {
+ let region: (Doc | undefined) = this.findRegion(this.props.currentBarX);
+ if (region !== undefined) {
+ this.props.node.hidden = false;
+ this.timeChange(this.props.currentBarX);
+ } else {
+ this.props.node.hidden = true;
+ }
+ });
+
+ // reaction(() => {
+ // let keys = Doc.allKeys(this.props.node);
+ // let x = keys.indexOf("keyframes");
+ // let afterX = keys.slice(x + 1);
+ // let beforeX = keys.slice(0, x);
+ // keys = beforeX.concat(afterX);
+ // return keys.map(key => FieldValue(this.props.node[key]));
+ // }, data => {
+ // if (this.keyframes.length !== 0){
+ // let kf:(Doc | undefined) = this.findKeyframe(this.props.currentBarX);
+ // }
+ // });
+ }
+ /**
+ * removes reaction when the component is removed from the timeline
+ */
+ componentWillUnmount() {
+ this._reactionDisposers.forEach(disp => disp());
+ this._reactionDisposers = [];
+ }
@action
timeChange = async (time: number) => {
- let singlekfd = this.findKeyframe(time);
- let leftkf: (Doc | undefined) = this.calcMinLeft(singlekfd!);
- let rightkf: (Doc | undefined) = this.calcMinRight(singlekfd!);
-
- if (leftkf && rightkf){
- this.interpolate(leftkf, rightkf);
- } else if(leftkf){
- console.log("left exists");
+ let region = this.findRegion(time);
+ let leftkf: (Doc | undefined) = this.calcMinLeft(region!);
+ let rightkf: (Doc | undefined) = this.calcMinRight(region!);
+
+ if (leftkf && rightkf) {
+ this.interpolate(leftkf, rightkf);
+ } else if (leftkf) {
+ console.log("left exists");
this._keys.forEach(k => {
- let data = leftkf!.key as Doc;
- this.props.node[k] = data[k];
- });
- } else if (rightkf){
- console.log("right exists");
+ let data = leftkf!.key as Doc;
+ this.props.node[k] = data[k];
+ });
+ } else if (rightkf) {
+ console.log("right exists");
this._keys.forEach(k => {
- let data = rightkf!.key as Doc;
- this.props.node[k] = data[k];
- });
+ let data = rightkf!.key as Doc;
+ this.props.node[k] = data[k];
+ });
}
}
-
+
/**
* calculates the closest left keyframe, if there is one
* @param kfList: keyframe list
* @param time
*/
@action
- calcMinLeft = (singlekfd: Doc): (Doc|undefined) => { //returns the time of the closet keyframe to the left
- let leftKf:Doc = new Doc();
- leftKf.time = Infinity;
- (singlekfd.kfs! as List<Doc>).forEach((kf) => {
+ calcMinLeft = (region: Doc): (Doc | undefined) => { //returns the time of the closet keyframe to the left
+ let leftKf: Doc = new Doc();
+ leftKf.time = Infinity;
+ (region.keyframes! as List<Doc>).forEach((kf) => {
kf = kf as Doc;
if (NumCast(kf.time) < this.props.currentBarX && NumCast(leftKf.time) > NumCast(kf.time)) {
- leftKf = kf;
+ leftKf = kf;
}
});
- if (NumCast(leftKf.time) === Infinity){
- return undefined;
+ if (NumCast(leftKf.time) === Infinity) {
+ return undefined;
}
return leftKf;
}
@@ -115,36 +116,36 @@ export class Track extends React.Component<IProp> {
* @param time: time
*/
@action
- calcMinRight = (singlekfd: Doc): (Doc|undefined) => { //returns the time of the closest keyframe to the right
- let rightKf:Doc = new Doc();
- rightKf.time = Infinity;
- (singlekfd.kfs! as List<Doc>).forEach((kf) => {
+ calcMinRight = (region: Doc): (Doc | undefined) => { //returns the time of the closest keyframe to the right
+ let rightKf: Doc = new Doc();
+ rightKf.time = Infinity;
+ (region.keyframes! as List<Doc>).forEach((kf) => {
kf = kf as Doc;
if (NumCast(kf.time) > this.props.currentBarX && NumCast(rightKf.time) > NumCast(kf.time)) {
- rightKf = kf;
+ rightKf = kf;
}
});
- if (NumCast(rightKf.time) === Infinity){
- return undefined;
+ if (NumCast(rightKf.time) === Infinity) {
+ return undefined;
}
return rightKf;
}
- /**
- * Linearly interpolates a document from time1 to time2
- * @param Doc that needs to be modified
- * @param kf1 timeandposition of the first yellow bar
- * @param kf2 timeandposition of the second yellow bar
- * @param time time that you want to interpolate
- */
+ /**
+ * Linearly interpolates a document from time1 to time2
+ * @param Doc that needs to be modified
+ * @param kf1 timeandposition of the first yellow bar
+ * @param kf2 timeandposition of the second yellow bar
+ * @param time time that you want to interpolate
+ */
@action
interpolate = async (kf1: Doc, kf2: Doc) => {
- let node1 = kf1.key as Doc;
- let node2 = kf2.key as Doc;
- console.log(toJS(node1));
- console.log(toJS(node2));
+ let node1 = kf1.key as Doc;
+ let node2 = kf2.key as Doc;
+ console.log(toJS(node1));
+ console.log(toJS(node2));
const dif_time = NumCast(kf2.time) - NumCast(kf1.time);
const ratio = (this.props.currentBarX - NumCast(kf1.time)) / dif_time; //linear
@@ -155,74 +156,38 @@ export class Track extends React.Component<IProp> {
});
}
- @action
- componentDidMount() {
- this.props.node.hidden = true;
- this.props.node.opacity = 0;
- this.props.node.keyframes = new List<Doc>();
- reaction (() => this.props.currentBarX, () => {
- this.keyframes.forEach((kfd) => {
- kfd = KeyframeData(kfd as Doc);
- if (kfd.length !== 0){
- let singlekfd:(Doc | undefined) = this.findKeyframe(this.props.currentBarX);
- if (singlekfd !== undefined){
- this.props.node.hidden = false;
- this.timeChange(this.props.currentBarX);
- } else {
- this.props.node.hidden = true;
- }
- }
- });
- });
-
- // reaction(() => {
- // let keys = Doc.allKeys(this.props.node);
- // let x = keys.indexOf("keyframes");
- // let afterX = keys.slice(x + 1);
- // let beforeX = keys.slice(0, x);
- // keys = beforeX.concat(afterX);
- // return keys.map(key => FieldValue(this.props.node[key]));
- // }, data => {
- // if (this.keyframes.length !== 0){
- // let kf:(Doc | undefined) = this.findKeyframe(this.props.currentBarX);
- // }
- // });
- }
- @action
- findKeyframe(time:number): (Doc | undefined){
- let foundKeyframe = undefined;
- this.keyframes.map(kfd => {
- kfd = KeyframeData(kfd as Doc);
- if (time >= NumCast(kfd.position) && time <= (NumCast(kfd.position) + NumCast(kfd.duration))){
- foundKeyframe = kfd;
- }
- });
- return foundKeyframe;
- }
- /**
- * removes reaction when the component is removed from the timeline
- */
- componentWillUnmount() {
- this._reactionDisposers.forEach(disp => disp());
- this._reactionDisposers = [];
+ @action
+ findRegion(time: number): (Doc | undefined) {
+ let foundRegion = undefined;
+ this.regions.map(region => {
+ region = RegionData(region as Doc);
+ if (time >= NumCast(region.position) && time <= (NumCast(region.position) + NumCast(region.duration))) {
+ foundRegion = region;
+ }
+ });
+ return foundRegion;
}
- @observable private _keyframes: JSX.Element[] = [];
-
- @action
+ @action
onInnerDoubleClick = (e: React.MouseEvent) => {
- let inner = this._inner.current!;
+ let inner = this._inner.current!;
let left = inner.getBoundingClientRect().left;
let offsetX = Math.round(e.clientX - left);
- let keyframedata:Doc = new Doc();
- keyframedata.duration = 200;
- keyframedata.position = offsetX;
- keyframedata.kfs = new List<Doc>();
- this.keyframes.push(keyframedata);
- this._keyframes.push(<Keyframe node={this.props.node} keyframedata={keyframedata}/>);
+ let regiondata: Doc = new Doc(); //creating regiond ata
+ regiondata.duration = 200;
+ regiondata.position = offsetX;
+ regiondata.keyframes = new List<Doc>();
+ this.regions.push(regiondata);
+ }
+
+
+ @computed
+ private get regions() {
+ console.log((Cast(this.props.node.regions, listSpec(Doc)) as List<Doc>).length + "from get");
+ return Cast(this.props.node.regions, listSpec(Doc)) as List<Doc>;
}
render() {
@@ -230,7 +195,9 @@ export class Track extends React.Component<IProp> {
<div className="track-container">
<div className="track">
<div className="inner" ref={this._inner} onDoubleClick={this.onInnerDoubleClick}>
- {this._keyframes.map((element)=> element)}
+ {this.regions.map((region) => {
+ return <Keyframe node={this.props.node} RegionData={region as Doc}/>;
+ })}
</div>
</div>
</div>