aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/animationtimeline/Timeline.scss92
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx88
-rw-r--r--src/client/views/animationtimeline/TimelineOverview.scss29
-rw-r--r--src/client/views/animationtimeline/TimelineOverview.tsx180
4 files changed, 284 insertions, 105 deletions
diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss
index 02c1bdb16..a8dd9b9e7 100644
--- a/src/client/views/animationtimeline/Timeline.scss
+++ b/src/client/views/animationtimeline/Timeline.scss
@@ -10,39 +10,79 @@ $timelineDark: #77a1aa;
display: flex;
align-items: flex-start;
flex-direction: row;
- justify-content: space-evenly;
+ // justify-content: space-evenly;
align-items: center;
- top: 20px;
+ top: 3px;
+ width: 100%;
- .timeline-icon {
- color: $timelineColor;
+ .overview-tool {
+ display: flex;
+ justify-content: center;
}
- div {
- padding: 0px;
+ .playbackControls {
+ display: flex;
+ margin-left: 30px;
+ max-width: 84px;
+ width: 84px;
+
+ .timeline-icon {
+ color: $timelineColor;
+ margin-left: 3px;
+ }
+
+ }
+
+ .grid-box {
+ display: grid;
+ grid-template-columns: [first] 50% [line2] 25% [line3] 25%;
+ width: calc(100% - 150px);
+ // width: 100%;
margin-left: 10px;
+
+ .time-box {
+ margin-left: 5px;
+ display: flex;
+ }
+
+ .mode-box {
+ display: flex;
+ margin-left: 5px;
+ }
+
+ .overview-box {
+ width: 100%;
+ display: flex;
+ }
+
+ div {
+ padding: 0px;
+ // margin-left: 10px;
+ }
}
.animation-text {
- font-size: 20px;
+ // font-size: 16px;
height: auto;
width: auto;
white-space: nowrap;
- font-size: 16px;
+ font-size: 14px;
color: black;
letter-spacing: 2px;
text-transform: uppercase;
}
.round-toggle {
- height: 40px;
- width: 80px;
+ height: 20px;
+ width: 40px;
+ min-width: 40px;
background-color: white;
- border: 2px solid black;
+ border: 2px solid $timelineDark;
border-radius: 20px;
animation-fill-mode: forwards;
animation-duration: 500ms;
top: 30px;
+ margin-left: 5px;
input {
position: absolute;
@@ -52,29 +92,30 @@ $timelineDark: #77a1aa;
}
.round-toggle-slider {
- height: 35px;
- width: 35px;
+ height: 17px;
+ width: 17px;
background-color: white;
- border: 3px solid black;
- border-radius: 20px;
+ border: 2px solid $timelineDark;
+ border-radius: 50%;
transition: transform 500ms ease-in-out;
margin-left: 0px;
- margin-top: 0.5px;
+ // margin-top: 0.5px;
}
}
}
.time-input {
- height: 40px;
- width: 120px;
+ height: 20px;
+ // width: 120px;
+ width: 100%;
white-space: nowrap;
- font-size: 16px;
+ font-size: 12px;
color: black;
letter-spacing: 2px;
text-transform: uppercase;
padding-left: 5px;
-
+ margin-left: 5px;
}
.tick {
@@ -99,7 +140,7 @@ $timelineDark: #77a1aa;
transition: transform 500ms ease;
.info-container {
- margin-top: 80px;
+ margin-top: 50px;
right: 20px;
position: absolute;
height: calc(100% - 100px);
@@ -138,9 +179,12 @@ $timelineDark: #77a1aa;
.trackbox {
top: 30px;
+ // TODO: where is this 30px coming from?
height: calc(100% - 30px);
+ // height: 100%;
width: 100%;
- border: 2px solid black;
+ border-top: 2px solid black;
+ border-bottom: 2px solid black;
overflow: hidden;
background-color: white;
position: absolute;
@@ -150,7 +194,7 @@ $timelineDark: #77a1aa;
}
.title-container {
- margin-top: 110px;
+ margin-top: 80px;
margin-left: 20px;
height: calc(100% - 100px - 30px);
width: 100px;
@@ -159,6 +203,7 @@ $timelineDark: #77a1aa;
border-left: 2px solid black;
border-top: 2px solid black;
border-bottom: 2px solid black;
+ border-right: 2px solid $timelineDark;
.datapane {
top: 0px;
@@ -181,6 +226,7 @@ $timelineDark: #77a1aa;
height: 20px;
width: 40px;
left: calc(50% - 25px);
+ color: $timelineDark;
}
}
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 37d93f6c1..e6201d431 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -3,7 +3,7 @@ import "./Timeline.scss";
import { listSpec } from "../../../new_fields/Schema";
import { observer } from "mobx-react";
import { Track } from "./Track";
-import { observable, action, computed, runInAction } from "mobx";
+import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx";
import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
import { List } from "../../../new_fields/List";
import { Doc, DocListCast } from "../../../new_fields/Doc";
@@ -77,6 +77,11 @@ export class Timeline extends React.Component<FieldViewProps> {
@observable private _doubleClickEnabled = false;
@observable private _titleHeight = 0;
+ // so a reaction can be made
+ @observable public _isAuthoring = this.props.Document.isATOn;
+ @observable private _resizeReaction?: IReactionDisposer;
+ @observable private _panelWidth = 0;
+
/**
* collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit.
*/
@@ -114,6 +119,19 @@ export class Timeline extends React.Component<FieldViewProps> {
this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on
this.toggleHandle();
});
+
+ this._resizeReaction = reaction(
+ () => this.props.PanelWidth,
+ () => {
+ // if (!this.props.parent._isAuthoring) {
+ // runInAction(() => {
+ console.log("resizing");
+ // this.setOverviewWidth();
+ // });
+ // }
+ },
+ );
+
}
componentWillUnmount() {
@@ -402,19 +420,58 @@ export class Timeline extends React.Component<FieldViewProps> {
private timelineToolBox = (scale: number) => {
let size = 40 * scale; //50 is default
let iconSize = 25;
+
+ //decides if information should be omitted because the timeline is very small
+ // if its less than 950 pixels then it's going to be overlapping
+ let shouldCompress = false;
+ let width: number = this.props.PanelWidth();
+ if (width < 850) {
+ shouldCompress = true;
+ }
+
+ let modeString, overviewString, lengthString;
+ let modeType = this.props.Document.isATOn ? "Author" : "Play";
+
+ if (!shouldCompress) {
+ modeString = "Mode: " + modeType;
+ overviewString = "Overview:";
+ lengthString = "Length: ";
+ }
+ else {
+ modeString = modeType;
+ overviewString = "";
+ lengthString = "";
+ }
+
+
+ // let modeType: string = this.props.Document.isATOn ? "Author" : "Play";
+ // let modeString: string = "Mode: " + modeType;
+ // let overviewString: string = "Overview:";
+ // let lengthString: string = "Length: ";
+
return (
<div key="timeline_toolbox" className="timeline-toolbox" style={{ height: `${size}px` }}>
- <div className="timeline-icon" key="timeline_windBack" onClick={this.windBackward}> <FontAwesomeIcon icon={faBackward} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
- <div className="timeline-icon" key=" timeline_play" onClick={this.onPlay}> <FontAwesomeIcon icon={this._playButton} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
- <div className="timeline-icon" key="timeline_windForward" onClick={this.windForward}> <FontAwesomeIcon icon={faForward} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
- <div key="overview-text" className="animation-text">Timeline Overview</div>
- <TimelineOverview isAuthoring={BoolCast(this.props.Document.isATOn)} currentBarX={this._currentBarX} totalLength={this._totalLength} visibleLength={this._visibleLength} visibleStart={this._visibleStart} changeCurrentBarX={this.changeCurrentBarX} movePanX={this.movePanX} />
- <div key="animation-text" className="animation-text">Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}</div>
- <div key="round-toggle" ref={this._roundToggleContainerRef} className="round-toggle">
- <div key="round-toggle-slider" ref={this._roundToggleRef} className="round-toggle-slider" onPointerDown={this.toggleChecked}> </div>
+ <div className="playbackControls">
+ <div className="timeline-icon" key="timeline_windBack" onClick={this.windBackward} title="Slow Down Animation"> <FontAwesomeIcon icon={faBackward} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
+ <div className="timeline-icon" key=" timeline_play" onClick={this.onPlay} title="Play/Pause"> <FontAwesomeIcon icon={this._playButton} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
+ <div className="timeline-icon" key="timeline_windForward" onClick={this.windForward} title="Speed Up Animation"> <FontAwesomeIcon icon={faForward} style={{ height: `${iconSize}px`, width: `${iconSize}px` }} /> </div>
+ </div>
+ <div className="grid-box overview-tool">
+ <div className="overview-box">
+ <div key="overview-text" className="animation-text">{overviewString}</div>
+ <TimelineOverview parent={this} isAuthoring={BoolCast(this.props.Document.isATOn)} currentBarX={this._currentBarX} totalLength={this._totalLength} visibleLength={this._visibleLength} visibleStart={this._visibleStart} changeCurrentBarX={this.changeCurrentBarX} movePanX={this.movePanX} />
+ </div>
+ <div className="mode-box overview-tool">
+ <div key="animation-text" className="animation-text">{modeString}</div>
+ <div key="round-toggle" ref={this._roundToggleContainerRef} className="round-toggle">
+ <div key="round-toggle-slider" ref={this._roundToggleRef} className="round-toggle-slider" onPointerDown={this.toggleChecked}> </div>
+ </div>
+ </div>
+ <div className="time-box overview-tool" style={{ display: this._timelineVisible ? "flex" : "none" }}>
+ <div key="time-text" className="animation-text" style={{ visibility: this.props.Document.isATOn ? "visible" : "hidden" }}>{lengthString}</div>
+ <input className="time-input" style={{ visibility: this.props.Document.isATOn ? "visible" : "hidden" }} placeholder={String(Math.floor(this._time) / 1000) + " s"} ref={this._timeInputRef} onKeyDown={this.onTimeInput} />
+ </div>
</div>
- <div key="time-text" className="animation-text" style={{ visibility: this.props.Document.isATOn ? "visible" : "hidden" }}>Length: </div>
- <input className="time-input" style={{ visibility: this.props.Document.isATOn ? "visible" : "hidden" }} placeholder={String(this._time) + "ms"} ref={this._timeInputRef} onKeyDown={this.onTimeInput} />
</div>
);
}
@@ -457,13 +514,15 @@ export class Timeline extends React.Component<FieldViewProps> {
roundToggleContainer.style.backgroundColor = "white";
timelineContainer.style.top = `${-this._containerHeight}px`;
this.props.Document.isATOn = false;
+ this._isAuthoring = false;
} else {
- roundToggle.style.transform = "translate(40px, 0px)";
+ roundToggle.style.transform = "translate(20px, 0px)";
roundToggle.style.animationName = "turnon";
roundToggleContainer.style.animationName = "turnon";
roundToggleContainer.style.backgroundColor = "#9acedf";
timelineContainer.style.top = "0px";
this.props.Document.isATOn = true;
+ this._isAuthoring = true;
}
}
@@ -498,6 +557,11 @@ export class Timeline extends React.Component<FieldViewProps> {
* basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region)
*/
render() {
+ console.log(this.props.PanelWidth());
+ runInAction(() => {
+ this._panelWidth = this.props.PanelWidth();
+ console.log("changing!!")
+ });
return (
<div>
<div style={{ visibility: this._timelineVisible ? "visible" : "hidden" }}>
diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss
index 3517d3f39..a0b9d462b 100644
--- a/src/client/views/animationtimeline/TimelineOverview.scss
+++ b/src/client/views/animationtimeline/TimelineOverview.scss
@@ -1,23 +1,34 @@
@import "./../globalCssVariables.scss";
$timelineColor: #9acedf;
+$timelineDark: #77a1aa;
+
+.timelineOverview-bounding {
+ width: 100%;
+ margin-right: 10px;
+}
.timeline-overview-container {
- padding: 0px;
- margin: 0px;
- width: 300px;
- height: 40px;
+ // padding: 0px;
+ margin-right: 5px;
+ // margin: 0px;
+ margin-left: 5px;
+ // width: 300px;
+ width: 100%;
+ height: 25px;
background: white;
position: relative;
- border: 2px solid black;
+ border: 2px solid $timelineDark;
+ // width: 100%;
.timeline-overview-visible {
position: absolute;
- height: 98%;
+ height: 21px;
background: $timelineColor;
display: inline-block;
margin: 0px;
padding: 0px;
+ // top: 1px;
}
.timeline-overview-scrubber-container {
@@ -38,9 +49,9 @@ $timelineColor: #9acedf;
position: absolute;
height: 10px;
width: 10px;
- background-color: black;
+ background-color: white;
border-radius: 50%;
- // border: 3px solid black;
+ border: 2px solid black;
left: -4px;
// top: -30px;
top: -10px;
@@ -54,7 +65,7 @@ $timelineColor: #9acedf;
position: relative;
padding: 0px;
margin: 0px;
- width: 300px;
+ width: 100%;
height: 4px;
background-color: $timelineColor;
border-radius: 20px;
diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx
index 4741969dc..4907a1ae1 100644
--- a/src/client/views/animationtimeline/TimelineOverview.tsx
+++ b/src/client/views/animationtimeline/TimelineOverview.tsx
@@ -1,101 +1,159 @@
-import * as React from "react";
-import {observable, action} from "mobx";
-import {observer} from "mobx-react";
-import "./TimelineOverview.scss";
+import * as React from "react";
+import { observable, action, computed, runInAction, reaction, IReactionDisposer } from "mobx";
+import { observer } from "mobx-react";
+import "./TimelineOverview.scss";
+import * as $ from 'jquery';
+import { Timeline } from "./Timeline";
-
-interface TimelineOverviewProps{
- totalLength: number;
- visibleLength:number;
- visibleStart:number;
- currentBarX:number;
- isAuthoring: boolean;
- changeCurrentBarX: (pixel:number) => void;
- movePanX: (pixel:number) => any;
+interface TimelineOverviewProps {
+ totalLength: number;
+ visibleLength: number;
+ visibleStart: number;
+ currentBarX: number;
+ isAuthoring: boolean;
+ parent: Timeline;
+ changeCurrentBarX: (pixel: number) => void;
+ movePanX: (pixel: number) => any;
}
@observer
export class TimelineOverview extends React.Component<TimelineOverviewProps>{
- @observable private _visibleRef = React.createRef<HTMLDivElement>();
- @observable private _scrubberRef = React.createRef<HTMLDivElement>();
- private readonly DEFAULT_HEIGHT = 50;
- private readonly DEFAULT_WIDTH = 300;
+ @observable private _visibleRef = React.createRef<HTMLDivElement>();
+ @observable private _scrubberRef = React.createRef<HTMLDivElement>();
+ @observable private overviewBarWidth: number = 0;
+ @observable private _authoringReaction?: IReactionDisposer;
+ @observable private _resizeReaction?: IReactionDisposer;
+ private readonly DEFAULT_HEIGHT = 50;
+ private readonly DEFAULT_WIDTH = 300;
+
+ componentDidMount = () => {
+ this.setOverviewWidth();
+
+ this._authoringReaction = reaction(
+ () => this.props.parent._isAuthoring,
+ () => {
+ if (!this.props.parent._isAuthoring) {
+ runInAction(() => {
+ this.setOverviewWidth();
+ });
+ }
+ },
+ );
+ // this._resizeReaction = reaction(
+ // () => this.props.parent.props.PanelWidth,
+ // () => {
+ // // if (!this.props.parent._isAuthoring) {
+ // // runInAction(() => {
+ // console.log("resizing");
+ // this.setOverviewWidth();
+ // // });
+ // // }
+ // },
+ // );
+ }
+
+ componentWillUnmount = () => {
+ this._authoringReaction && this._authoringReaction();
+ this._resizeReaction && this._resizeReaction();
+ }
@action
- onPointerDown = (e:React.PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
- document.removeEventListener("pointermove", this.onPanX);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointermove", this.onPanX);
- document.addEventListener("pointerup", this.onPointerUp);
+ setOverviewWidth() {
+ let width = $("#timelineOverview").width();
+ if (width) this.overviewBarWidth = width;
+ else this.overviewBarWidth = 0;
+ }
+
+ @action
+ onPointerDown = (e: React.PointerEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ document.removeEventListener("pointermove", this.onPanX);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointermove", this.onPanX);
+ document.addEventListener("pointerup", this.onPointerUp);
}
@action
onPanX = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
- let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH) + e.movementX;
- this.props.movePanX((movX / (this.DEFAULT_WIDTH )) * this.props.totalLength);
+ e.stopPropagation();
+ e.preventDefault();
+ let movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX;
+ // let movX = (this.props.visibleStart / this.props.totalLength) * (this.overviewWidth) + e.movementX;
+ this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength);
+ // this.props.movePanX((movX / (this.overviewWidth) * this.props.totalLength);
+
+ // console.log(this.props.totalLength);
}
@action
onPointerUp = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
- document.removeEventListener("pointermove", this.onPanX);
- document.removeEventListener("pointerup", this.onPointerUp);
+ e.stopPropagation();
+ e.preventDefault();
+ document.removeEventListener("pointermove", this.onPanX);
+ document.removeEventListener("pointerup", this.onPointerUp);
}
@action
- onScrubberDown = ( e:React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.removeEventListener("pointermove", this.onScrubberMove);
- document.removeEventListener("pointerup", this.onScrubberUp);
- document.addEventListener("pointermove", this.onScrubberMove);
+ onScrubberDown = (e: React.PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.removeEventListener("pointermove", this.onScrubberMove);
+ document.removeEventListener("pointerup", this.onScrubberUp);
+ document.addEventListener("pointermove", this.onScrubberMove);
document.addEventListener("pointerup", this.onScrubberUp);
}
@action
onScrubberMove = (e: PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- let scrubberRef = this._scrubberRef.current!;
- let left = scrubberRef.getBoundingClientRect().left;
- let offsetX = Math.round(e.clientX - left);
- this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX);
+ e.preventDefault();
+ e.stopPropagation();
+ let scrubberRef = this._scrubberRef.current!;
+ let left = scrubberRef.getBoundingClientRect().left;
+ let offsetX = Math.round(e.clientX - left);
+ this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX);
}
@action
- onScrubberUp = (e:PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.removeEventListener("pointermove", this.onScrubberMove);
+ onScrubberUp = (e: PointerEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ document.removeEventListener("pointermove", this.onScrubberMove);
document.removeEventListener("pointerup", this.onScrubberUp);
}
- render(){
+ render() {
+ // calculates where everything should fall based on its size
+ let percentVisible = this.props.visibleLength / this.props.totalLength;
+ let visibleBarWidth = percentVisible * this.overviewBarWidth;
+
+ let percentScrubberStart = this.props.currentBarX / this.props.totalLength;
+ let scrubberStart = percentScrubberStart * this.overviewBarWidth;
+
+ let percentBarStart = this.props.visibleStart / this.props.totalLength;
+ let barStart = percentBarStart * this.overviewBarWidth;
+
let timeline = this.props.isAuthoring ? [
- <div key="timeline-overview-container" className="timeline-overview-container">
- <div ref={this._visibleRef} key="timeline-overview-visible" className="timeline-overview-visible" style={{left:`${(Math.round(this.props.visibleStart) / Math.round(this.props.totalLength)) * 296}px`, width:`${(Math.round(this.props.visibleLength) / Math.round(this.props.totalLength)) * 296}px`}} onPointerDown={this.onPointerDown}></div>,
- <div ref={this._scrubberRef} key="timeline-overview-scrubber-container" className="timeline-overview-scrubber-container" style={{left:`${(this.props.currentBarX / this.props.totalLength) * 294}px`}} onPointerDown={this.onScrubberDown}>
+
+ <div key="timeline-overview-container" className="timeline-overview-container" id="timelineOverview">
+ <div ref={this._visibleRef} key="timeline-overview-visible" className="timeline-overview-visible" style={{ left: `${barStart}px`, width: `${visibleBarWidth}px` }} onPointerDown={this.onPointerDown}></div>,
+ <div ref={this._scrubberRef} key="timeline-overview-scrubber-container" className="timeline-overview-scrubber-container" style={{ left: `${scrubberStart}px` }} onPointerDown={this.onScrubberDown}>
<div key="timeline-overview-scrubber-head" className="timeline-overview-scrubber-head"></div>
- </div>
+ </div>
</div>
] : [
- <div className="timeline-play-bar">
- <div ref={this._scrubberRef} className="timeline-play-head" style={{left:`${(this.props.currentBarX / this.props.totalLength) * 294}px`}} onPointerDown={this.onScrubberDown}></div>
- </div>,
- <div className="timeline-play-tail" style={{width: `${(this.props.currentBarX / this.props.totalLength) * 294}px`}}></div>
- ];
- return(
- <div>
+ <div className="timeline-play-bar">
+ <div ref={this._scrubberRef} className="timeline-play-head" style={{ left: `${(this.props.currentBarX / this.props.totalLength) * 294}px` }} onPointerDown={this.onScrubberDown}></div>
+ </div>,
+ <div className="timeline-play-tail" style={{ width: `${(this.props.currentBarX / this.props.totalLength) * 294}px` }}></div>
+ ];
+ return (
+ <div className="timelineOverview-bounding">
{timeline}
</div>
- );
+ );
}
}