diff options
| author | bobzel <zzzman@gmail.com> | 2023-12-21 14:55:48 -0500 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2023-12-21 14:55:48 -0500 |
| commit | 1caba64ee0f32ee8af79263cd4ef2a8bc5d5146e (patch) | |
| tree | 0fa0e957d1f342fdc6ed4a4b43f5dddfddb1298a /src/client/views/animationtimeline | |
| parent | 02eb7da95df283606d4275a22d9451cef371c3b5 (diff) | |
| parent | 2691b951d96f2ce7652acbea9e340b61737b3b57 (diff) | |
Merge branch 'moreUpgrading' into dataViz-annotations
Diffstat (limited to 'src/client/views/animationtimeline')
| -rw-r--r-- | src/client/views/animationtimeline/Region.scss | 2 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/Region.tsx | 62 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/Timeline.scss | 18 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/Timeline.tsx | 62 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/TimelineMenu.scss | 78 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/TimelineMenu.tsx | 5 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/TimelineOverview.scss | 6 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/Track.scss | 5 | ||||
| -rw-r--r-- | src/client/views/animationtimeline/Track.tsx | 68 |
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> |
