From 11326788a7212eca86e06ee8f2c9a4aa65ab6070 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 2 Jul 2019 16:49:56 -0400 Subject: context menu + repositioning + interpolation and data --- src/client/views/nodes/Keyframe.scss | 1 - src/client/views/nodes/Keyframe.tsx | 103 ++++++++++------------ src/client/views/nodes/Timeline.scss | 29 +++++-- src/client/views/nodes/Timeline.tsx | 161 ++++++++++++++++++++++------------- src/client/views/nodes/Track.tsx | 24 +++--- 5 files changed, 180 insertions(+), 138 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/Keyframe.scss b/src/client/views/nodes/Keyframe.scss index 44850cd64..19a61bde1 100644 --- a/src/client/views/nodes/Keyframe.scss +++ b/src/client/views/nodes/Keyframe.scss @@ -78,7 +78,6 @@ background-color:white; border:3px solid green; z-index: 1000; - pointer-events: none; position:absolute; } diff --git a/src/client/views/nodes/Keyframe.tsx b/src/client/views/nodes/Keyframe.tsx index 263df0fd5..10ae2f427 100644 --- a/src/client/views/nodes/Keyframe.tsx +++ b/src/client/views/nodes/Keyframe.tsx @@ -10,28 +10,18 @@ import { List } from "../../../new_fields/List"; import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; import { any } from "bluebird"; import { FlyoutProps } from "./Timeline"; -import { exportDefaultSpecifier } from "babel-types"; enum Direction { left = "left", right = "right" } -interface IProp { +interface IProps { node: Doc; RegionData: Doc; setFlyout:(props:FlyoutProps) => any; } - -const KeyframeDataSchema = createSchema({ - time: defaultSpec("number", 0), - key: Doc -}); -type KeyframeData = makeInterface<[typeof KeyframeDataSchema]>; -const KeyframeData = makeInterface(KeyframeDataSchema); - - const RegionDataSchema = createSchema({ position: defaultSpec("number", 0), duration: defaultSpec("number", 0), @@ -42,18 +32,14 @@ export const RegionData = makeInterface(RegionDataSchema); @observer -export class Keyframe extends React.Component { +export class Keyframe extends React.Component { - @observable private _display: string = "none"; - @observable private _bar = React.createRef(); - @observable private _keyframes: number[] = []; - @observable private position: number = 0; + @observable private _bar = React.createRef(); @observable private fadein: number = 0; @observable private fadeout: number = 0; @action componentDidMount() { - // need edge case here when keyframe data already exists when loading.....................; } @@ -88,7 +74,6 @@ export class Keyframe extends React.Component { TK.key = Doc.MakeCopy(this.props.node); this.regiondata.keyframes!.push(TK); } - } @action @@ -102,20 +87,12 @@ export class Keyframe extends React.Component { document.addEventListener("pointerup", (e: PointerEvent) => { document.removeEventListener("pointermove", this.onBarPointerMove); }); - } else if(mouse.which === 3) { - e.preventDefault(); - e.stopPropagation(); - let bar = this._bar.current!; - this.props.setFlyout({x:this.regiondata.position + 130, y: bar.getBoundingClientRect().bottom,display:"block", time: this.regiondata.position, duration:this.regiondata.duration}); - let removeFlyout = (e:PointerEvent) => { - if (e.which === 1){ - console.log("wut"); - this.props.setFlyout({display:"none"}); - document.removeEventListener("pointerdown", removeFlyout); - } - }; - document.addEventListener("pointerdown", removeFlyout); - } + }// else if(mouse.which === 3) { + // e.preventDefault(); + // e.stopPropagation(); + // let bar = this._bar.current!; + // this.props.setFlyout({x:e.clientX, y: e.clientY,display:"block", time: this.regiondata.position, duration:this.regiondata.duration}); + // } } @action @@ -169,7 +146,6 @@ export class Keyframe extends React.Component { document.addEventListener("pointermove", this.onDragResizeLeft); document.addEventListener("pointerup", () => { document.removeEventListener("pointermove", this.onDragResizeLeft); - }); } @@ -180,7 +156,6 @@ export class Keyframe extends React.Component { document.addEventListener("pointermove", this.onDragResizeRight); document.addEventListener("pointerup", () => { document.removeEventListener("pointermove", this.onDragResizeRight); - }); } @@ -193,10 +168,6 @@ export class Keyframe extends React.Component { 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; - }); } @@ -207,11 +178,10 @@ export class Keyframe extends React.Component { 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 => { + createDivider = (type?: Direction): JSX.Element => { if (type === "left") { return
; } else if (type === "right") { @@ -224,33 +194,48 @@ export class Keyframe extends React.Component { createKeyframe = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - let mouse = e.nativeEvent; + let bar = this._bar.current!; + let offset = e.clientX - bar.getBoundingClientRect().left; let position = NumCast(this.regiondata.position); - this._keyframes.push(mouse.offsetX); - this.makeKeyData(position + mouse.offsetX); + this.makeKeyData(position + offset); } + @action + moveKeyframe = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + + } render() { return (
-
-
-
-
{this.createDivider("left")}
-
{this.createDivider("right")}
- {this._keyframes.map(kf => { - return
- {this.createDivider()} -
-
; - })} - {this.createDivider("left")} - {this.createDivider("right")} -
+
{ + let mouse = e.nativeEvent; + if (mouse.which === 3){ + this.props.setFlyout({x:e.clientX, y: e.clientY, display:"block"}); + } else { + this.props.setFlyout({display:"block"}); + } + })}> +
+
+
{this.createDivider(Direction.left)}
+
{this.createDivider(Direction.right)}
+ {this.regiondata.keyframes!.map(kf => { + kf = kf as Doc; + return
+ {this.createDivider()} +
+
; + })} + {this.createDivider(Direction.left)} + {this.createDivider(Direction.right)} +
); } diff --git a/src/client/views/nodes/Timeline.scss b/src/client/views/nodes/Timeline.scss index 44b6cf03e..a416cbb1c 100644 --- a/src/client/views/nodes/Timeline.scss +++ b/src/client/views/nodes/Timeline.scss @@ -1,5 +1,11 @@ @import "./../globalCssVariables.scss"; +.minimize{ + position:relative; + z-index: 1000; + height: 30px; + width: 100px; +} .flyout-container{ background-color: transparent; position:absolute; @@ -15,17 +21,22 @@ width: 100%; height: 100%; } - div{ - color: white; - position:absolute; - top:30px; - left:0px; + .input-container{ + position: absolute; + right:0px; + top: 30px; + width: 70px; + input{ + width: 100%; + } } - input{ + .text-container{ position:absolute; - width: 40px; - right:0px; + top:30px; + left:0px; + color:white } + } @@ -35,6 +46,8 @@ position:absolute; background-color: $light-color-secondary; box-shadow: 0px 10px 20px; + transition: transform 1000ms ease-in-out; + .toolbox{ position:absolute; width: 100%; diff --git a/src/client/views/nodes/Timeline.tsx b/src/client/views/nodes/Timeline.tsx index 8050830fa..fd235fad3 100644 --- a/src/client/views/nodes/Timeline.tsx +++ b/src/client/views/nodes/Timeline.tsx @@ -12,16 +12,18 @@ import { List } from "../../../new_fields/List"; import { Self } from "../../../new_fields/FieldSymbols"; 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 { faCircle, faPlayCircle, faBackward, faForward, faGripLines } from "@fortawesome/free-solid-svg-icons"; import { DocumentContentsView } from "./DocumentContentsView"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { ContextMenu } from "../ContextMenu"; -export interface FlyoutProps{ - x?: number; - y?: number; - display?:string; - time?:number; - duration?:number; +export interface FlyoutProps { + x?: number; + y?: number; + display?: string; + time?: number; + duration?: number; } @@ -31,11 +33,12 @@ export class Timeline extends CollectionSubView(Document) { private readonly MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; - @observable private _tickSpacing = 50; + @observable private _tickSpacing = 50; @observable private _scrubberbox = React.createRef(); @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); + @observable private _timelineContainer = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; @@ -47,8 +50,9 @@ export class Timeline extends CollectionSubView(Document) { @observable private _infoContainer = React.createRef(); @observable private _ticks: number[] = []; - @observable private flyoutInfo:FlyoutProps = {x:0, y:0,display:"none"}; + @observable private flyoutInfo: FlyoutProps = { x: 0, y: 0, display: "none" }; + private block = false; @action componentDidMount() { @@ -73,6 +77,22 @@ export class Timeline extends CollectionSubView(Document) { this._ticks.push(i); i += 1000; } + document.addEventListener("pointerdown", this.closeFlyout); + } + + @action + onFlyoutDown = (e: React.PointerEvent) => { + this.flyoutInfo.display = "block"; + this.block = true; + } + + @action + closeFlyout = (e: PointerEvent) => { + if (this.block) { + this.block = false; + return; + } + this.flyoutInfo.display = "none"; } @action @@ -80,7 +100,7 @@ export class Timeline extends CollectionSubView(Document) { this._time = 100001; } componentWillUnmount() { - + document.removeEventListener("pointerdown", this.closeFlyout); } //for playing @@ -211,75 +231,100 @@ export class Timeline extends CollectionSubView(Document) { } } + @observable private _isMinimized = false; @action minimize = (e: React.MouseEvent) => { - this._containerHeight = 0; + e.preventDefault(); + e.stopPropagation(); + let timelineContainer = this._timelineContainer.current!; + if (this._isMinimized) { + this._isMinimized = false; + timelineContainer.style.transform = `translate(0px, 0px)`; + } else { + this._isMinimized = true; + timelineContainer.style.transform = `translate(0px, ${- this._containerHeight - 30}px)`; + } } @action - getFlyout = (props: FlyoutProps) => { - for(const[k, v] of Object.entries(props)){ - (this.flyoutInfo as any)[k] = v; + getFlyout = (props: FlyoutProps) => { + for (const [k, v] of Object.entries(props)) { + (this.flyoutInfo as any)[k] = v; } - - } + } - @action - onFlyoutDown = (e: React.PointerEvent) => { - console.log("clicked!"); - this.flyoutInfo.display = "block"; + timelineContextMenu = (e: React.MouseEvent): void => { + let subitems: ContextMenuProps[] = []; + let timelineContainer = this._timelineContainer.current!; + subitems.push({ description: "Pin to Top", event: action(() => { timelineContainer.style.transform = "translate(0px, 0px)"; }), icon: "pinterest" }); + subitems.push({ + description: "Pin to Bottom", event: action(() => { + timelineContainer.style.transform = `translate(0px, ${e.pageY - this._containerHeight}px)`; + }), icon: "pinterest" + }); + ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems }); } render() { return ( -
-
- -
-

Time:

-

Duration:

-

Fade-in

-

Fade-out

+
+ +
+
+ +
+

Time:

+

Duration:

+

Fade-in

+

Fade-out

+
+
+ + + + +
-
-
-
-
-
- {/*
-

Timeline Overview

-
-
*/} -
-
- -
- {this._ticks.map(element => { - return

{this.toTime(element)}

; - })} +
+
+
+
+ {/*
+

Timeline Overview

+
+
*/}
-
-
+
+ +
+ {this._ticks.map(element => { + return

{this.toTime(element)}

; + })} +
+
+
+
+
+ {this._nodes.map(doc => { + return ; + })} +
-
+
{this._nodes.map(doc => { - return ; + return
+

{((doc as any).value() as Doc).title}

+
; })}
+
+ +
-
- {this._nodes.map(doc => { - return
-

{((doc as any).value() as Doc).title}

-
; - })} -
-
- -
+
); } diff --git a/src/client/views/nodes/Track.tsx b/src/client/views/nodes/Track.tsx index 94c0b5563..cf613a827 100644 --- a/src/client/views/nodes/Track.tsx +++ b/src/client/views/nodes/Track.tsx @@ -73,16 +73,20 @@ export class Track extends React.Component { 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"); + console.log(leftkf.time); this._keys.forEach(k => { let data = leftkf!.key as Doc; this.props.node[k] = data[k]; }); } else if (rightkf) { + console.log("right exists"); + console.log(rightkf.time); this._keys.forEach(k => { let data = rightkf!.key as Doc; this.props.node[k] = data[k]; @@ -98,17 +102,15 @@ export class Track extends React.Component { */ @action calcMinLeft = (region: Doc): (Doc | undefined) => { //returns the time of the closet keyframe to the left - let leftKf: Doc = new Doc(); - leftKf.time = Infinity; + let leftKf:(Doc| undefined) = undefined; + let time:number = 0; (region.keyframes! as List).forEach((kf) => { kf = kf as Doc; - if (NumCast(kf.time) < this.props.currentBarX && NumCast(leftKf.time) > NumCast(kf.time)) { + if (NumCast(kf.time) < this.props.currentBarX && NumCast(kf.time) >= NumCast(time)) { leftKf = kf; + time = NumCast(kf.time); } }); - if (NumCast(leftKf.time) === Infinity) { - return undefined; - } return leftKf; } @@ -119,17 +121,15 @@ export class Track extends React.Component { */ @action calcMinRight = (region: Doc): (Doc | undefined) => { //returns the time of the closest keyframe to the right - let rightKf: Doc = new Doc(); - rightKf.time = Infinity; + let rightKf: (Doc|undefined) = undefined; + let time:number = Infinity; (region.keyframes! as List).forEach((kf) => { kf = kf as Doc; - if (NumCast(kf.time) > this.props.currentBarX && NumCast(rightKf.time) > NumCast(kf.time)) { + if (NumCast(kf.time) > this.props.currentBarX && NumCast(kf.time) <= NumCast(time)) { rightKf = kf; + time = NumCast(kf.time); } }); - if (NumCast(rightKf.time) === Infinity) { - return undefined; - } return rightKf; } -- cgit v1.2.3-70-g09d2