aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/animationtimeline
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-06-23 21:44:01 -0400
committerbobzel <zzzman@gmail.com>2023-06-23 21:44:01 -0400
commit85c017527f209c9d007d67ac70958843ab45e729 (patch)
treee2649860002e0c60e98d84439a67235002ddd9a4 /src/client/views/animationtimeline
parente9d5dbeef2bf1dab9dfb863d970b70b3074e3d0a (diff)
parent1429ab79eac9aa316082f52c14c576f6b3a97111 (diff)
Merge branch 'master' into heartbeat
Diffstat (limited to 'src/client/views/animationtimeline')
-rw-r--r--src/client/views/animationtimeline/Keyframe.tsx418
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx14
-rw-r--r--src/client/views/animationtimeline/Track.tsx261
3 files changed, 376 insertions, 317 deletions
diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx
index 92d3e2bed..3465a5283 100644
--- a/src/client/views/animationtimeline/Keyframe.tsx
+++ b/src/client/views/animationtimeline/Keyframe.tsx
@@ -1,38 +1,37 @@
-import { action, computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc, DocListCast, Opt } from "../../../fields/Doc";
-import { List } from "../../../fields/List";
-import { createSchema, defaultSpec, listSpec, makeInterface } from "../../../fields/Schema";
-import { Cast, NumCast } from "../../../fields/Types";
-import { Docs } from "../../documents/Documents";
-import { Transform } from "../../util/Transform";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import "../global/globalCssVariables.scss";
-import "./Keyframe.scss";
-import "./Timeline.scss";
-import { TimelineMenu } from "./TimelineMenu";
-
+import { action, computed, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { createSchema, defaultSpec, listSpec, makeInterface } from '../../../fields/Schema';
+import { Cast, NumCast } from '../../../fields/Types';
+import { Docs } from '../../documents/Documents';
+import { Transform } from '../../util/Transform';
+import { CollectionDockingView } from '../collections/CollectionDockingView';
+import '../global/globalCssVariables.scss';
+import { OpenWhereMod } from '../nodes/DocumentView';
+import './Keyframe.scss';
+import './Timeline.scss';
+import { TimelineMenu } from './TimelineMenu';
/**
- * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also
+ * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also
*/
export namespace KeyframeFunc {
-
export enum KeyframeType {
- end = "end",
- fade = "fade",
- default = "default",
+ end = 'end',
+ fade = 'fade',
+ default = 'default',
}
export enum Direction {
- left = "left",
- right = "right"
+ left = 'left',
+ right = 'right',
}
- export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: Doc[]): (RegionData | undefined) => {
- let leftMost: (RegionData | undefined) = undefined;
- let rightMost: (RegionData | undefined) = undefined;
+ export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: Doc[]): RegionData | undefined => {
+ let leftMost: RegionData | undefined = undefined;
+ let rightMost: RegionData | undefined = undefined;
regions.forEach(region => {
const neighbor = RegionData(region);
if (currentRegion.position! > neighbor.position) {
@@ -52,11 +51,12 @@ export namespace KeyframeFunc {
}
};
- export const calcMinLeft = (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closet keyframe to the left
+ export const calcMinLeft = (region: Doc, currentBarX: number, ref?: Doc) => {
+ //returns the time of the closet keyframe to the left
let leftKf: Opt<Doc>;
let time: number = 0;
const keyframes = DocListCast(region.keyframes!);
- keyframes.map((kf) => {
+ keyframes.map(kf => {
let compTime = currentBarX;
if (ref) compTime = NumCast(ref.time);
if (NumCast(kf.time) < compTime && NumCast(kf.time) >= time) {
@@ -67,11 +67,11 @@ export namespace KeyframeFunc {
return leftKf;
};
-
- export const calcMinRight = (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closest keyframe to the right
+ export const calcMinRight = (region: Doc, currentBarX: number, ref?: Doc) => {
+ //returns the time of the closest keyframe to the right
let rightKf: Opt<Doc>;
let time: number = Infinity;
- DocListCast(region.keyframes!).forEach((kf) => {
+ DocListCast(region.keyframes!).forEach(kf => {
let compTime = currentBarX;
if (ref) compTime = NumCast(ref.time);
if (NumCast(kf.time) > compTime && NumCast(kf.time) <= NumCast(time)) {
@@ -93,27 +93,31 @@ export namespace KeyframeFunc {
return regiondata;
};
-
- export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing: number, tickIncrement: number) => {
- const time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement;
+ export const convertPixelTime = (pos: number, unit: 'mili' | 'sec' | 'min' | 'hr', dir: 'pixel' | 'time', tickSpacing: number, tickIncrement: number) => {
+ const time = dir === 'pixel' ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement;
switch (unit) {
- case "mili": return time;
- case "sec": return dir === "pixel" ? time / 1000 : time * 1000;
- case "min": return dir === "pixel" ? time / 60000 : time * 60000;
- case "hr": return dir === "pixel" ? time / 3600000 : time * 3600000;
- default: return time;
+ case 'mili':
+ return time;
+ case 'sec':
+ return dir === 'pixel' ? time / 1000 : time * 1000;
+ case 'min':
+ return dir === 'pixel' ? time / 60000 : time * 60000;
+ case 'hr':
+ return dir === 'pixel' ? time / 3600000 : time * 3600000;
+ default:
+ return time;
}
};
}
export const RegionDataSchema = createSchema({
- position: defaultSpec("number", 0),
- duration: defaultSpec("number", 0),
+ position: defaultSpec('number', 0),
+ duration: defaultSpec('number', 0),
keyframes: listSpec(Doc),
- fadeIn: defaultSpec("number", 0),
- fadeOut: defaultSpec("number", 0),
+ fadeIn: defaultSpec('number', 0),
+ fadeOut: defaultSpec('number', 0),
functions: listSpec(Doc),
- hasData: defaultSpec("boolean", false)
+ hasData: defaultSpec('boolean', false),
});
export type RegionData = makeInterface<[typeof RegionDataSchema]>;
export const RegionData = makeInterface(RegionDataSchema);
@@ -130,50 +134,63 @@ interface IProps {
makeKeyData: (region: RegionData, pos: number, kftype: KeyframeFunc.KeyframeType) => Doc;
}
-
/**
- *
+ *
* This class handles the green region stuff
* Key facts:
- *
+ *
* Structure looks like this
- *
+ *
* region as a whole
* <------------------------------REGION------------------------------->
- *
- * region broken down
- *
+ *
+ * region broken down
+ *
* <|---------|############ MAIN CONTENT #################|-----------|> .....followed by void.........
* (start) (Fade 2)
* (fade 1) (finish)
- *
- *
- * As you can see, this is different from After Effect and Premiere Pro, but this is how TAG worked.
- * If you want to checkout TAG, it's in the lockers, and the password is the usual lab door password. It's the blue laptop.
- * If you want to know the exact location of the computer, message me.
- *
- * @author Andrew Kim
+ *
+ *
+ * As you can see, this is different from After Effect and Premiere Pro, but this is how TAG worked.
+ * If you want to checkout TAG, it's in the lockers, and the password is the usual lab door password. It's the blue laptop.
+ * If you want to know the exact location of the computer, message me.
+ *
+ * @author Andrew Kim
*/
@observer
export class Keyframe extends React.Component<IProps> {
-
@observable private _bar = React.createRef<HTMLDivElement>();
@observable private _mouseToggled = false;
@observable private _doubleClickEnabled = false;
- @computed private get regiondata() { return RegionData(this.props.RegionData); }
- @computed private get regions() { return DocListCast(this.props.node.regions); }
- @computed private get keyframes() { return DocListCast(this.regiondata.keyframes); }
- @computed private get pixelPosition() { return KeyframeFunc.convertPixelTime(this.regiondata.position, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); }
- @computed private get pixelDuration() { return KeyframeFunc.convertPixelTime(this.regiondata.duration, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); }
- @computed private get pixelFadeIn() { return KeyframeFunc.convertPixelTime(this.regiondata.fadeIn, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); }
- @computed private get pixelFadeOut() { return KeyframeFunc.convertPixelTime(this.regiondata.fadeOut, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); }
+ @computed private get regiondata() {
+ return RegionData(this.props.RegionData);
+ }
+ @computed private get regions() {
+ return DocListCast(this.props.node.regions);
+ }
+ @computed private get keyframes() {
+ return DocListCast(this.regiondata.keyframes);
+ }
+ @computed private get pixelPosition() {
+ return KeyframeFunc.convertPixelTime(this.regiondata.position, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ }
+ @computed private get pixelDuration() {
+ return KeyframeFunc.convertPixelTime(this.regiondata.duration, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ }
+ @computed private get pixelFadeIn() {
+ return KeyframeFunc.convertPixelTime(this.regiondata.fadeIn, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ }
+ @computed private get pixelFadeOut() {
+ return KeyframeFunc.convertPixelTime(this.regiondata.fadeOut, 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ }
constructor(props: any) {
super(props);
}
componentDidMount() {
- setTimeout(() => { //giving it a temporary 1sec delay...
+ 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, KeyframeFunc.KeyframeType.end);
const fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade);
@@ -202,12 +219,12 @@ export class Keyframe extends React.Component<IProps> {
this._doubleClickEnabled = false;
}, 200);
this._doubleClickEnabled = true;
- document.addEventListener("pointermove", this.onBarPointerMove);
- document.addEventListener("pointerup", (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onBarPointerMove);
+ document.addEventListener('pointermove', this.onBarPointerMove);
+ document.addEventListener('pointerup', (e: PointerEvent) => {
+ document.removeEventListener('pointermove', this.onBarPointerMove);
});
}
- }
+ };
@action
onBarPointerMove = (e: PointerEvent) => {
@@ -219,46 +236,46 @@ export class Keyframe extends React.Component<IProps> {
const left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!;
const right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions)!;
const prevX = this.regiondata.position;
- const futureX = this.regiondata.position + KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement);
+ const futureX = this.regiondata.position + KeyframeFunc.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)) {
+ } else if (left && left.position + left.duration >= futureX) {
this.regiondata.position = left.position + left.duration;
- } else if ((right && right.position <= futureX + this.regiondata.duration)) {
+ } else if (right && right.position <= futureX + this.regiondata.duration) {
this.regiondata.position = right.position - this.regiondata.duration;
} else {
this.regiondata.position = futureX;
}
const movement = this.regiondata.position - prevX;
- this.keyframes.forEach(kf => kf.time = NumCast(kf.time) + movement);
- }
+ this.keyframes.forEach(kf => (kf.time = NumCast(kf.time) + movement));
+ };
@action
onResizeLeft = (e: React.PointerEvent) => {
e.preventDefault();
e.stopPropagation();
- document.addEventListener("pointermove", this.onDragResizeLeft);
- document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onDragResizeLeft);
+ document.addEventListener('pointermove', this.onDragResizeLeft);
+ document.addEventListener('pointerup', () => {
+ document.removeEventListener('pointermove', this.onDragResizeLeft);
});
- }
+ };
@action
onResizeRight = (e: React.PointerEvent) => {
e.preventDefault();
e.stopPropagation();
- document.addEventListener("pointermove", this.onDragResizeRight);
- document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onDragResizeRight);
+ document.addEventListener('pointermove', this.onDragResizeRight);
+ document.addEventListener('pointerup', () => {
+ document.removeEventListener('pointermove', this.onDragResizeRight);
});
- }
+ };
@action
onDragResizeLeft = (e: PointerEvent) => {
e.preventDefault();
e.stopPropagation();
const bar = this._bar.current!;
- const offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement);
+ const offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
const leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions);
if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) {
this.regiondata.position = leftRegion.position + leftRegion.duration;
@@ -275,90 +292,91 @@ export class Keyframe extends React.Component<IProps> {
}
this.keyframes[0].time = this.regiondata.position;
this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn;
- }
-
+ };
@action
onDragResizeRight = (e: PointerEvent) => {
e.preventDefault();
e.stopPropagation();
const bar = this._bar.current!;
- const offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement);
+ const offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement);
const rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.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) { //case 1: when third to last keyframe is in the way
+ if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= fadeOutKeyframeTime) {
+ //case 1: when third to last keyframe is in the way
this.regiondata.duration = fadeOutKeyframeTime - this.regiondata.position + this.regiondata.fadeOut;
- } else if (rightRegion && (this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position)) {
+ } else if (rightRegion && this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position) {
this.regiondata.duration = rightRegion.position - this.regiondata.position;
} else {
this.regiondata.duration += offset;
}
this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut;
this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration;
- }
-
+ };
@action
createKeyframe = async (clientX: number) => {
this._mouseToggled = true;
const bar = this._bar.current!;
- const offset = KeyframeFunc.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 offset = KeyframeFunc.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), KeyframeFunc.KeyframeType.default);
this.regiondata.hasData = true;
- this.props.changeCurrentBarX(KeyframeFunc.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(KeyframeFunc.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
}
- }
-
+ };
@action
moveKeyframe = async (e: React.MouseEvent, kf: Doc) => {
e.preventDefault();
e.stopPropagation();
- this.props.changeCurrentBarX(KeyframeFunc.convertPixelTime(NumCast(kf.time!), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement));
- }
+ this.props.changeCurrentBarX(KeyframeFunc.convertPixelTime(NumCast(kf.time!), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement));
+ };
/**
* custom keyframe context menu items (when clicking on the keyframe circle)
*/
@action
makeKeyframeMenu = (kf: Doc, e: MouseEvent) => {
- TimelineMenu.Instance.addItem("button", "Toggle Fade Only", () => {
+ TimelineMenu.Instance.addItem('button', 'Toggle Fade Only', () => {
kf.type = kf.type === KeyframeFunc.KeyframeType.fade ? KeyframeFunc.KeyframeType.default : KeyframeFunc.KeyframeType.fade;
}),
- TimelineMenu.Instance.addItem("button", "Show Data", action(() => {
- const kvp = Docs.Create.KVPDocument(kf, { _width: 300, _height: 300 });
- CollectionDockingView.AddSplit(kvp, "right");
- })),
- TimelineMenu.Instance.addItem("button", "Delete", action(() => {
- (this.regiondata.keyframes as List<Doc>).splice(this.keyframes.indexOf(kf), 1);
- this.forceUpdate();
- })),
- TimelineMenu.Instance.addItem("input", "Move", action((val) => {
- let cannotMove: boolean = false;
- const kfIndex: number = this.keyframes.indexOf(kf);
- if (val < 0 || (val < NumCast(this.keyframes[kfIndex - 1].time) || val > NumCast(this.keyframes[kfIndex + 1].time))) {
- cannotMove = true;
- }
- if (!cannotMove) {
- this.keyframes[kfIndex].time = parseInt(val, 10);
- this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn;
- }
- }));
- TimelineMenu.Instance.addMenu("Keyframe");
+ TimelineMenu.Instance.addItem(
+ 'button',
+ 'Delete',
+ action(() => {
+ (this.regiondata.keyframes as List<Doc>).splice(this.keyframes.indexOf(kf), 1);
+ this.forceUpdate();
+ })
+ ),
+ TimelineMenu.Instance.addItem(
+ 'input',
+ 'Move',
+ action(val => {
+ let cannotMove: boolean = false;
+ const kfIndex: number = this.keyframes.indexOf(kf);
+ if (val < 0 || val < NumCast(this.keyframes[kfIndex - 1].time) || val > NumCast(this.keyframes[kfIndex + 1].time)) {
+ cannotMove = true;
+ }
+ if (!cannotMove) {
+ this.keyframes[kfIndex].time = parseInt(val, 10);
+ this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn;
+ }
+ })
+ );
+ TimelineMenu.Instance.addMenu('Keyframe');
TimelineMenu.Instance.openMenu(e.clientX, e.clientY);
- }
+ };
/**
- * context menu for region (anywhere on the green region).
+ * context menu for region (anywhere on the green region).
*/
@action
makeRegionMenu = (kf: Doc, e: MouseEvent) => {
- TimelineMenu.Instance.addItem("button", "Remove Region", () =>
- Cast(this.props.node.regions, listSpec(Doc))?.splice(this.regions.indexOf(this.props.RegionData), 1)),
- TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => {
+ TimelineMenu.Instance.addItem('button', 'Remove Region', () => Cast(this.props.node.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;
if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position) {
@@ -370,7 +388,7 @@ export class Keyframe extends React.Component<IProps> {
}
});
}),
- TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => {
+ TimelineMenu.Instance.addItem('input', `fadeOut: ${this.regiondata.fadeOut}ms`, val => {
runInAction(() => {
let cannotMove: boolean = false;
if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)) {
@@ -382,34 +400,38 @@ export class Keyframe extends React.Component<IProps> {
}
});
}),
- TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => {
+ TimelineMenu.Instance.addItem('input', `position: ${this.regiondata.position}ms`, val => {
runInAction(() => {
const prevPosition = this.regiondata.position;
let cannotMove: boolean = false;
- this.regions.map(region => ({ pos: NumCast(region.position), dur: NumCast(region.duration) })).forEach(({ pos, dur }) => {
- if (pos !== this.regiondata.position) {
- if ((val < 0) || (val > pos && val < pos + dur || (this.regiondata.duration + val > pos && this.regiondata.duration + val < pos + dur))) {
- cannotMove = true;
+ this.regions
+ .map(region => ({ pos: NumCast(region.position), dur: NumCast(region.duration) }))
+ .forEach(({ pos, dur }) => {
+ if (pos !== this.regiondata.position) {
+ if (val < 0 || (val > pos && val < pos + dur) || (this.regiondata.duration + val > pos && this.regiondata.duration + val < pos + dur)) {
+ cannotMove = true;
+ }
}
- }
- });
+ });
if (!cannotMove) {
this.regiondata.position = parseInt(val, 10);
this.updateKeyframes(this.regiondata.position - prevPosition);
}
});
}),
- TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => {
+ TimelineMenu.Instance.addItem('input', `duration: ${this.regiondata.duration}ms`, val => {
runInAction(() => {
let cannotMove: boolean = false;
- this.regions.map(region => ({ pos: NumCast(region.position), dur: NumCast(region.duration) })).forEach(({ pos, dur }) => {
- if (pos !== this.regiondata.position) {
- val += this.regiondata.position;
- if ((val < 0) || (val > pos && val < pos + dur)) {
- cannotMove = true;
+ this.regions
+ .map(region => ({ pos: NumCast(region.position), dur: NumCast(region.duration) }))
+ .forEach(({ pos, dur }) => {
+ if (pos !== this.regiondata.position) {
+ val += this.regiondata.position;
+ if (val < 0 || (val > pos && val < pos + dur)) {
+ cannotMove = true;
+ }
}
- }
- });
+ });
if (!cannotMove) {
this.regiondata.duration = parseInt(val, 10);
this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration;
@@ -417,9 +439,9 @@ export class Keyframe extends React.Component<IProps> {
}
});
}),
- TimelineMenu.Instance.addMenu("Region");
+ TimelineMenu.Instance.addMenu('Region');
TimelineMenu.Instance.openMenu(e.clientX, e.clientY);
- }
+ };
@action
updateKeyframes = (incr: number, filter: number[] = []) => {
@@ -428,7 +450,7 @@ export class Keyframe extends React.Component<IProps> {
kf.time = NumCast(kf.time) + incr;
}
});
- }
+ };
/**
* hovering effect when hovered (hidden div darkens)
@@ -438,9 +460,9 @@ export class Keyframe extends React.Component<IProps> {
e.preventDefault();
e.stopPropagation();
const div = ref.current!;
- div.style.opacity = "1";
+ div.style.opacity = '1';
Doc.BrushDoc(this.props.node);
- }
+ };
/**
* hovering effect when hovered out (hidden div becomes invisible)
@@ -450,14 +472,12 @@ export class Keyframe extends React.Component<IProps> {
e.preventDefault();
e.stopPropagation();
const div = ref.current!;
- div.style.opacity = "0";
+ div.style.opacity = '0';
Doc.UnBrushDoc(this.props.node);
- }
-
+ };
///////////////////////UI STUFF /////////////////////////
-
/**
* drawing keyframe. Handles both keyframe with a circle (one that you create by double clicking) and one without circle (fades)
* this probably needs biggest change, since everyone expected all keyframes to have a circle (and draggable)
@@ -465,32 +485,43 @@ export class Keyframe extends React.Component<IProps> {
drawKeyframes = () => {
const keyframeDivs: JSX.Element[] = [];
return DocListCast(this.regiondata.keyframes).map(kf => {
- if (kf.type as KeyframeFunc.KeyframeType !== KeyframeFunc.KeyframeType.end) {
- return <>
- <div className="keyframe" style={{ left: `${KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement) - this.pixelPosition}px` }}>
- <div className="divider"></div>
- <div className="keyframeCircle keyframe-indicator"
- onPointerDown={(e) => { e.preventDefault(); e.stopPropagation(); this.moveKeyframe(e, kf); }}
- onContextMenu={(e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- this.makeKeyframeMenu(kf, e.nativeEvent);
- }}
- onDoubleClick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
+ if ((kf.type as KeyframeFunc.KeyframeType) !== KeyframeFunc.KeyframeType.end) {
+ return (
+ <>
+ <div className="keyframe" style={{ left: `${KeyframeFunc.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement) - this.pixelPosition}px` }}>
+ <div className="divider"></div>
+ <div
+ className="keyframeCircle keyframe-indicator"
+ onPointerDown={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.moveKeyframe(e, kf);
+ }}
+ onContextMenu={(e: React.MouseEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.makeKeyframeMenu(kf, e.nativeEvent);
+ }}
+ onDoubleClick={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ }}></div>
</div>
- </div>
- <div className="keyframe-information" />
- </>;
+ <div className="keyframe-information" />
+ </>
+ );
} else {
- return <div className="keyframe" style={{ left: `${KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement) - this.pixelPosition}px` }}>
- <div className="divider" />
- </div>;
+ return (
+ <div className="keyframe" style={{ left: `${KeyframeFunc.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement) - this.pixelPosition}px` }}>
+ <div className="divider" />
+ </div>
+ );
}
});
- }
+ };
/**
- * drawing the hidden divs that partition different intervals within a region.
+ * drawing the hidden divs that partition different intervals within a region.
*/
@action
drawKeyframeDividers = () => {
@@ -500,26 +531,36 @@ export class Keyframe extends React.Component<IProps> {
if (index !== this.keyframes.length - 1) {
const right = this.keyframes[index + 1];
const bodyRef = React.createRef<HTMLDivElement>();
- const kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement);
- const rightPos = KeyframeFunc.convertPixelTime(NumCast(right.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement);
+ const kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
+ const rightPos = KeyframeFunc.convertPixelTime(NumCast(right.time), 'mili', 'pixel', this.props.tickSpacing, this.props.tickIncrement);
keyframeDividers.push(
- <div ref={bodyRef} className="body-container" style={{ left: `${kfPos - this.pixelPosition}px`, width: `${rightPos - kfPos}px` }}
- onPointerOver={(e) => { e.preventDefault(); e.stopPropagation(); this.onContainerOver(e, bodyRef); }}
- onPointerOut={(e) => { e.preventDefault(); e.stopPropagation(); this.onContainerOut(e, bodyRef); }}
- onContextMenu={(e) => {
+ <div
+ ref={bodyRef}
+ className="body-container"
+ style={{ left: `${kfPos - this.pixelPosition}px`, width: `${rightPos - kfPos}px` }}
+ onPointerOver={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.onContainerOver(e, bodyRef);
+ }}
+ onPointerOut={e => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.onContainerOut(e, bodyRef);
+ }}
+ onContextMenu={e => {
e.preventDefault();
e.stopPropagation();
if (index !== 0 || index !== this.keyframes.length - 2) {
this._mouseToggled = true;
}
this.makeRegionMenu(kf, e.nativeEvent);
- }}>
- </div>
+ }}></div>
);
}
});
return keyframeDividers;
- }
+ };
/**
* rendering that green region
@@ -527,13 +568,18 @@ export class Keyframe extends React.Component<IProps> {
//154, 206, 223
render() {
return (
- <div className="bar" ref={this._bar} style={{
- transform: `translate(${this.pixelPosition}px)`,
- width: `${this.pixelDuration}px`,
- background: `linear-gradient(90deg, rgba(154, 206, 223, 0) 0%, rgba(154, 206, 223, 1) ${this.pixelFadeIn / this.pixelDuration * 100}%, rgba(154, 206, 223, 1) ${(this.pixelDuration - this.pixelFadeOut) / this.pixelDuration * 100}%, rgba(154, 206, 223, 0) 100% )`
- }}
+ <div
+ className="bar"
+ ref={this._bar}
+ style={{
+ transform: `translate(${this.pixelPosition}px)`,
+ width: `${this.pixelDuration}px`,
+ background: `linear-gradient(90deg, rgba(154, 206, 223, 0) 0%, rgba(154, 206, 223, 1) ${(this.pixelFadeIn / this.pixelDuration) * 100}%, rgba(154, 206, 223, 1) ${
+ ((this.pixelDuration - this.pixelFadeOut) / this.pixelDuration) * 100
+ }%, rgba(154, 206, 223, 0) 100% )`,
+ }}
onPointerDown={this.onBarPointerDown}>
- <div className="leftResize keyframe-indicator" onPointerDown={this.onResizeLeft} ></div>
+ <div className="leftResize keyframe-indicator" onPointerDown={this.onResizeLeft}></div>
{/* <div className="keyframe-information"></div> */}
<div className="rightResize keyframe-indicator" onPointerDown={this.onResizeRight}></div>
{/* <div className="keyframe-information"></div> */}
@@ -542,4 +588,4 @@ export class Keyframe extends React.Component<IProps> {
</div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 7a393a4f7..adc97bbb4 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -76,7 +76,7 @@ export class Timeline extends React.Component<FieldViewProps> {
private get children(): Doc[] {
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]);
}
@@ -290,15 +290,15 @@ export class Timeline extends React.Component<FieldViewProps> {
};
resetView(doc: Doc) {
- doc._panX = doc._customOriginX ?? 0;
- doc._panY = doc._customOriginY ?? 0;
- doc._viewScale = doc._customOriginScale ?? 1;
+ doc._freeform_panX = doc._customOriginX ?? 0;
+ doc._freeform_panY = doc._customOriginY ?? 0;
+ doc._freeform_scale = doc._customOriginScale ?? 1;
}
setView(doc: Doc) {
- doc._customOriginX = doc._panX;
- doc._customOriginY = doc._panY;
- doc._customOriginScale = doc._viewScale;
+ doc._customOriginX = doc._freeform_panX;
+ doc._customOriginY = doc._freeform_panY;
+ doc._customOriginScale = doc._freeform_scale;
}
/**
* zooming mechanism (increment and spacing changes)
diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx
index 25c2e68e7..2349ba786 100644
--- a/src/client/views/animationtimeline/Track.tsx
+++ b/src/client/views/animationtimeline/Track.tsx
@@ -1,15 +1,15 @@
-import { action, computed, intercept, observable, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
-import { Copy } from "../../../fields/FieldSymbols";
-import { List } from "../../../fields/List";
-import { ObjectField } from "../../../fields/ObjectField";
-import { listSpec } from "../../../fields/Schema";
-import { Cast, NumCast } from "../../../fields/Types";
-import { Transform } from "../../util/Transform";
-import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe";
-import "./Track.scss";
+import { action, computed, intercept, observable, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast, Opt, DocListCastAsync } from '../../../fields/Doc';
+import { Copy } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
+import { ObjectField } from '../../../fields/ObjectField';
+import { listSpec } from '../../../fields/Schema';
+import { Cast, NumCast } from '../../../fields/Types';
+import { Transform } from '../../util/Transform';
+import { Keyframe, KeyframeFunc, RegionData } from './Keyframe';
+import './Track.scss';
interface IProps {
node: Doc;
@@ -32,27 +32,22 @@ export class Track extends React.Component<IProps> {
@observable private _newKeyframe: boolean = false;
private readonly MAX_TITLE_HEIGHT = 75;
@observable private _trackHeight = 0;
- private primitiveWhitelist = [
- "x",
- "y",
- "_width",
- "_height",
- "opacity",
- "_scrollTop"
- ];
- private objectWhitelist = [
- "data"
- ];
+ private primitiveWhitelist = ['x', 'y', '_width', '_height', 'opacity', '_layout_scrollTop'];
+ private objectWhitelist = ['data'];
- @computed private get regions() { return DocListCast(this.props.node.regions); }
- @computed private get time() { return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); }
+ @computed private get regions() {
+ return DocListCast(this.props.node.regions);
+ }
+ @computed private get time() {
+ return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+ }
async componentDidMount() {
const regions = await DocListCastAsync(this.props.node.regions);
if (!regions) this.props.node.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
+ //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
+ 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.node.regions).length === 0) this.createRegion(this.time);
@@ -71,7 +66,6 @@ export class Track extends React.Component<IProps> {
}
////////////////////////////////
-
getLastRegionTime = () => {
let lastTime: number = 0;
let lastRegion: Opt<Doc>;
@@ -83,11 +77,11 @@ export class Track extends React.Component<IProps> {
}
});
return lastRegion ? lastTime + NumCast(lastRegion.duration) : 0;
- }
+ };
/**
* keyframe save logic. Needs to be changed so it's more efficient
- *
+ *
*/
@action
saveKeyframe = async () => {
@@ -97,16 +91,18 @@ export class Track extends React.Component<IProps> {
if (this._newKeyframe) {
DocListCast(this.saveStateRegion?.keyframes).forEach((kf, index) => {
this.copyDocDataToKeyFrame(kf);
- kf.opacity = (index === 0 || index === 3) ? 0.1 : 1;
+ kf.opacity = index === 0 || index === 3 ? 0.1 : 1;
});
this._newKeyframe = false;
}
if (!kf) return;
- if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades
+ if (kf.type === KeyframeFunc.KeyframeType.default) {
+ // only save for non-fades
this.copyDocDataToKeyFrame(kf);
const leftkf = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists
- const rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists
- if (leftkf?.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades
+ const rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists
+ if (leftkf?.type === KeyframeFunc.KeyframeType.fade) {
+ //replicating this keyframe to fades
const edge = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf);
edge && this.copyDocDataToKeyFrame(edge);
leftkf && this.copyDocDataToKeyFrame(leftkf);
@@ -124,8 +120,7 @@ export class Track extends React.Component<IProps> {
keyframes[kfIndex] = kf;
this.saveStateKf = undefined;
this.saveStateRegion = undefined;
- }
-
+ };
/**
* autocreates keyframe
@@ -136,23 +131,27 @@ export class Track extends React.Component<IProps> {
intercept(this.props.node, change => {
return change;
});
- return reaction(() => {
- return [...this.primitiveWhitelist.map(key => this.props.node[key]), ...objects];
- }, (changed, reaction) => {
- //check for region
- const region = this.findRegion(this.time);
- if (region !== undefined) { //if region at scrub time exist
- const r = region as RegionData; //for some region is returning undefined... which is not the case
- if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined) { //basically when there is no additional keyframe at that timespot
- this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default);
+ return reaction(
+ () => {
+ return [...this.primitiveWhitelist.map(key => this.props.node[key]), ...objects];
+ },
+ (changed, reaction) => {
+ //check for region
+ const region = this.findRegion(this.time);
+ if (region !== undefined) {
+ //if region at scrub time exist
+ const r = region as RegionData; //for some region is returning undefined... which is not the case
+ if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined) {
+ //basically when there is no additional keyframe at that timespot
+ this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default);
+ }
}
- }
- }, { fireImmediately: false });
- }
-
-
+ },
+ { fireImmediately: false }
+ );
+ };
- // @observable private _storedState:(Doc | undefined) = undefined;
+ // @observable private _storedState:(Doc | undefined) = undefined;
// /**
// * reverting back to previous state before editing on AT
// */
@@ -161,54 +160,62 @@ export class Track extends React.Component<IProps> {
// if (this._storedState) this.applyKeys(this._storedState);
// }
-
/**
* Reaction when scrubber bar changes
* made into function so it's easier to dispose later
- */
+ */
@action
currentBarXReaction = () => {
- return reaction(() => this.props.currentBarX, () => {
- const regiondata = this.findRegion(this.time);
- if (regiondata) {
- this.props.node.hidden = false;
- // if (!this._autoKfReaction) {
- // // this._autoKfReaction = this.autoCreateKeyframe();
- // }
- this.timeChange();
- } else {
- this.props.node.hidden = true;
- this.props.node.opacity = 0;
- //if (this._autoKfReaction) this._autoKfReaction();
+ return reaction(
+ () => this.props.currentBarX,
+ () => {
+ const regiondata = this.findRegion(this.time);
+ if (regiondata) {
+ this.props.node.hidden = false;
+ // if (!this._autoKfReaction) {
+ // // this._autoKfReaction = this.autoCreateKeyframe();
+ // }
+ this.timeChange();
+ } else {
+ this.props.node.hidden = true;
+ this.props.node.opacity = 0;
+ //if (this._autoKfReaction) this._autoKfReaction();
+ }
}
- });
- }
+ );
+ };
/**
* when timeline is visible, reaction is ran so states are reverted
*/
@action
timelineVisibleReaction = () => {
- return reaction(() => {
- return this.props.timelineVisible;
- }, isVisible => {
- if (isVisible) {
- this.regions.filter(region => !region.hasData).forEach(region => {
- for (let i = 0; i < 4; i++) {
- this.copyDocDataToKeyFrame(DocListCast(region.keyframes)[i]);
- if (i === 0 || i === 3) { //manually inputing fades
- DocListCast(region.keyframes)[i].opacity = 0.1;
- }
- }
- });
- } else {
- //this.revertState();
+ return reaction(
+ () => {
+ return this.props.timelineVisible;
+ },
+ isVisible => {
+ if (isVisible) {
+ this.regions
+ .filter(region => !region.hasData)
+ .forEach(region => {
+ for (let i = 0; i < 4; i++) {
+ this.copyDocDataToKeyFrame(DocListCast(region.keyframes)[i]);
+ if (i === 0 || i === 3) {
+ //manually inputing fades
+ DocListCast(region.keyframes)[i].opacity = 0.1;
+ }
+ }
+ });
+ } else {
+ //this.revertState();
+ }
}
- });
- }
+ );
+ };
- @observable private saveStateKf: (Doc | undefined) = undefined;
- @observable private saveStateRegion: (Doc | undefined) = undefined;
+ @observable private saveStateKf: Doc | undefined = undefined;
+ @observable private saveStateRegion: Doc | undefined = undefined;
/**w
* when scrubber position changes. Need to edit the logic
@@ -222,9 +229,9 @@ export class Track extends React.Component<IProps> {
}
const regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on
if (regiondata) {
- const leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists
- const rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists
- const currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe
+ const leftkf: Doc | undefined = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists
+ const rightkf: Doc | undefined = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists
+ const currentkf: Doc | undefined = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe
if (currentkf) {
await this.applyKeys(currentkf);
this.saveStateKf = currentkf;
@@ -233,10 +240,10 @@ export class Track extends React.Component<IProps> {
await this.interpolate(leftkf, rightkf);
}
}
- }
+ };
/**
- * applying changes (when saving the keyframe)
+ * applying changes (when saving the keyframe)
* need to change the logic here
*/
@action
@@ -249,73 +256,73 @@ export class Track extends React.Component<IProps> {
this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
}
});
- }
-
+ };
/**
* calculating current keyframe, if the scrubber is right on the keyframe
*/
@action
calcCurrent = (region: Doc) => {
- let currentkf: (Doc | undefined) = undefined;
+ let currentkf: Doc | undefined = undefined;
const keyframes = DocListCast(region.keyframes!);
- keyframes.forEach((kf) => {
+ keyframes.forEach(kf => {
if (NumCast(kf.time) === Math.round(this.time)) currentkf = kf;
});
return currentkf;
- }
-
+ };
/**
- * basic linear interpolation function
+ * basic linear interpolation function
*/
@action
interpolate = async (left: Doc, right: Doc) => {
this.primitiveWhitelist.forEach(key => {
- if (left[key] && right[key] && typeof (left[key]) === "number" && typeof (right[key]) === "number") { //if it is number, interpolate
+ if (left[key] && right[key] && typeof left[key] === 'number' && typeof right[key] === 'number') {
+ //if it is number, interpolate
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.node[key] = NumCast(left[key]) + (dif * ratio);
- } else { // case data
+ this.props.node[key] = NumCast(left[key]) + dif * ratio;
+ } else {
+ // case data
const stored = left[key];
this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored;
}
});
- }
+ };
/**
* finds region that corresponds to specific time (is there a region at this time?)
* linear O(n) (maybe possible to optimize this with other Data structures?)
*/
findRegion = (time: number) => {
- return this.regions?.find(rd => (time >= NumCast(rd.position) && time <= (NumCast(rd.position) + NumCast(rd.duration))));
- }
-
+ return this.regions?.find(rd => time >= NumCast(rd.position) && time <= NumCast(rd.position) + NumCast(rd.duration));
+ };
/**
- * double click on track. Signalling keyframe creation.
+ * double click on track. Signalling keyframe creation.
*/
@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(KeyframeFunc.convertPixelTime(offsetX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement));
- }
-
+ this.createRegion(KeyframeFunc.convertPixelTime(offsetX, 'mili', 'time', this.props.tickSpacing, this.props.tickIncrement));
+ };
/**
- * creates a region (KEYFRAME.TSX stuff).
+ * creates a region (KEYFRAME.TSX stuff).
*/
@action
createRegion = (time: number) => {
- if (this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions)
+ if (this.findRegion(time) === undefined) {
+ //check if there is a region where double clicking (prevents phantom regions)
const regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data
regiondata.position = time; //set position
const rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions);
- if (rightRegion && rightRegion.position - regiondata.position <= 4000) { //edge case when there is less than default 4000 duration space between this and right region
+ if (rightRegion && rightRegion.position - regiondata.position <= 4000) {
+ //edge case when there is less than default 4000 duration space between this and right region
regiondata.duration = rightRegion.position - regiondata.position;
}
if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) {
@@ -325,27 +332,30 @@ export class Track extends React.Component<IProps> {
return regiondata;
}
}
- }
+ };
@action
- makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time
+ makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => {
+ //Kfpos is mouse offsetX, representing time
const trackKeyFrames = DocListCast(regiondata.keyframes);
const existingkf = trackKeyFrames.find(TK => TK.time === time);
if (existingkf) return existingkf;
- //else creates a new doc.
+ //else creates a new doc.
const newKeyFrame: Doc = new Doc();
newKeyFrame.time = time;
newKeyFrame.type = type;
this.copyDocDataToKeyFrame(newKeyFrame);
//assuming there are already keyframes (for keeping keyframes in order, sorted by time)
if (trackKeyFrames.length === 0) regiondata.keyframes!.push(newKeyFrame);
- trackKeyFrames.map(kf => NumCast(kf.time)).forEach((kfTime, index) => {
- if ((kfTime < time && index === trackKeyFrames.length - 1) || (kfTime < time && time < NumCast(trackKeyFrames[index + 1].time))) {
- regiondata.keyframes!.splice(index + 1, 0, newKeyFrame);
- }
- });
+ trackKeyFrames
+ .map(kf => NumCast(kf.time))
+ .forEach((kfTime, index) => {
+ if ((kfTime < time && index === trackKeyFrames.length - 1) || (kfTime < time && time < NumCast(trackKeyFrames[index + 1].time))) {
+ regiondata.keyframes!.splice(index + 1, 0, newKeyFrame);
+ }
+ });
return newKeyFrame;
- }
+ };
@action
copyDocDataToKeyFrame = (doc: Doc) => {
@@ -353,7 +363,7 @@ export class Track extends React.Component<IProps> {
const originalVal = this.props.node[key];
doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : originalVal;
});
- }
+ };
/**
* UI sstuff here. Not really much to change
@@ -362,10 +372,13 @@ export class Track extends React.Component<IProps> {
return (
<div className="track-container">
<div className="track">
- <div className="inner" ref={this._inner} style={{ height: `${this._trackHeight}px` }}
+ <div
+ className="inner"
+ ref={this._inner}
+ style={{ height: `${this._trackHeight}px` }}
onDoubleClick={this.onInnerDoubleClick}
onPointerOver={() => Doc.BrushDoc(this.props.node)}
- onPointerOut={() => Doc.UnBrushDoc(this.props.node)} >
+ onPointerOut={() => Doc.UnBrushDoc(this.props.node)}>
{this.regions?.map((region, i) => {
return <Keyframe key={`${i}`} {...this.props} RegionData={region} makeKeyData={this.makeKeyData} />;
})}
@@ -374,4 +387,4 @@ export class Track extends React.Component<IProps> {
</div>
);
}
-} \ No newline at end of file
+}