aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorloudonclear <loudon_cohen@brown.edu>2019-06-12 17:37:35 -0400
committerloudonclear <loudon_cohen@brown.edu>2019-06-12 17:37:35 -0400
commit854a1439fd33f63d0836ddc24c4fc5abdf70af4b (patch)
tree3aca2bd6a8dcc6183838f6c39be48cabf5deb072
parent3979682b4cb76fe006eb70b853e2577b17f986c3 (diff)
for the demo
-rw-r--r--src/client/views/nodes/Timeline.scss2
-rw-r--r--src/client/views/nodes/Timeline.tsx194
2 files changed, 150 insertions, 46 deletions
diff --git a/src/client/views/nodes/Timeline.scss b/src/client/views/nodes/Timeline.scss
index cf63c987c..c352c9519 100644
--- a/src/client/views/nodes/Timeline.scss
+++ b/src/client/views/nodes/Timeline.scss
@@ -27,7 +27,7 @@
button {
height: 30px;
- width: 100px;
+ width: 50px;
font-size: 1em;
position: relative;
margin: 5px;
diff --git a/src/client/views/nodes/Timeline.tsx b/src/client/views/nodes/Timeline.tsx
index edb88e7be..ac29b0ff3 100644
--- a/src/client/views/nodes/Timeline.tsx
+++ b/src/client/views/nodes/Timeline.tsx
@@ -1,7 +1,7 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import { observer } from "mobx-react";
-import { observable, reaction, action, IReactionDisposer, observe, IObservableArray } from "mobx";
+import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed } from "mobx";
import "./Timeline.scss";
import { CollectionViewProps } from "../collections/CollectionBaseView";
import { CollectionSubView, SubCollectionViewProps } from "../collections/CollectionSubView";
@@ -10,17 +10,17 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec
import { Doc, DocListCastAsync } from "../../../new_fields/Doc";
import { Document, listSpec, createSchema, makeInterface, defaultSpec } from "../../../new_fields/Schema";
import { FieldValue, Cast, NumCast, BoolCast } from "../../../new_fields/Types";
-import { emptyStatement, thisExpression } from "babel-types";
+import { emptyStatement, thisExpression, react } from "babel-types";
import { DocumentManager } from "../../util/DocumentManager";
import { SelectionManager } from "../../util/SelectionManager";
import { List } from "../../../new_fields/List";
import { Self } from "../../../new_fields/FieldSymbols";
import { list } from "serializr";
-import { arrays } from "typescript-collections";
+import { arrays, Dictionary } from "typescript-collections";
import { forEach } from "typescript-collections/dist/lib/arrays";
import { CompileScript } from "../../util/Scripting";
-type Data = List<Doc>; //data?
+type Data = List<Doc>;
type Keyframes = List<List<Doc>>;
const PositionSchema = createSchema({
@@ -30,7 +30,6 @@ const PositionSchema = createSchema({
type Position = makeInterface<[typeof PositionSchema]>;
const Position = makeInterface(PositionSchema);
-
const TimeAndPositionSchema = createSchema({
time: defaultSpec("number", 0),
position: Doc
@@ -44,64 +43,76 @@ const TimeAndPosition = makeInterface(TimeAndPositionSchema);
export class Timeline extends CollectionSubView(Document) {
@observable private _inner = React.createRef<HTMLDivElement>();
@observable private _timeInput = React.createRef<HTMLInputElement>();
+ @observable private _playButton = React.createRef<HTMLButtonElement>();
@observable private _isRecording: Boolean = false;
+ @observable private _windSpeed: number = 1;
private _reactionDisposers: IReactionDisposer[] = [];
private _selectionManagerChanged?: IReactionDisposer;
@observable private _currentBarX: number = 0;
- @observable private _keys = ["x", "y"];
- @observable private _data: Doc[] = []; // 1D list of nodes
- @observable private _keyframes: Doc[][] = []; //2D list of infos
+ @observable private _keys = ["x", "y", "width", "height", "panX", "panY", "scale"];
@observable private _bars: { x: number, doc: Doc }[] = [];
@observable private _barMoved: boolean = false;
-
+ @computed private get _keyframes() {
+ return Cast(this.props.Document.keyframes, listSpec(Doc)) as any as List<List<Doc>>;
+ }
+
+ @computed private get _data() {
+ return Cast(this.props.Document.dataa, listSpec(Doc)) as List<Doc>;
+ //return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))!;
+ }
+
/**
* when the record button is pressed
* @param e MouseEvent
*/
@action
onRecord = (e: React.MouseEvent) => {
+ console.log(this._data.length + " from record");
+ console.log(this._keyframes.length + " from record");
if (this._isRecording === true) {
this._isRecording = false;
return;
- }
+ }
this._isRecording = true;
let children = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc));
if (!children) {
return;
}
- let childrenList = (children[Self] as any).__fields;
-
+ let childrenList = ((children[Self] as any).__fields);
const addReaction = (node: Doc) => {
node = (node as any).value();
return reaction(() => {
+ console.log(this._data.length);
return this._keys.map(key => FieldValue(node[key]));
}, async data => {
- if (this._inner.current) {
- if (!this._barMoved) {
- if (this._data.indexOf(node) === -1) {
- this._data.push(node);
- let index = this._data.indexOf(node);
-
+ if (!this._barMoved) {
+ console.log(this._keyframes.length + " keyframes length");
+ console.log(this._data.length + " data length");
+ if (this._data.indexOf(node) === -1) {
+ let timeandpos = this.setTimeAndPos(node);
+ //change it to dictionary here............................................................................
+ let dict = new Dictionary<number, Doc>();
+ this._data.push(node);
+ let info: List<Doc> = new List<Doc>(new Array<Doc>(1000)); //kinda weird
+ info[this._currentBarX] = timeandpos;
+ this._keyframes.push(info);
+ console.log(this._keyframes.length);
+ this._bars = [];
+ this._bars.push({ x: this._currentBarX, doc: node });
+ //...................................................................................................
+ } else {
+ let index = this._data.indexOf(node);
+ console.log(index);
+ if (this._keyframes[index][this._currentBarX] !== undefined) { //when node is in data, but doesn't have data for this specific time.
let timeandpos = this.setTimeAndPos(node);
- let info: Doc[] = new Array(1000); //kinda weird
- info[this._currentBarX] = timeandpos;
- this._keyframes[index] = info;
- this._bars = [];
+ this._keyframes[index][this._currentBarX] = timeandpos;
this._bars.push({ x: this._currentBarX, doc: node });
- } else {
- let index = this._data.indexOf(node);
- if (this._keyframes[index][this._currentBarX] !== undefined) { //when node is in data, but doesn't have data for this specific time.
- let timeandpos = this.setTimeAndPos(node);
- this._keyframes[index][this._currentBarX] = timeandpos;
- //this._bars [];
- this._bars.push({ x: this._currentBarX, doc: node });
- } else { //when node is in data, and has data for this specific time
- let timeandpos = this.setTimeAndPos(node);
- this._keyframes[index][this._currentBarX] = timeandpos;
- }
+ } else { //when node is in data, and has data for this specific time
+ let timeandpos = this.setTimeAndPos(node);
+ this._keyframes[index][this._currentBarX] = timeandpos;
}
}
}
@@ -109,10 +120,11 @@ export class Timeline extends CollectionSubView(Document) {
};
-
observe(childrenList as IObservableArray<Doc>, change => {
+ console.log(childrenList + " has been printed");
if (change.type === "update") {
this._reactionDisposers[change.index]();
+ console.log(this._data.length);
this._reactionDisposers[change.index] = addReaction(change.newValue);
} else {
let removed = this._reactionDisposers.splice(change.index, change.removedCount, ...change.added.map(addReaction));
@@ -143,23 +155,30 @@ export class Timeline extends CollectionSubView(Document) {
@action
timeChange = async (time: number) => {
const docs = this._data;
+ console.log(docs.length +" from time change");
docs.forEach(async (oneDoc, i) => {
+ let OD: Doc = await oneDoc;
let leftKf!: TimeAndPosition;
let rightKf!: TimeAndPosition;
let singleFrame: Doc | undefined = undefined;
let oneKf = this._keyframes[i];
oneKf.forEach((singleKf) => {
+ singleKf = singleKf as Doc;
if (singleKf !== undefined) {
let leftMin = Infinity;
let rightMin = Infinity;
if (singleKf.time !== time) { //choose closest time neighbors
leftMin = this.calcMinLeft(oneKf, time);
if (leftMin !== Infinity) {
- leftKf = TimeAndPosition(this._keyframes[i][leftMin]);
+ let kf = this._keyframes[i][leftMin] as Doc;
+ leftKf = TimeAndPosition(kf);
}
+ console.log(oneKf);
+ console.log(time);
rightMin = this.calcMinRight(oneKf, time);
if (rightMin !== Infinity) {
- rightKf = TimeAndPosition(this._keyframes[i][rightMin]);
+ let kf = this._keyframes[i][rightMin] as Doc;
+ rightKf = TimeAndPosition(kf);
}
} else {
singleFrame = singleKf;
@@ -168,10 +187,13 @@ export class Timeline extends CollectionSubView(Document) {
});
if (singleFrame) {
if (true || oneKf[i] !== undefined) {
- this._keys.map(key => FieldValue(oneDoc[key]));
+ this._keys.map(key => {
+ let temp = OD[key];
+ FieldValue(OD[key]);
+ });
}
} else if (leftKf && rightKf) {
- this.interpolate(oneDoc, leftKf, rightKf, this._currentBarX);
+ this.interpolate(OD, leftKf, rightKf, this._currentBarX);
}
});
}
@@ -182,10 +204,11 @@ export class Timeline extends CollectionSubView(Document) {
* @param time
*/
@action
- calcMinLeft = (kfList: Doc[], time: number): number => { //returns the time of the closet keyframe to the left
+ calcMinLeft = (kfList: List<Doc>, time: number): number => { //returns the time of the closet keyframe to the left
let counter: number = Infinity;
let leftMin: number = Infinity;
kfList.forEach((kf) => {
+ kf = kf as Doc;
if (kf !== undefined && NumCast(kf.time) < time) {
let diff: number = Math.abs(NumCast(kf.time) - time);
if (diff < counter) {
@@ -204,10 +227,11 @@ export class Timeline extends CollectionSubView(Document) {
*/
@action
- calcMinRight = (kfList: Doc[], time: number): number => { //returns the time of the closest keyframe to the right
+ calcMinRight = (kfList: List<Doc>, time: number): number => { //returns the time of the closest keyframe to the right
let counter: number = Infinity;
let rightMin: number = Infinity;
kfList.forEach((kf) => {
+ kf = kf as Doc;
if (kf !== undefined && NumCast(kf.time) > time) {
let diff: number = Math.abs(NumCast(kf.time!) - time);
if (diff < counter) {
@@ -232,8 +256,18 @@ export class Timeline extends CollectionSubView(Document) {
const keyFrame1 = (await kf1.position)!;
const keyFrame2 = (await kf2.position)!;
+ //e^x exponential
+ let eExp1 = Math.log(kf2.time);
+ let eExp2 = Math.log(kf1.time);
+
+
+ // e ^ x + pos1, e^x + pos2
+ //const ratio = (time - eExp1) / dif_time;
+
+
+ //for linaer
const dif_time = kf2.time - kf1.time;
- const ratio = (time - kf1.time) / dif_time;
+ const ratio = (time - kf1.time) / dif_time; //linear
this._keys.forEach(key => {
const diff = NumCast(keyFrame2[key]) - NumCast(keyFrame1[key]);
@@ -249,7 +283,9 @@ export class Timeline extends CollectionSubView(Document) {
@action
onInnerPointerUp = (e: React.PointerEvent) => {
if (this._inner.current) {
- this._barMoved = false;
+ if (!this._isPlaying) {
+ this._barMoved = false;
+ }
this._inner.current.removeEventListener("pointermove", this.onInnerPointerMove);
}
}
@@ -271,6 +307,7 @@ export class Timeline extends CollectionSubView(Document) {
this._inner.current.removeEventListener("pointermove", this.onInnerPointerMove);
this._inner.current.addEventListener("pointermove", this.onInnerPointerMove);
this.timeChange(this._currentBarX);
+ console.log("from down")
}
}
@@ -288,6 +325,54 @@ export class Timeline extends CollectionSubView(Document) {
let offsetX = Math.round(e.offsetX); //currentbarX is rounded so it is indexable
this._currentBarX = offsetX;
this.timeChange(this._currentBarX);
+ console.log("from move");
+ }
+
+ @observable private _isPlaying = false;
+
+ @action
+ onPlay = async (e: React.MouseEvent) => {
+ let playButton: HTMLButtonElement = (await this._playButton.current)!;
+ if (this._isPlaying) {
+ playButton.innerHTML = "Play";
+ this._isPlaying = false;
+ this._barMoved = false;
+ } else {
+ playButton.innerHTML = "Stop";
+ this._barMoved = true;
+ this._isPlaying = true;
+ this.changeCurrentX();
+
+ }
+
+ }
+
+
+ @action
+ changeCurrentX = async () => {
+ if (this._currentBarX >= 484 && this._isPlaying === true) {
+ this._currentBarX = 0;
+ }
+ if (this._currentBarX <= 484 && this._isPlaying === true) { ///////////////////////////////////////////////////////////////////////////// needs to be width
+ this._currentBarX = this._currentBarX + this._windSpeed;
+ setTimeout(this.changeCurrentX, 15);
+ this.timeChange(this._currentBarX);
+ }
+ }
+
+
+ @action
+ windForward = (e: React.MouseEvent) => {
+ if (this._windSpeed < 64) { //max speed is 32
+ this._windSpeed = this._windSpeed * 2;
+ }
+ }
+
+ @action
+ windBackward = (e: React.MouseEvent) => {
+ if (this._windSpeed > 1 / 16) { // min speed is 1/8
+ this._windSpeed = this._windSpeed / 2;
+ }
}
/**
@@ -325,9 +410,19 @@ export class Timeline extends CollectionSubView(Document) {
}
}
+
+ componentDidMount() {
+ if (!this._keyframes) {
+ console.log("new data");
+ this.props.Document.keyframes = new List<List<Doc>>();
+ this.props.Document.dataa = new List<Doc>();
+ }
+ }
+
/**
* removes reaction when the component is removed from the timeline
*/
+
componentWillUnmount() {
this._reactionDisposers.forEach(disp => disp());
this._reactionDisposers = [];
@@ -340,11 +435,16 @@ export class Timeline extends CollectionSubView(Document) {
@action
displayKeyFrames = (doc: Doc) => {
let views: (JSX.Element | null)[] = [];
+
this._data.forEach((node, i) => {
if (node === doc) {
+ console.log(this._keyframes[i].length);
views = this._keyframes[i].map(tp => {
- if (tp !== undefined) {
- const timeandpos = TimeAndPosition(tp);
+ let n:Doc = Cast(tp, Doc) as Doc;
+
+ console.log(n);
+ if (n !== undefined) {
+ const timeandpos = TimeAndPosition(n);
let time = timeandpos.time;
let bar = this.createBar(5, time, "yellow");
return bar;
@@ -364,14 +464,18 @@ export class Timeline extends CollectionSubView(Document) {
<div className="inner" ref={this._inner} onPointerDown={this.onInnerPointerDown} onPointerUp={this.onInnerPointerUp}>
{SelectionManager.SelectedDocuments().map(dv => this.displayKeyFrames(dv.props.Document))}
{this._bars.map((data) => {
- return this.createBar(5, data.x, "yellow");
+ return this.createBar(5, data.x, "yellow");
})}
{this.createBar(5, this._currentBarX)}
</div>
</div>
<button onClick={this.onRecord}>Record</button>
+
<input placeholder={this._currentBarX.toString()} ref={this._timeInput} onKeyDown={this.onTimeEntered} ></input>
+ <button onClick={this.windBackward}> {"<"}</button>
+ <button onClick={this.onPlay} ref={this._playButton}> Play </button>
+ <button onClick={this.windForward}>{">"}</button>
</div>
</div>
);