aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/animationtimeline
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-12-21 14:55:48 -0500
committerbobzel <zzzman@gmail.com>2023-12-21 14:55:48 -0500
commit1caba64ee0f32ee8af79263cd4ef2a8bc5d5146e (patch)
tree0fa0e957d1f342fdc6ed4a4b43f5dddfddb1298a /src/client/views/animationtimeline
parent02eb7da95df283606d4275a22d9451cef371c3b5 (diff)
parent2691b951d96f2ce7652acbea9e340b61737b3b57 (diff)
Merge branch 'moreUpgrading' into dataViz-annotations
Diffstat (limited to 'src/client/views/animationtimeline')
-rw-r--r--src/client/views/animationtimeline/Region.scss2
-rw-r--r--src/client/views/animationtimeline/Region.tsx62
-rw-r--r--src/client/views/animationtimeline/Timeline.scss18
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx62
-rw-r--r--src/client/views/animationtimeline/TimelineMenu.scss78
-rw-r--r--src/client/views/animationtimeline/TimelineMenu.tsx5
-rw-r--r--src/client/views/animationtimeline/TimelineOverview.scss6
-rw-r--r--src/client/views/animationtimeline/Track.scss5
-rw-r--r--src/client/views/animationtimeline/Track.tsx68
9 files changed, 151 insertions, 155 deletions
diff --git a/src/client/views/animationtimeline/Region.scss b/src/client/views/animationtimeline/Region.scss
index f7476ab55..b390ae34e 100644
--- a/src/client/views/animationtimeline/Region.scss
+++ b/src/client/views/animationtimeline/Region.scss
@@ -1,4 +1,4 @@
-@import './../global/globalCssVariables.scss';
+@import './../global/globalCssVariables.module.scss';
$timelineColor: #9acedf;
$timelineDark: #77a1aa;
diff --git a/src/client/views/animationtimeline/Region.tsx b/src/client/views/animationtimeline/Region.tsx
index 53c5c4718..15cbbc16f 100644
--- a/src/client/views/animationtimeline/Region.tsx
+++ b/src/client/views/animationtimeline/Region.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
@@ -6,10 +6,11 @@ import { List } from '../../../fields/List';
import { createSchema, defaultSpec, listSpec, makeInterface } from '../../../fields/Schema';
import { Cast, NumCast } from '../../../fields/Types';
import { Transform } from '../../util/Transform';
-import '../global/globalCssVariables.scss';
+import '../global/globalCssVariables.module.scss';
import './Region.scss';
import './Timeline.scss';
import { TimelineMenu } from './TimelineMenu';
+import { ObservableReactComponent } from '../ObservableReactComponent';
/**
* Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also
@@ -31,11 +32,11 @@ export namespace RegionHelpers {
let rightMost: RegionData | undefined = undefined;
regions.forEach(region => {
const neighbor = RegionData(region);
- if (currentRegion.position! > neighbor.position) {
+ if (NumCast(currentRegion.position) > neighbor.position) {
if (!leftMost || neighbor.position > leftMost.position) {
leftMost = neighbor;
}
- } else if (currentRegion.position! < neighbor.position) {
+ } else if (NumCast(currentRegion.position) < neighbor.position) {
if (!rightMost || neighbor.position < rightMost.position) {
rightMost = neighbor;
}
@@ -156,44 +157,45 @@ interface IProps {
* @author Andrew Kim
*/
@observer
-export class Region extends React.Component<IProps> {
+export class Region extends ObservableReactComponent<IProps> {
@observable private _bar = React.createRef<HTMLDivElement>();
@observable private _mouseToggled = false;
@observable private _doubleClickEnabled = false;
@computed private get regiondata() {
- return RegionData(this.props.RegionData);
+ return RegionData(this._props.RegionData);
}
@computed private get regions() {
- return DocListCast(this.props.animatedDoc.regions);
+ return DocListCast(this._props.animatedDoc.regions);
}
@computed private get keyframes() {
return DocListCast(this.regiondata.keyframes);
}
@computed private get pixelPosition() {
- return RegionHelpers.convertPixelTime(this.regiondata.position, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ return RegionHelpers.convertPixelTime(this.regiondata.position, 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
}
@computed private get pixelDuration() {
- return RegionHelpers.convertPixelTime(this.regiondata.duration, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ return RegionHelpers.convertPixelTime(this.regiondata.duration, 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
}
@computed private get pixelFadeIn() {
- return RegionHelpers.convertPixelTime(this.regiondata.fadeIn, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ return RegionHelpers.convertPixelTime(this.regiondata.fadeIn, 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
}
@computed private get pixelFadeOut() {
- return RegionHelpers.convertPixelTime(this.regiondata.fadeOut, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ return RegionHelpers.convertPixelTime(this.regiondata.fadeOut, 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
}
constructor(props: any) {
super(props);
+ makeObservable(this);
}
componentDidMount() {
setTimeout(() => {
//giving it a temporary 1sec delay...
if (!this.regiondata.keyframes) this.regiondata.keyframes = new List<Doc>();
- const start = this.props.makeKeyData(this.regiondata, this.regiondata.position, RegionHelpers.KeyframeType.end);
- const fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, RegionHelpers.KeyframeType.fade);
- const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, RegionHelpers.KeyframeType.fade);
- const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, RegionHelpers.KeyframeType.end);
+ const start = this._props.makeKeyData(this.regiondata, this.regiondata.position, RegionHelpers.KeyframeType.end);
+ const fadeIn = this._props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, RegionHelpers.KeyframeType.fade);
+ const fadeOut = this._props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, RegionHelpers.KeyframeType.fade);
+ const finish = this._props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, RegionHelpers.KeyframeType.end);
fadeIn.opacity = 1;
fadeOut.opacity = 1;
start.opacity = 0.1;
@@ -212,7 +214,7 @@ export class Region extends React.Component<IProps> {
this._doubleClickEnabled = false;
} else {
setTimeout(() => {
- if (!this._mouseToggled && this._doubleClickEnabled) this.props.changeCurrentBarX(this.pixelPosition + (clientX - this._bar.current!.getBoundingClientRect().left) * this.props.transform.Scale);
+ if (!this._mouseToggled && this._doubleClickEnabled) this._props.changeCurrentBarX(this.pixelPosition + (clientX - this._bar.current!.getBoundingClientRect().left) * this._props.transform.Scale);
this._mouseToggled = false;
this._doubleClickEnabled = false;
}, 200);
@@ -234,7 +236,7 @@ export class Region extends React.Component<IProps> {
const left = RegionHelpers.findAdjacentRegion(RegionHelpers.Direction.left, this.regiondata, this.regions)!;
const right = RegionHelpers.findAdjacentRegion(RegionHelpers.Direction.right, this.regiondata, this.regions)!;
const prevX = this.regiondata.position;
- const futureX = this.regiondata.position + RegionHelpers.convertPixelTime(e.movementX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
+ const futureX = this.regiondata.position + RegionHelpers.convertPixelTime(e.movementX, 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement);
if (futureX <= 0) {
this.regiondata.position = 0;
} else if (left && left.position + left.duration >= futureX) {
@@ -273,7 +275,7 @@ export class Region extends React.Component<IProps> {
e.preventDefault();
e.stopPropagation();
const bar = this._bar.current!;
- const offset = RegionHelpers.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
+ const offset = RegionHelpers.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this._props.transform.Scale), 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement);
const leftRegion = RegionHelpers.findAdjacentRegion(RegionHelpers.Direction.left, this.regiondata, this.regions);
if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) {
this.regiondata.position = leftRegion.position + leftRegion.duration;
@@ -297,7 +299,7 @@ export class Region extends React.Component<IProps> {
e.preventDefault();
e.stopPropagation();
const bar = this._bar.current!;
- const offset = RegionHelpers.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
+ const offset = RegionHelpers.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this._props.transform.Scale), 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement);
const rightRegion = RegionHelpers.findAdjacentRegion(RegionHelpers.Direction.right, this.regiondata, this.regions);
const fadeOutKeyframeTime = NumCast(this.keyframes[this.keyframes.length - 3].time);
if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= fadeOutKeyframeTime) {
@@ -316,13 +318,13 @@ export class Region extends React.Component<IProps> {
createKeyframe = (clientX: number) => {
this._mouseToggled = true;
const bar = this._bar.current!;
- const offset = RegionHelpers.convertPixelTime(Math.round((clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
+ const offset = RegionHelpers.convertPixelTime(Math.round((clientX - bar.getBoundingClientRect().left) * this._props.transform.Scale), 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement);
if (offset > this.regiondata.fadeIn && offset < this.regiondata.duration - this.regiondata.fadeOut) {
//make sure keyframe is not created inbetween fades and ends
const position = this.regiondata.position;
- this.props.makeKeyData(this.regiondata, Math.round(position + offset), RegionHelpers.KeyframeType.default);
+ this._props.makeKeyData(this.regiondata, Math.round(position + offset), RegionHelpers.KeyframeType.default);
this.regiondata.hasData = true;
- this.props.changeCurrentBarX(RegionHelpers.convertPixelTime(Math.round(position + offset), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement)); //first move the keyframe to the correct location and make a copy so the correct file gets coppied
+ this._props.changeCurrentBarX(RegionHelpers.convertPixelTime(Math.round(position + offset), 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement)); //first move the keyframe to the correct location and make a copy so the correct file gets coppied
}
};
@@ -330,7 +332,7 @@ export class Region extends React.Component<IProps> {
moveKeyframe = (e: React.MouseEvent, kf: Doc) => {
e.preventDefault();
e.stopPropagation();
- this.props.changeCurrentBarX(RegionHelpers.convertPixelTime(NumCast(kf.time!), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement));
+ this._props.changeCurrentBarX(RegionHelpers.convertPixelTime(NumCast(kf.time!), 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement));
};
/**
@@ -373,7 +375,7 @@ export class Region extends React.Component<IProps> {
*/
@action
makeRegionMenu = (kf: Doc, e: MouseEvent) => {
- TimelineMenu.Instance.addItem('button', 'Remove Region', () => Cast(this.props.animatedDoc.regions, listSpec(Doc))?.splice(this.regions.indexOf(this.props.RegionData), 1)),
+ TimelineMenu.Instance.addItem('button', 'Remove Region', () => Cast(this._props.animatedDoc.regions, listSpec(Doc))?.splice(this.regions.indexOf(this._props.RegionData), 1)),
TimelineMenu.Instance.addItem('input', `fadeIn: ${this.regiondata.fadeIn}ms`, val => {
runInAction(() => {
let cannotMove: boolean = false;
@@ -459,7 +461,7 @@ export class Region extends React.Component<IProps> {
e.stopPropagation();
const div = ref.current!;
div.style.opacity = '1';
- Doc.BrushDoc(this.props.animatedDoc);
+ Doc.BrushDoc(this._props.animatedDoc);
};
/**
@@ -471,7 +473,7 @@ export class Region extends React.Component<IProps> {
e.stopPropagation();
const div = ref.current!;
div.style.opacity = '0';
- Doc.UnBrushDoc(this.props.animatedDoc);
+ Doc.UnBrushDoc(this._props.animatedDoc);
};
///////////////////////UI STUFF /////////////////////////
@@ -485,12 +487,12 @@ export class Region extends React.Component<IProps> {
return DocListCast(this.regiondata.keyframes).map(kf => {
return (
<>
- <div className="keyframe" style={{ left: `${RegionHelpers.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement) - this.pixelPosition}px` }}>
+ <div className="keyframe" style={{ left: `${RegionHelpers.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement) - this.pixelPosition}px` }}>
<div className="divider"></div>
<div
className="keyframeCircle keyframe-indicator"
style={{
- borderColor: this.props.saveStateKf === kf ? 'red' : undefined,
+ borderColor: this._props.saveStateKf === kf ? 'red' : undefined,
}}
onPointerDown={e => {
e.preventDefault();
@@ -525,8 +527,8 @@ export class Region extends React.Component<IProps> {
if (index !== this.keyframes.length - 1) {
const right = this.keyframes[index + 1];
const bodyRef = React.createRef<HTMLDivElement>();
- const kfPos = RegionHelpers.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
- const rightPos = RegionHelpers.convertPixelTime(NumCast(right.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ const kfPos = RegionHelpers.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
+ const rightPos = RegionHelpers.convertPixelTime(NumCast(right.time), 'mili', 'pixel', this._props.tickSpacing, this._props.tickIncrement);
keyframeDividers.push(
<div
ref={bodyRef}
diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss
index 48422b789..35ba0fa7f 100644
--- a/src/client/views/animationtimeline/Timeline.scss
+++ b/src/client/views/animationtimeline/Timeline.scss
@@ -1,4 +1,4 @@
-@import "./../global/globalCssVariables.scss";
+@import './../global/globalCssVariables.module.scss';
$timelineColor: #9acedf;
$timelineDark: #77a1aa;
@@ -30,7 +30,6 @@ $timelineDark: #77a1aa;
color: $timelineColor;
margin-left: 3px;
}
-
}
.grid-box {
@@ -61,7 +60,7 @@ $timelineDark: #77a1aa;
-webkit-transform: scale(1.1);
-ms-transform: scale(1.1);
transform: scale(1.1);
- transition: .2s ease;
+ transition: 0.2s ease;
}
}
@@ -128,7 +127,6 @@ $timelineDark: #77a1aa;
// margin-top: 0.5px;
}
}
-
}
.time-input {
@@ -154,7 +152,7 @@ $timelineDark: #77a1aa;
.number-label {
color: black;
transform: rotate(-90deg) translate(-15px, 8px);
- font-size: .85em;
+ font-size: 0.85em;
}
.timeline-container {
@@ -178,7 +176,6 @@ $timelineDark: #77a1aa;
background-color: transparent;
height: 30px;
width: 100%;
-
}
.scrubber {
@@ -217,7 +214,6 @@ $timelineDark: #77a1aa;
position: absolute;
// box-shadow: -10px 0px 10px 10px red;
}
-
}
.currentTime {
@@ -266,7 +262,6 @@ $timelineDark: #77a1aa;
p {
hyphens: auto;
}
-
}
}
@@ -280,8 +275,6 @@ $timelineDark: #77a1aa;
}
}
-
-
.overview {
position: absolute;
height: 50px;
@@ -298,7 +291,6 @@ $timelineDark: #77a1aa;
}
}
-
.timeline-checker {
height: auto;
width: auto;
@@ -312,11 +304,11 @@ $timelineDark: #77a1aa;
width: auto;
overflow: hidden;
margin: 0px 10px;
- cursor: pointer
+ cursor: pointer;
}
.check {
width: 50px;
height: 50px;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 4be3b05ab..f27a2d2fd 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -1,7 +1,7 @@
import { IconLookup } from '@fortawesome/fontawesome-svg-core';
import { faBackward, faForward, faGripLines, faPauseCircle, faPlayCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
@@ -14,6 +14,7 @@ import { RegionHelpers } from './Region';
import './Timeline.scss';
import { TimelineOverview } from './TimelineOverview';
import { Track } from './Track';
+import { ObservableReactComponent } from '../ObservableReactComponent';
/**
* Timeline class controls most of timeline functions besides individual region and track mechanism. Main functions are
@@ -43,7 +44,7 @@ import { Track } from './Track';
*/
@observer
-export class Timeline extends React.Component<FieldViewProps> {
+export class Timeline extends ObservableReactComponent<FieldViewProps> {
//readonly constants
private readonly DEFAULT_TICK_SPACING: number = 50;
private readonly MAX_TITLE_HEIGHT = 75;
@@ -54,6 +55,11 @@ export class Timeline extends React.Component<FieldViewProps> {
private DEFAULT_CONTAINER_HEIGHT: number = 330;
private MIN_CONTAINER_HEIGHT: number = 205;
+ constructor(props: any) {
+ super(props);
+ makeObservable(this);
+ }
+
//react refs
@observable private _trackbox = React.createRef<HTMLDivElement>();
@observable private _titleContainer = React.createRef<HTMLDivElement>();
@@ -82,11 +88,11 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@computed
private get children(): Doc[] {
- const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this.props.Document.type) as any);
+ const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this._props.Document.type) as any);
if (annotatedDoc) {
- return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + '_annotations']);
+ return DocListCast(this._props.Document[Doc.LayoutFieldKey(this._props.Document) + '_annotations']);
}
- return DocListCast(this.props.Document[this.props.fieldKey]);
+ return DocListCast(this._props.Document[this._props.fieldKey]);
}
/////////lifecycle functions////////////
@@ -96,21 +102,21 @@ export class Timeline extends React.Component<FieldViewProps> {
this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //check if relHeight is less than Maxheight. Else, just set relheight to max
this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; //offset
this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; //twice the titleheight + offset
- if (!this.props.Document.AnimationLength) {
+ if (!this._props.Document.AnimationLength) {
//if animation length did not exist
- this.props.Document.AnimationLength = this._time; //set it to default time
+ this._props.Document.AnimationLength = this._time; //set it to default time
} else {
- this._time = NumCast(this.props.Document.AnimationLength); //else, set time to animationlength stored from before
+ this._time = NumCast(this._props.Document.AnimationLength); //else, set time to animationlength stored from before
}
this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); //the entire length of the timeline div (actual div part itself)
this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; //the visible length of the timeline (the length that you current see)
this._visibleStart = this._infoContainer.current!.scrollLeft; //where the div starts
- this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on
+ this._props.Document.isATOn = !this._props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on
this.toggleHandle();
}
componentWillUnmount() {
- this.props.Document.AnimationLength = this._time; //save animation length
+ this._props.Document.AnimationLength = this._time; //save animation length
}
/////////////////////////////////////////////////
@@ -206,7 +212,7 @@ export class Timeline extends React.Component<FieldViewProps> {
onScrubberMove = (e: PointerEvent) => {
const scrubberbox = this._infoContainer.current!;
const left = scrubberbox.getBoundingClientRect().left;
- const offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale;
+ const offsetX = Math.round(e.clientX - left) * this._props.ScreenToLocalTransform().Scale;
this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position
return false;
};
@@ -233,7 +239,7 @@ export class Timeline extends React.Component<FieldViewProps> {
this._visibleStart -= e.movementX;
this._totalLength -= e.movementX;
this._time -= RegionHelpers.convertPixelTime(e.movementX, 'mili', 'time', this._tickSpacing, this._tickIncrement);
- this.props.Document.AnimationLength = this._time;
+ this._props.Document.AnimationLength = this._time;
}
return false;
};
@@ -349,8 +355,8 @@ export class Timeline extends React.Component<FieldViewProps> {
private timelineToolBox = (scale: number, totalTime: number) => {
const size = 40 * scale; //50 is default
const iconSize = 25;
- const width: number = this.props.PanelWidth();
- const modeType = this.props.Document.isATOn ? 'Author' : 'Play';
+ const width: number = this._props.PanelWidth();
+ const modeType = this._props.Document.isATOn ? 'Author' : 'Play';
//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
@@ -389,7 +395,7 @@ export class Timeline extends React.Component<FieldViewProps> {
tickIncrement={this._tickIncrement}
time={this._time}
parent={this}
- isAuthoring={BoolCast(this.props.Document.isATOn)}
+ isAuthoring={BoolCast(this._props.Document.isATOn)}
currentBarX={this._currentBarX}
totalLength={this._totalLength}
visibleLength={this._visibleLength}
@@ -410,10 +416,10 @@ export class Timeline extends React.Component<FieldViewProps> {
</div>
<div className="time-box overview-tool" style={{ display: 'flex' }}>
{this.timeIndicator(lengthString, totalTime)}
- <div className="resetView-tool" title="Return to Default View" onClick={() => this.resetView(this.props.Document)}>
+ <div className="resetView-tool" title="Return to Default View" onClick={() => this.resetView(this._props.Document)}>
<FontAwesomeIcon icon="compress-arrows-alt" size="lg" />
</div>
- <div className="resetView-tool" style={{ display: this.props.Document.isATOn ? 'flex' : 'none' }} title="Set Default View" onClick={() => this.setView(this.props.Document)}>
+ <div className="resetView-tool" style={{ display: this._props.Document.isATOn ? 'flex' : 'none' }} title="Set Default View" onClick={() => this.setView(this._props.Document)}>
<FontAwesomeIcon icon="expand-arrows-alt" size="lg" />
</div>
</div>
@@ -423,17 +429,17 @@ export class Timeline extends React.Component<FieldViewProps> {
};
timeIndicator(lengthString: string, totalTime: number) {
- if (this.props.Document.isATOn) {
- return <div key="time-text" className="animation-text" style={{ visibility: this.props.Document.isATOn ? 'visible' : 'hidden', display: this.props.Document.isATOn ? 'flex' : 'none' }}>{`Total: ${this.toReadTime(totalTime)}`}</div>;
+ if (this._props.Document.isATOn) {
+ return <div key="time-text" className="animation-text" style={{ visibility: this._props.Document.isATOn ? 'visible' : 'hidden', display: this._props.Document.isATOn ? 'flex' : 'none' }}>{`Total: ${this.toReadTime(totalTime)}`}</div>;
} else {
const ctime = `Current: ${this.getCurrentTime()}`;
const ttime = `Total: ${this.toReadTime(this._time)}`;
return (
<div style={{ flexDirection: 'column' }}>
- <div className="animation-text" style={{ fontSize: '10px', width: '100%', display: !this.props.Document.isATOn ? 'block' : 'none' }}>
+ <div className="animation-text" style={{ fontSize: '10px', width: '100%', display: !this._props.Document.isATOn ? 'block' : 'none' }}>
{ctime}
</div>
- <div className="animation-text" style={{ fontSize: '10px', width: '100%', display: !this.props.Document.isATOn ? 'block' : 'none' }}>
+ <div className="animation-text" style={{ fontSize: '10px', width: '100%', display: !this._props.Document.isATOn ? 'block' : 'none' }}>
{ttime}
</div>
</div>
@@ -459,8 +465,8 @@ export class Timeline extends React.Component<FieldViewProps> {
const roundToggleContainer = this._roundToggleContainerRef.current!;
const timelineContainer = this._timelineContainer.current!;
- this.props.Document.isATOn = !this.props.Document.isATOn;
- if (!BoolCast(this.props.Document.isATOn)) {
+ this._props.Document.isATOn = !this._props.Document.isATOn;
+ if (!BoolCast(this._props.Document.isATOn)) {
//turning on playmode...
roundToggle.style.transform = 'translate(0px, 0px)';
roundToggle.style.animationName = 'turnoff';
@@ -535,7 +541,7 @@ export class Timeline extends React.Component<FieldViewProps> {
// change visible and total width
return (
<div style={{ visibility: 'visible' }}>
- <div key="timeline_wrapper" style={{ visibility: this.props.Document.isATOn ? 'visible' : 'hidden', left: '0px', top: '0px', position: 'absolute', width: '100%', transform: 'translate(0px, 0px)' }}>
+ <div key="timeline_wrapper" style={{ visibility: this._props.Document.isATOn ? 'visible' : 'hidden', left: '0px', top: '0px', position: 'absolute', width: '100%', transform: 'translate(0px, 0px)' }}>
<div key="timeline_container" className="timeline-container" ref={this._timelineContainer} style={{ height: `${this._containerHeight}px`, top: `0px` }}>
<div key="timeline_info" className="info-container" onPointerDown={this.onPanDown} ref={this._infoContainer} onWheel={this.onWheelZoom}>
{this.drawTicks()}
@@ -543,18 +549,18 @@ export class Timeline extends React.Component<FieldViewProps> {
<div key="timeline_scrubberhead" className="scrubberhead" onPointerDown={this.onScrubberDown}></div>
</div>
<div key="timeline_trackbox" className="trackbox" ref={this._trackbox} style={{ width: `${this._totalLength}px` }}>
- {[...this.children, this.props.Document].map(doc => (
+ {[...this.children, this._props.Document].map(doc => (
<Track
ref={ref => this.mapOfTracks.push(ref)}
timeline={this}
animatedDoc={doc}
currentBarX={this._currentBarX}
changeCurrentBarX={this.changeCurrentBarX}
- transform={this.props.ScreenToLocalTransform()}
+ transform={this._props.ScreenToLocalTransform()}
time={this._time}
tickSpacing={this._tickSpacing}
tickIncrement={this._tickIncrement}
- collection={this.props.Document}
+ collection={this._props.Document}
timelineVisible={true}
/>
))}
@@ -562,7 +568,7 @@ export class Timeline extends React.Component<FieldViewProps> {
</div>
<div className="currentTime">Current: {this.getCurrentTime()}</div>
<div key="timeline_title" className="title-container" ref={this._titleContainer}>
- {[...this.children, this.props.Document].map(doc => (
+ {[...this.children, this._props.Document].map(doc => (
<div style={{ height: `${this._titleHeight}px` }} className="datapane" onPointerOver={() => Doc.BrushDoc(doc)} onPointerOut={() => Doc.UnBrushDoc(doc)}>
<p>{StrCast(doc.title)}</p>
</div>
diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss
index 43a89419e..de2042f17 100644
--- a/src/client/views/animationtimeline/TimelineMenu.scss
+++ b/src/client/views/animationtimeline/TimelineMenu.scss
@@ -1,56 +1,49 @@
-@import "./../global/globalCssVariables.scss";
+@import './../global/globalCssVariables.module.scss';
-
-.timeline-menu-container{
+.timeline-menu-container {
position: absolute;
display: flex;
box-shadow: $medium-gray 0.2vw 0.2vw 0.4vw;
flex-direction: column;
background: whitesmoke;
z-index: 10000;
- width: 200px;
+ width: 200px;
padding-bottom: 10px;
border-radius: 15px;
- border: solid #BBBBBBBB 1px;
-
-
+ border: solid #bbbbbbbb 1px;
- .timeline-menu-input{
- font: $sans-serif;
- font-size: 13px;
- width:100%;
- text-transform: uppercase;
- letter-spacing: 2px;
- margin-left: 10px;
- background-color: transparent;
- border-width: 0px;
- transition: border-width 500ms;
+ .timeline-menu-input {
+ font: $sans-serif;
+ font-size: 13px;
+ width: 100%;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ margin-left: 10px;
+ background-color: transparent;
+ border-width: 0px;
+ transition: border-width 500ms;
}
- .timeline-menu-input:hover{
- border-width: 2px;
+ .timeline-menu-input:hover {
+ border-width: 2px;
}
-
-
-
- .timeline-menu-header{
- border-top-left-radius: 15px;
- border-top-right-radius: 15px;
- text-transform: uppercase;
- background: $dark-gray;
- letter-spacing: 2px;
+ .timeline-menu-header {
+ border-top-left-radius: 15px;
+ border-top-right-radius: 15px;
+ text-transform: uppercase;
+ background: $dark-gray;
+ letter-spacing: 2px;
- .timeline-menu-header-desc{
- font:$sans-serif;
- font-size: 13px;
- text-align: center;
- color: whitesmoke;
+ .timeline-menu-header-desc {
+ font: $sans-serif;
+ font-size: 13px;
+ text-align: center;
+ color: whitesmoke;
}
}
-
.timeline-menu-item {
// width: 11vw; //10vw
height: 30px; //2vh
@@ -64,7 +57,7 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
- transition: all .1s;
+ transition: all 0.1s;
border-style: none;
// padding: 10px 0px 10px 0px;
white-space: nowrap;
@@ -73,22 +66,21 @@
letter-spacing: 2px;
text-transform: uppercase;
padding-right: 20px;
- padding-left: 10px;
+ padding-left: 10px;
}
.timeline-menu-item:hover {
- border-width: .11px;
+ border-width: 0.11px;
border-style: none;
border-color: $medium-gray;
border-bottom-style: solid;
border-top-style: solid;
- background: $medium-blue;
+ background: $medium-blue;
}
.timeline-menu-desc {
- padding-left: 10px;
- font:$sans-serif;
- font-size: 13px;
+ padding-left: 10px;
+ font: $sans-serif;
+ font-size: 13px;
}
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx
index 1769c41bd..97a571dc4 100644
--- a/src/client/views/animationtimeline/TimelineMenu.tsx
+++ b/src/client/views/animationtimeline/TimelineMenu.tsx
@@ -1,7 +1,7 @@
import { IconLookup } from '@fortawesome/fontawesome-svg-core';
import { faChartLine, faClipboard } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, observable } from 'mobx';
+import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Utils } from '../../../Utils';
@@ -16,8 +16,9 @@ export class TimelineMenu extends React.Component {
@observable private _y = 0;
@observable private _currentMenu: JSX.Element[] = [];
- constructor(props: Readonly<{}>) {
+ constructor(props: any) {
super(props);
+ makeObservable(this);
TimelineMenu.Instance = this;
}
diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss
index c8d96c399..2878232e6 100644
--- a/src/client/views/animationtimeline/TimelineOverview.scss
+++ b/src/client/views/animationtimeline/TimelineOverview.scss
@@ -1,4 +1,4 @@
-@import "./../global/globalCssVariables.scss";
+@import './../global/globalCssVariables.module.scss';
$timelineColor: #9acedf;
$timelineDark: #77a1aa;
@@ -66,8 +66,6 @@ $timelineDark: #77a1aa;
}
}
-
-
.timeline-play-bar {
position: relative;
padding: 0px;
@@ -104,4 +102,4 @@ $timelineDark: #77a1aa;
border-radius: 20px;
margin-top: -4px;
cursor: pointer;
-} \ No newline at end of file
+}
diff --git a/src/client/views/animationtimeline/Track.scss b/src/client/views/animationtimeline/Track.scss
index f45e0556d..f56b2fe5f 100644
--- a/src/client/views/animationtimeline/Track.scss
+++ b/src/client/views/animationtimeline/Track.scss
@@ -1,7 +1,6 @@
-@import "./../global/globalCssVariables.scss";
+@import './../global/globalCssVariables.module.scss';
.track-container {
-
.track {
.inner {
top: 0px;
@@ -12,4 +11,4 @@
z-index: 100;
}
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx
index d959241d0..00aa51cac 100644
--- a/src/client/views/animationtimeline/Track.tsx
+++ b/src/client/views/animationtimeline/Track.tsx
@@ -1,4 +1,4 @@
-import { action, computed, intercept, observable, reaction, runInAction } from 'mobx';
+import { action, computed, intercept, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, DocListCastAsync, Opt } from '../../../fields/Doc';
@@ -11,6 +11,7 @@ import { Transform } from '../../util/Transform';
import { Region, RegionData, RegionHelpers } from './Region';
import { Timeline } from './Timeline';
import './Track.scss';
+import { ObservableReactComponent } from '../ObservableReactComponent';
interface IProps {
timeline: Timeline;
@@ -26,7 +27,7 @@ interface IProps {
}
@observer
-export class Track extends React.Component<IProps> {
+export class Track extends ObservableReactComponent<IProps> {
@observable private _inner = React.createRef<HTMLDivElement>();
@observable private _currentBarXReaction: any;
@observable private _timelineVisibleReaction: any;
@@ -37,24 +38,29 @@ export class Track extends React.Component<IProps> {
private primitiveWhitelist = ['x', 'y', '_freeform_panX', '_freeform_panY', '_width', '_height', '_rotation', 'opacity', '_layout_scrollTop'];
private objectWhitelist = ['data'];
+ constructor(props: any) {
+ super(props);
+ makeObservable(this);
+ }
+
@computed private get regions() {
- return DocListCast(this.props.animatedDoc.regions);
+ return DocListCast(this._props.animatedDoc.regions);
}
@computed private get time() {
- return NumCast(RegionHelpers.convertPixelTime(this.props.currentBarX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+ return NumCast(RegionHelpers.convertPixelTime(this._props.currentBarX, 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement));
}
componentDidMount() {
- DocListCastAsync(this.props.animatedDoc.regions).then(regions => {
- if (!regions) this.props.animatedDoc.regions = new List<Doc>(); //if there is no region, then create new doc to store stuff
+ DocListCastAsync(this._props.animatedDoc.regions).then(regions => {
+ if (!regions) this._props.animatedDoc.regions = new List<Doc>(); //if there is no region, then create new doc to store stuff
//these two lines are exactly same from timeline.tsx
const relativeHeight = window.innerHeight / 20;
runInAction(() => (this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT)); //for responsiveness
this._timelineVisibleReaction = this.timelineVisibleReaction();
this._currentBarXReaction = this.currentBarXReaction();
- if (DocListCast(this.props.animatedDoc.regions).length === 0) this.createRegion(this.time);
- this.props.animatedDoc.hidden = false;
- this.props.animatedDoc.opacity = 1;
+ if (DocListCast(this._props.animatedDoc.regions).length === 0) this.createRegion(this.time);
+ this._props.animatedDoc.hidden = false;
+ this._props.animatedDoc.opacity = 1;
// this.autoCreateKeyframe();
});
}
@@ -88,7 +94,7 @@ export class Track extends React.Component<IProps> {
*/
@action
saveKeyframe = () => {
- if (this.props.timeline.IsPlaying || !this.saveStateRegion || !this.saveStateKf) {
+ if (this._props.timeline.IsPlaying || !this.saveStateRegion || !this.saveStateKf) {
this.saveStateKf = undefined;
this.saveStateRegion = undefined;
return;
@@ -130,13 +136,13 @@ export class Track extends React.Component<IProps> {
*/
@action
autoCreateKeyframe = () => {
- const objects = this.objectWhitelist.map(key => this.props.animatedDoc[key]);
- intercept(this.props.animatedDoc, change => {
+ const objects = this.objectWhitelist.map(key => this._props.animatedDoc[key]);
+ intercept(this._props.animatedDoc, change => {
return change;
});
return reaction(
() => {
- return [...this.primitiveWhitelist.map(key => this.props.animatedDoc[key]), ...objects];
+ return [...this.primitiveWhitelist.map(key => this._props.animatedDoc[key]), ...objects];
},
(changed, reaction) => {
//check for region
@@ -170,18 +176,18 @@ export class Track extends React.Component<IProps> {
@action
currentBarXReaction = () => {
return reaction(
- () => this.props.currentBarX,
+ () => this._props.currentBarX,
() => {
const regiondata = this.findRegion(this.time);
if (regiondata) {
- this.props.animatedDoc.hidden = false;
+ this._props.animatedDoc.hidden = false;
// if (!this._autoKfReaction) {
// // this._autoKfReaction = this.autoCreateKeyframe();
// }
this.timeChange();
} else {
- this.props.animatedDoc.hidden = true;
- this.props.animatedDoc !== this.props.collection && (this.props.animatedDoc.opacity = 0);
+ this._props.animatedDoc.hidden = true;
+ this._props.animatedDoc !== this._props.collection && (this._props.animatedDoc.opacity = 0);
//if (this._autoKfReaction) this._autoKfReaction();
}
}
@@ -195,7 +201,7 @@ export class Track extends React.Component<IProps> {
timelineVisibleReaction = () => {
return reaction(
() => {
- return this.props.timelineVisible;
+ return this._props.timelineVisible;
},
isVisible => {
if (isVisible) {
@@ -252,14 +258,14 @@ export class Track extends React.Component<IProps> {
@action
private applyKeys = (kf: Doc) => {
this.primitiveWhitelist.forEach(key => {
- if (key === 'opacity' && this.props.animatedDoc === this.props.collection) {
+ if (key === 'opacity' && this._props.animatedDoc === this._props.collection) {
return;
}
if (!kf[key]) {
- this.props.animatedDoc[key] = undefined;
+ this._props.animatedDoc[key] = undefined;
} else {
const stored = kf[key];
- this.props.animatedDoc[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
+ this._props.animatedDoc[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
}
});
};
@@ -283,7 +289,7 @@ export class Track extends React.Component<IProps> {
@action
interpolate = (left: Doc, right: Doc) => {
this.primitiveWhitelist.forEach(key => {
- if (key === 'opacity' && this.props.animatedDoc === this.props.collection) {
+ if (key === 'opacity' && this._props.animatedDoc === this._props.collection) {
return;
}
if (typeof left[key] === 'number' && typeof right[key] === 'number') {
@@ -291,11 +297,11 @@ export class Track extends React.Component<IProps> {
const dif = NumCast(right[key]) - NumCast(left[key]);
const deltaLeft = this.time - NumCast(left.time);
const ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time));
- this.props.animatedDoc[key] = NumCast(left[key]) + dif * ratio;
+ this._props.animatedDoc[key] = NumCast(left[key]) + dif * ratio;
} else {
// case data
const stored = left[key];
- this.props.animatedDoc[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
+ this._props.animatedDoc[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
}
});
};
@@ -314,8 +320,8 @@ export class Track extends React.Component<IProps> {
@action
onInnerDoubleClick = (e: React.MouseEvent) => {
const inner = this._inner.current!;
- const offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale);
- this.createRegion(RegionHelpers.convertPixelTime(offsetX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+ const offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this._props.transform.Scale);
+ this.createRegion(RegionHelpers.convertPixelTime(offsetX, 'mili', 'time', this._props.tickSpacing, this._props.tickIncrement));
};
/**
@@ -335,7 +341,7 @@ export class Track extends React.Component<IProps> {
regiondata.duration = rightRegion.position - regiondata.position;
}
if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) {
- Cast(this.props.animatedDoc.regions, listSpec(Doc))?.push(regiondata);
+ Cast(this._props.animatedDoc.regions, listSpec(Doc))?.push(regiondata);
this._newKeyframe = true;
this.saveStateRegion = regiondata;
return regiondata;
@@ -370,7 +376,7 @@ export class Track extends React.Component<IProps> {
copyDocDataToKeyFrame = (doc: Doc) => {
var somethingChanged = false;
this.primitiveWhitelist.map(key => {
- const originalVal = this.props.animatedDoc[key];
+ const originalVal = this._props.animatedDoc[key];
somethingChanged = somethingChanged || originalVal !== doc[key];
if (doc.type === RegionHelpers.KeyframeType.end && key === 'opacity') doc.opacity = 0;
else doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : originalVal;
@@ -391,10 +397,10 @@ export class Track extends React.Component<IProps> {
ref={this._inner}
style={{ height: `${this._trackHeight}px` }}
onDoubleClick={this.onInnerDoubleClick}
- onPointerOver={() => Doc.BrushDoc(this.props.animatedDoc)}
- onPointerOut={() => Doc.UnBrushDoc(this.props.animatedDoc)}>
+ onPointerOver={() => Doc.BrushDoc(this._props.animatedDoc)}
+ onPointerOut={() => Doc.UnBrushDoc(this._props.animatedDoc)}>
{this.regions?.map((region, i) => {
- return <Region key={`${i}`} {...this.props} saveStateKf={saveStateKf} RegionData={region} makeKeyData={this.makeKeyData} />;
+ return <Region key={`${i}`} {...this._props} saveStateKf={saveStateKf} RegionData={region} makeKeyData={this.makeKeyData} />;
})}
</div>
</div>