From bf3d45f8a16d23384a308f65adfa9a2baee495af Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Thu, 1 Aug 2019 17:00:10 -0400 Subject: prosemirror --- src/client/views/animationtimeline/Keyframe.scss | 94 ++++ src/client/views/animationtimeline/Keyframe.tsx | 551 +++++++++++++++++++++ src/client/views/animationtimeline/Timeline.scss | 170 +++++++ src/client/views/animationtimeline/Timeline.tsx | 530 ++++++++++++++++++++ .../views/animationtimeline/TimelineMenu.scss | 0 .../views/animationtimeline/TimelineMenu.tsx | 47 ++ src/client/views/animationtimeline/Track.scss | 15 + src/client/views/animationtimeline/Track.tsx | 276 +++++++++++ 8 files changed, 1683 insertions(+) create mode 100644 src/client/views/animationtimeline/Keyframe.scss create mode 100644 src/client/views/animationtimeline/Keyframe.tsx create mode 100644 src/client/views/animationtimeline/Timeline.scss create mode 100644 src/client/views/animationtimeline/Timeline.tsx create mode 100644 src/client/views/animationtimeline/TimelineMenu.scss create mode 100644 src/client/views/animationtimeline/TimelineMenu.tsx create mode 100644 src/client/views/animationtimeline/Track.scss create mode 100644 src/client/views/animationtimeline/Track.tsx (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.scss b/src/client/views/animationtimeline/Keyframe.scss new file mode 100644 index 000000000..b1e8b0b65 --- /dev/null +++ b/src/client/views/animationtimeline/Keyframe.scss @@ -0,0 +1,94 @@ +@import "./../globalCssVariables.scss"; + +.bar { + height: 100%; + width: 5px; + position: absolute; + + // pointer-events: none; + .menubox { + width: 200px; + height:200px; + top: 50%; + position: relative; + background-color: $light-color; + .menutable{ + tr:nth-child(odd){ + background-color:$light-color-secondary; + } + } + } + + .leftResize{ + left:-12.5px; + height:25px; + width:25px; + border-radius: 50%; + background-color: white; + border:3px solid black; + top: calc(50% - 12.5px); + z-index: 1000; + position:absolute; + } + .rightResize{ + right:-12.5px; + height:25px; + width:25px; + border-radius: 50%; + top:calc(50% - 12.5px); + background-color:white; + border:3px solid black; + z-index: 1000; + position:absolute; + } + .fadeLeft{ + left:0px; + height:100%; + position:absolute; + pointer-events: none; + background: linear-gradient(to left, #4d9900 10%, $light-color); + } + + .fadeRight{ + right:0px; + height:100%; + position:absolute; + pointer-events: none; + background: linear-gradient(to right, #4d9900 10%, $light-color); + } + .divider{ + height:100%; + width: 1px; + position: absolute; + background-color:black; + cursor: col-resize; + pointer-events:none; + } + .keyframe{ + height:100%; + position:absolute; + } + .keyframeCircle{ + left:-15px; + height:30px; + width:30px; + border-radius: 50%; + top:calc(50% - 15px); + background-color:white; + border:3px solid green; + z-index: 1000; + position:absolute; + } + + .fadeIn-container, .fadeOut-container, .body-container{ + position:absolute; + height:100%; + background-color: rgba(0, 0, 0, 0.5); + opacity: 0; + } + + +} + + + diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx new file mode 100644 index 000000000..995a5b402 --- /dev/null +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -0,0 +1,551 @@ +import * as React from "react"; +import "./Keyframe.scss"; +import "./Timeline.scss"; +import "../globalCssVariables.scss"; +import { observer, Observer } from "mobx-react"; +import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, isComputedProp, runInAction } from "mobx"; +import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; +import { Cast, FieldValue, StrCast, NumCast } from "../../../new_fields/Types"; +import { List } from "../../../new_fields/List"; +import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; +import { FlyoutProps } from "./Timeline"; +import { Transform } from "../../util/Transform"; +import { InkField, StrokeData } from "../../../new_fields/InkField"; +import { number } from "prop-types"; + +export namespace KeyframeFunc { + export enum KeyframeType { + fade = "fade", + default = "default", + } + export enum Direction { + left = "left", + right = "right" + } + export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: List): (RegionData | undefined) => { + let leftMost: (RegionData | undefined) = undefined; + let rightMost: (RegionData | undefined) = undefined; + DocListCast(regions).forEach(region => { + let neighbor = RegionData(region as Doc); + if (currentRegion.position! > neighbor.position) { + if (!leftMost || neighbor.position > leftMost.position) { + leftMost = neighbor; + } + } else if (currentRegion.position! < neighbor.position) { + if (!rightMost || neighbor.position < rightMost.position) { + rightMost = neighbor; + } + } + }); + if (dir === Direction.left) { + return leftMost; + } else if (dir === Direction.right) { + return rightMost; + } + }; + + export const calcMinLeft = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closet keyframe to the left + let leftKf: (Doc | undefined) = undefined; + let time: number = 0; + let keyframes = await DocListCastAsync(region.keyframes!); + keyframes!.forEach((kf) => { + let compTime = currentBarX; + if (ref) { + compTime = NumCast(ref.time); + } + if (NumCast(kf.time) < compTime && NumCast(kf.time) >= time) { + leftKf = kf; + time = NumCast(kf.time); + } + }); + return leftKf; + }; + + + export const calcMinRight = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closest keyframe to the right + let rightKf: (Doc | undefined) = undefined; + let time: number = Infinity; + let keyframes = await DocListCastAsync(region.keyframes!); + keyframes!.forEach((kf) => { + let compTime = currentBarX; + if (ref) { + compTime = NumCast(ref.time); + } + if (NumCast(kf.time) > compTime && NumCast(kf.time) <= NumCast(time)) { + rightKf = kf; + time = NumCast(kf.time); + } + }); + return rightKf; + }; + + export const defaultKeyframe = () => { + let regiondata = new Doc(); //creating regiondata + regiondata.duration = 200; + regiondata.position = 0; + regiondata.fadeIn = 20; + regiondata.fadeOut = 20; + regiondata.functions = new List(); + return regiondata; + }; +} + +export const RegionDataSchema = createSchema({ + position: defaultSpec("number", 0), + duration: defaultSpec("number", 0), + keyframes: listSpec(Doc), + fadeIn: defaultSpec("number", 0), + fadeOut: defaultSpec("number", 0), + functions: listSpec(Doc) +}); +export type RegionData = makeInterface<[typeof RegionDataSchema]>; +export const RegionData = makeInterface(RegionDataSchema); + +interface IProps { + node: Doc; + RegionData: Doc; + collection: Doc; + changeCurrentBarX: (x: number) => void; + setFlyout: (props: FlyoutProps) => any; + transform: Transform; +} + +@observer +export class Keyframe extends React.Component { + + @observable private _bar = React.createRef(); + @observable private _gain = 20; //default + + @computed + private get regiondata() { + let index = this.regions.indexOf(this.props.RegionData); + return RegionData(this.regions[index] as Doc); + } + + @computed + private get regions() { + return Cast(this.props.node.regions, listSpec(Doc)) as List; + } + + @computed + private get firstKeyframe() { + let first: (Doc | undefined) = undefined; + DocListCast(this.regiondata.keyframes!).forEach(kf => { + if (kf.type !== KeyframeFunc.KeyframeType.fade) { + if (!first || first && NumCast(kf.time) < NumCast(first.time)) { + first = kf; + } + } + }); + return first; + } + + @computed + private get lastKeyframe() { + let last: (Doc | undefined) = undefined; + DocListCast(this.regiondata.keyframes!).forEach(kf => { + if (kf.type !== KeyframeFunc.KeyframeType.fade) { + if (!last || last && NumCast(kf.time) > NumCast(last.time)) { + last = kf; + } + } + }); + return last; + } + @computed + private get keyframes(){ + return DocListCast(this.regiondata.keyframes); + } + + @computed + private get inks() { + if (this.props.collection.data_ext) { + let data_ext = Cast(this.props.collection.data_ext, Doc) as Doc; + let ink = Cast(data_ext.ink, InkField) as InkField; + if (ink) { + return ink.inkData; + } + } + } + + async componentWillMount() { + if (!this.regiondata.keyframes) { + this.regiondata.keyframes = new List(); + } + let fadeIn = await this.makeKeyData(this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade)!; + let fadeOut = await this.makeKeyData(this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade)!; + let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.fade)!; + let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; + (fadeIn.key! as Doc).opacity = 1; + (fadeOut.key! as Doc).opacity = 1; + (start.key! as Doc).opacity = 0.1; + (finish.key! as Doc).opacity = 0.1; + + observe(this.regiondata, change => { + if (change.type === "update") { + fadeIn.time = this.regiondata.position + this.regiondata.fadeIn; + fadeOut.time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; + start.time = this.regiondata.position; + finish.time = this.regiondata.position + this.regiondata.duration; + this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(fadeIn)] = fadeIn; + this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(fadeOut)] = fadeOut; + this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(start)] = start; + this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(finish)] = finish; + this.forceUpdate(); + } + }); + } + + @action + makeKeyData = async (kfpos: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + let doclist = (await DocListCastAsync(this.regiondata.keyframes))!; + let existingkf: (Doc | undefined) = undefined; + doclist.forEach(TK => { + TK = TK as Doc; + if (TK.time === kfpos) existingkf = TK; + }); + if (existingkf) return existingkf; + let TK: Doc = new Doc(); + TK.time = kfpos; + TK.key = Doc.MakeCopy(this.props.node, true); + TK.type = type; + this.regiondata.keyframes!.push(TK); + + let interpolationFunctions = new Doc(); + interpolationFunctions.interpolationX = new List([0, 1]); + interpolationFunctions.interpolationY = new List([0,100]); + interpolationFunctions.pathX = new List(); + interpolationFunctions.pathY = new List(); + + this.regiondata.functions!.push(interpolationFunctions); + let found:boolean = false; + this.regiondata.keyframes!.forEach(compkf => { + compkf = compkf as Doc; + if (kfpos < NumCast(compkf.time) && !found) { + runInAction(() => { + this.regiondata.keyframes!.splice(doclist.indexOf(compkf as Doc), 0, TK); + this.regiondata.keyframes!.pop(); + found = true; + }); + return; + } + }); + + let index = this.regiondata.keyframes!.indexOf(TK); + console.log(toJS(this.regiondata.keyframes!)); + + return TK; + } + + @action + onBarPointerDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.addEventListener("pointermove", this.onBarPointerMove); + document.addEventListener("pointerup", (e: PointerEvent) => { + document.removeEventListener("pointermove", this.onBarPointerMove); + }); + } + + + @action + onBarPointerMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; + let right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions!); + let prevX = this.regiondata.position; + let futureX = this.regiondata.position + e.movementX; + if (futureX <= 0) { + this.regiondata.position = 0; + } else if ((left && left.position + left.duration >= futureX)) { + this.regiondata.position = left.position + left.duration; + } else if ((right && right.position <= futureX + this.regiondata.duration)) { + this.regiondata.position = right.position - this.regiondata.duration; + } else { + this.regiondata.position = futureX; + } + for (let i = 0; i < this.regiondata.keyframes!.length; i++) { + if ((this.regiondata.keyframes![i] as Doc).type !== KeyframeFunc.KeyframeType.fade) { + let movement = this.regiondata.position - prevX; + (this.regiondata.keyframes![i] as Doc).time = NumCast((this.regiondata.keyframes![i] as Doc).time) + movement; + } + } + this.forceUpdate(); + } + + @action + onResizeLeft = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + 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); + }); + } + + @action + onDragResizeLeft = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let bar = this._bar.current!; + let offset = Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); + let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions); + let firstkf: (Doc | undefined) = this.firstKeyframe; + if (firstkf && this.regiondata.position + this.regiondata.fadeIn + offset >= NumCast(firstkf!.time)) { + let dif = NumCast(firstkf!.time) - (this.regiondata.position + this.regiondata.fadeIn); + this.regiondata.position = NumCast(firstkf!.time) - this.regiondata.fadeIn; + this.regiondata.duration -= dif; + } else if (this.regiondata.duration - offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // no keyframes, just fades + this.regiondata.position -= (this.regiondata.fadeIn + this.regiondata.fadeOut - this.regiondata.duration); + this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; + } else if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) { + let dif = this.regiondata.position - (leftRegion.position + leftRegion.duration); + this.regiondata.position = leftRegion.position + leftRegion.duration; + this.regiondata.duration += dif; + + } else { + this.regiondata.duration -= offset; + this.regiondata.position += offset; + } + } + + + @action + onDragResizeRight = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let bar = this._bar.current!; + let offset = Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale); + let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); + if (this.lastKeyframe! && this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= NumCast((this.lastKeyframe! as Doc).time)) { + let dif = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - NumCast((this.lastKeyframe! as Doc).time); + this.regiondata.duration -= dif; + } else if (this.regiondata.duration + offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // nokeyframes, just fades + this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; + } else if (rightRegion && this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position) { + let dif = rightRegion.position - (this.regiondata.position + this.regiondata.duration); + this.regiondata.duration += dif; + } else { + this.regiondata.duration += offset; + } + } + + createDivider = (type?: KeyframeFunc.Direction): JSX.Element => { + if (type === "left") { + return
; + } else if (type === "right") { + return
; + } + return
; + } + + @action + createKeyframe = async (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + let bar = this._bar.current!; + let offset = Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); + if (offset > this.regiondata.fadeIn && offset < this.regiondata.duration - this.regiondata.fadeOut) { //make sure keyframe is not created inbetween fades and ends + let position = NumCast(this.regiondata.position); + await this.makeKeyData(Math.round(position + offset)); + console.log(this.regiondata.keyframes!.length); + this.props.changeCurrentBarX(NumCast(Math.round(position + offset))); //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(NumCast(kf.time!)); + } + + + @action + onKeyframeOver = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.props.node.backgroundColor = "#000000"; + + } + @action + private createKeyframeJSX = (kf: Doc, type = KeyframeFunc.KeyframeType.default) => { + if (type === KeyframeFunc.KeyframeType.default) { + return ( +
+ {this.createDivider()} +
{ this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + }}>
+
); + } + return ( +
+ {this.createDivider()} +
+ ); + } + + onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { + e.preventDefault(); + e.stopPropagation(); + let div = ref.current!; + div.style.opacity = "1"; + } + + onContainerOut = (e: React.PointerEvent, ref: React.RefObject) => { + e.preventDefault(); + e.stopPropagation(); + let div = ref.current!; + div.style.opacity = "0"; + } + + + private _reac: (undefined | IReactionDisposer) = undefined; + private _plotList: ([string, StrokeData] | undefined) = undefined; + private _interpolationKeyframe: (Doc | undefined) = undefined; + private _type: string = ""; + + @action + onContainerDown = (e: React.MouseEvent, kf: Doc) => { + e.preventDefault(); + e.stopPropagation(); + let listenerCreated = false; + let type = prompt("Type? (interpolate or path)"); + if (type) { + if (type !== "interpolate" && type !=="path") { + alert("Wrong type. Try again."); + return; + } + this._type = type; + this.props.collection.backgroundColor = "rgb(0,0,0)"; + this._reac = reaction(() => { + return this.inks; + }, data => { + if (!listenerCreated) { + this._plotList = Array.from(data!)[data!.size - 1]!; + this._interpolationKeyframe = kf; + document.addEventListener("pointerup", this.onReactionListen); + listenerCreated = true; + } + }); + } + + } + + + + + @action + onReactionListen = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let message = prompt("GRAPHING MODE: Enter gain"); + if (message) { + let messageContent = parseInt(message, 10); + if (messageContent === NaN) { + this._gain = Infinity; + } else { + this._gain = messageContent; + } + + } + if (this._reac && this._plotList && this._interpolationKeyframe) { + this.props.collection.backgroundColor = "#FFF"; + this._reac(); + let xPlots = new List(); + let yPlots = new List(); + let maxY = 0; + let minY = Infinity; + let pathData = this._plotList![1].pathData; + for (let i = 0; i < pathData.length - 1;) { + let val = pathData[i]; + if (val.y > maxY) { + maxY = val.y; + } + if (val.y < minY) { + minY = val.y; + } + xPlots.push(val.x); + yPlots.push(val.y); + let increment = Math.floor(pathData.length / this._gain); + if (pathData.length > this._gain) { + if (i + increment < pathData.length) { + i = i + increment; + } else { + i = pathData.length - 1; + } + } else { + i++; + } + } + let index = this.keyframes.indexOf(this._interpolationKeyframe!); + if (this._type === "interpolate"){ + (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationX = xPlots; + (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationY = yPlots; + } else if (this._type === "path") { + (Cast(this.regiondata.functions![index], Doc) as Doc).pathX = xPlots; + (Cast(this.regiondata.functions![index], Doc) as Doc).pathY = yPlots; + } + + this._reac = undefined; + this._interpolationKeyframe = undefined; + this._plotList = undefined; + this._type = ""; + document.removeEventListener("pointerup", this.onReactionListen); + } + } + + + render() { + return ( +
+
{ + e.preventDefault(); + e.stopPropagation(); + console.log("has been clicked!"); + let offsetLeft = this._bar.current!.getBoundingClientRect().left - this._bar.current!.parentElement!.getBoundingClientRect().left; + let offsetTop = this._bar.current!.getBoundingClientRect().top; //+ this._bar.current!.parentElement!.getBoundingClientRect().top; + this.props.setFlyout({ x: offsetLeft * this.props.transform.Scale, y: offsetTop * this.props.transform.Scale, display: "block", regiondata: this.regiondata, regions: this.regions }); + })}> +
+
+ {this.regiondata.keyframes!.map(kf => { + return this.createKeyframeJSX(kf as Doc, (kf! as Doc).type as KeyframeFunc.KeyframeType); + })} + {this.keyframes.map( kf => { + if(this.keyframes.indexOf(kf) !== this.keyframes.length - 1) { + + let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; + let bodyRef = React.createRef(); + return ( +
{ this.onContainerOver(e, bodyRef); }} + onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} + onContextMenu={(e) => { this.onContainerDown(e, kf); }}> +
+ ); + } + })} + +
+
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss new file mode 100644 index 000000000..47f448adb --- /dev/null +++ b/src/client/views/animationtimeline/Timeline.scss @@ -0,0 +1,170 @@ +@import "./../globalCssVariables.scss"; + +.minimize{ + position:relative; + z-index: 1000; + height: 30px; + width: 100px; +} +.flyout-container{ + background-color: transparent; + position:absolute; + + z-index:9999; + height: 150px; + width: 150px; + + .flyout{ + background-color: transparent; + transform: rotate(180deg); + left:0px; + top:0px; + width: 100%; + height: 100%; + } + .input-container{ + position: absolute; + right:0px; + top: 30px; + width: 70px; + input{ + width: 100%; + } + } + .text-container{ + position:absolute; + top:30px; + left:0px; + color:white + } +} + +.placement-highlight{ + background-color:blue; + transform: translate(0px, 0px); + transition: width 1000ms ease-in-out; + transition: height 1000ms ease-in-out; + position: absolute; +} + +.timeline-container{ + width:100%; + height:300px; + position:absolute; + background-color: $light-color-secondary; + box-shadow: 0px 10px 20px; + //transition: transform 1000ms ease-in-out; + + .toolbox{ + position:absolute; + width: 100%; + top: 10px; + left: 20px; + div{ + float:left; + margin-left: 10px; + position:relative; + .overview{ + width: 200px; + height: 100%; + background-color: black; + position:absolute; + } + } + } + .info-container{ + margin-top: 50px; + right:20px; + position:absolute; + height: calc(100% - 100px); + width: calc(100% - 140px); + overflow: hidden; + + .scrubberbox{ + position:absolute; + background-color: transparent; + height: 30px; + width:100%; + + .tick{ + height:100%; + width: 1px; + background-color:black; + + } + } + .scrubber{ + top:30px; + height: 100%; + width: 2px; + position:absolute; + z-index: 1001; + background-color:black; + .scrubberhead{ + top: -30px; + height: 30px; + width: 30px; + background-color:transparent; + border-radius: 50%; + border: 5px solid black; + left: -15px; + position:absolute; + } + } + + .trackbox{ + top: 30px; + height:calc(100% - 30px); + width:100%; + border:1px; + overflow:hidden; + background-color:white; + position:absolute; + box-shadow: -10px 0px 10px 10px grey; + } + + } + .title-container{ + margin-top: 80px; + margin-left: 20px; + height: calc(100% - 100px - 30px); + width: 100px; + background-color:white; + overflow: hidden; + .datapane{ + top:0px; + width: 100px; + height: 75px; + border: 1px solid $dark-color; + background-color: $intermediate-color; + color: white; + position:relative; + float:left; + border-style:solid; + } + } + .resize{ + bottom: 5px; + position:absolute; + height: 30px; + width: 50px; + left: calc(50% - 25px); + } +} + + + +.overview{ + position: absolute; + height: 50px; + width: 200px; + background-color: black; + .container{ + position: absolute; + float: left 0px; + top: 25%; + height: 75%; + width: 100%; + background-color: grey; + } +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx new file mode 100644 index 000000000..d2714592e --- /dev/null +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -0,0 +1,530 @@ +import * as React from "react"; +import "./Timeline.scss"; +import { CollectionSubView } from "../collections/CollectionSubView"; +import { Document, listSpec } from "../../../new_fields/Schema"; +import { observer } from "mobx-react"; +import { Track } from "./Track"; +import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, Reaction, IObservableObject, trace, autorun, runInAction } from "mobx"; +import { Cast, NumCast, FieldValue, StrCast } from "../../../new_fields/Types"; +import { List } from "../../../new_fields/List"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle } from "@fortawesome/free-solid-svg-icons"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { ContextMenu } from "../ContextMenu"; +import { DocumentManager } from "../../util/DocumentManager"; +import { VideoBox } from "../nodes/VideoBox"; +import { VideoField } from "../../../new_fields/URLField"; +import { CollectionVideoView } from "../collections/CollectionVideoView"; +import { Transform } from "../../util/Transform"; +import { faGrinTongueSquint } from "@fortawesome/free-regular-svg-icons"; +import { InkField } from "../../../new_fields/InkField"; +import { AddComparisonParameters } from "../../northstar/model/idea/idea"; +import { keepAlive } from "mobx-utils"; + + +export interface FlyoutProps { + x?: number; + y?: number; + display?: string; + regiondata?: Doc; + regions?: List; +} + + +@observer +export class Timeline extends CollectionSubView(Document) { + private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; + private readonly DEFAULT_TICK_SPACING: number = 50; + private readonly MIN_CONTAINER_HEIGHT: number = 205; + private readonly MAX_CONTAINER_HEIGHT: number = 800; + private readonly DEFAULT_TICK_INCREMENT: number = 1000; + + @observable private _isMinimized = false; + @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; + @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; + + @observable private _scrubberbox = React.createRef(); + @observable private _scrubber = React.createRef(); + @observable private _trackbox = React.createRef(); + @observable private _titleContainer = React.createRef(); + @observable private _timelineContainer = React.createRef(); + + @observable private _timelineWrapper = React.createRef(); + @observable private _infoContainer = React.createRef(); + + + @observable private _currentBarX: number = 0; + @observable private _windSpeed: number = 1; + @observable private _isPlaying: boolean = false; //scrubber playing + @observable private _isFrozen: boolean = false; //timeline freeze + @observable private _boxLength: number = 0; + @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; + @observable private _time = 100000; //DEFAULT + @observable private _ticks: number[] = []; + @observable private _playButton = faPlayCircle; + @observable private flyoutInfo: FlyoutProps = { x: 0, y: 0, display: "none", regiondata: new Doc(), regions: new List() }; + + @computed + private get children(): List { + let extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); + + if (extendedDocument) { + if (this.props.Document.data_ext) { + return Cast((Cast(this.props.Document.data_ext, Doc) as Doc).annotations, listSpec(Doc)) as List; + } else { + return new List(); + } + } + return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; + } + + @computed + private get inks(){ + if (this.props.Document.data_ext){ + let data_ext = Cast(this.props.Document.data_ext, Doc) as Doc; + let ink = Cast(data_ext.ink, InkField) as InkField; + if (ink){ + return ink.inkData; + } + } + } + + + componentDidMount() { + if (StrCast(this.props.Document.type) === "video") { + console.log("ran"); + console.log(this.props.Document.duration); + if (this.props.Document.duration) { + this._time = Math.round(NumCast(this.props.Document.duration)) * 1000; + + reaction(() => { + return NumCast(this.props.Document.curPage); + }, curPage => { + this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); + }); + + } + + } + runInAction(() => { + + reaction(() => { + return this._time; + }, () => { + this._ticks = []; + for (let i = 0; i < this._time;) { + this._ticks.push(i); + i += this._tickIncrement; + } + let trackbox = this._trackbox.current!; + this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; + trackbox.style.width = `${this._boxLength}`; + this._scrubberbox.current!.style.width = `${this._boxLength}`; + }, { fireImmediately: true }); + }); + } + + @action + changeCurrentBarX = (x: number) => { + this._currentBarX = x; + } + + //for playing + @action + onPlay = async (e: React.MouseEvent) => { + if (this._isPlaying) { + this._isPlaying = false; + this._playButton = faPlayCircle; + } else { + this._isPlaying = true; + this._playButton = faPauseCircle; + this.changeCurrentX(); + } + } + + @action + changeCurrentX = () => { + if (this._currentBarX === this._boxLength && this._isPlaying) { + this._currentBarX = 0; + } + if (this._currentBarX <= this._boxLength && this._isPlaying) { + this._currentBarX = this._currentBarX + this._windSpeed; + setTimeout(this.changeCurrentX, 15); + } + } + + @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; + } + } + + //for scrubber action + @action + onScrubberDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.addEventListener("pointermove", this.onScrubberMove); + document.addEventListener("pointerup", () => { + document.removeEventListener("pointermove", this.onScrubberMove); + }); + } + + @action + onScrubberMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let scrubberbox = this._scrubberbox.current!; + let left = scrubberbox.getBoundingClientRect().left; + let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; + this._currentBarX = offsetX; + } + + @action + onScrubberClick = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + let scrubberbox = this._scrubberbox.current!; + let offset = (e.clientX - scrubberbox.getBoundingClientRect().left) * this.props.ScreenToLocalTransform().Scale; + this._currentBarX = offset; + } + + + + @action + onPanDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.addEventListener("pointermove", this.onPanMove); + document.addEventListener("pointerup", () => { + document.removeEventListener("pointermove", this.onPanMove); + }); + } + + @action + onPanMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let infoContainer = this._infoContainer.current!; + let trackbox = this._trackbox.current!; + let titleContainer = this._titleContainer.current!; + infoContainer.scrollLeft = infoContainer.scrollLeft - e.movementX; + trackbox.scrollTop = trackbox.scrollTop - e.movementY; + titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; + } + + + @action + onResizeDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.addEventListener("pointermove", this.onResizeMove); + document.addEventListener("pointerup", () => { + document.removeEventListener("pointermove", this.onResizeMove); + }); + } + + @action + onResizeMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; + if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT) { + this._containerHeight = this.MIN_CONTAINER_HEIGHT; + } else if (this._containerHeight + offset >= this.MAX_CONTAINER_HEIGHT) { + this._containerHeight = this.MAX_CONTAINER_HEIGHT; + } else { + this._containerHeight += offset; + } + } + + @action + onTimelineDown = (e: React.PointerEvent) => { + e.preventDefault(); + if (e.nativeEvent.which === 1 && !this._isFrozen) { + document.addEventListener("pointermove", this.onTimelineMove); + document.addEventListener("pointerup", () => { document.removeEventListener("pointermove", this.onTimelineMove); }); + } + } + + @action + onTimelineMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let timelineContainer = this._timelineWrapper.current!; + let left = parseFloat(timelineContainer.style.left!); + let top = parseFloat(timelineContainer.style.top!); + timelineContainer.style.left = `${left + e.movementX}px`; + timelineContainer.style.top = `${top + e.movementY}px`; + } + + @action + minimize = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + let timelineContainer = this._timelineContainer.current!; + if (this._isMinimized) { + this._isMinimized = false; + timelineContainer.style.visibility = "visible"; + } else { + this._isMinimized = true; + timelineContainer.style.visibility = "hidden"; + } + } + + @action + toTime = (time: number): string => { + const inSeconds = time / 1000; + let min: (string | number) = Math.floor(inSeconds / 60); + let sec: (string | number) = inSeconds % 60; + + if (Math.floor(sec / 10) === 0) { + sec = "0" + sec; + } + return `${min}:${sec}`; + } + + + private _freezeText = "Freeze Timeline"; + + timelineContextMenu = (e: React.MouseEvent): void => { + let subitems: ContextMenuProps[] = []; + let timelineContainer = this._timelineWrapper.current!; + subitems.push({ + description: "Pin to Top", event: action(() => { + if (!this._isFrozen) { + timelineContainer.style.transition = "top 1000ms ease-in, left 1000ms ease-in"; //????? + timelineContainer.style.left = "0px"; + timelineContainer.style.top = "0px"; + timelineContainer.style.transition = "none"; + } + }), icon: faArrowUp + }); + subitems.push({ + description: "Pin to Bottom", event: action(() => { + console.log(this.props.Document.y); + + if (!this._isFrozen) { + timelineContainer.style.transform = `translate(0px, ${e.pageY - this._containerHeight}px)`; + } + }), icon: faArrowDown + }); + subitems.push({ + description: this._freezeText, event: action(() => { + if (this._isFrozen) { + this._isFrozen = false; + this._freezeText = "Freeze Timeline"; + } else { + this._isFrozen = true; + this._freezeText = "Unfreeze Timeline"; + } + }), icon: "thumbtack" + }); + ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems, icon: faClock }); + } + + + + @action + getFlyout = (props: FlyoutProps) => { + for (const [k, v] of Object.entries(props)) { + (this.flyoutInfo as any)[k] = v; + } + console.log(this.flyoutInfo); + } + + render() { + return ( +
+ +
+ +
+
+
+
+
+
+
+ {this._ticks.map(element => { + return

{this.toTime(element)}

; + })} +
+
+
+
+
+ {DocListCast(this.children).map(doc => )} +
+
+
+ {DocListCast(this.children).map(doc =>

{doc.title}

)} +
+
+ +
+
+
+ ); + } + +} + + +interface TimelineFlyoutProps { + flyoutInfo: FlyoutProps; + tickSpacing: number; + +} + +interface TimelineOverviewProps { + currentBarX: number; +} + +class TimelineOverview extends React.Component{ + + componentWillMount() { + + } + + render() { + return ( +
+
+
+
+
+
+
+ ); + } +} + +class TimelineFlyout extends React.Component{ + + @observable private _timeInput = React.createRef(); + @observable private _durationInput = React.createRef(); + @observable private _fadeInInput = React.createRef(); + @observable private _fadeOutInput = React.createRef(); + @observable private _data: FlyoutProps = { x: 0, y: 0, display: "none", regiondata: new Doc(), regions: new List() }; + + private block = false; + + componentDidMount() { + + document.addEventListener("pointerdown", this.closeFlyout); + } + + + componentWillUnmount() { + document.removeEventListener("pointerdown", this.closeFlyout); + } + + + @action + changeTime = (e: React.KeyboardEvent) => { + let time = this._timeInput.current!; + if (e.keyCode === 13) { + if (!Number.isNaN(Number(time.value))) { + this.props.flyoutInfo.regiondata!.position = Number(time.value) / 1000 * this.props.tickSpacing; + time.placeholder = time.value + "ms"; + time.value = ""; + } + } + } + @action + onFlyoutDown = (e: React.PointerEvent) => { + this._data.display = "block"; + this.block = true; + } + + @action + closeFlyout = (e: PointerEvent) => { + if (this.block) { + this.block = false; + return; + } + this._data.display = "none"; + } + + @action + changeDuration = (e: React.KeyboardEvent) => { + let duration = this._durationInput.current!; + if (e.keyCode === 13) { + if (!Number.isNaN(Number(duration.value))) { + this.props.flyoutInfo.regiondata!.duration = Number(duration.value) / 1000 * this.props.tickSpacing; + duration.placeholder = duration.value + "ms"; + duration.value = ""; + } + } + } + + @action + changeFadeIn = (e: React.KeyboardEvent) => { + let fadeIn = this._fadeInInput.current!; + if (e.keyCode === 13) { + if (!Number.isNaN(Number(fadeIn.value))) { + this.props.flyoutInfo.regiondata!.fadeIn = Number(fadeIn.value); + fadeIn.placeholder = fadeIn.value + "ms"; + fadeIn.value = ""; + } + } + } + + @action + changeFadeOut = (e: React.KeyboardEvent) => { + let fadeOut = this._fadeOutInput.current!; + if (e.keyCode === 13) { + if (!Number.isNaN(Number(fadeOut.value))) { + this.props.flyoutInfo.regiondata!.fadeOut = Number(fadeOut.value); + fadeOut.placeholder = fadeOut.value + "ms"; + fadeOut.value = ""; + } + } + } + + render() { + return ( +
+
+ +
+

Time:

+

Duration:

+

Fade-in

+

Fade-out

+
+
+ + + + +
+ +
+
+ ); + } +} + +class TimelineZoom extends React.Component { + componentDidMount() { + + } + render() { + return ( +
+ +
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx new file mode 100644 index 000000000..e82075f6a --- /dev/null +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -0,0 +1,47 @@ + +import * as React from "react"; + + +/** + * TimelineMenu: + * + * + * Timeline: + * - + * + * + * Keyframe: + * - Delete keyframe + * - Move keyframe + * - Edit keyframe (shows schema) + * + * + * Region: + * - Add Keyframe + * - Copy Interpolation + * - Copy path + * - Add Interpolation + * - Add Path + * - Change fades + * - position region + * - duration region + * - + */ +export class TimelineMenu extends React.Component { + public static Instance:TimelineMenu; + + constructor (props:Readonly<{}>){ + super(props); + TimelineMenu.Instance = this; + } + + + + + render() { + return ( +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/Track.scss b/src/client/views/animationtimeline/Track.scss new file mode 100644 index 000000000..c8d56edf6 --- /dev/null +++ b/src/client/views/animationtimeline/Track.scss @@ -0,0 +1,15 @@ +@import "./../globalCssVariables.scss"; + +.track-container{ + + .track { + .inner { + top:0px; + height: 75px; + width: calc(100%); + background-color: $light-color; + border: 1px solid $dark-color; + position:relative; + } + } +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx new file mode 100644 index 000000000..4f78f86b8 --- /dev/null +++ b/src/client/views/animationtimeline/Track.tsx @@ -0,0 +1,276 @@ +import * as React from "react"; +import { observer } from "mobx-react"; +import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, IObservableObject, runInAction, autorun } from "mobx"; +import "./Track.scss"; +import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; +import { listSpec } from "../../../new_fields/Schema"; +import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; +import { List } from "../../../new_fields/List"; +import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; +import { FlyoutProps } from "./Timeline"; +import { Transform } from "../../util/Transform"; +import { AddComparisonParameters } from "../../northstar/model/idea/idea"; +import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; +import { DocumentManager } from "../../util/DocumentManager"; +import { DocumentView } from "../nodes/DocumentView"; +import { RichTextField } from "../../../new_fields/RichTextField"; + +interface IProps { + node: Doc; + currentBarX: number; + transform: Transform; + collection: Doc; + changeCurrentBarX: (x: number) => void; + setFlyout: (props: FlyoutProps) => any; +} + +@observer +export class Track extends React.Component { + @observable private _inner = React.createRef(); + @observable private _reactionDisposers: IReactionDisposer[] = []; + @observable private _keyReaction: any; //reaction that is used to dispose when necessary + @observable private _currentBarXReaction: any; + + @computed + private get regions() { + return Cast(this.props.node.regions, listSpec(Doc)) as List; + } + + componentWillMount() { + if (!this.props.node.regions) { + this.props.node.regions = new List(); + } + this.props.node.opacity = 1; + } + + componentDidMount() { + runInAction(() => { + this._currentBarXReaction = this.currentBarXReaction(); + if (this.regions.length === 0) this.createRegion(this.props.currentBarX); + this.props.node.hidden = false; + }); + } + + componentWillUnmount() { + runInAction(() => { + if (this._keyReaction) this._keyReaction(); + if (this._currentBarXReaction) this._currentBarXReaction(); + }); + } + + @action + keyReaction = () => { + return reaction( () => { + return Doc.allKeys(this.props.node).map(key => FieldValue(this.props.node[key])); + }, async () => { + console.log("rAN"); + let regiondata: (Doc | undefined) = await this.findRegion(this.props.currentBarX) ; + if (regiondata) { + let keyframes = await DocListCastAsync((regiondata as Doc).keyframes!); + keyframes!.forEach( async (kf) => { + if (kf.type === KeyframeFunc.KeyframeType.default && kf.time === this.props.currentBarX) { + console.log("full keychange triggered"); + //for this specific keyframe + kf.key = Doc.MakeCopy(this.props.node, true); + + //for fades + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, kf); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.props.currentBarX, kf); //right keyframe, if it exists + if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades + let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, leftkf!); + edge!.key = Doc.MakeCopy(kf.key as Doc, true); + leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); + (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; + (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; + } + if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { + let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,this.props.currentBarX, rightkf!); + edge!.key = Doc.MakeCopy(kf.key as Doc, true); + rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); + (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; + (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; + } + } + }); + } + }, {fireImmediately: true}); + } + + @action + currentBarXReaction = () => { + return reaction(() => this.props.currentBarX, async () => { + if (this._keyReaction) this._keyReaction(); //dispose previous reaction first + let regiondata: (Doc | undefined) = await this.findRegion(this.props.currentBarX); + if (regiondata) { + this.props.node.hidden = false; + await this.timeChange(this.props.currentBarX); + } else { + this.props.node.hidden = true; + } + }, { fireImmediately: true }); + } + + + @action + timeChange = async (time: number) => { + let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on + if (regiondata) { + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.props.currentBarX); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.props.currentBarX); //right keyframe, if it exists + let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe + if (currentkf) { + await this.applyKeys(currentkf); + this._keyReaction = this.keyReaction(); //reactivates reaction. + } else if (leftkf && rightkf) { + await this.interpolate(leftkf, rightkf, regiondata); + } + } + } + + @action + private applyKeys = async (kf: Doc) => { + let kfNode = await Cast(kf.key, Doc) as Doc; + let docFromApply = kfNode; + if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; + this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { + if (key === "type") { + if (this.props.node[key] === "text") { + this.props.node.dataDocTest = new RichTextField(StrCast(kfNode.stateData)); + console.log("updated"); + } + } + if (!kfNode[key]) { + this.props.node[key] = undefined; + } else { + this.props.node[key] = kfNode[key]; + } + }); + } + + + @action + private filterKeys = (keys: string[]): string[] => { + return keys.reduce((acc: string[], key: string) => { + if (key !== "regions" && key !== "data" && key !== "creationDate" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns") acc.push(key); + return acc; + }, []) as string[]; + } + + @action + calcCurrent = async (region: Doc) => { + let currentkf: (Doc | undefined) = undefined; + let keyframes = await DocListCastAsync(region.keyframes!); + keyframes!.forEach((kf) => { + if (NumCast(kf.time) === Math.round(this.props.currentBarX)) currentkf = kf; + }); + return currentkf; + } + + @action + interpolate = async (left: Doc, right: Doc, regiondata:Doc) => { + console.log("interpolating"); + let leftNode = left.key as Doc; + let rightNode = right.key as Doc; + const dif_time = NumCast(right.time) - NumCast(left.time); + const timeratio = (this.props.currentBarX - NumCast(left.time)) / dif_time; //linear + let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; + let indexLeft = keyframes.indexOf(left); + let interY:List = await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List; + let realIndex = (interY.length - 1) * timeratio; + let xIndex = Math.floor(realIndex); + let yValue = interY[xIndex]; + let secondYOffset:number = yValue; + let minY = interY[0]; // for now + let maxY = interY[interY.length - 1]; //for now + if (interY.length !== 1) { + secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; + } + let finalRatio = secondYOffset / (maxY - minY); + let pathX:List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; + let pathY:List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; + let proposedX = 0; + let proposedY = 0; + if (pathX.length !== 0) { + let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); + let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); + if (pathCorrespondingIndex >= pathX.length - 1) { + proposedX = pathX[pathX.length - 1]; + proposedY = pathY[pathY.length - 1]; + } else if (pathCorrespondingIndex < 0){ + proposedX = pathX[0]; + proposedY = pathY[0]; + } else { + proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); + proposedY = pathY[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathY[pathCorrespondingIndex + 1] - pathY[pathCorrespondingIndex]); + } + + } + + + this.filterKeys(Doc.allKeys(leftNode)).forEach(key => { + if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate + if ((key === "x" || key === "y") && pathX.length !== 0){ + if (key === "x") this.props.node[key] = proposedX; + if (key === "y") this.props.node[key] = proposedY; + console.log(pathX.length); + + } else { + const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); + const adjusted = diff * finalRatio; + this.props.node[key] = NumCast(leftNode[key]) + adjusted; + } + } else { + this.props.node[key] = leftNode[key]; + } + }); + } + + @action + findRegion = async (time: number) => { + let foundRegion:(Doc | undefined) = undefined; + let regions = await DocListCastAsync(this.regions); + regions!.forEach(region => { + region = region as RegionData; + if (time >= NumCast(region.position) && time <= (NumCast(region.position) + NumCast(region.duration))) { + foundRegion = region; + } + }); + return foundRegion; + } + + @action + onInnerDoubleClick = (e: React.MouseEvent) => { + let inner = this._inner.current!; + let offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale); + this.createRegion(offsetX); + } + + createRegion = (position: number) => { + let regiondata = KeyframeFunc.defaultKeyframe(); + regiondata.position = position; + let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, regiondata, this.regions); + let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); + if ((rightRegion && leftRegion && rightRegion.position - (leftRegion.position + leftRegion.duration) < NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut)) || (rightRegion && rightRegion.position - regiondata.position < NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { + return; + } else if (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut)) { + regiondata.duration = rightRegion.position - regiondata.position; + } + this.regions.push(regiondata); + return regiondata; + } + + + render() { + return ( +
+
+
+ {DocListCast(this.regions).map((region) => { + return ; + })} +
+
+
+ ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 62a34043949f051533ca549be48b774696331d43 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Mon, 5 Aug 2019 17:37:43 -0400 Subject: richtext + buttons --- src/client/views/MainView.tsx | 1 + src/client/views/animationtimeline/Timeline.tsx | 3 + .../views/animationtimeline/TimelineMenu.tsx | 12 +- src/client/views/animationtimeline/Track.tsx | 124 +++++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/nodes/FormattedTextBox.tsx | 2 - src/new_fields/RichTextField.ts | 1 + 7 files changed, 85 insertions(+), 62 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f5a6715e5..669b8f018 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -400,6 +400,7 @@ export class MainView extends React.Component {
  • +
  • {btns.map(btn => diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index d2714592e..7a6d9fa52 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -34,6 +34,9 @@ export interface FlyoutProps { @observer export class Timeline extends CollectionSubView(Document) { + static Instance:Timeline; + + private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; private readonly DEFAULT_TICK_SPACING: number = 50; private readonly MIN_CONTAINER_HEIGHT: number = 205; diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index e82075f6a..7768f51df 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -1,6 +1,6 @@ - import * as React from "react"; - +import {observable, action, runInAction} from "mobx"; +import {observer} from "mobx-react"; /** * TimelineMenu: @@ -27,9 +27,17 @@ import * as React from "react"; * - duration region * - */ + +@observer export class TimelineMenu extends React.Component { public static Instance:TimelineMenu; + @observable private _opacity = 1; + @observable private _x = 0; + @observable private _y = 0; + @observable private _type: "timeline" | "keyframe" | "region" | "" = ""; + + constructor (props:Readonly<{}>){ super(props); TimelineMenu.Instance = this; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 4f78f86b8..fc2cacba8 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -9,10 +9,6 @@ import { List } from "../../../new_fields/List"; import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; -import { AddComparisonParameters } from "../../northstar/model/idea/idea"; -import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; -import { DocumentManager } from "../../util/DocumentManager"; -import { DocumentView } from "../nodes/DocumentView"; import { RichTextField } from "../../../new_fields/RichTextField"; interface IProps { @@ -28,8 +24,11 @@ interface IProps { export class Track extends React.Component { @observable private _inner = React.createRef(); @observable private _reactionDisposers: IReactionDisposer[] = []; - @observable private _keyReaction: any; //reaction that is used to dispose when necessary - @observable private _currentBarXReaction: any; + @observable private _currentBarXReaction: any; + @observable private _isOnKeyframe: boolean = false; + @observable private _onKeyframe: (Doc | undefined) = undefined; + @observable private _onRegionData : ( Doc | undefined) = undefined; + @observable private _leftCurrKeyframe: (Doc | undefined) = undefined; @computed private get regions() { @@ -53,53 +52,44 @@ export class Track extends React.Component { componentWillUnmount() { runInAction(() => { - if (this._keyReaction) this._keyReaction(); if (this._currentBarXReaction) this._currentBarXReaction(); }); } @action - keyReaction = () => { - return reaction( () => { - return Doc.allKeys(this.props.node).map(key => FieldValue(this.props.node[key])); - }, async () => { - console.log("rAN"); - let regiondata: (Doc | undefined) = await this.findRegion(this.props.currentBarX) ; - if (regiondata) { - let keyframes = await DocListCastAsync((regiondata as Doc).keyframes!); - keyframes!.forEach( async (kf) => { - if (kf.type === KeyframeFunc.KeyframeType.default && kf.time === this.props.currentBarX) { - console.log("full keychange triggered"); - //for this specific keyframe - kf.key = Doc.MakeCopy(this.props.node, true); - - //for fades - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.props.currentBarX, kf); //right keyframe, if it exists - if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, leftkf!); - edge!.key = Doc.MakeCopy(kf.key as Doc, true); - leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); - (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; - (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; - } - if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,this.props.currentBarX, rightkf!); - edge!.key = Doc.MakeCopy(kf.key as Doc, true); - rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); - (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; - (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; - } - } - }); + saveKeyframe = async (ref:Doc, regiondata:Doc) => { + let keyframes:List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); + let kfIndex:number = keyframes.indexOf(ref); + let kf = keyframes[kfIndex] as Doc; + if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for fades + console.log("full keychange triggered"); + kf.key = Doc.MakeCopy(this.props.node, true); + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, kf); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.props.currentBarX, kf); //right keyframe, if it exists + if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades + let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, leftkf!); + edge!.key = Doc.MakeCopy(kf.key as Doc, true); + leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); + (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; + (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; } - }, {fireImmediately: true}); + if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { + let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,this.props.currentBarX, rightkf!); + edge!.key = Doc.MakeCopy(kf.key as Doc, true); + rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); + (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; + (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; + } + } + keyframes[kfIndex] = kf; + this._onKeyframe = undefined; + this._onRegionData = undefined; + this._isOnKeyframe = false; } - + @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { - if (this._keyReaction) this._keyReaction(); //dispose previous reaction first let regiondata: (Doc | undefined) = await this.findRegion(this.props.currentBarX); if (regiondata) { this.props.node.hidden = false; @@ -113,6 +103,10 @@ export class Track extends React.Component { @action timeChange = async (time: number) => { + if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { + console.log("saving"); + await this.saveKeyframe(this._onKeyframe, this._onRegionData); + } let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on if (regiondata) { let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.props.currentBarX); // lef keyframe, if it exists @@ -120,7 +114,10 @@ export class Track extends React.Component { let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); - this._keyReaction = this.keyReaction(); //reactivates reaction. + this._leftCurrKeyframe = currentkf; + this._isOnKeyframe = true; + this._onKeyframe = currentkf; + this._onRegionData = regiondata; } else if (leftkf && rightkf) { await this.interpolate(leftkf, rightkf, regiondata); } @@ -133,17 +130,21 @@ export class Track extends React.Component { let docFromApply = kfNode; if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { - if (key === "type") { - if (this.props.node[key] === "text") { - this.props.node.dataDocTest = new RichTextField(StrCast(kfNode.stateData)); - console.log("updated"); - } - } if (!kfNode[key]) { this.props.node[key] = undefined; } else { - this.props.node[key] = kfNode[key]; + if (key === "data") { + if (this.props.node.type === "text"){ + let nodeData = (kfNode[key] as RichTextField).Data; + this.props.node[key] = new RichTextField(nodeData); + } + } else if (key === "creationDate") { + } else { + this.props.node[key] = kfNode[key]; + } + } + }); } @@ -151,7 +152,7 @@ export class Track extends React.Component { @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { - if (key !== "regions" && key !== "data" && key !== "creationDate" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns") acc.push(key); + if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns") acc.push(key); return acc; }, []) as string[]; } @@ -205,22 +206,31 @@ export class Track extends React.Component { } } - - this.filterKeys(Doc.allKeys(leftNode)).forEach(key => { if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate if ((key === "x" || key === "y") && pathX.length !== 0){ if (key === "x") this.props.node[key] = proposedX; if (key === "y") this.props.node[key] = proposedY; - console.log(pathX.length); - } else { const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); const adjusted = diff * finalRatio; this.props.node[key] = NumCast(leftNode[key]) + adjusted; } } else { - this.props.node[key] = leftNode[key]; + if (key === "data") { + if (this.props.node.type === "text"){ + let nodeData = StrCast((leftNode[key] as RichTextField).Data); + let currentNodeData = StrCast((this.props.node[key] as RichTextField).Data); + if (nodeData !== currentNodeData) { + this.props.node[key] = new RichTextField(nodeData); + } + } + + } else if (key === "creationDate") { + + } else { + this.props.node[key] = leftNode[key]; + } } }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 676a49288..71329f166 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -573,7 +573,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); }; } - + private _timeline = ; + se = () => { + } render() { const easing = () => this.props.Document.panTransformType === "Ease"; Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 9b37a6491..03fa7f0cd 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -166,8 +166,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"); if (this.extensionDoc) this.extensionDoc.lastModified = new DateField(new Date(Date.now())); this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON())); - this.props.Document.stateData = JSON.stringify(state.toJSON()); - this.props.Document.dataDocTest = this.dataDoc[this.props.fieldKey]; this._applyingChange = false; let title = StrCast(this.dataDoc.title); if (title && title.startsWith("-") && this._editorView && !this.Document.customTitle) { diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index 78a3a4067..0095eb31f 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -15,6 +15,7 @@ export class RichTextField extends ObjectField { this.Data = data; } + [Copy]() { return new RichTextField(this.Data); } -- cgit v1.2.3-70-g09d2 From 2c86a6958186c020ce7fbe99555f07ffe9f9f821 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 6 Aug 2019 12:25:09 -0400 Subject: timeline contextmenu --- src/client/views/MainView.tsx | 5 ++ src/client/views/animationtimeline/Keyframe.tsx | 4 +- .../views/animationtimeline/TimelineMenu.scss | 7 ++ .../views/animationtimeline/TimelineMenu.tsx | 79 +++++++++++++++++++++- 4 files changed, 92 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 669b8f018..589fcc409 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -39,6 +39,7 @@ import { FilterBox } from './search/FilterBox'; import { CollectionTreeView } from './collections/CollectionTreeView'; import { ClientUtils } from '../util/ClientUtils'; import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField'; +import { TimelineMenu } from './animationtimeline/TimelineMenu'; @observer export class MainView extends React.Component { @@ -148,6 +149,9 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.closeMenu(); + } + if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-container") === -1){ + TimelineMenu.Instance.closeMenu(); } }), true); } @@ -461,6 +465,7 @@ export class MainView extends React.Component { {this.nodesMenu()} {this.miscButtons} + diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 995a5b402..9dae3896f 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -12,6 +12,7 @@ import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; import { InkField, StrokeData } from "../../../new_fields/InkField"; import { number } from "prop-types"; +import { TimelineMenu } from "./TimelineMenu"; export namespace KeyframeFunc { export enum KeyframeType { @@ -389,6 +390,7 @@ export class Keyframe extends React.Component {
    { this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); + TimelineMenu.Instance.openMenu("keyframe", e.clientX, e.clientY); }}>
    ); } @@ -538,7 +540,7 @@ export class Keyframe extends React.Component {
    { this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} - onContextMenu={(e) => { this.onContainerDown(e, kf); }}> + onContextMenu={(e) => {TimelineMenu.Instance.openMenu("region", e.clientX, e.clientY);}}>
    ); } diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss index e69de29bb..458c1eda1 100644 --- a/src/client/views/animationtimeline/TimelineMenu.scss +++ b/src/client/views/animationtimeline/TimelineMenu.scss @@ -0,0 +1,7 @@ +.timeline-menu-container{ + position: absolute; + z-index: 10000; + width: 500px; + height: 500px; + background-color: black; +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 7768f51df..adbd21e62 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -1,6 +1,8 @@ import * as React from "react"; import {observable, action, runInAction} from "mobx"; import {observer} from "mobx-react"; +import "./TimelineMenu.scss"; +import { jSXAttribute } from "babel-types"; /** * TimelineMenu: @@ -32,7 +34,7 @@ import {observer} from "mobx-react"; export class TimelineMenu extends React.Component { public static Instance:TimelineMenu; - @observable private _opacity = 1; + @observable private _opacity = 0; @observable private _x = 0; @observable private _y = 0; @observable private _type: "timeline" | "keyframe" | "region" | "" = ""; @@ -42,13 +44,86 @@ export class TimelineMenu extends React.Component { super(props); TimelineMenu.Instance = this; } + @action + pointerDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.removeEventListener("pointerup", this.pointerUp); + document.addEventListener("pointerup", this.pointerUp); + document.removeEventListener("pointermove", this.pointerMove); + document.addEventListener("pointermove", this.pointerMove); + + + } + @action + pointerMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + } + @action + pointerUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.pointerMove); + document.removeEventListener("pointerup", this.pointerUp); + } + + @action + openMenu = (type: "timeline" | "keyframe" | "region", x?:number, y?:number) => { + this._type = type; + this._opacity = 1; + x ? this._x = x : this._x = 0; + y ? this._y = y : this._y = 0; + } + + @action + closeMenu = () => { + this._opacity = 0; + } + @action + addEase = (e: React.MouseEvent) => { + + } + @action + addPath = (e:React.MouseEvent) => { + + } render() { + let menu: (JSX.Element[] | undefined); + switch(this._type){ + case "keyframe": + menu = [ + , + , + + + ]; + break; + case "region" : + menu = [ + , + , + , + , + , + , + ]; + break; + case "timeline": + menu = [ + + ]; + break; + default: + break; + + } return ( -
    +
    + {menu} +
    ); } -- cgit v1.2.3-70-g09d2 From a4b5fa0273bb7bc872699f0f0ce047ec0fbc7d43 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 6 Aug 2019 16:02:35 -0400 Subject: debug and context menu --- src/client/views/MainView.tsx | 3 +++ src/client/views/animationtimeline/Keyframe.tsx | 4 ---- src/client/views/animationtimeline/TimelineMenu.scss | 13 +++++++++++-- src/client/views/animationtimeline/TimelineMenu.tsx | 18 +++++++++--------- src/client/views/animationtimeline/Track.tsx | 2 ++ src/new_fields/Doc.ts | 3 ++- 6 files changed, 27 insertions(+), 16 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f38367d98..270e9b183 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -149,6 +149,9 @@ export class MainView extends React.Component { if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.closeMenu(); } + if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-container") === -1) { + TimelineMenu.Instance.closeMenu(); + } }); globalPointerUp = () => this.isPointerDown = false; diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 9dae3896f..b27cb6d98 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -231,10 +231,6 @@ export class Keyframe extends React.Component { return; } }); - - let index = this.regiondata.keyframes!.indexOf(TK); - console.log(toJS(this.regiondata.keyframes!)); - return TK; } diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss index 458c1eda1..ed047e52d 100644 --- a/src/client/views/animationtimeline/TimelineMenu.scss +++ b/src/client/views/animationtimeline/TimelineMenu.scss @@ -1,7 +1,16 @@ .timeline-menu-container{ position: absolute; z-index: 10000; - width: 500px; - height: 500px; + width: 150px; + height: auto; background-color: black; + .timeline-menu-button{ + width:100%; + height: 30px; + + } + .timeline-menu-input{ + width:100%; + height: 30px; + } } \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index adbd21e62..52f6f6535 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -95,20 +95,20 @@ export class TimelineMenu extends React.Component { switch(this._type){ case "keyframe": menu = [ - , - , - + , + , + ]; break; case "region" : menu = [ - , - , - , - , - , - , + , + , + , + , + , + , ]; break; case "timeline": diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index fc2cacba8..363ab4074 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -128,8 +128,10 @@ export class Track extends React.Component { private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; let docFromApply = kfNode; + console.log(Doc.allKeys(docFromApply)); if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { + console.log(key); if (!kfNode[key]) { this.props.node[key] = undefined; } else { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c01f4e8cf..b272bc1b9 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -425,12 +425,13 @@ export namespace Doc { export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { - const field = ProxyField.WithoutProxy(() => doc[key]); if (key === "proto" && copyProto) { + const field = doc[key]; if (field instanceof Doc) { copy[key] = Doc.MakeCopy(field); } } else { + const field = ProxyField.WithoutProxy(() => doc[key]); if (field instanceof RefField) { copy[key] = field; } else if (field instanceof ObjectField) { -- cgit v1.2.3-70-g09d2 From 300aff743835dfd1c021609fd005819c8f2fd584 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 7 Aug 2019 14:56:48 -0400 Subject: working timelinemenu --- src/client/views/ContextMenu.scss | 1 + src/client/views/MainView.tsx | 6 +- src/client/views/animationtimeline/Keyframe.tsx | 73 +++++++++-------- .../views/animationtimeline/TimelineMenu.scss | 94 ++++++++++++++++++++-- .../views/animationtimeline/TimelineMenu.tsx | 85 ++++++++++++------- 5 files changed, 185 insertions(+), 74 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index e2c0de8af..6c619fbe1 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -7,6 +7,7 @@ box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw; flex-direction: column; background: whitesmoke; + padding-top: 10px; padding-bottom: 10px; border-radius: 15px; border: solid #BBBBBBBB 1px; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 270e9b183..3941c9c20 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -149,9 +149,9 @@ export class MainView extends React.Component { if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.closeMenu(); } - if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-container") === -1) { - TimelineMenu.Instance.closeMenu(); - } + // if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-container") === -1) { + // TimelineMenu.Instance.closeMenu(); + // } }); globalPointerUp = () => this.isPointerDown = false; diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index b27cb6d98..d1975d847 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -386,7 +386,7 @@ export class Keyframe extends React.Component {
    { this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - TimelineMenu.Instance.openMenu("keyframe", e.clientX, e.clientY); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); }}>
    ); } @@ -418,29 +418,21 @@ export class Keyframe extends React.Component { private _type: string = ""; @action - onContainerDown = (e: React.MouseEvent, kf: Doc) => { - e.preventDefault(); - e.stopPropagation(); + onContainerDown = (kf: Doc, type: string) => { let listenerCreated = false; - let type = prompt("Type? (interpolate or path)"); - if (type) { - if (type !== "interpolate" && type !=="path") { - alert("Wrong type. Try again."); - return; + this._type = type; + this.props.collection.backgroundColor = "rgb(0,0,0)"; + this._reac = reaction(() => { + return this.inks; + }, data => { + if (!listenerCreated) { + this._plotList = Array.from(data!)[data!.size - 1]!; + this._interpolationKeyframe = kf; + document.addEventListener("pointerup", this.onReactionListen); + listenerCreated = true; } - this._type = type; - this.props.collection.backgroundColor = "rgb(0,0,0)"; - this._reac = reaction(() => { - return this.inks; - }, data => { - if (!listenerCreated) { - this._plotList = Array.from(data!)[data!.size - 1]!; - this._interpolationKeyframe = kf; - document.addEventListener("pointerup", this.onReactionListen); - listenerCreated = true; - } - }); - } + }); + } @@ -508,20 +500,26 @@ export class Keyframe extends React.Component { } + + /** + * + * + * TEMPORARY + * let items = [ + TimelineMenu.Instance.addItem("button", "Show Data", () => {console.log(toJS(this.props.node));}), + TimelineMenu.Instance.addItem("button", "Delete", () => {}), + TimelineMenu.Instance.addItem("input", "Move", (val) => {console.log(val);}) + ]; + TimelineMenu.Instance.addMenu("Keyframe", items); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + * + */ render() { return (
    { - e.preventDefault(); - e.stopPropagation(); - console.log("has been clicked!"); - let offsetLeft = this._bar.current!.getBoundingClientRect().left - this._bar.current!.parentElement!.getBoundingClientRect().left; - let offsetTop = this._bar.current!.getBoundingClientRect().top; //+ this._bar.current!.parentElement!.getBoundingClientRect().top; - this.props.setFlyout({ x: offsetLeft * this.props.transform.Scale, y: offsetTop * this.props.transform.Scale, display: "block", regiondata: this.regiondata, regions: this.regions }); - })}> + onDoubleClick={this.createKeyframe}>
    {this.regiondata.keyframes!.map(kf => { @@ -536,7 +534,18 @@ export class Keyframe extends React.Component {
    { this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} - onContextMenu={(e) => {TimelineMenu.Instance.openMenu("region", e.clientX, e.clientY);}}> + onContextMenu={(e) => { + let items = [ + TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), + TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), + TimelineMenu.Instance.addItem("input", "fadeIn", (val) => {this.regiondata.fadeIn = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "fadeOut", (val) => {this.regiondata.fadeOut = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "position", (val) => {this.regiondata.position = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "duration", (val) => {this.regiondata.duration = parseInt(val, 10);}), + ]; + TimelineMenu.Instance.addMenu("Region", items); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + }}>
    ); } diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss index ed047e52d..90cc53b4c 100644 --- a/src/client/views/animationtimeline/TimelineMenu.scss +++ b/src/client/views/animationtimeline/TimelineMenu.scss @@ -1,16 +1,94 @@ +@import "./../globalCssVariables.scss"; + + .timeline-menu-container{ position: absolute; + display: flex; + box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw; + flex-direction: column; + background: whitesmoke; z-index: 10000; width: 150px; - height: auto; - background-color: black; - .timeline-menu-button{ - width:100%; - height: 30px; + padding-bottom: 10px; + border-radius: 15px; + + border: solid #BBBBBBBB 1px; + + - } .timeline-menu-input{ - width:100%; - height: 30px; + 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-header{ + border-top-left-radius: 15px; + border-top-right-radius: 15px; + text-transform: uppercase; + background: $dark-color; + letter-spacing: 2px; + + .timeline-menu-header-desc{ + font:$sans-serif; + font-size: 13px; + text-align: center; + color: whitesmoke; + } + } + + + .timeline-menu-item { + // width: 11vw; //10vw + height: 30px; //2vh + background: whitesmoke; + display: flex; //comment out to allow search icon to be inline with search text + justify-content: left; + align-items: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-style: none; + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 13px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; + padding-right: 20px; + padding-left: 10px; + } + + .timeline-menu-item:hover { + border-width: .11px; + border-style: none; + border-color: $intermediate-color; + border-bottom-style: solid; + border-top-style: solid; + background: $darker-alt-accent; + } + + .timeline-menu-desc { + 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 52f6f6535..8b47448f2 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -3,6 +3,10 @@ import {observable, action, runInAction} from "mobx"; import {observer} from "mobx-react"; import "./TimelineMenu.scss"; import { jSXAttribute } from "babel-types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faChartLine, faRoad, faClipboard, faPen, faTrash, faTable } from "@fortawesome/free-solid-svg-icons"; +import { AddComparisonResult } from "../../northstar/model/idea/idea"; + /** * TimelineMenu: @@ -38,8 +42,7 @@ export class TimelineMenu extends React.Component { @observable private _x = 0; @observable private _y = 0; @observable private _type: "timeline" | "keyframe" | "region" | "" = ""; - - + @observable private _currentMenu:JSX.Element[] = []; constructor (props:Readonly<{}>){ super(props); TimelineMenu.Instance = this; @@ -67,8 +70,7 @@ export class TimelineMenu extends React.Component { } @action - openMenu = (type: "timeline" | "keyframe" | "region", x?:number, y?:number) => { - this._type = type; + openMenu = (x?:number, y?:number) => { this._opacity = 1; x ? this._x = x : this._x = 0; y ? this._y = y : this._y = 0; @@ -88,41 +90,62 @@ export class TimelineMenu extends React.Component { } + addItem = (type: "input" | "button", title: string, event: (e:any) => void) => { + if (type === "input"){ + let ref = React.createRef(); + let text = ""; + return
    {text = e.target.value;}} onKeyDown={(e:React.KeyboardEvent) => { + if(e.keyCode === 13){ + event(text); + }}}/>
    ; + } else if (type === "button") { + let ref = React.createRef(); + return

    {title}

    ; + } + return
    ; + } + @action + addMenu = (title:string, items: JSX.Element[]) => { + items.unshift(

    {title}

    ); + this._currentMenu = items; + } render() { - let menu: (JSX.Element[] | undefined); - switch(this._type){ - case "keyframe": - menu = [ - , - , - + // let menu: (JSX.Element[] | undefined); + // switch(this._type){ + // case "keyframe": + // menu = [ + //

    Keyframe

    , + //

    Show Data

    , + //

    Delete

    , + //
    - ]; - break; - case "region" : - menu = [ - , - , - , - , - , - , - ]; - break; - case "timeline": - menu = [ + // ]; + // break; + // case "region" : + // menu = [ + //

    Region

    , + //

    Add Ease

    , + //

    Add Path

    , + //
    , + //
    , + //
    , + //
    , + // ]; + // break; + // case "timeline": + // menu = [ - ]; - break; - default: - break; + // ]; + // break; + // default: + // break; - } + // } return (
    - {menu} + {this._currentMenu}
    ); } -- cgit v1.2.3-70-g09d2 From 2ec9f8160204aaaa94239910731facce260c34a5 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Thu, 8 Aug 2019 17:01:05 -0400 Subject: added functionalities --- src/client/views/animationtimeline/Keyframe.tsx | 14 +++- .../views/animationtimeline/TimelineMenu.tsx | 77 ++-------------------- src/client/views/graph/Graph.tsx | 20 ++++-- 3 files changed, 33 insertions(+), 78 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index d1975d847..3c0d17796 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -13,6 +13,9 @@ import { Transform } from "../../util/Transform"; import { InkField, StrokeData } from "../../../new_fields/InkField"; import { number } from "prop-types"; import { TimelineMenu } from "./TimelineMenu"; +import { Docs } from "../../documents/Documents"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; export namespace KeyframeFunc { export enum KeyframeType { @@ -310,7 +313,6 @@ export class Keyframe extends React.Component { let dif = this.regiondata.position - (leftRegion.position + leftRegion.duration); this.regiondata.position = leftRegion.position + leftRegion.duration; this.regiondata.duration += dif; - } else { this.regiondata.duration -= offset; this.regiondata.position += offset; @@ -386,6 +388,15 @@ export class Keyframe extends React.Component {
    { this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); + let items = [ + TimelineMenu.Instance.addItem("button", "Show Data", () => { + runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); + }), + TimelineMenu.Instance.addItem("button", "Delete", () => {}), + TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}) + ]; + TimelineMenu.Instance.addMenu("Keyframe", items); TimelineMenu.Instance.openMenu(e.clientX, e.clientY); }}>
    ); @@ -527,7 +538,6 @@ export class Keyframe extends React.Component { })} {this.keyframes.map( kf => { if(this.keyframes.indexOf(kf) !== this.keyframes.length - 1) { - let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; let bodyRef = React.createRef(); return ( diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 8b47448f2..4223ee099 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -2,38 +2,10 @@ import * as React from "react"; import {observable, action, runInAction} from "mobx"; import {observer} from "mobx-react"; import "./TimelineMenu.scss"; -import { jSXAttribute } from "babel-types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChartLine, faRoad, faClipboard, faPen, faTrash, faTable } from "@fortawesome/free-solid-svg-icons"; -import { AddComparisonResult } from "../../northstar/model/idea/idea"; -/** - * TimelineMenu: - * - * - * Timeline: - * - - * - * - * Keyframe: - * - Delete keyframe - * - Move keyframe - * - Edit keyframe (shows schema) - * - * - * Region: - * - Add Keyframe - * - Copy Interpolation - * - Copy path - * - Add Interpolation - * - Add Path - * - Change fades - * - position region - * - duration region - * - - */ - @observer export class TimelineMenu extends React.Component { public static Instance:TimelineMenu; @@ -41,12 +13,13 @@ export class TimelineMenu extends React.Component { @observable private _opacity = 0; @observable private _x = 0; @observable private _y = 0; - @observable private _type: "timeline" | "keyframe" | "region" | "" = ""; @observable private _currentMenu:JSX.Element[] = []; + constructor (props:Readonly<{}>){ super(props); TimelineMenu.Instance = this; } + @action pointerDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -54,15 +27,15 @@ export class TimelineMenu extends React.Component { document.removeEventListener("pointerup", this.pointerUp); document.addEventListener("pointerup", this.pointerUp); document.removeEventListener("pointermove", this.pointerMove); - document.addEventListener("pointermove", this.pointerMove); - - + document.addEventListener("pointermove", this.pointerMove); } + @action pointerMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); } + @action pointerUp = (e: PointerEvent) => { document.removeEventListener("pointermove", this.pointerMove); @@ -81,15 +54,6 @@ export class TimelineMenu extends React.Component { this._opacity = 0; } - @action - addEase = (e: React.MouseEvent) => { - - } - @action - addPath = (e:React.MouseEvent) => { - - } - addItem = (type: "input" | "button", title: string, event: (e:any) => void) => { if (type === "input"){ let ref = React.createRef(); @@ -112,37 +76,6 @@ export class TimelineMenu extends React.Component { } render() { - // let menu: (JSX.Element[] | undefined); - // switch(this._type){ - // case "keyframe": - // menu = [ - //

    Keyframe

    , - //

    Show Data

    , - //

    Delete

    , - //
    - - // ]; - // break; - // case "region" : - // menu = [ - //

    Region

    , - //

    Add Ease

    , - //

    Add Path

    , - //
    , - //
    , - //
    , - //
    , - // ]; - // break; - // case "timeline": - // menu = [ - - // ]; - // break; - // default: - // break; - - // } return (
    {this._currentMenu} diff --git a/src/client/views/graph/Graph.tsx b/src/client/views/graph/Graph.tsx index 864bb8f46..326f33358 100644 --- a/src/client/views/graph/Graph.tsx +++ b/src/client/views/graph/Graph.tsx @@ -1,17 +1,29 @@ import * as React from "react"; +import {observable} from "mobx"; +import { observer } from "mobx-react"; +import { Document, listSpec } from "../../../new_fields/Schema"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { CollectionSubView, CollectionViewProps, SubCollectionViewProps } from "../collections/CollectionSubView"; -export class Graph extends React.Component { - - +export class Graph extends CollectionSubView(Document) { + static Instance:Graph; + + private constructor(props:SubCollectionViewProps) { + super(props); + Graph.Instance = this; + } + + render() { return ( - ) + + + ); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From c8cb602f06f1b6c325ce467eea8dfa405b673810 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Fri, 9 Aug 2019 17:10:49 -0400 Subject: some changes --- src/client/views/animationtimeline/Keyframe.tsx | 20 +---- src/client/views/animationtimeline/Timeline.tsx | 114 ------------------------ src/client/views/animationtimeline/Track.tsx | 9 +- src/client/views/graph/Graph.tsx | 5 +- 4 files changed, 9 insertions(+), 139 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 3c0d17796..dbc26e3d4 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -11,7 +11,6 @@ import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; import { InkField, StrokeData } from "../../../new_fields/InkField"; -import { number } from "prop-types"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -509,22 +508,6 @@ export class Keyframe extends React.Component { document.removeEventListener("pointerup", this.onReactionListen); } } - - - - /** - * - * - * TEMPORARY - * let items = [ - TimelineMenu.Instance.addItem("button", "Show Data", () => {console.log(toJS(this.props.node));}), - TimelineMenu.Instance.addItem("button", "Delete", () => {}), - TimelineMenu.Instance.addItem("input", "Move", (val) => {console.log(val);}) - ]; - TimelineMenu.Instance.addMenu("Keyframe", items); - TimelineMenu.Instance.openMenu(e.clientX, e.clientY); - * - */ render() { return (
    @@ -537,13 +520,14 @@ export class Keyframe extends React.Component { return this.createKeyframeJSX(kf as Doc, (kf! as Doc).type as KeyframeFunc.KeyframeType); })} {this.keyframes.map( kf => { - if(this.keyframes.indexOf(kf) !== this.keyframes.length - 1) { + if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; let bodyRef = React.createRef(); return (
    { this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} + onPointerDown={(e) => { this.props.changeCurrentBarX(NumCast(kf.time) + (e.clientX - bodyRef.current!.getBoundingClientRect().left) * this.props.transform.Scale);}} onContextMenu={(e) => { let items = [ TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 7a6d9fa52..052e6e925 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -350,7 +350,6 @@ export class Timeline extends CollectionSubView(Document) {
    -
    @@ -383,12 +382,6 @@ export class Timeline extends CollectionSubView(Document) { } -interface TimelineFlyoutProps { - flyoutInfo: FlyoutProps; - tickSpacing: number; - -} - interface TimelineOverviewProps { currentBarX: number; } @@ -412,116 +405,9 @@ class TimelineOverview extends React.Component{ } } -class TimelineFlyout extends React.Component{ - - @observable private _timeInput = React.createRef(); - @observable private _durationInput = React.createRef(); - @observable private _fadeInInput = React.createRef(); - @observable private _fadeOutInput = React.createRef(); - @observable private _data: FlyoutProps = { x: 0, y: 0, display: "none", regiondata: new Doc(), regions: new List() }; - - private block = false; - - componentDidMount() { - - document.addEventListener("pointerdown", this.closeFlyout); - } - - - componentWillUnmount() { - document.removeEventListener("pointerdown", this.closeFlyout); - } - - - @action - changeTime = (e: React.KeyboardEvent) => { - let time = this._timeInput.current!; - if (e.keyCode === 13) { - if (!Number.isNaN(Number(time.value))) { - this.props.flyoutInfo.regiondata!.position = Number(time.value) / 1000 * this.props.tickSpacing; - time.placeholder = time.value + "ms"; - time.value = ""; - } - } - } - @action - onFlyoutDown = (e: React.PointerEvent) => { - this._data.display = "block"; - this.block = true; - } - - @action - closeFlyout = (e: PointerEvent) => { - if (this.block) { - this.block = false; - return; - } - this._data.display = "none"; - } - - @action - changeDuration = (e: React.KeyboardEvent) => { - let duration = this._durationInput.current!; - if (e.keyCode === 13) { - if (!Number.isNaN(Number(duration.value))) { - this.props.flyoutInfo.regiondata!.duration = Number(duration.value) / 1000 * this.props.tickSpacing; - duration.placeholder = duration.value + "ms"; - duration.value = ""; - } - } - } - - @action - changeFadeIn = (e: React.KeyboardEvent) => { - let fadeIn = this._fadeInInput.current!; - if (e.keyCode === 13) { - if (!Number.isNaN(Number(fadeIn.value))) { - this.props.flyoutInfo.regiondata!.fadeIn = Number(fadeIn.value); - fadeIn.placeholder = fadeIn.value + "ms"; - fadeIn.value = ""; - } - } - } - - @action - changeFadeOut = (e: React.KeyboardEvent) => { - let fadeOut = this._fadeOutInput.current!; - if (e.keyCode === 13) { - if (!Number.isNaN(Number(fadeOut.value))) { - this.props.flyoutInfo.regiondata!.fadeOut = Number(fadeOut.value); - fadeOut.placeholder = fadeOut.value + "ms"; - fadeOut.value = ""; - } - } - } - - render() { - return ( -
    -
    - -
    -

    Time:

    -

    Duration:

    -

    Fade-in

    -

    Fade-out

    -
    -
    - - - - -
    - -
    -
    - ); - } -} class TimelineZoom extends React.Component { componentDidMount() { - } render() { return ( diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 363ab4074..64e94f0f1 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -61,8 +61,7 @@ export class Track extends React.Component { let keyframes:List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); let kfIndex:number = keyframes.indexOf(ref); let kf = keyframes[kfIndex] as Doc; - if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for fades - console.log("full keychange triggered"); + if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, kf); // lef keyframe, if it exists let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.props.currentBarX, kf); //right keyframe, if it exists @@ -104,7 +103,6 @@ export class Track extends React.Component { @action timeChange = async (time: number) => { if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { - console.log("saving"); await this.saveKeyframe(this._onKeyframe, this._onRegionData); } let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on @@ -169,9 +167,9 @@ export class Track extends React.Component { return currentkf; } + @action interpolate = async (left: Doc, right: Doc, regiondata:Doc) => { - console.log("interpolating"); let leftNode = left.key as Doc; let rightNode = right.key as Doc; const dif_time = NumCast(right.time) - NumCast(left.time); @@ -226,8 +224,7 @@ export class Track extends React.Component { if (nodeData !== currentNodeData) { this.props.node[key] = new RichTextField(nodeData); } - } - + } } else if (key === "creationDate") { } else { diff --git a/src/client/views/graph/Graph.tsx b/src/client/views/graph/Graph.tsx index 326f33358..d925cc32c 100644 --- a/src/client/views/graph/Graph.tsx +++ b/src/client/views/graph/Graph.tsx @@ -20,8 +20,11 @@ export class Graph extends CollectionSubView(Document) { render() { + let collection = ; + return ( - +
    +
    ); } -- cgit v1.2.3-70-g09d2 From c7e258d9d56990daec490b239e4103f9ca9d521a Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Mon, 12 Aug 2019 15:17:20 -0400 Subject: playmode / authoring mode --- src/client/views/animationtimeline/Timeline.scss | 66 ++----------- src/client/views/animationtimeline/Timeline.tsx | 121 +++++++++-------------- src/client/views/nodes/DocumentView.tsx | 3 +- 3 files changed, 57 insertions(+), 133 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 47f448adb..e5d898502 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -6,72 +6,24 @@ height: 30px; width: 100px; } -.flyout-container{ - background-color: transparent; - position:absolute; - - z-index:9999; - height: 150px; - width: 150px; - .flyout{ - background-color: transparent; - transform: rotate(180deg); - left:0px; - top:0px; - width: 100%; - height: 100%; - } - .input-container{ - position: absolute; - right:0px; - top: 30px; - width: 70px; - input{ - width: 100%; - } +.timeline-toolbox{ + position:absolute; + display:flex; + align-items: flex-start; + flex-direction: row; + top: 10px; + div{ + margin-left:10px; } - .text-container{ - position:absolute; - top:30px; - left:0px; - color:white - } -} - -.placement-highlight{ - background-color:blue; - transform: translate(0px, 0px); - transition: width 1000ms ease-in-out; - transition: height 1000ms ease-in-out; - position: absolute; } - .timeline-container{ width:100%; height:300px; position:absolute; background-color: $light-color-secondary; box-shadow: 0px 10px 20px; - //transition: transform 1000ms ease-in-out; - - .toolbox{ - position:absolute; - width: 100%; - top: 10px; - left: 20px; - div{ - float:left; - margin-left: 10px; - position:relative; - .overview{ - width: 200px; - height: 100%; - background-color: black; - position:absolute; - } - } - } + .info-container{ margin-top: 50px; right:20px; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 052e6e925..c8f11db5b 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -5,7 +5,7 @@ import { Document, listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, Reaction, IObservableObject, trace, autorun, runInAction } from "mobx"; -import { Cast, NumCast, FieldValue, StrCast } from "../../../new_fields/Types"; +import { Cast, NumCast, FieldValue, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -82,51 +82,48 @@ export class Timeline extends CollectionSubView(Document) { return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } - @computed - private get inks(){ - if (this.props.Document.data_ext){ - let data_ext = Cast(this.props.Document.data_ext, Doc) as Doc; - let ink = Cast(data_ext.ink, InkField) as InkField; - if (ink){ - return ink.inkData; - } - } + componentWillMount() { + this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; } - componentDidMount() { if (StrCast(this.props.Document.type) === "video") { console.log("ran"); console.log(this.props.Document.duration); if (this.props.Document.duration) { this._time = Math.round(NumCast(this.props.Document.duration)) * 1000; - reaction(() => { return NumCast(this.props.Document.curPage); }, curPage => { this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); }); - } } runInAction(() => { - reaction(() => { - return this._time; - }, () => { - this._ticks = []; - for (let i = 0; i < this._time;) { - this._ticks.push(i); - i += this._tickIncrement; - } - let trackbox = this._trackbox.current!; - this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; - trackbox.style.width = `${this._boxLength}`; - this._scrubberbox.current!.style.width = `${this._boxLength}`; - }, { fireImmediately: true }); + return this.props.Document.isAnimating; + }, async isAnimating => { + if (isAnimating){ + this._ticks = []; + for (let i = 0; i < this._time;) { + this._ticks.push(i); + i += this._tickIncrement; + } + observe(this._trackbox, change => {if (change.type === "update"){ + if (this.props.Document.isAnimating){ + let trackbox = this._trackbox.current!; + this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; + trackbox.style.width = `${this._boxLength}`; + this._scrubberbox.current!.style.width = `${this._boxLength}`; + } + }}); + } + + }); }); } + @action changeCurrentBarX = (x: number) => { @@ -346,73 +343,47 @@ export class Timeline extends CollectionSubView(Document) { } render() { - return ( -
    - -
    -
    -
    -
    -
    + let timeline:JSX.Element[] = []; + BoolCast(this.props.Document.isAnimating) ? timeline = [ +
    + +
    +
    +
    +
    +
    -
    -
    +
    +
    {this._ticks.map(element => { return

    {this.toTime(element)}

    ; })}
    -
    -
    +
    +
    -
    +
    {DocListCast(this.children).map(doc => )}
    -
    +
    {DocListCast(this.children).map(doc =>

    {doc.title}

    )}
    -
    +
    - ); - } - -} - - -interface TimelineOverviewProps { - currentBarX: number; -} - -class TimelineOverview extends React.Component{ - - componentWillMount() { - - } - - render() { - return ( -
    -
    -
    -
    -
    -
    -
    - ); - } -} - + ] : timeline = [ +
    +
    +
    +
    +
    ]; -class TimelineZoom extends React.Component { - componentDidMount() { - } - render() { return (
    - + {timeline}
    ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a7b4f33db..95970cb81 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -107,7 +107,7 @@ const schema = createSchema({ nativeHeight: "number", backgroundColor: "string", opacity: "number", - hidden: "boolean" + hidden: "boolean", }); export const positionSchema = createSchema({ @@ -565,6 +565,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); cm.addItem({ description: "Transcribe Speech", event: this.listen, icon: "microphone" }); + cm.addItem({ description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => {BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true;}, icon:BoolCast(this.props.Document.isAnimating) ? "play" : "edit"}); let makes: ContextMenuProps[] = []; makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); -- cgit v1.2.3-70-g09d2 From eab360d4c415163e4bfe14f167c84b58902971b5 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Mon, 12 Aug 2019 17:04:36 -0400 Subject: authoring/play mode and timeline overview --- src/client/views/animationtimeline/Timeline.tsx | 100 ++++++++++----------- .../views/animationtimeline/TimelineOverview.scss | 13 +++ .../views/animationtimeline/TimelineOverview.tsx | 33 +++++++ 3 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 src/client/views/animationtimeline/TimelineOverview.scss create mode 100644 src/client/views/animationtimeline/TimelineOverview.tsx (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index c8f11db5b..97b9ad4db 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -21,6 +21,7 @@ import { faGrinTongueSquint } from "@fortawesome/free-regular-svg-icons"; import { InkField } from "../../../new_fields/InkField"; import { AddComparisonParameters } from "../../northstar/model/idea/idea"; import { keepAlive } from "mobx-utils"; +import { TimelineOverview } from "./TimelineOverview"; export interface FlyoutProps { @@ -102,24 +103,17 @@ export class Timeline extends CollectionSubView(Document) { } runInAction(() => { reaction(() => { - return this.props.Document.isAnimating; - }, async isAnimating => { - if (isAnimating){ - this._ticks = []; - for (let i = 0; i < this._time;) { - this._ticks.push(i); - i += this._tickIncrement; - } - observe(this._trackbox, change => {if (change.type === "update"){ - if (this.props.Document.isAnimating){ - let trackbox = this._trackbox.current!; - this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; - trackbox.style.width = `${this._boxLength}`; - this._scrubberbox.current!.style.width = `${this._boxLength}`; - } - }}); - } - + return this._time; + }, () => { + this._ticks = []; + for (let i = 0; i < this._time;) { + this._ticks.push(i); + i += this._tickIncrement; + } + let trackbox = this._trackbox.current!; + this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; + trackbox.style.width = `${this._boxLength}`; + this._scrubberbox.current!.style.width = `${this._boxLength}`; }); }); } @@ -343,47 +337,45 @@ export class Timeline extends CollectionSubView(Document) { } render() { - let timeline:JSX.Element[] = []; - BoolCast(this.props.Document.isAnimating) ? timeline = [ -
    - -
    -
    -
    -
    -
    -
    -
    -
    - {this._ticks.map(element => { - return

    {this.toTime(element)}

    ; - })} + + + return ( +
    +
    + +
    +
    +
    +
    +
    -
    -
    +
    +
    + {this._ticks.map(element => { + return

    {this.toTime(element)}

    ; + })} +
    +
    +
    +
    +
    + {DocListCast(this.children).map(doc => )} +
    -
    - {DocListCast(this.children).map(doc => )} +
    + {DocListCast(this.children).map(doc =>

    {doc.title}

    )} +
    +
    +
    -
    -
    - {DocListCast(this.children).map(doc =>

    {doc.title}

    )} -
    -
    -
    -
    - ] : timeline = [ -
    -
    -
    -
    -
    ]; - - return ( -
    - {timeline} +
    +
    +
    +
    + +
    ); } diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss new file mode 100644 index 000000000..a71abf348 --- /dev/null +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -0,0 +1,13 @@ +.timeline-overview-container{ + width: 300px; + height: 40px; + margin-top: 10px; + margin-left: 20px; + background: white; + border: 1px solid black; + .timeline-overview-visible{ + height: 100%; + background: green; + border: 1px solid black; + } +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx new file mode 100644 index 000000000..0e10e655d --- /dev/null +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -0,0 +1,33 @@ +import * as React from "react"; +import {observable} from "mobx"; +import {observer} from "mobx-react"; +import "./TimelineOverview.scss"; + + + +interface TimelineOverviewProps{ + totalLength: number; + visibleLength:number; + visibleStart:number; + changeCurrentBarX: (x:number) => any; +} + + +export class TimelineOverview extends React.Component{ + + + render(){ + return( +
    +
    +
    +
    +
    +
    +
    + ); + } + +} + + -- cgit v1.2.3-70-g09d2 From 91335b57dafdeda7a1feb703b0839337fcbbfecd Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 13 Aug 2019 17:26:32 -0400 Subject: timeline overview completed! --- src/client/views/animationtimeline/Keyframe.tsx | 2 + src/client/views/animationtimeline/Timeline.tsx | 77 ++++++++++++++-------- .../views/animationtimeline/TimelineOverview.scss | 24 +++++++ .../views/animationtimeline/TimelineOverview.tsx | 61 +++++++++++++++-- src/client/views/animationtimeline/Track.tsx | 1 + 5 files changed, 134 insertions(+), 31 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index dbc26e3d4..f6c04d43e 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -91,6 +91,8 @@ export namespace KeyframeFunc { regiondata.functions = new List(); return regiondata; }; + + } export const RegionDataSchema = createSchema({ diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 97b9ad4db..a29758694 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import "./Timeline.scss"; -import { CollectionSubView } from "../collections/CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "../collections/CollectionSubView"; import { Document, listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; @@ -35,8 +35,6 @@ export interface FlyoutProps { @observer export class Timeline extends CollectionSubView(Document) { - static Instance:Timeline; - private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; private readonly DEFAULT_TICK_SPACING: number = 50; @@ -53,16 +51,16 @@ export class Timeline extends CollectionSubView(Document) { @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); - @observable private _timelineWrapper = React.createRef(); @observable private _infoContainer = React.createRef(); - @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing @observable private _isFrozen: boolean = false; //timeline freeze - @observable private _boxLength: number = 0; + @observable private _totalLength: number = 0; + @observable private _visibleLength: number = 0; + @observable private _visibleStart: number = 0; @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; @observable private _time = 100000; //DEFAULT @observable private _ticks: number[] = []; @@ -83,8 +81,10 @@ export class Timeline extends CollectionSubView(Document) { return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } + componentWillMount() { this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; + console.log(this._currentBarX); } componentDidMount() { @@ -99,11 +99,10 @@ export class Timeline extends CollectionSubView(Document) { this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); }); } - } runInAction(() => { reaction(() => { - return this._time; + return this._time; }, () => { this._ticks = []; for (let i = 0; i < this._time;) { @@ -111,17 +110,22 @@ export class Timeline extends CollectionSubView(Document) { i += this._tickIncrement; } let trackbox = this._trackbox.current!; - this._boxLength = this._tickIncrement / 1000 * this._tickSpacing * this._ticks.length; - trackbox.style.width = `${this._boxLength}`; - this._scrubberbox.current!.style.width = `${this._boxLength}`; - }); + this._totalLength = this._tickSpacing * this._ticks.length; + trackbox.style.width = `${this._totalLength}`; + this._scrubberbox.current!.style.width = `${this._totalLength}`; + }, {fireImmediately:true}); + this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; + this._visibleStart = this._infoContainer.current!.scrollLeft; }); + } + + @action - changeCurrentBarX = (x: number) => { - this._currentBarX = x; + changeCurrentBarX = (pixel: number) => { + this._currentBarX = pixel; } //for playing @@ -139,10 +143,10 @@ export class Timeline extends CollectionSubView(Document) { @action changeCurrentX = () => { - if (this._currentBarX === this._boxLength && this._isPlaying) { + if (this._currentBarX === this._totalLength && this._isPlaying) { this._currentBarX = 0; } - if (this._currentBarX <= this._boxLength && this._isPlaying) { + if (this._currentBarX <= this._totalLength && this._isPlaying) { this._currentBarX = this._currentBarX + this._windSpeed; setTimeout(this.changeCurrentX, 15); } @@ -208,13 +212,18 @@ export class Timeline extends CollectionSubView(Document) { onPanMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let infoContainer = this._infoContainer.current!; let trackbox = this._trackbox.current!; let titleContainer = this._titleContainer.current!; - infoContainer.scrollLeft = infoContainer.scrollLeft - e.movementX; + this.movePanX(this._visibleStart - e.movementX); trackbox.scrollTop = trackbox.scrollTop - e.movementY; titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; } + @action + movePanX = (pixel:number) => { + let infoContainer = this._infoContainer.current!; + infoContainer.scrollLeft = pixel; + this._visibleStart = infoContainer.scrollLeft; + } @action @@ -276,7 +285,7 @@ export class Timeline extends CollectionSubView(Document) { } @action - toTime = (time: number): string => { + toReadTime = (time: number): string => { const inSeconds = time / 1000; let min: (string | number) = Math.floor(inSeconds / 60); let sec: (string | number) = inSeconds % 60; @@ -288,6 +297,23 @@ export class Timeline extends CollectionSubView(Document) { } + convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time") => { + let time = dir === "pixel" ? pos / this._tickSpacing * this._tickIncrement : pos * this._tickSpacing / this._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; + } + } + + private _freezeText = "Freeze Timeline"; timelineContextMenu = (e: React.MouseEvent): void => { @@ -337,22 +363,21 @@ export class Timeline extends CollectionSubView(Document) { } render() { - - return (
    -
    -
    -
    +
    +
    +
    +
    {this._ticks.map(element => { - return

    {this.toTime(element)}

    ; + return

    {this.toReadTime(element)}

    ; })}
    @@ -374,7 +399,7 @@ export class Timeline extends CollectionSubView(Document) {
    - +
    ); diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index a71abf348..21988927d 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -5,9 +5,33 @@ margin-left: 20px; background: white; border: 1px solid black; + padding: 0px; + display:inline-block; .timeline-overview-visible{ height: 100%; background: green; border: 1px solid black; + margin: 0px; + } + .timeline-overview-scrubber-container{ + height: 100%; + margin-top: -40px; + margin-left: 0px; + width: 2px; + z-index: 1001; + background-color:black; + display: inline-block; + .timeline-overview-scrubber-head{ + position:absolute; + height: 30px; + width: 30px; + background-color:transparent; + border-radius: 50%; + border: 5px solid black; + margin-left: -15px; + top: -15px; + + } + } } \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 0e10e655d..1ad7d20e5 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import {observable} from "mobx"; +import {observable, action} from "mobx"; import {observer} from "mobx-react"; import "./TimelineOverview.scss"; @@ -9,20 +9,71 @@ interface TimelineOverviewProps{ totalLength: number; visibleLength:number; visibleStart:number; - changeCurrentBarX: (x:number) => any; + currentBarX:number; + changeCurrentBarX: (pixel:number) => void; + movePanX: (pixel:number) => any; } +@observer export class TimelineOverview extends React.Component{ + @observable private _visibleRef = React.createRef(); + @observable private _scrubberRef = React.createRef(); + + @action + onPointerDown = (e:React.PointerEvent) => { + document.removeEventListener("pointermove", this.onPanX); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointermove", this.onPanX); + document.addEventListener("pointerup", this.onPointerUp); + } + + @action + onPanX = (e: PointerEvent) => { + let movX = (this.props.visibleStart / this.props.totalLength)* 300 + e.movementX; + this.props.movePanX((movX / 300) * this.props.totalLength); + } + + @action + onPointerUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.onPanX); + document.removeEventListener("pointerup", this.onPointerUp); + } + @action + onScrubberDown = ( e:React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.removeEventListener("pointermove", this.onScrubberMove); + document.removeEventListener("pointerup", this.onScrubberUp); + document.addEventListener("pointermove", this.onScrubberMove); + document.addEventListener("pointerup", this.onScrubberUp); + } + + @action + onScrubberMove = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let scrubberRef = this._scrubberRef.current!; + let left = scrubberRef.getBoundingClientRect().left; + let offsetX = Math.round(e.clientX - left); + this.props.changeCurrentBarX(((offsetX / 300) * this.props.totalLength) + this.props.currentBarX); + } + + @action + onScrubberUp = (e:PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.removeEventListener("pointermove", this.onScrubberMove); + document.removeEventListener("pointerup", this.onScrubberUp); + } render(){ return(
    -
    -
    +
    +
    -
    ); diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 64e94f0f1..6bdabeb93 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -94,6 +94,7 @@ export class Track extends React.Component { this.props.node.hidden = false; await this.timeChange(this.props.currentBarX); } else { + console.log("heuulloo"); this.props.node.hidden = true; } }, { fireImmediately: true }); -- cgit v1.2.3-70-g09d2 From f43509c132b5302b9983667aaf99251051b38b59 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 14 Aug 2019 11:52:33 -0400 Subject: bug fix with currentBarX --- src/client/views/animationtimeline/Keyframe.tsx | 4 ++-- src/client/views/animationtimeline/Timeline.tsx | 8 ++++---- src/client/views/animationtimeline/Track.tsx | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index f6c04d43e..6a0525eb8 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -183,8 +183,8 @@ export class Keyframe extends React.Component { let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; (fadeIn.key! as Doc).opacity = 1; (fadeOut.key! as Doc).opacity = 1; - (start.key! as Doc).opacity = 0.1; - (finish.key! as Doc).opacity = 0.1; + (start.key! as Doc).opacity = 0; + (finish.key! as Doc).opacity = 0; observe(this.regiondata, change => { if (change.type === "update") { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index a29758694..29787fa03 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -125,7 +125,7 @@ export class Timeline extends CollectionSubView(Document) { @action changeCurrentBarX = (pixel: number) => { - this._currentBarX = pixel; + pixel <= 0 ? this._currentBarX = 0 : pixel >= this._totalLength ? this._currentBarX = this._totalLength : this._currentBarX = pixel; } //for playing @@ -184,7 +184,7 @@ export class Timeline extends CollectionSubView(Document) { let scrubberbox = this._scrubberbox.current!; let left = scrubberbox.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; - this._currentBarX = offsetX; + this.changeCurrentBarX(offsetX); } @action @@ -192,8 +192,8 @@ export class Timeline extends CollectionSubView(Document) { e.preventDefault(); e.stopPropagation(); let scrubberbox = this._scrubberbox.current!; - let offset = (e.clientX - scrubberbox.getBoundingClientRect().left) * this.props.ScreenToLocalTransform().Scale; - this._currentBarX = offset; + let offsetX = (e.clientX - scrubberbox.getBoundingClientRect().left) * this.props.ScreenToLocalTransform().Scale; + this.changeCurrentBarX(offsetX); } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 6bdabeb93..288a1d2ad 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -94,8 +94,8 @@ export class Track extends React.Component { this.props.node.hidden = false; await this.timeChange(this.props.currentBarX); } else { - console.log("heuulloo"); - this.props.node.hidden = true; + this.props.node.hidden = true; + this.props.node.opacity = 0; } }, { fireImmediately: true }); } -- cgit v1.2.3-70-g09d2 From e04277caf25be1c657a2f779a64eb5fcb4e19461 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 14 Aug 2019 16:08:01 -0400 Subject: UI improvements, pointerevents, and improved overview --- src/client/views/animationtimeline/Keyframe.tsx | 51 +++++++---- src/client/views/animationtimeline/Timeline.scss | 2 +- src/client/views/animationtimeline/Timeline.tsx | 100 ++++++++------------- .../views/animationtimeline/TimelineOverview.scss | 5 +- .../views/animationtimeline/TimelineOverview.tsx | 19 ++-- src/client/views/animationtimeline/Track.tsx | 5 +- src/client/views/graph/GraphManager.ts | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- 8 files changed, 90 insertions(+), 96 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 6a0525eb8..784765318 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -2,10 +2,10 @@ import * as React from "react"; import "./Keyframe.scss"; import "./Timeline.scss"; import "../globalCssVariables.scss"; -import { observer, Observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, isComputedProp, runInAction } from "mobx"; +import { observer} from "mobx-react"; +import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction } from "mobx"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { Cast, FieldValue, StrCast, NumCast } from "../../../new_fields/Types"; +import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FlyoutProps } from "./Timeline"; @@ -13,7 +13,6 @@ import { Transform } from "../../util/Transform"; import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionDockingView } from "../collections/CollectionDockingView"; export namespace KeyframeFunc { @@ -111,7 +110,6 @@ interface IProps { RegionData: Doc; collection: Doc; changeCurrentBarX: (x: number) => void; - setFlyout: (props: FlyoutProps) => any; transform: Transform; } @@ -183,8 +181,8 @@ export class Keyframe extends React.Component { let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; (fadeIn.key! as Doc).opacity = 1; (fadeOut.key! as Doc).opacity = 1; - (start.key! as Doc).opacity = 0; - (finish.key! as Doc).opacity = 0; + (start.key! as Doc).opacity = 0.1; + (finish.key! as Doc).opacity = 0.1; observe(this.regiondata, change => { if (change.type === "update") { @@ -238,14 +236,32 @@ export class Keyframe extends React.Component { return TK; } + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; @action onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - document.addEventListener("pointermove", this.onBarPointerMove); - document.addEventListener("pointerup", (e: PointerEvent) => { + + let clientX = e.clientX; + if (this._doubleClickEnabled){ + this.createKeyframe(clientX); + this._doubleClickEnabled = false; + } else { + setTimeout(() => {if(!this._mouseToggled && this._doubleClickEnabled)this.props.changeCurrentBarX(this.regiondata.position + (clientX - this._bar.current!.getBoundingClientRect().left) * this.props.transform.Scale); + this._mouseToggled = false; + this._doubleClickEnabled = false; }, 200); + this._doubleClickEnabled = true; + document.addEventListener("pointermove", this.onBarPointerMove); + document.addEventListener("pointerup", (e: PointerEvent) => { document.removeEventListener("pointermove", this.onBarPointerMove); }); + + } + + + + } @@ -253,6 +269,9 @@ export class Keyframe extends React.Component { onBarPointerMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); + if (e.movementX !== 0) { + this._mouseToggled = true; + } let left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; let right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions!); let prevX = this.regiondata.position; @@ -351,11 +370,10 @@ export class Keyframe extends React.Component { } @action - createKeyframe = async (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); + createKeyframe = async (clientX:number) => { + this._mouseToggled = true; let bar = this._bar.current!; - let offset = Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); + let offset = Math.round((clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); if (offset > this.regiondata.fadeIn && offset < this.regiondata.duration - this.regiondata.fadeOut) { //make sure keyframe is not created inbetween fades and ends let position = NumCast(this.regiondata.position); await this.makeKeyData(Math.round(position + offset)); @@ -514,8 +532,7 @@ export class Keyframe extends React.Component { return (
    + onPointerDown={this.onBarPointerDown}>
    {this.regiondata.keyframes!.map(kf => { @@ -529,8 +546,10 @@ export class Keyframe extends React.Component {
    { this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} - onPointerDown={(e) => { this.props.changeCurrentBarX(NumCast(kf.time) + (e.clientX - bodyRef.current!.getBoundingClientRect().left) * this.props.transform.Scale);}} onContextMenu={(e) => { + e.preventDefault(); + e.stopPropagation(); + this._mouseToggled = true; let items = [ TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index e5d898502..1457d5a84 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -8,7 +8,7 @@ } .timeline-toolbox{ - position:absolute; + position:absolute; display:flex; align-items: flex-start; flex-direction: row; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 29787fa03..3d878660d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -1,26 +1,17 @@ import * as React from "react"; import "./Timeline.scss"; -import { CollectionSubView, SubCollectionViewProps } from "../collections/CollectionSubView"; +import { CollectionSubView } from "../collections/CollectionSubView"; import { Document, listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, Reaction, IObservableObject, trace, autorun, runInAction } from "mobx"; -import { Cast, NumCast, FieldValue, StrCast, BoolCast } from "../../../new_fields/Types"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction } from "mobx"; +import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle } from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; -import { DocumentManager } from "../../util/DocumentManager"; -import { VideoBox } from "../nodes/VideoBox"; -import { VideoField } from "../../../new_fields/URLField"; -import { CollectionVideoView } from "../collections/CollectionVideoView"; -import { Transform } from "../../util/Transform"; -import { faGrinTongueSquint } from "@fortawesome/free-regular-svg-icons"; -import { InkField } from "../../../new_fields/InkField"; -import { AddComparisonParameters } from "../../northstar/model/idea/idea"; -import { keepAlive } from "mobx-utils"; import { TimelineOverview } from "./TimelineOverview"; @@ -57,7 +48,7 @@ export class Timeline extends CollectionSubView(Document) { @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing - @observable private _isFrozen: boolean = false; //timeline freeze + @observable private _isFrozen: boolean = true; //timeline freeze @observable private _totalLength: number = 0; @observable private _visibleLength: number = 0; @observable private _visibleStart: number = 0; @@ -65,7 +56,6 @@ export class Timeline extends CollectionSubView(Document) { @observable private _time = 100000; //DEFAULT @observable private _ticks: number[] = []; @observable private _playButton = faPlayCircle; - @observable private flyoutInfo: FlyoutProps = { x: 0, y: 0, display: "none", regiondata: new Doc(), regions: new List() }; @computed private get children(): List { @@ -130,30 +120,33 @@ export class Timeline extends CollectionSubView(Document) { //for playing @action - onPlay = async (e: React.MouseEvent) => { + onPlay = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); if (this._isPlaying) { this._isPlaying = false; this._playButton = faPlayCircle; } else { this._isPlaying = true; this._playButton = faPauseCircle; - this.changeCurrentX(); - } - } - - @action - changeCurrentX = () => { - if (this._currentBarX === this._totalLength && this._isPlaying) { - this._currentBarX = 0; - } - if (this._currentBarX <= this._totalLength && this._isPlaying) { - this._currentBarX = this._currentBarX + this._windSpeed; - setTimeout(this.changeCurrentX, 15); + const playTimeline = () => { + if (this._isPlaying){ + if (this._currentBarX >= this._totalLength) { + this.changeCurrentBarX(0); + } else { + this.changeCurrentBarX(this._currentBarX + this._windSpeed); + setTimeout(playTimeline, 15); + } + } + }; + playTimeline(); } } @action windForward = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); if (this._windSpeed < 64) { //max speed is 32 this._windSpeed = this._windSpeed * 2; } @@ -161,6 +154,8 @@ export class Timeline extends CollectionSubView(Document) { @action windBackward = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); if (this._windSpeed > 1 / 16) { // min speed is 1/8 this._windSpeed = this._windSpeed / 2; } @@ -313,16 +308,12 @@ export class Timeline extends CollectionSubView(Document) { } } - - private _freezeText = "Freeze Timeline"; - timelineContextMenu = (e: React.MouseEvent): void => { let subitems: ContextMenuProps[] = []; let timelineContainer = this._timelineWrapper.current!; subitems.push({ description: "Pin to Top", event: action(() => { if (!this._isFrozen) { - timelineContainer.style.transition = "top 1000ms ease-in, left 1000ms ease-in"; //????? timelineContainer.style.left = "0px"; timelineContainer.style.top = "0px"; timelineContainer.style.transition = "none"; @@ -330,22 +321,11 @@ export class Timeline extends CollectionSubView(Document) { }), icon: faArrowUp }); subitems.push({ - description: "Pin to Bottom", event: action(() => { - console.log(this.props.Document.y); - - if (!this._isFrozen) { - timelineContainer.style.transform = `translate(0px, ${e.pageY - this._containerHeight}px)`; - } - }), icon: faArrowDown - }); - subitems.push({ - description: this._freezeText, event: action(() => { + description: this._isFrozen ? "Unfreeze Timeline" : "Freeze Timeline", event: action(() => { if (this._isFrozen) { this._isFrozen = false; - this._freezeText = "Freeze Timeline"; } else { this._isFrozen = true; - this._freezeText = "Unfreeze Timeline"; } }), icon: "thumbtack" }); @@ -353,27 +333,24 @@ export class Timeline extends CollectionSubView(Document) { } - - @action - getFlyout = (props: FlyoutProps) => { - for (const [k, v] of Object.entries(props)) { - (this.flyoutInfo as any)[k] = v; - } - console.log(this.flyoutInfo); + private timelineToolBox = (scale:number) => { + let size = 50 * scale; //50 is default + return ( +
    +
    +
    +
    + +
    + ); } - render() { return (
    -
    -
    -
    -
    - -
    + {this.timelineToolBox(0.5)}
    {this._ticks.map(element => { @@ -384,7 +361,7 @@ export class Timeline extends CollectionSubView(Document) {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    @@ -395,12 +372,7 @@ export class Timeline extends CollectionSubView(Document) {
    -
    -
    -
    -
    - -
    + {BoolCast(this.props.Document.isAnimating) ?
    : this.timelineToolBox(1) }
    ); } diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index 21988927d..9e69c2adf 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -1,16 +1,17 @@ +@import "./../globalCssVariables.scss"; + .timeline-overview-container{ width: 300px; height: 40px; margin-top: 10px; margin-left: 20px; background: white; - border: 1px solid black; + border: 2px solid black; padding: 0px; display:inline-block; .timeline-overview-visible{ height: 100%; background: green; - border: 1px solid black; margin: 0px; } .timeline-overview-scrubber-container{ diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 1ad7d20e5..4fdf1381e 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -6,6 +6,7 @@ import "./TimelineOverview.scss"; interface TimelineOverviewProps{ + scale: number; totalLength: number; visibleLength:number; visibleStart:number; @@ -19,7 +20,9 @@ interface TimelineOverviewProps{ export class TimelineOverview extends React.Component{ @observable private _visibleRef = React.createRef(); @observable private _scrubberRef = React.createRef(); - + private readonly DEFAULT_HEIGHT = 50; + private readonly DEFAULT_WIDTH = 300; + @action onPointerDown = (e:React.PointerEvent) => { document.removeEventListener("pointermove", this.onPanX); @@ -30,8 +33,8 @@ export class TimelineOverview extends React.Component{ @action onPanX = (e: PointerEvent) => { - let movX = (this.props.visibleStart / this.props.totalLength)* 300 + e.movementX; - this.props.movePanX((movX / 300) * this.props.totalLength); + let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH * this.props.scale) + e.movementX; + this.props.movePanX((movX / (this.DEFAULT_WIDTH * this.props.scale)) * this.props.totalLength); } @action @@ -57,7 +60,7 @@ export class TimelineOverview extends React.Component{ let scrubberRef = this._scrubberRef.current!; let left = scrubberRef.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left); - this.props.changeCurrentBarX(((offsetX / 300) * this.props.totalLength) + this.props.currentBarX); + this.props.changeCurrentBarX(((offsetX / (this.DEFAULT_WIDTH * this.props.scale)) * this.props.totalLength) + this.props.currentBarX); } @action @@ -70,10 +73,10 @@ export class TimelineOverview extends React.Component{ render(){ return( -
    -
    -
    -
    +
    +
    +
    +
    ); diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 288a1d2ad..d91954022 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -17,7 +17,6 @@ interface IProps { transform: Transform; collection: Doc; changeCurrentBarX: (x: number) => void; - setFlyout: (props: FlyoutProps) => any; } @observer @@ -177,7 +176,7 @@ export class Track extends React.Component { const timeratio = (this.props.currentBarX - NumCast(left.time)) / dif_time; //linear let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; let indexLeft = keyframes.indexOf(left); - let interY:List = await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List; + let interY:List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; let realIndex = (interY.length - 1) * timeratio; let xIndex = Math.floor(realIndex); let yValue = interY[xIndex]; @@ -276,7 +275,7 @@ export class Track extends React.Component {
    {DocListCast(this.regions).map((region) => { - return ; + return ; })}
    diff --git a/src/client/views/graph/GraphManager.ts b/src/client/views/graph/GraphManager.ts index 9d62b1ef8..b62f2337b 100644 --- a/src/client/views/graph/GraphManager.ts +++ b/src/client/views/graph/GraphManager.ts @@ -32,7 +32,7 @@ export class GraphManager { defaultGraphs = () => { - this.GraphData.linear = ; + } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f2be7097a..28af39fb3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -729,7 +729,7 @@ export class DocumentView extends DocComponent(Docu render() { - trace(); + // trace(); let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ? this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); -- cgit v1.2.3-70-g09d2 From e507271488fe4c8dcb548dc766ab131fa84f4437 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 14 Aug 2019 16:52:19 -0400 Subject: ink fix and overview fix --- src/client/views/InkingCanvas.scss | 2 +- src/client/views/InkingCanvas.tsx | 4 ++-- src/client/views/animationtimeline/TimelineOverview.tsx | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index d95398f17..2052021d1 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -21,7 +21,7 @@ width: 8192px; height: 8192px; cursor: "crosshair"; - pointer-events: auto; + pointer-events: all; } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index b08133d80..1cfa8d644 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -170,12 +170,12 @@ export class InkingCanvas extends React.Component { return [!penPaths.length ? (null) : - {} + {penPaths} , !markerPaths.length ? (null) : - {} + {markerPaths} ]; } diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 4fdf1381e..38b823cbc 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -25,6 +25,8 @@ export class TimelineOverview extends React.Component{ @action onPointerDown = (e:React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); document.removeEventListener("pointermove", this.onPanX); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPanX); @@ -33,12 +35,16 @@ export class TimelineOverview extends React.Component{ @action onPanX = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH * this.props.scale) + e.movementX; this.props.movePanX((movX / (this.DEFAULT_WIDTH * this.props.scale)) * this.props.totalLength); } @action onPointerUp = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); document.removeEventListener("pointermove", this.onPanX); document.removeEventListener("pointerup", this.onPointerUp); } -- cgit v1.2.3-70-g09d2 From 3d99b990b95edd6481a6c12bc994cdac87e6c8dc Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Thu, 15 Aug 2019 12:48:06 -0400 Subject: uiux --- src/client/views/animationtimeline/Keyframe.tsx | 8 +---- src/client/views/animationtimeline/Timeline.tsx | 30 +++++++++++++---- .../views/animationtimeline/TimelineMenu.tsx | 39 ++++++---------------- 3 files changed, 36 insertions(+), 41 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 784765318..4e58b07d8 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -242,7 +242,6 @@ export class Keyframe extends React.Component { onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let clientX = e.clientX; if (this._doubleClickEnabled){ this.createKeyframe(clientX); @@ -254,14 +253,9 @@ export class Keyframe extends React.Component { this._doubleClickEnabled = true; document.addEventListener("pointermove", this.onBarPointerMove); document.addEventListener("pointerup", (e: PointerEvent) => { - document.removeEventListener("pointermove", this.onBarPointerMove); + document.removeEventListener("pointermove", this.onBarPointerMove); }); - } - - - - } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 3d878660d..10034263c 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -135,8 +135,8 @@ export class Timeline extends CollectionSubView(Document) { this.changeCurrentBarX(0); } else { this.changeCurrentBarX(this._currentBarX + this._windSpeed); - setTimeout(playTimeline, 15); - } + } + setTimeout(playTimeline, 15); } }; playTimeline(); @@ -193,20 +193,38 @@ export class Timeline extends CollectionSubView(Document) { + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; @action onPanDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - document.addEventListener("pointermove", this.onPanMove); - document.addEventListener("pointerup", () => { - document.removeEventListener("pointermove", this.onPanMove); - }); + let clientX = e.clientX; + if (this._doubleClickEnabled){ + this._doubleClickEnabled = false; + } else { + setTimeout(() => {if(!this._mouseToggled && this._doubleClickEnabled) this.changeCurrentBarX(this._trackbox.current!.scrollLeft + clientX - this._trackbox.current!.getBoundingClientRect().left); + this._mouseToggled = false; + this._doubleClickEnabled = false;}, 200); + this._doubleClickEnabled = true; + document.addEventListener("pointermove", this.onPanMove); + document.addEventListener("pointerup", () => { + document.removeEventListener("pointermove", this.onPanMove); + if (!this._doubleClickEnabled) { + this._mouseToggled = false; + } + }); + + } } @action onPanMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); + if (e.movementX !== 0 || e.movementY !== 0) { + this._mouseToggled = true; + } let trackbox = this._trackbox.current!; let titleContainer = this._titleContainer.current!; this.movePanX(this._visibleStart - e.movementX); diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 4223ee099..3e63eec61 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -19,28 +19,6 @@ export class TimelineMenu extends React.Component { super(props); TimelineMenu.Instance = this; } - - @action - pointerDown = (e: React.PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - document.removeEventListener("pointerup", this.pointerUp); - document.addEventListener("pointerup", this.pointerUp); - document.removeEventListener("pointermove", this.pointerMove); - document.addEventListener("pointermove", this.pointerMove); - } - - @action - pointerMove = (e: PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - } - - @action - pointerUp = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.pointerMove); - document.removeEventListener("pointerup", this.pointerUp); - } @action openMenu = (x?:number, y?:number) => { @@ -52,16 +30,20 @@ export class TimelineMenu extends React.Component { @action closeMenu = () => { this._opacity = 0; + this._currentMenu = []; } addItem = (type: "input" | "button", title: string, event: (e:any) => void) => { if (type === "input"){ let ref = React.createRef(); - let text = ""; - return
    {text = e.target.value;}} onKeyDown={(e:React.KeyboardEvent) => { - if(e.keyCode === 13){ - event(text); - }}}/>
    ; + return
    { + let text = e.target.value; + document.addEventListener("keypress", (e:KeyboardEvent) => { + if (e.keyCode === 13) { + event(text); + } + }); + }}/>
    ; } else if (type === "button") { let ref = React.createRef(); return

    {title}

    ; @@ -72,7 +54,8 @@ export class TimelineMenu extends React.Component { @action addMenu = (title:string, items: JSX.Element[]) => { items.unshift(

    {title}

    ); - this._currentMenu = items; + this._currentMenu = items; + } render() { -- cgit v1.2.3-70-g09d2 From 02f5eed127280a6827ed57e86663291ce184495b Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Thu, 15 Aug 2019 17:05:53 -0400 Subject: Timeline visibility --- src/client/views/animationtimeline/Timeline.tsx | 46 ++++++++++++++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +-- src/client/views/nodes/DocumentView.tsx | 1 - 3 files changed, 36 insertions(+), 17 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 10034263c..be1ae1773 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -4,15 +4,18 @@ import { CollectionSubView } from "../collections/CollectionSubView"; import { Document, listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction } from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, observe } from "mobx"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle } from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; +import { playcustomapp } from "googleapis/build/src/apis/playcustomapp"; +import { FieldView, FieldViewProps } from "../nodes/FieldView"; + export interface FlyoutProps { @@ -25,7 +28,7 @@ export interface FlyoutProps { @observer -export class Timeline extends CollectionSubView(Document) { +export class Timeline extends React.Component { private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; private readonly DEFAULT_TICK_SPACING: number = 50; @@ -56,6 +59,7 @@ export class Timeline extends CollectionSubView(Document) { @observable private _time = 100000; //DEFAULT @observable private _ticks: number[] = []; @observable private _playButton = faPlayCircle; + @observable private _timelineVisible = false; @computed private get children(): List { @@ -74,6 +78,7 @@ export class Timeline extends CollectionSubView(Document) { componentWillMount() { this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; + document.addEventListener("contextmenu", (e) => {this.timelineContextMenu(e);}); console.log(this._currentBarX); } @@ -86,7 +91,12 @@ export class Timeline extends CollectionSubView(Document) { reaction(() => { return NumCast(this.props.Document.curPage); }, curPage => { - this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); + if (!this._isPlaying) { + this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); + this.props.Document.curPage = this._currentBarX; + this.play(); + } + }); } } @@ -123,6 +133,10 @@ export class Timeline extends CollectionSubView(Document) { onPlay = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); + this.play(); + } + + play = () => { if (this._isPlaying) { this._isPlaying = false; this._playButton = faPlayCircle; @@ -143,6 +157,8 @@ export class Timeline extends CollectionSubView(Document) { } } + + @action windForward = (e: React.MouseEvent) => { e.preventDefault(); @@ -326,7 +342,7 @@ export class Timeline extends CollectionSubView(Document) { } } - timelineContextMenu = (e: React.MouseEvent): void => { + timelineContextMenu = (e:MouseEvent): void => { let subitems: ContextMenuProps[] = []; let timelineContainer = this._timelineWrapper.current!; subitems.push({ @@ -340,13 +356,17 @@ export class Timeline extends CollectionSubView(Document) { }); subitems.push({ description: this._isFrozen ? "Unfreeze Timeline" : "Freeze Timeline", event: action(() => { - if (this._isFrozen) { - this._isFrozen = false; - } else { - this._isFrozen = true; - } + this._isFrozen = !this._isFrozen; }), icon: "thumbtack" }); + subitems.push({ + description: this._timelineVisible ? "Hide Timeline" : "Show Timeline", event: action(() => { + this._timelineVisible = !this._timelineVisible; + }), icon: this._timelineVisible ? faEyeSlash : "eye" + }); + subitems.push({ description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => { + BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true;} + , icon:BoolCast(this.props.Document.isAnimating) ? "play" : "edit"}); ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems, icon: faClock }); } @@ -364,10 +384,10 @@ export class Timeline extends CollectionSubView(Document) { } render() { return ( -
    -
    +
    +
    -
    +
    {this.timelineToolBox(0.5)}
    diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d01e5cadc..d10150f30 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -742,7 +742,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } let docviews = docs.filter(doc => doc instanceof Doc).reduce((prev, doc) => { var page = NumCast(doc.page, -1); - if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { + // if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { let minim = BoolCast(doc.isMinimized); if (minim === undefined || !minim) { const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : @@ -755,7 +755,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { bounds: (pos.x !== undefined && pos.y !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } : undefined }); } - } + // } return prev; }, elements); @@ -902,7 +902,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { - + {this.overlayChildViews()}
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 28af39fb3..8d33c4570 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -570,7 +570,6 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); - cm.addItem({ description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => {BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true;}, icon:BoolCast(this.props.Document.isAnimating) ? "play" : "edit"}); let existingMake = ContextMenu.Instance.findByDescription("Make..."); let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : []; makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); -- cgit v1.2.3-70-g09d2 From 078abf5548a18945527f12dde1a79095bd30e50e Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Fri, 16 Aug 2019 00:08:45 -0400 Subject: partially working zoom --- src/client/views/animationtimeline/Timeline.tsx | 61 +++++++++++++++------- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 ++-- src/client/views/nodes/VideoBox.tsx | 2 + 3 files changed, 49 insertions(+), 23 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index be1ae1773..d0f83676b 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -60,6 +60,9 @@ export class Timeline extends React.Component { @observable private _ticks: number[] = []; @observable private _playButton = faPlayCircle; @observable private _timelineVisible = false; + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; + @computed private get children(): List { @@ -78,8 +81,6 @@ export class Timeline extends React.Component { componentWillMount() { this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; - document.addEventListener("contextmenu", (e) => {this.timelineContextMenu(e);}); - console.log(this._currentBarX); } componentDidMount() { @@ -92,7 +93,7 @@ export class Timeline extends React.Component { return NumCast(this.props.Document.curPage); }, curPage => { if (!this._isPlaying) { - this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); + this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); this.props.Document.curPage = this._currentBarX; this.play(); } @@ -107,21 +108,17 @@ export class Timeline extends React.Component { this._ticks = []; for (let i = 0; i < this._time;) { this._ticks.push(i); - i += this._tickIncrement; + i += 1000; } - let trackbox = this._trackbox.current!; - this._totalLength = this._tickSpacing * this._ticks.length; - trackbox.style.width = `${this._totalLength}`; - this._scrubberbox.current!.style.width = `${this._totalLength}`; + this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); }, {fireImmediately:true}); + this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; - this._visibleStart = this._infoContainer.current!.scrollLeft; + this._visibleStart = this._infoContainer.current!.scrollLeft; }); - } - - + } @action changeCurrentBarX = (pixel: number) => { @@ -136,6 +133,7 @@ export class Timeline extends React.Component { this.play(); } + @action play = () => { if (this._isPlaying) { this._isPlaying = false; @@ -209,8 +207,6 @@ export class Timeline extends React.Component { - @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; @action onPanDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -370,6 +366,35 @@ export class Timeline extends React.Component { ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems, icon: faClock }); } + @action + onWheelZoom = (e: React.WheelEvent) => { + e.preventDefault(); + e.stopPropagation(); + e.deltaY < 0 ? this.zoom(true) : this.zoom(false); + } + + @action + zoom = (dir: boolean) => { + if (dir){ + if (!(this._tickSpacing === 100 && this._tickIncrement === 1000)){ + if (this._tickSpacing >= 100) { + this._tickIncrement /= 2; + this._tickSpacing = 50; + this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); //CONSIDER THIS MUST CHANGE + } else { + this._tickSpacing += 10; + } + } + } else { + if (this._tickSpacing <= 50) { + this._tickSpacing = 100; + this._tickIncrement *= 2; + this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); //CONSIDER THIS MUST CHANGE + } else { + this._tickSpacing -= 10; + } + } + } private timelineToolBox = (scale:number) => { let size = 50 * scale; //50 is default @@ -389,16 +414,16 @@ export class Timeline extends React.Component {
    {this.timelineToolBox(0.5)} -
    -
    +
    +
    {this._ticks.map(element => { - return

    {this.toReadTime(element)}

    ; + if(element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; })}
    -
    +
    {DocListCast(this.children).map(doc => )}
    diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d10150f30..b932db424 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -194,6 +194,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _lastY: number = 0; private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } + private _timelineRef = React.createRef(); private inkKey = "ink"; constructor(props: any) { @@ -842,6 +843,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; analyzers.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" }); + this._timelineRef.current!.timelineContextMenu(e.nativeEvent); } @@ -879,10 +881,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined); addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); }; - } - private _timeline = ; - se = () => { - } + } render() { const easing = () => this.props.Document.panTransformType === "Ease"; Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); @@ -902,7 +901,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { - + {this.overlayChildViews()}
    diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 704030d85..a33155fff 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -166,6 +166,8 @@ export class VideoBox extends DocComponent(VideoD this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect; } } + + this.player && (this.player.style.transform = ""); } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 8ab017ac1928db4a9a9f8eb6b579245814cde725 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Fri, 16 Aug 2019 17:26:43 -0400 Subject: zooming fixes --- src/client/views/animationtimeline/Keyframe.tsx | 169 +++++++++++++----------- src/client/views/animationtimeline/Timeline.tsx | 35 ++--- src/client/views/animationtimeline/Track.tsx | 49 +++++-- 3 files changed, 139 insertions(+), 114 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 4e58b07d8..b02d89bf0 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -82,16 +82,30 @@ export namespace KeyframeFunc { }; export const defaultKeyframe = () => { - let regiondata = new Doc(); //creating regiondata - regiondata.duration = 200; + let regiondata = new Doc(); //creating regiondata in MILI + regiondata.duration = 4000; regiondata.position = 0; - regiondata.fadeIn = 20; - regiondata.fadeOut = 20; + regiondata.fadeIn = 1000; + regiondata.fadeOut = 1000; regiondata.functions = new List(); return regiondata; }; - + export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing:number, tickIncrement:number) => { + let 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; + } + }; } export const RegionDataSchema = createSchema({ @@ -109,6 +123,9 @@ interface IProps { node: Doc; RegionData: Doc; collection: Doc; + tickSpacing: number; + tickIncrement: number; + time: number; changeCurrentBarX: (x: number) => void; transform: Transform; } @@ -118,6 +135,8 @@ export class Keyframe extends React.Component { @observable private _bar = React.createRef(); @observable private _gain = 20; //default + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; @computed private get regiondata() { @@ -155,6 +174,7 @@ export class Keyframe extends React.Component { }); return last; } + @computed private get keyframes(){ return DocListCast(this.regiondata.keyframes); @@ -171,6 +191,26 @@ export class Keyframe extends React.Component { } } + @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); + } + async componentWillMount() { if (!this.regiondata.keyframes) { this.regiondata.keyframes = new List(); @@ -183,20 +223,6 @@ export class Keyframe extends React.Component { (fadeOut.key! as Doc).opacity = 1; (start.key! as Doc).opacity = 0.1; (finish.key! as Doc).opacity = 0.1; - - observe(this.regiondata, change => { - if (change.type === "update") { - fadeIn.time = this.regiondata.position + this.regiondata.fadeIn; - fadeOut.time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; - start.time = this.regiondata.position; - finish.time = this.regiondata.position + this.regiondata.duration; - this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(fadeIn)] = fadeIn; - this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(fadeOut)] = fadeOut; - this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(start)] = start; - this.regiondata.keyframes![this.regiondata.keyframes!.indexOf(finish)] = finish; - this.forceUpdate(); - } - }); } @action @@ -236,8 +262,7 @@ export class Keyframe extends React.Component { return TK; } - @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; + @action onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -247,14 +272,14 @@ export class Keyframe extends React.Component { this.createKeyframe(clientX); this._doubleClickEnabled = false; } else { - setTimeout(() => {if(!this._mouseToggled && this._doubleClickEnabled)this.props.changeCurrentBarX(this.regiondata.position + (clientX - this._bar.current!.getBoundingClientRect().left) * this.props.transform.Scale); + setTimeout(() => {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); this._doubleClickEnabled = true; document.addEventListener("pointermove", this.onBarPointerMove); document.addEventListener("pointerup", (e: PointerEvent) => { document.removeEventListener("pointermove", this.onBarPointerMove); - }); + }); } } @@ -269,23 +294,20 @@ export class Keyframe extends React.Component { let left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; let right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions!); let prevX = this.regiondata.position; - let futureX = this.regiondata.position + e.movementX; + let 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)) { this.regiondata.position = left.position + left.duration; - } else if ((right && right.position <= futureX + this.regiondata.duration)) { - this.regiondata.position = right.position - this.regiondata.duration; + } else if ((right && right.position <= futureX + this.pixelDuration)) { + this.regiondata.position = right.position - this.pixelDuration; } else { this.regiondata.position = futureX; - } - for (let i = 0; i < this.regiondata.keyframes!.length; i++) { - if ((this.regiondata.keyframes![i] as Doc).type !== KeyframeFunc.KeyframeType.fade) { - let movement = this.regiondata.position - prevX; - (this.regiondata.keyframes![i] as Doc).time = NumCast((this.regiondata.keyframes![i] as Doc).time) + movement; - } - } - this.forceUpdate(); + } + let movement = this.regiondata.position - prevX; + this.keyframes.forEach(kf => { + kf.time = NumCast(kf.time) + movement; + }); } @action @@ -313,11 +335,11 @@ export class Keyframe extends React.Component { e.preventDefault(); e.stopPropagation(); let bar = this._bar.current!; - let offset = Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); + let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions); let firstkf: (Doc | undefined) = this.firstKeyframe; if (firstkf && this.regiondata.position + this.regiondata.fadeIn + offset >= NumCast(firstkf!.time)) { - let dif = NumCast(firstkf!.time) - (this.regiondata.position + this.regiondata.fadeIn); + let dif = NumCast(firstkf!.time) - (this.pixelPosition + this.pixelFadeIn); this.regiondata.position = NumCast(firstkf!.time) - this.regiondata.fadeIn; this.regiondata.duration -= dif; } else if (this.regiondata.duration - offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // no keyframes, just fades @@ -331,6 +353,7 @@ export class Keyframe extends React.Component { this.regiondata.duration -= offset; this.regiondata.position += offset; } + } @@ -339,7 +362,7 @@ export class Keyframe extends React.Component { e.preventDefault(); e.stopPropagation(); let bar = this._bar.current!; - let offset = Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale); + let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); if (this.lastKeyframe! && this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= NumCast((this.lastKeyframe! as Doc).time)) { let dif = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - NumCast((this.lastKeyframe! as Doc).time); @@ -352,27 +375,18 @@ export class Keyframe extends React.Component { } else { this.regiondata.duration += offset; } - } - - createDivider = (type?: KeyframeFunc.Direction): JSX.Element => { - if (type === "left") { - return
    ; - } else if (type === "right") { - return
    ; - } - return
    ; + } @action createKeyframe = async (clientX:number) => { this._mouseToggled = true; let bar = this._bar.current!; - let offset = Math.round((clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale); + let 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 - let position = NumCast(this.regiondata.position); + let position = this.regiondata.position; await this.makeKeyData(Math.round(position + offset)); - console.log(this.regiondata.keyframes!.length); - this.props.changeCurrentBarX(NumCast(Math.round(position + offset))); //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 } } @@ -381,7 +395,7 @@ export class Keyframe extends React.Component { moveKeyframe = async (e: React.MouseEvent, kf: Doc) => { e.preventDefault(); e.stopPropagation(); - this.props.changeCurrentBarX(NumCast(kf.time!)); + this.props.changeCurrentBarX(KeyframeFunc.convertPixelTime(NumCast(kf.time!), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement)); } @@ -390,33 +404,38 @@ export class Keyframe extends React.Component { e.preventDefault(); e.stopPropagation(); this.props.node.backgroundColor = "#000000"; - } + + @action + makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { + let items = [ + TimelineMenu.Instance.addItem("button", "Show Data", () => { + runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); + }), + TimelineMenu.Instance.addItem("button", "Delete", () => {}), + TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}) + ]; + TimelineMenu.Instance.addMenu("Keyframe", items); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); +} @action private createKeyframeJSX = (kf: Doc, type = KeyframeFunc.KeyframeType.default) => { if (type === KeyframeFunc.KeyframeType.default) { return ( -
    - {this.createDivider()} +
    +
    { this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - let items = [ - TimelineMenu.Instance.addItem("button", "Show Data", () => { - runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); - CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); - }), - TimelineMenu.Instance.addItem("button", "Delete", () => {}), - TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}) - ]; - TimelineMenu.Instance.addMenu("Keyframe", items); - TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + this.makeKeyframeMenu(kf, e.nativeEvent); }}>
    -
    ); +
    + ); } return ( -
    - {this.createDivider()} +
    +
    ); } @@ -460,9 +479,6 @@ export class Keyframe extends React.Component { } - - - @action onReactionListen = (e: PointerEvent) => { e.preventDefault(); @@ -514,7 +530,6 @@ export class Keyframe extends React.Component { (Cast(this.regiondata.functions![index], Doc) as Doc).pathX = xPlots; (Cast(this.regiondata.functions![index], Doc) as Doc).pathY = yPlots; } - this._reac = undefined; this._interpolationKeyframe = undefined; this._plotList = undefined; @@ -525,19 +540,21 @@ export class Keyframe extends React.Component { render() { return (
    -
    - {this.regiondata.keyframes!.map(kf => { - return this.createKeyframeJSX(kf as Doc, (kf! as Doc).type as KeyframeFunc.KeyframeType); - })} + {this.keyframes.map(kf => { this.createKeyframeJSX(kf, kf.type as KeyframeFunc.KeyframeType); })} {this.keyframes.map( kf => { if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; let bodyRef = React.createRef(); + let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); return ( -
    { this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} onContextMenu={(e) => { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index d0f83676b..036c3ad9b 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -110,7 +110,7 @@ export class Timeline extends React.Component { this._ticks.push(i); i += 1000; } - this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); + this._totalLength = this._tickSpacing * (this._time/ this._tickIncrement); }, {fireImmediately:true}); this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; @@ -322,22 +322,6 @@ export class Timeline extends React.Component { } - convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time") => { - let time = dir === "pixel" ? pos / this._tickSpacing * this._tickIncrement : pos * this._tickSpacing / this._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; - } - } - timelineContextMenu = (e:MouseEvent): void => { let subitems: ContextMenuProps[] = []; let timelineContainer = this._timelineWrapper.current!; @@ -380,20 +364,21 @@ export class Timeline extends React.Component { if (this._tickSpacing >= 100) { this._tickIncrement /= 2; this._tickSpacing = 50; - this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); //CONSIDER THIS MUST CHANGE } else { this._tickSpacing += 10; } } } else { - if (this._tickSpacing <= 50) { - this._tickSpacing = 100; - this._tickIncrement *= 2; - this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); //CONSIDER THIS MUST CHANGE - } else { - this._tickSpacing -= 10; + if (this._totalLength >= this._infoContainer.current!.getBoundingClientRect().width){ + if (this._tickSpacing <= 50) { + this._tickSpacing = 100; + this._tickIncrement *= 2; + } else { + this._tickSpacing -= 10; + } } } + this._totalLength = this._tickSpacing * (this._time/ this._tickIncrement); } private timelineToolBox = (scale:number) => { @@ -424,7 +409,7 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index d91954022..5a43f5b2a 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -10,12 +10,17 @@ import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; import { RichTextField } from "../../../new_fields/RichTextField"; +import { createObjectBindingPattern } from "typescript"; +import { DateField } from "../../../new_fields/DateField"; interface IProps { node: Doc; currentBarX: number; transform: Transform; collection: Doc; + time: number; + tickIncrement: number; + tickSpacing: number; changeCurrentBarX: (x: number) => void; } @@ -44,7 +49,7 @@ export class Track extends React.Component { componentDidMount() { runInAction(() => { this._currentBarXReaction = this.currentBarXReaction(); - if (this.regions.length === 0) this.createRegion(this.props.currentBarX); + if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); this.props.node.hidden = false; }); } @@ -62,17 +67,33 @@ export class Track extends React.Component { let kf = keyframes[kfIndex] as Doc; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.props.currentBarX, kf); //right keyframe, if it exists + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); //right keyframe, if it exists + // while (leftkf !== undefined) { + // if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { + // let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); + // edge!.key = Doc.MakeCopy(kf.key as Doc, true); + // leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); + // (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; + // (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; + // } else if (leftkf!.key ) { + // leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); + // } + + // } + + + + if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.props.currentBarX, leftkf!); + let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; } if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,this.props.currentBarX, rightkf!); + let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), rightkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; @@ -88,10 +109,10 @@ export class Track extends React.Component { @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { - let regiondata: (Doc | undefined) = await this.findRegion(this.props.currentBarX); + let regiondata: (Doc | undefined) = await this.findRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); if (regiondata) { this.props.node.hidden = false; - await this.timeChange(this.props.currentBarX); + await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } else { this.props.node.hidden = true; this.props.node.opacity = 0; @@ -107,8 +128,8 @@ export class Track extends React.Component { } let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on if (regiondata) { - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.props.currentBarX); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.props.currentBarX); //right keyframe, if it exists + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); @@ -139,6 +160,8 @@ export class Track extends React.Component { this.props.node[key] = new RichTextField(nodeData); } } else if (key === "creationDate") { + + this.props.node[key] = new DateField(); } else { this.props.node[key] = kfNode[key]; } @@ -162,7 +185,7 @@ export class Track extends React.Component { let currentkf: (Doc | undefined) = undefined; let keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { - if (NumCast(kf.time) === Math.round(this.props.currentBarX)) currentkf = kf; + if (NumCast(kf.time) === Math.round(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement))) currentkf = kf; }); return currentkf; } @@ -173,7 +196,7 @@ export class Track extends React.Component { let leftNode = left.key as Doc; let rightNode = right.key as Doc; const dif_time = NumCast(right.time) - NumCast(left.time); - const timeratio = (this.props.currentBarX - NumCast(left.time)) / dif_time; //linear + const timeratio = (KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement) - NumCast(left.time)) / dif_time; //linear let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; let indexLeft = keyframes.indexOf(left); let interY:List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; @@ -251,7 +274,7 @@ export class Track extends React.Component { onInnerDoubleClick = (e: React.MouseEvent) => { let inner = this._inner.current!; let offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale); - this.createRegion(offsetX); + this.createRegion(KeyframeFunc.convertPixelTime(offsetX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } createRegion = (position: number) => { @@ -275,7 +298,7 @@ export class Track extends React.Component {
    {DocListCast(this.regions).map((region) => { - return ; + return ; })}
    -- cgit v1.2.3-70-g09d2 From 1b7e8873ead3cc15349bd4c9e669f3b1edcbbc2b Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Mon, 19 Aug 2019 00:25:14 -0400 Subject: updates --- src/client/views/MainView.tsx | 6 +-- src/client/views/animationtimeline/Keyframe.tsx | 59 ++++++++++++---------- src/client/views/animationtimeline/Timeline.tsx | 51 +++++++++++-------- .../views/animationtimeline/TimelineMenu.tsx | 20 ++++---- src/client/views/animationtimeline/Track.tsx | 40 ++++----------- 5 files changed, 87 insertions(+), 89 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index d5482bc12..126760234 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -206,9 +206,9 @@ export class MainView extends React.Component { if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.closeMenu(); } - // if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-container") === -1) { - // TimelineMenu.Instance.closeMenu(); - // } + if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-desc") === -1 || targets[0].className.toString().indexOf("timeline-menu-item") === -1 || targets[0].className.toString().indexOf("timeline-menu-item") === -1 || targets[0].className.toString().indexOf("timeline-menu-input") === -1){ + TimelineMenu.Instance.closeMenu(); + } }); globalPointerUp = () => this.isPointerDown = false; diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index b02d89bf0..2f0a968b9 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -28,7 +28,7 @@ export namespace KeyframeFunc { let leftMost: (RegionData | undefined) = undefined; let rightMost: (RegionData | undefined) = undefined; DocListCast(regions).forEach(region => { - let neighbor = RegionData(region as Doc); + let neighbor = RegionData(region); if (currentRegion.position! > neighbor.position) { if (!leftMost || neighbor.position > leftMost.position) { leftMost = neighbor; @@ -230,7 +230,6 @@ export class Keyframe extends React.Component { let doclist = (await DocListCastAsync(this.regiondata.keyframes))!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { - TK = TK as Doc; if (TK.time === kfpos) existingkf = TK; }); if (existingkf) return existingkf; @@ -299,8 +298,8 @@ export class Keyframe extends React.Component { this.regiondata.position = 0; } else if ((left && left.position + left.duration >= futureX)) { this.regiondata.position = left.position + left.duration; - } else if ((right && right.position <= futureX + this.pixelDuration)) { - this.regiondata.position = right.position - this.pixelDuration; + } else if ((right && right.position <= futureX + this.regiondata.duration)) { + this.regiondata.position = right.position - this.regiondata.duration; } else { this.regiondata.position = futureX; } @@ -353,7 +352,8 @@ export class Keyframe extends React.Component { this.regiondata.duration -= offset; this.regiondata.position += offset; } - + this.keyframes[0].time = this.regiondata.position; + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } @@ -375,6 +375,8 @@ export class Keyframe extends React.Component { } 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; } @@ -408,24 +410,36 @@ export class Keyframe extends React.Component { @action makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { - let items = [ - TimelineMenu.Instance.addItem("button", "Show Data", () => { - runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + + TimelineMenu.Instance.addItem("button", "Show Data", () => { + runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); - }), - TimelineMenu.Instance.addItem("button", "Delete", () => {}), - TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}) - ]; - TimelineMenu.Instance.addMenu("Keyframe", items); + }), + TimelineMenu.Instance.addItem("button", "Delete", () => {}), + TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}); + + TimelineMenu.Instance.addMenu("Keyframe"); TimelineMenu.Instance.openMenu(e.clientX, e.clientY); -} + } + + @action + makeRegionMenu = (kf: Doc, e: MouseEvent) => { + TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), + TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), + TimelineMenu.Instance.addItem("input", "fadeIn", (val) => {this.regiondata.fadeIn = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "fadeOut", (val) => {this.regiondata.fadeOut = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "position", (val) => {this.regiondata.position = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", "duration", (val) => {this.regiondata.duration = parseInt(val, 10);}), + TimelineMenu.Instance.addMenu("Region"); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + } @action private createKeyframeJSX = (kf: Doc, type = KeyframeFunc.KeyframeType.default) => { if (type === KeyframeFunc.KeyframeType.default) { return (
    -
    { this.moveKeyframe(e, kf as Doc); }} onContextMenu={(e: React.MouseEvent) => { +
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); this.makeKeyframeMenu(kf, e.nativeEvent); @@ -546,7 +560,9 @@ export class Keyframe extends React.Component { onPointerDown={this.onBarPointerDown}>
    - {this.keyframes.map(kf => { this.createKeyframeJSX(kf, kf.type as KeyframeFunc.KeyframeType); })} + {this.keyframes.map(kf => { + return this.createKeyframeJSX(kf, kf.type as KeyframeFunc.KeyframeType); + })} {this.keyframes.map( kf => { if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; @@ -561,16 +577,7 @@ export class Keyframe extends React.Component { e.preventDefault(); e.stopPropagation(); this._mouseToggled = true; - let items = [ - TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), - TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), - TimelineMenu.Instance.addItem("input", "fadeIn", (val) => {this.regiondata.fadeIn = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "fadeOut", (val) => {this.regiondata.fadeOut = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "position", (val) => {this.regiondata.position = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "duration", (val) => {this.regiondata.duration = parseInt(val, 10);}), - ]; - TimelineMenu.Instance.addMenu("Region", items); - TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + this.makeRegionMenu(kf, e.nativeEvent); }}>
    ); diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 036c3ad9b..4eb5958b5 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import "./Timeline.scss"; -import { CollectionSubView } from "../collections/CollectionSubView"; -import { Document, listSpec } from "../../../new_fields/Schema"; +import { listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; import { observable, reaction, action, IReactionDisposer, computed, runInAction, observe } from "mobx"; @@ -13,8 +12,8 @@ import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDow import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; -import { playcustomapp } from "googleapis/build/src/apis/playcustomapp"; -import { FieldView, FieldViewProps } from "../nodes/FieldView"; +import { FieldViewProps } from "../nodes/FieldView"; +import { KeyframeFunc } from "./Keyframe"; @@ -62,6 +61,8 @@ export class Timeline extends React.Component { @observable private _timelineVisible = false; @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; + @observable private _mutationDisposer:MutationObserver[] = []; + @observable private _reactionDisposer:IReactionDisposer[] = []; @computed @@ -89,7 +90,7 @@ export class Timeline extends React.Component { console.log(this.props.Document.duration); if (this.props.Document.duration) { this._time = Math.round(NumCast(this.props.Document.duration)) * 1000; - reaction(() => { + this._reactionDisposer.push(reaction(() => { return NumCast(this.props.Document.curPage); }, curPage => { if (!this._isPlaying) { @@ -97,12 +98,11 @@ export class Timeline extends React.Component { this.props.Document.curPage = this._currentBarX; this.play(); } - - }); + })); } } runInAction(() => { - reaction(() => { + this._reactionDisposer.push(reaction(() => { return this._time; }, () => { this._ticks = []; @@ -111,7 +111,7 @@ export class Timeline extends React.Component { i += 1000; } this._totalLength = this._tickSpacing * (this._time/ this._tickIncrement); - }, {fireImmediately:true}); + }, {fireImmediately:true})); this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; this._visibleStart = this._infoContainer.current!.scrollLeft; @@ -321,7 +321,6 @@ export class Timeline extends React.Component { return `${min}:${sec}`; } - timelineContextMenu = (e:MouseEvent): void => { let subitems: ContextMenuProps[] = []; let timelineContainer = this._timelineWrapper.current!; @@ -354,31 +353,41 @@ export class Timeline extends React.Component { onWheelZoom = (e: React.WheelEvent) => { e.preventDefault(); e.stopPropagation(); + let offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; + let prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); e.deltaY < 0 ? this.zoom(true) : this.zoom(false); + let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this._infoContainer.current!.scrollLeft = currPixel - offset; + this._visibleStart = currPixel - offset; } @action zoom = (dir: boolean) => { + let spacingChange = this._tickSpacing; + let incrementChange = this._tickIncrement; if (dir){ if (!(this._tickSpacing === 100 && this._tickIncrement === 1000)){ if (this._tickSpacing >= 100) { - this._tickIncrement /= 2; - this._tickSpacing = 50; + incrementChange /= 2; + spacingChange = 50; } else { - this._tickSpacing += 10; + spacingChange += 5; } } } else { - if (this._totalLength >= this._infoContainer.current!.getBoundingClientRect().width){ - if (this._tickSpacing <= 50) { - this._tickSpacing = 100; - this._tickIncrement *= 2; - } else { - this._tickSpacing -= 10; - } + if (this._tickSpacing <= 50) { + spacingChange = 100; + incrementChange *= 2; + } else { + spacingChange -= 5; } } - this._totalLength = this._tickSpacing * (this._time/ this._tickIncrement); + let finalLength = spacingChange * (this._time / incrementChange); + if (finalLength >= this._infoContainer.current!.getBoundingClientRect().width){ + this._totalLength = finalLength; + this._tickSpacing = spacingChange; + this._tickIncrement = incrementChange; + } } private timelineToolBox = (scale:number) => { diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 3e63eec61..572b35b90 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -31,31 +31,31 @@ export class TimelineMenu extends React.Component { closeMenu = () => { this._opacity = 0; this._currentMenu = []; + this._x = -1000000; + this._y = -1000000; } + @action addItem = (type: "input" | "button", title: string, event: (e:any) => void) => { if (type === "input"){ - let ref = React.createRef(); - return
    { + let inputRef = React.createRef(); + this._currentMenu.push(
    { let text = e.target.value; document.addEventListener("keypress", (e:KeyboardEvent) => { if (e.keyCode === 13) { event(text); } }); - }}/>
    ; + }}/>
    ); } else if (type === "button") { - let ref = React.createRef(); - return

    {title}

    ; + let buttonRef = React.createRef(); + this._currentMenu.push(

    {title}

    ); } - return
    ; } @action - addMenu = (title:string, items: JSX.Element[]) => { - items.unshift(

    {title}

    ); - this._currentMenu = items; - + addMenu = (title:string) => { + this._currentMenu.unshift(

    {title}

    ); } render() { diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 5a43f5b2a..13fe55e80 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,16 +1,14 @@ import * as React from "react"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, observe, IObservableArray, computed, toJS, IObservableObject, runInAction, autorun } from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun } from "mobx"; import "./Track.scss"; import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; -import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; import { RichTextField } from "../../../new_fields/RichTextField"; -import { createObjectBindingPattern } from "typescript"; import { DateField } from "../../../new_fields/DateField"; interface IProps { @@ -68,23 +66,7 @@ export class Track extends React.Component { if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); //right keyframe, if it exists - // while (leftkf !== undefined) { - // if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { - // let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); - // edge!.key = Doc.MakeCopy(kf.key as Doc, true); - // leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); - // (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; - // (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; - // } else if (leftkf!.key ) { - // leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); - // } - - // } - - - - + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); //right keyframe, if it exists if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); @@ -160,7 +142,6 @@ export class Track extends React.Component { this.props.node[key] = new RichTextField(nodeData); } } else if (key === "creationDate") { - this.props.node[key] = new DateField(); } else { this.props.node[key] = kfNode[key]; @@ -175,9 +156,9 @@ export class Track extends React.Component { @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { - if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns") acc.push(key); + if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns" && key !== "creationDate") acc.push(key); return acc; - }, []) as string[]; + }, []); } @action @@ -280,15 +261,16 @@ export class Track extends React.Component { createRegion = (position: number) => { let regiondata = KeyframeFunc.defaultKeyframe(); regiondata.position = position; - let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, regiondata, this.regions); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); - if ((rightRegion && leftRegion && rightRegion.position - (leftRegion.position + leftRegion.duration) < NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut)) || (rightRegion && rightRegion.position - regiondata.position < NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { - return; - } else if (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut)) { + + if (rightRegion && rightRegion.position - regiondata.position <= 4000) { regiondata.duration = rightRegion.position - regiondata.position; + } + if(this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))){ + this.regions.push(regiondata); + return regiondata; } - this.regions.push(regiondata); - return regiondata; + } -- cgit v1.2.3-70-g09d2 From c7678db105f952e7562f1b573266fb295e13cf7b Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Fri, 6 Sep 2019 11:00:37 -0400 Subject: initial transfer commit --- src/client/views/animationtimeline/Track.tsx | 175 ++++++++++++++------------- 1 file changed, 90 insertions(+), 85 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 13fe55e80..8f0e2d1cc 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -10,15 +10,16 @@ import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { Transform } from "../../util/Transform"; import { RichTextField } from "../../../new_fields/RichTextField"; import { DateField } from "../../../new_fields/DateField"; +import { Copy } from "../../../new_fields/FieldSymbols"; interface IProps { node: Doc; currentBarX: number; transform: Transform; - collection: Doc; - time: number; - tickIncrement: number; - tickSpacing: number; + collection: Doc; + time: number; + tickIncrement: number; + tickSpacing: number; changeCurrentBarX: (x: number) => void; } @@ -26,11 +27,11 @@ interface IProps { export class Track extends React.Component { @observable private _inner = React.createRef(); @observable private _reactionDisposers: IReactionDisposer[] = []; - @observable private _currentBarXReaction: any; - @observable private _isOnKeyframe: boolean = false; - @observable private _onKeyframe: (Doc | undefined) = undefined; - @observable private _onRegionData : ( Doc | undefined) = undefined; - @observable private _leftCurrKeyframe: (Doc | undefined) = undefined; + @observable private _currentBarXReaction: any; + @observable private _isOnKeyframe: boolean = false; + @observable private _onKeyframe: (Doc | undefined) = undefined; + @observable private _onRegionData: (Doc | undefined) = undefined; + @observable private _leftCurrKeyframe: (Doc | undefined) = undefined; @computed private get regions() { @@ -59,36 +60,36 @@ export class Track extends React.Component { } @action - saveKeyframe = async (ref:Doc, regiondata:Doc) => { - let keyframes:List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); - let kfIndex:number = keyframes.indexOf(ref); - let kf = keyframes[kfIndex] as Doc; + saveKeyframe = async (ref: Doc, regiondata: Doc) => { + let keyframes: List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); + let kfIndex: number = keyframes.indexOf(ref); + let kf = keyframes[kfIndex] as Doc; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); //right keyframe, if it exists if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge:(Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; } if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge:(Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!,KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), rightkf!); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), rightkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; - } + } } - keyframes[kfIndex] = kf; - this._onKeyframe = undefined; - this._onRegionData = undefined; - this._isOnKeyframe = false; + keyframes[kfIndex] = kf; + this._onKeyframe = undefined; + this._onRegionData = undefined; + this._isOnKeyframe = false; } - - @action + + @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { let regiondata: (Doc | undefined) = await this.findRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); @@ -96,8 +97,8 @@ export class Track extends React.Component { this.props.node.hidden = false; await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } else { - this.props.node.hidden = true; - this.props.node.opacity = 0; + this.props.node.hidden = true; + this.props.node.opacity = 0; } }, { fireImmediately: true }); } @@ -105,8 +106,8 @@ export class Track extends React.Component { @action timeChange = async (time: number) => { - if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { - await this.saveKeyframe(this._onKeyframe, this._onRegionData); + if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { + await this.saveKeyframe(this._onKeyframe, this._onRegionData); } let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on if (regiondata) { @@ -115,10 +116,10 @@ export class Track extends React.Component { let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); - this._leftCurrKeyframe = currentkf; - this._isOnKeyframe = true; - this._onKeyframe = currentkf; - this._onRegionData = regiondata; + this._leftCurrKeyframe = currentkf; + this._isOnKeyframe = true; + this._onKeyframe = currentkf; + this._onRegionData = regiondata; } else if (leftkf && rightkf) { await this.interpolate(leftkf, rightkf, regiondata); } @@ -127,28 +128,32 @@ export class Track extends React.Component { @action private applyKeys = async (kf: Doc) => { - let kfNode = await Cast(kf.key, Doc) as Doc; - let docFromApply = kfNode; - console.log(Doc.allKeys(docFromApply)); - if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; + let kfNode = await Cast(kf.key, Doc) as Doc; + let docFromApply = kfNode; + console.log(Doc.allKeys(docFromApply)); + if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { console.log(key); if (!kfNode[key]) { - this.props.node[key] = undefined; + this.props.node[key] = undefined; } else { if (key === "data") { - if (this.props.node.type === "text"){ - let nodeData = (kfNode[key] as RichTextField).Data; - this.props.node[key] = new RichTextField(nodeData); + if (this.props.node.type === "text") { + let nodeData = (kfNode[key] as RichTextField).Data; + this.props.node[key] = new RichTextField(nodeData); } } else if (key === "creationDate") { - this.props.node[key] = new DateField(); - } else { - this.props.node[key] = kfNode[key]; + this.props.node[key] = new DateField(); + } else { + let stored = kfNode[key]; + if (stored instanceof DateField) { + stored = stored[Copy](); + } + this.props.node[key] = stored; } } - + }); } @@ -156,7 +161,7 @@ export class Track extends React.Component { @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { - if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns" && key !== "creationDate") acc.push(key); + if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns" && key !== "creationDate") acc.push(key); return acc; }, []); } @@ -164,57 +169,57 @@ export class Track extends React.Component { @action calcCurrent = async (region: Doc) => { let currentkf: (Doc | undefined) = undefined; - let keyframes = await DocListCastAsync(region.keyframes!); + let keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { if (NumCast(kf.time) === Math.round(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement))) currentkf = kf; }); return currentkf; } - + @action - interpolate = async (left: Doc, right: Doc, regiondata:Doc) => { + interpolate = async (left: Doc, right: Doc, regiondata: Doc) => { let leftNode = left.key as Doc; let rightNode = right.key as Doc; const dif_time = NumCast(right.time) - NumCast(left.time); const timeratio = (KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement) - NumCast(left.time)) / dif_time; //linear - let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; - let indexLeft = keyframes.indexOf(left); - let interY:List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; - let realIndex = (interY.length - 1) * timeratio; - let xIndex = Math.floor(realIndex); - let yValue = interY[xIndex]; - let secondYOffset:number = yValue; + let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; + let indexLeft = keyframes.indexOf(left); + let interY: List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; + let realIndex = (interY.length - 1) * timeratio; + let xIndex = Math.floor(realIndex); + let yValue = interY[xIndex]; + let secondYOffset: number = yValue; let minY = interY[0]; // for now let maxY = interY[interY.length - 1]; //for now if (interY.length !== 1) { - secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; - } - let finalRatio = secondYOffset / (maxY - minY); - let pathX:List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; - let pathY:List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; - let proposedX = 0; - let proposedY = 0; + secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; + } + let finalRatio = secondYOffset / (maxY - minY); + let pathX: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; + let pathY: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; + let proposedX = 0; + let proposedY = 0; if (pathX.length !== 0) { - let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); - let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); + let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); + let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); if (pathCorrespondingIndex >= pathX.length - 1) { - proposedX = pathX[pathX.length - 1]; - proposedY = pathY[pathY.length - 1]; - } else if (pathCorrespondingIndex < 0){ - proposedX = pathX[0]; - proposedY = pathY[0]; + proposedX = pathX[pathX.length - 1]; + proposedY = pathY[pathY.length - 1]; + } else if (pathCorrespondingIndex < 0) { + proposedX = pathX[0]; + proposedY = pathY[0]; } else { - proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); + proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); proposedY = pathY[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathY[pathCorrespondingIndex + 1] - pathY[pathCorrespondingIndex]); } - + } this.filterKeys(Doc.allKeys(leftNode)).forEach(key => { if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate - if ((key === "x" || key === "y") && pathX.length !== 0){ - if (key === "x") this.props.node[key] = proposedX; - if (key === "y") this.props.node[key] = proposedY; + if ((key === "x" || key === "y") && pathX.length !== 0) { + if (key === "x") this.props.node[key] = proposedX; + if (key === "y") this.props.node[key] = proposedY; } else { const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); const adjusted = diff * finalRatio; @@ -222,13 +227,13 @@ export class Track extends React.Component { } } else { if (key === "data") { - if (this.props.node.type === "text"){ - let nodeData = StrCast((leftNode[key] as RichTextField).Data); - let currentNodeData = StrCast((this.props.node[key] as RichTextField).Data); + if (this.props.node.type === "text") { + let nodeData = StrCast((leftNode[key] as RichTextField).Data); + let currentNodeData = StrCast((this.props.node[key] as RichTextField).Data); if (nodeData !== currentNodeData) { - this.props.node[key] = new RichTextField(nodeData); + this.props.node[key] = new RichTextField(nodeData); } - } + } } else if (key === "creationDate") { } else { @@ -239,9 +244,9 @@ export class Track extends React.Component { } @action - findRegion = async (time: number) => { - let foundRegion:(Doc | undefined) = undefined; - let regions = await DocListCastAsync(this.regions); + findRegion = async (time: number) => { + let foundRegion: (Doc | undefined) = undefined; + let regions = await DocListCastAsync(this.regions); regions!.forEach(region => { region = region as RegionData; if (time >= NumCast(region.position) && time <= (NumCast(region.position) + NumCast(region.duration))) { @@ -262,15 +267,15 @@ export class Track extends React.Component { let regiondata = KeyframeFunc.defaultKeyframe(); regiondata.position = position; let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); - + if (rightRegion && rightRegion.position - regiondata.position <= 4000) { regiondata.duration = rightRegion.position - regiondata.position; - } - if(this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))){ + } + if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { this.regions.push(regiondata); return regiondata; } - + } @@ -280,7 +285,7 @@ export class Track extends React.Component {
    {DocListCast(this.regions).map((region) => { - return ; + return ; })}
    -- cgit v1.2.3-70-g09d2 From 96551aa8ef23485f48f6090192f18451ff66b557 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 15 Sep 2019 17:01:13 -0400 Subject: changes --- src/client/views/animationtimeline/Keyframe.tsx | 48 +++++----- src/client/views/animationtimeline/Timeline.tsx | 10 +-- src/client/views/animationtimeline/Track.tsx | 100 ++++++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + 4 files changed, 88 insertions(+), 71 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 2f0a968b9..253515dfd 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -410,14 +410,17 @@ export class Keyframe extends React.Component { @action makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { - TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); }), - TimelineMenu.Instance.addItem("button", "Delete", () => {}), + TimelineMenu.Instance.addItem("button", "Delete", () => { + runInAction(() => { + console.log(this.keyframes.indexOf(kf)); + this.keyframes.splice(this.keyframes.indexOf(kf), 1); + }); + }), TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}); - TimelineMenu.Instance.addMenu("Keyframe"); TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } @@ -425,7 +428,8 @@ export class Keyframe extends React.Component { @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), - TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), + TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), + TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{this.regions.splice(this.regions.indexOf(this.regiondata), 1);}), TimelineMenu.Instance.addItem("input", "fadeIn", (val) => {this.regiondata.fadeIn = parseInt(val, 10);}), TimelineMenu.Instance.addItem("input", "fadeOut", (val) => {this.regiondata.fadeOut = parseInt(val, 10);}), TimelineMenu.Instance.addItem("input", "position", (val) => {this.regiondata.position = parseInt(val, 10);}), @@ -435,23 +439,7 @@ export class Keyframe extends React.Component { } @action private createKeyframeJSX = (kf: Doc, type = KeyframeFunc.KeyframeType.default) => { - if (type === KeyframeFunc.KeyframeType.default) { - return ( -
    -
    -
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.makeKeyframeMenu(kf, e.nativeEvent); - }}>
    -
    - ); - } - return ( -
    -
    -
    - ); + } onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { @@ -561,7 +549,23 @@ export class Keyframe extends React.Component {
    {this.keyframes.map(kf => { - return this.createKeyframeJSX(kf, kf.type as KeyframeFunc.KeyframeType); + if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { + return ( +
    +
    +
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.makeKeyframeMenu(kf, e.nativeEvent); + }}>
    +
    + ); + } + return ( +
    +
    +
    + ); })} {this.keyframes.map( kf => { if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 4eb5958b5..187c9396d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -3,7 +3,7 @@ import "./Timeline.scss"; import { listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, observe } from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, observe, toJS } from "mobx"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; @@ -61,14 +61,12 @@ export class Timeline extends React.Component { @observable private _timelineVisible = false; @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; - @observable private _mutationDisposer:MutationObserver[] = []; @observable private _reactionDisposer:IReactionDisposer[] = []; @computed private get children(): List { let extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); - if (extendedDocument) { if (this.props.Document.data_ext) { return Cast((Cast(this.props.Document.data_ext, Doc) as Doc).annotations, listSpec(Doc)) as List; @@ -86,7 +84,7 @@ export class Timeline extends React.Component { componentDidMount() { if (StrCast(this.props.Document.type) === "video") { - console.log("ran"); + console.log("video"); console.log(this.props.Document.duration); if (this.props.Document.duration) { this._time = Math.round(NumCast(this.props.Document.duration)) * 1000; @@ -358,7 +356,7 @@ export class Timeline extends React.Component { e.deltaY < 0 ? this.zoom(true) : this.zoom(false); let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); this._infoContainer.current!.scrollLeft = currPixel - offset; - this._visibleStart = currPixel - offset; + this._visibleStart = currPixel - offset; } @action @@ -418,7 +416,7 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 8f0e2d1cc..e99da6648 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -8,9 +8,8 @@ import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_field import { List } from "../../../new_fields/List"; import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { Transform } from "../../util/Transform"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { DateField } from "../../../new_fields/DateField"; import { Copy } from "../../../new_fields/FieldSymbols"; +import { ObjectField } from "../../../new_fields/ObjectField"; interface IProps { node: Doc; @@ -20,19 +19,20 @@ interface IProps { time: number; tickIncrement: number; tickSpacing: number; + timelineVisible: boolean; changeCurrentBarX: (x: number) => void; } @observer export class Track extends React.Component { @observable private _inner = React.createRef(); - @observable private _reactionDisposers: IReactionDisposer[] = []; @observable private _currentBarXReaction: any; + @observable private _timelineVisibleReaction: any; @observable private _isOnKeyframe: boolean = false; @observable private _onKeyframe: (Doc | undefined) = undefined; @observable private _onRegionData: (Doc | undefined) = undefined; - @observable private _leftCurrKeyframe: (Doc | undefined) = undefined; - + @observable private _storedState: (Doc | undefined) = undefined; + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; @@ -40,22 +40,31 @@ export class Track extends React.Component { componentWillMount() { if (!this.props.node.regions) { - this.props.node.regions = new List(); + this.props.node.regions = new List(); } - this.props.node.opacity = 1; + + } componentDidMount() { - runInAction(() => { + runInAction(async () => { + this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); - this.props.node.hidden = false; + this.props.node.hidden = false; + this.props.node.opacity = 1; + let state = new Doc(); + state.key = Doc.MakeCopy(await this.props.node, true); + console.log(this.props.node.x); + this._storedState = state; }); + } componentWillUnmount() { runInAction(() => { if (this._currentBarXReaction) this._currentBarXReaction(); + if (this._timelineVisibleReaction) this._timelineVisibleReaction(); }); } @@ -89,6 +98,15 @@ export class Track extends React.Component { this._isOnKeyframe = false; } + @action + revertState = () => { + let copyDoc = Doc.MakeCopy(this.props.node, true); + this.applyKeys(this._storedState!); + let newState = new Doc(); + newState.key = copyDoc; + this._storedState = newState; + } + @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { @@ -100,9 +118,16 @@ export class Track extends React.Component { this.props.node.hidden = true; this.props.node.opacity = 0; } - }, { fireImmediately: true }); + }); + } + @action + timelineVisibleReaction = () => { + return reaction(() => { + return this.props.timelineVisible; + }, isVisible => { + this.revertState(); + }); } - @action timeChange = async (time: number) => { @@ -116,7 +141,6 @@ export class Track extends React.Component { let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); - this._leftCurrKeyframe = currentkf; this._isOnKeyframe = true; this._onKeyframe = currentkf; this._onRegionData = regiondata; @@ -129,39 +153,38 @@ export class Track extends React.Component { @action private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; - let docFromApply = kfNode; - console.log(Doc.allKeys(docFromApply)); + let docFromApply = kfNode; if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { - console.log(key); if (!kfNode[key]) { this.props.node[key] = undefined; } else { - if (key === "data") { - if (this.props.node.type === "text") { - let nodeData = (kfNode[key] as RichTextField).Data; - this.props.node[key] = new RichTextField(nodeData); - } - } else if (key === "creationDate") { - this.props.node[key] = new DateField(); + let stored = kfNode[key]; + if(stored instanceof ObjectField){ + this.props.node[key] = stored[Copy](); } else { - let stored = kfNode[key]; - if (stored instanceof DateField) { - stored = stored[Copy](); - } - this.props.node[key] = stored; + this.props.node[key] = stored; } - } - }); } + private filterList = [ + "regions", + "cursors", + "hidden", + "nativeHeight", + "nativeWidth", + "schemaColumns", + "baseLayout", + "backgroundLayout", + "layout", + ]; @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { - if (key !== "regions" && key !== "cursors" && key !== "hidden" && key !== "nativeHeight" && key !== "nativeWidth" && key !== "schemaColumns" && key !== "creationDate") acc.push(key); + if (!this.filterList.includes(key)) acc.push(key); return acc; }, []); } @@ -226,18 +249,11 @@ export class Track extends React.Component { this.props.node[key] = NumCast(leftNode[key]) + adjusted; } } else { - if (key === "data") { - if (this.props.node.type === "text") { - let nodeData = StrCast((leftNode[key] as RichTextField).Data); - let currentNodeData = StrCast((this.props.node[key] as RichTextField).Data); - if (nodeData !== currentNodeData) { - this.props.node[key] = new RichTextField(nodeData); - } - } - } else if (key === "creationDate") { - + let stored = leftNode[key]; + if(stored instanceof ObjectField){ + this.props.node[key] = stored[Copy](); } else { - this.props.node[key] = leftNode[key]; + this.props.node[key] = stored; } } }); @@ -277,8 +293,6 @@ export class Track extends React.Component { } } - - render() { return (
    diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d9fc388cd..67d700f1a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -912,6 +912,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (this.childDocs.some(d => BoolCast(d.isTemplate))) { layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" }); } + this._timelineRef.current!.timelineContextMenu(e.nativeEvent); layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); layoutItems.push({ -- cgit v1.2.3-70-g09d2 From 53c4f6ddad5534101d7a7482332cddb02ba99c21 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 17 Sep 2019 18:01:36 -0400 Subject: zoom, contextmenu fix --- src/client/views/MainView.tsx | 3 +-- src/client/views/animationtimeline/Timeline.tsx | 7 +++++-- src/client/views/animationtimeline/TimelineMenu.tsx | 6 +++++- src/client/views/animationtimeline/Track.tsx | 6 +----- src/new_fields/Doc.ts | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 6331763f1..139ac11db 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -206,8 +206,7 @@ export class MainView extends React.Component { if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.closeMenu(); } - console.log(targets.toString()); - if (targets && targets.length && targets[0].className.toString().indexOf("timeline-menu-desc") === -1 || targets[0].className.toString().indexOf("timeline-menu-item") === -1 || targets[0].className.toString().indexOf("timeline-menu-item") === -1 || targets[0].className.toString().indexOf("timeline-menu-input") === -1){ + if (targets && (targets.length && targets[0].className.toString() !== "timeline-menu-desc" && targets[0].className.toString() !== "timeline-menu-item" && targets[0].className.toString() !=="timeline-menu-input")){ TimelineMenu.Instance.closeMenu(); } }); diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 187c9396d..c50ffa51b 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -352,11 +352,14 @@ export class Timeline extends React.Component { e.preventDefault(); e.stopPropagation(); let offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; - let prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); + let prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); + let prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX,"mili", "time", this._tickSpacing, this._tickIncrement); e.deltaY < 0 ? this.zoom(true) : this.zoom(false); let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + let currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); this._infoContainer.current!.scrollLeft = currPixel - offset; - this._visibleStart = currPixel - offset; + this._visibleStart = currPixel - offset; + this.changeCurrentBarX(currCurrent); } @action diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 572b35b90..1fd97c6c1 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -44,12 +44,16 @@ export class TimelineMenu extends React.Component { document.addEventListener("keypress", (e:KeyboardEvent) => { if (e.keyCode === 13) { event(text); + this.closeMenu(); } }); }}/>
    ); } else if (type === "button") { let buttonRef = React.createRef(); - this._currentMenu.push(

    {title}

    ); + this._currentMenu.push(

    { + event(e); + this.closeMenu(); + }}>{title}

    ); } } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index e99da6648..89533c4df 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -53,10 +53,6 @@ export class Track extends React.Component { if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); this.props.node.hidden = false; this.props.node.opacity = 1; - let state = new Doc(); - state.key = Doc.MakeCopy(await this.props.node, true); - console.log(this.props.node.x); - this._storedState = state; }); } @@ -101,7 +97,7 @@ export class Track extends React.Component { @action revertState = () => { let copyDoc = Doc.MakeCopy(this.props.node, true); - this.applyKeys(this._storedState!); + if (this._storedState) this.applyKeys(this._storedState); let newState = new Doc(); newState.key = copyDoc; this._storedState = newState; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e3b5f78a7..01a064b69 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -334,7 +334,7 @@ export namespace Doc { } export function IndexOf(toFind: Doc, list: Doc[]) { - return list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)) + return list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); } export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { if (target[key] === undefined) { -- cgit v1.2.3-70-g09d2 From 4ae11ac54b25a5bfe935a934d3ce37084906ccdb Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 21 Sep 2019 16:55:18 -0400 Subject: changed boundaries --- src/client/views/animationtimeline/Keyframe.tsx | 36 ++++++++++++++++------ .../views/animationtimeline/TimelineMenu.scss | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 253515dfd..20fc8470d 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -412,7 +412,7 @@ export class Keyframe extends React.Component { makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); - CollectionDockingView.Instance.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); + CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); }), TimelineMenu.Instance.addItem("button", "Delete", () => { runInAction(() => { @@ -430,16 +430,34 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{this.regions.splice(this.regions.indexOf(this.regiondata), 1);}), - TimelineMenu.Instance.addItem("input", "fadeIn", (val) => {this.regiondata.fadeIn = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "fadeOut", (val) => {this.regiondata.fadeOut = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "position", (val) => {this.regiondata.position = parseInt(val, 10);}), - TimelineMenu.Instance.addItem("input", "duration", (val) => {this.regiondata.duration = parseInt(val, 10);}), + TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => {runInAction(() => { + this.regiondata.fadeIn = parseInt(val, 10); + });}), + TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => {runInAction(() => { + this.regiondata.fadeOut = parseInt(val, 10); + });}), + TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => {runInAction(() => { + if (this.checkInput(val)){ + DocListCast(this.regions).forEach(region => { + if (region !== this.regiondata){ + if (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration))){ + return undefined; + } + } + }); + this.regiondata.position = val; + } + this.regiondata.position = parseInt(val, 10); + });}), + TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => {runInAction(() => { + this.regiondata.duration = parseInt(val, 10); + });}), TimelineMenu.Instance.addMenu("Region"); TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } - @action - private createKeyframeJSX = (kf: Doc, type = KeyframeFunc.KeyframeType.default) => { - + + checkInput = (val: any) => { + return typeof(val === "number") } onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { @@ -544,7 +562,7 @@ export class Keyframe extends React.Component {
    diff --git a/src/client/views/animationtimeline/TimelineMenu.scss b/src/client/views/animationtimeline/TimelineMenu.scss index 90cc53b4c..7ee0a43d5 100644 --- a/src/client/views/animationtimeline/TimelineMenu.scss +++ b/src/client/views/animationtimeline/TimelineMenu.scss @@ -8,7 +8,7 @@ flex-direction: column; background: whitesmoke; z-index: 10000; - width: 150px; + width: 200px; padding-bottom: 10px; border-radius: 15px; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 9685f9bca..fcf483659 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -110,7 +110,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu
    Date: Sun, 22 Sep 2019 17:24:05 -0400 Subject: fixed zooming and context menu - stable --- src/client/views/animationtimeline/Keyframe.tsx | 121 ++++++++++++++++----- .../views/animationtimeline/TimelineMenu.tsx | 22 ++-- src/client/views/animationtimeline/Track.tsx | 1 + 3 files changed, 109 insertions(+), 35 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 20fc8470d..7197f4b49 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -416,48 +416,115 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("button", "Delete", () => { runInAction(() => { - console.log(this.keyframes.indexOf(kf)); - this.keyframes.splice(this.keyframes.indexOf(kf), 1); + (this.regiondata.keyframes as List).splice(this.keyframes.indexOf(kf), 1); }); }), - TimelineMenu.Instance.addItem("input", "Move", (val) => {kf.time = parseInt(val, 10);}); + TimelineMenu.Instance.addItem("input", "Move", (val) => { + runInAction(() => { + if (this.checkInput(val)){ + let cannotMove:boolean = false; + let 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); } @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { - TimelineMenu.Instance.addItem("button", "Add Ease", () => {this.onContainerDown(kf, "interpolate");}), - TimelineMenu.Instance.addItem("button", "Add Path", () => {this.onContainerDown(kf, "path");}), + TimelineMenu.Instance.addItem("button", "Add Ease", () => { + // this.onContainerDown(kf, "interpolate"); + }), + TimelineMenu.Instance.addItem("button", "Add Path", () => { + // this.onContainerDown(kf, "path"); + }), TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{this.regions.splice(this.regions.indexOf(this.regiondata), 1);}), - TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => {runInAction(() => { - this.regiondata.fadeIn = parseInt(val, 10); + TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)){ + let cannotMove:boolean = false; + if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position){ + cannotMove = true; + } + if (!cannotMove){ + this.regiondata.fadeIn = parseInt(val, 10); + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + } + } });}), - TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => {runInAction(() => { - this.regiondata.fadeOut = parseInt(val, 10); + TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)){ + let cannotMove:boolean = false; + if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)){ + cannotMove = true; + } + if (!cannotMove){ + this.regiondata.fadeOut = parseInt(val, 10); + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - val; + } + } });}), - TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => {runInAction(() => { - if (this.checkInput(val)){ + TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)){ + let prevPosition = this.regiondata.position; + let cannotMove:boolean = false; DocListCast(this.regions).forEach(region => { - if (region !== this.regiondata){ - if (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration))){ - return undefined; + if (NumCast(region.position) !== this.regiondata.position){ + if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))){ + cannotMove = true; } } }); - this.regiondata.position = val; + if (!cannotMove) { + this.regiondata.position = parseInt(val, 10); + this.updateKeyframes(this.regiondata.position - prevPosition ); + } } - this.regiondata.position = parseInt(val, 10); });}), - TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => {runInAction(() => { - this.regiondata.duration = parseInt(val, 10); + TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)){ + let cannotMove:boolean = false; + DocListCast(this.regions).forEach(region => { + if (NumCast(region.position) !== this.regiondata.position){ + val += this.regiondata.position; + if ((val < 0 ) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))){ + cannotMove = true; + } + } + }); + if (!cannotMove) { + this.regiondata.duration = parseInt(val, 10); + this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; + } + } });}), TimelineMenu.Instance.addMenu("Region"); TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } checkInput = (val: any) => { - return typeof(val === "number") + return typeof(val === "number"); + } + + @action + updateKeyframes = (incr:number, filter:number[] = []) => { + this.keyframes.forEach(kf => { + if (!filter.includes(this.keyframes.indexOf(kf))){ + kf.time = NumCast(kf.time) + incr; + } + }); } onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { @@ -495,8 +562,6 @@ export class Keyframe extends React.Component { listenerCreated = true; } }); - - } @action @@ -558,6 +623,7 @@ export class Keyframe extends React.Component { } } render() { + console.log("RERENDERING"); return (
    {
    ); } - return ( -
    -
    -
    - ); + else { + return ( +
    +
    +
    + ); + } + })} {this.keyframes.map( kf => { if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 1fd97c6c1..f3b985297 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -36,21 +36,25 @@ export class TimelineMenu extends React.Component { } @action - addItem = (type: "input" | "button", title: string, event: (e:any) => void) => { + addItem = (type: "input" | "button", title: string, event: (e:any, ...args:any[]) => void) => { if (type === "input"){ let inputRef = React.createRef(); - this._currentMenu.push(
    { - let text = e.target.value; - document.addEventListener("keypress", (e:KeyboardEvent) => { - if (e.keyCode === 13) { - event(text); - this.closeMenu(); - } - }); + let text = ""; + this._currentMenu.push(
    { + e.stopPropagation(); + text = e.target.value; + }} onKeyDown={(e) => { + if (e.keyCode === 13) { + event(text); + this.closeMenu(); + e.stopPropagation(); + } }}/>
    ); } else if (type === "button") { let buttonRef = React.createRef(); this._currentMenu.push(

    { + e.preventDefault(); + e.stopPropagation(); event(e); this.closeMenu(); }}>{title}

    ); diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 89533c4df..c68d9bb3a 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -69,6 +69,7 @@ export class Track extends React.Component { let keyframes: List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); let kfIndex: number = keyframes.indexOf(ref); let kf = keyframes[kfIndex] as Doc; + if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists -- cgit v1.2.3-70-g09d2 From bf8907cfc3e005f2ce6756820d9b3f9de35f1807 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 24 Sep 2019 16:50:23 -0400 Subject: brushing --- src/client/views/animationtimeline/Keyframe.tsx | 3 ++- src/client/views/animationtimeline/Timeline.tsx | 2 +- src/client/views/animationtimeline/Track.tsx | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 7197f4b49..9728c2462 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -532,6 +532,7 @@ export class Keyframe extends React.Component { e.stopPropagation(); let div = ref.current!; div.style.opacity = "1"; + Doc.BrushDoc(this.props.node); } onContainerOut = (e: React.PointerEvent, ref: React.RefObject) => { @@ -539,6 +540,7 @@ export class Keyframe extends React.Component { e.stopPropagation(); let div = ref.current!; div.style.opacity = "0"; + Doc.UnBrushDoc(this.props.node); } @@ -623,7 +625,6 @@ export class Keyframe extends React.Component { } } render() { - console.log("RERENDERING"); return (
    {
    - {DocListCast(this.children).map(doc =>

    {doc.title}

    )} + {DocListCast(this.children).map(doc =>
    {Doc.BrushDoc(doc);}} onPointerOut={() => {Doc.UnBrushDoc(doc);}}>

    {doc.title}

    )}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index c68d9bb3a..274b215d9 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -294,7 +294,7 @@ export class Track extends React.Component { return (
    -
    +
    {Doc.BrushDoc(this.props.node);}}onPointerOut={() => {Doc.UnBrushDoc(this.props.node);}}> {DocListCast(this.regions).map((region) => { return ; })} -- cgit v1.2.3-70-g09d2 From 8c018a7a686a752ef1b86b852ec2d298792aa354 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 28 Sep 2019 17:00:47 -0400 Subject: toggle --- src/client/views/animationtimeline/Keyframe.tsx | 100 ++++------------- src/client/views/animationtimeline/Timeline.scss | 20 ++++ src/client/views/animationtimeline/Timeline.tsx | 121 ++++++--------------- .../views/animationtimeline/TimelineMenu.tsx | 11 +- .../views/animationtimeline/TimelineOverview.tsx | 2 + src/client/views/animationtimeline/Track.tsx | 40 +++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- 7 files changed, 102 insertions(+), 195 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 9728c2462..66ad6a76d 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -8,7 +8,6 @@ import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; -import { FlyoutProps } from "./Timeline"; import { Transform } from "../../util/Transform"; import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; @@ -138,48 +137,13 @@ export class Keyframe extends React.Component { @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; - @computed - private get regiondata() { - let index = this.regions.indexOf(this.props.RegionData); - return RegionData(this.regions[index] as Doc); - } - - @computed - private get regions() { - return Cast(this.props.node.regions, listSpec(Doc)) as List; - } - - @computed - private get firstKeyframe() { - let first: (Doc | undefined) = undefined; - DocListCast(this.regiondata.keyframes!).forEach(kf => { - if (kf.type !== KeyframeFunc.KeyframeType.fade) { - if (!first || first && NumCast(kf.time) < NumCast(first.time)) { - first = kf; - } - } - }); - return first; - } - - @computed - private get lastKeyframe() { - let last: (Doc | undefined) = undefined; - DocListCast(this.regiondata.keyframes!).forEach(kf => { - if (kf.type !== KeyframeFunc.KeyframeType.fade) { - if (!last || last && NumCast(kf.time) > NumCast(last.time)) { - last = kf; - } - } - }); - return last; - } - - @computed - private get keyframes(){ - return DocListCast(this.regiondata.keyframes); - } - + @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc);} + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} + @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 inks() { if (this.props.collection.data_ext) { @@ -191,38 +155,18 @@ export class Keyframe extends React.Component { } } - @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); - } - - async componentWillMount() { - if (!this.regiondata.keyframes) { - this.regiondata.keyframes = new List(); - } - let fadeIn = await this.makeKeyData(this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade)!; - let fadeOut = await this.makeKeyData(this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade)!; - let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.fade)!; - let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; - (fadeIn.key! as Doc).opacity = 1; - (fadeOut.key! as Doc).opacity = 1; - (start.key! as Doc).opacity = 0.1; - (finish.key! as Doc).opacity = 0.1; + componentWillMount() { + runInAction(async () => { + if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); + let fadeIn = await this.makeKeyData(this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade)!; + let fadeOut = await this.makeKeyData(this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade)!; + let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.fade)!; + let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; + (fadeIn.key! as Doc).opacity = 1; + (fadeOut.key! as Doc).opacity = 1; + (start.key! as Doc).opacity = 0.1; + (finish.key! as Doc).opacity = 0.1; + }); } @action @@ -336,7 +280,7 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions); - let firstkf: (Doc | undefined) = this.firstKeyframe; + let firstkf: (Doc | undefined) = this.keyframes[0]; if (firstkf && this.regiondata.position + this.regiondata.fadeIn + offset >= NumCast(firstkf!.time)) { let dif = NumCast(firstkf!.time) - (this.pixelPosition + this.pixelFadeIn); this.regiondata.position = NumCast(firstkf!.time) - this.regiondata.fadeIn; @@ -364,8 +308,8 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); - if (this.lastKeyframe! && this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= NumCast((this.lastKeyframe! as Doc).time)) { - let dif = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - NumCast((this.lastKeyframe! as Doc).time); + if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= NumCast((this.keyframes[this.keyframes.length - 1]).time)) { + let dif = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - NumCast((this.keyframes[this.keyframes.length - 1]).time); this.regiondata.duration -= dif; } else if (this.regiondata.duration + offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // nokeyframes, just fades this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 1457d5a84..990bc681c 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -119,4 +119,24 @@ width: 100%; background-color: grey; } +} + +.round-toggle { + position: absolute; + height: 40px; + width: 80px; + background-color: white; + border: 2px solid purple; + border-radius: 20px; + input{ + opacity: 0; + height: 0; + width: 0; + } + .slider{ + height: 40px; + width: 40px; + background-color: black; + border-radius: 20px; + } } \ No newline at end of file diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 875a0b8f3..8f96315a0 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -15,17 +15,6 @@ import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; import { KeyframeFunc } from "./Keyframe"; - - -export interface FlyoutProps { - x?: number; - y?: number; - display?: string; - regiondata?: Doc; - regions?: List; -} - - @observer export class Timeline extends React.Component { @@ -35,26 +24,21 @@ export class Timeline extends React.Component { private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; - @observable private _isMinimized = false; - @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; - @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; - @observable private _scrubberbox = React.createRef(); - @observable private _scrubber = React.createRef(); @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); - @observable private _timelineWrapper = React.createRef(); @observable private _infoContainer = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing - @observable private _isFrozen: boolean = true; //timeline freeze @observable private _totalLength: number = 0; @observable private _visibleLength: number = 0; @observable private _visibleStart: number = 0; - @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; + @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; + @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; + @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; @observable private _time = 100000; //DEFAULT @observable private _ticks: number[] = []; @observable private _playButton = faPlayCircle; @@ -273,39 +257,7 @@ export class Timeline extends React.Component { } } - @action - onTimelineDown = (e: React.PointerEvent) => { - e.preventDefault(); - if (e.nativeEvent.which === 1 && !this._isFrozen) { - document.addEventListener("pointermove", this.onTimelineMove); - document.addEventListener("pointerup", () => { document.removeEventListener("pointermove", this.onTimelineMove); }); - } - } - @action - onTimelineMove = (e: PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - let timelineContainer = this._timelineWrapper.current!; - let left = parseFloat(timelineContainer.style.left!); - let top = parseFloat(timelineContainer.style.top!); - timelineContainer.style.left = `${left + e.movementX}px`; - timelineContainer.style.top = `${top + e.movementY}px`; - } - - @action - minimize = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - let timelineContainer = this._timelineContainer.current!; - if (this._isMinimized) { - this._isMinimized = false; - timelineContainer.style.visibility = "visible"; - } else { - this._isMinimized = true; - timelineContainer.style.visibility = "hidden"; - } - } @action toReadTime = (time: number): string => { @@ -321,21 +273,6 @@ export class Timeline extends React.Component { timelineContextMenu = (e:MouseEvent): void => { let subitems: ContextMenuProps[] = []; - let timelineContainer = this._timelineWrapper.current!; - subitems.push({ - description: "Pin to Top", event: action(() => { - if (!this._isFrozen) { - timelineContainer.style.left = "0px"; - timelineContainer.style.top = "0px"; - timelineContainer.style.transition = "none"; - } - }), icon: faArrowUp - }); - subitems.push({ - description: this._isFrozen ? "Unfreeze Timeline" : "Freeze Timeline", event: action(() => { - this._isFrozen = !this._isFrozen; - }), icon: "thumbtack" - }); subitems.push({ description: this._timelineVisible ? "Hide Timeline" : "Show Timeline", event: action(() => { this._timelineVisible = !this._timelineVisible; @@ -358,7 +295,8 @@ export class Timeline extends React.Component { let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); let currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); this._infoContainer.current!.scrollLeft = currPixel - offset; - this._visibleStart = currPixel - offset; + this._visibleStart = currPixel - offset > 0 ? currPixel - offset : 0; + this._visibleStart += this._visibleLength + this._visibleStart > this._totalLength ? this._totalLength - (this._visibleStart + this._visibleLength) :0; this.changeCurrentBarX(currCurrent); } @@ -402,35 +340,42 @@ export class Timeline extends React.Component {
    ); } + render() { return ( -
    -
    - -
    - {this.timelineToolBox(0.5)} -
    -
    - {this._ticks.map(element => { - if(element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; - })} +
    +
    +
    +
    + {this.timelineToolBox(0.5)} +
    +
    + {this._ticks.map(element => { + if(element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; + })} +
    +
    +
    +
    +
    + {DocListCast(this.children).map(doc => )} +
    -
    -
    +
    + {DocListCast(this.children).map(doc =>
    {Doc.BrushDoc(doc);}} onPointerOut={() => {Doc.UnBrushDoc(doc);}}>

    {doc.title}

    )}
    -
    - {DocListCast(this.children).map(doc => )} +
    +
    -
    - {DocListCast(this.children).map(doc =>
    {Doc.BrushDoc(doc);}} onPointerOut={() => {Doc.UnBrushDoc(doc);}}>

    {doc.title}

    )} -
    -
    - -
    + {BoolCast(this.props.Document.isAnimating) ?
    : this.timelineToolBox(1) }
    - {BoolCast(this.props.Document.isAnimating) ?
    : this.timelineToolBox(1) } + +
    ); } diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index f3b985297..59c25596e 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -4,6 +4,7 @@ import {observer} from "mobx-react"; import "./TimelineMenu.scss"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChartLine, faRoad, faClipboard, faPen, faTrash, faTable } from "@fortawesome/free-solid-svg-icons"; +import { Utils } from "../../../Utils"; @observer @@ -40,7 +41,7 @@ export class TimelineMenu extends React.Component { if (type === "input"){ let inputRef = React.createRef(); let text = ""; - this._currentMenu.push(
    { + this._currentMenu.push(
    { e.stopPropagation(); text = e.target.value; }} onKeyDown={(e) => { @@ -52,23 +53,23 @@ export class TimelineMenu extends React.Component { }}/>
    ); } else if (type === "button") { let buttonRef = React.createRef(); - this._currentMenu.push(

    { + this._currentMenu.push(

    { e.preventDefault(); e.stopPropagation(); event(e); this.closeMenu(); }}>{title}

    ); - } + } } @action addMenu = (title:string) => { - this._currentMenu.unshift(

    {title}

    ); + this._currentMenu.unshift(

    {title}

    ); } render() { return ( -
    +
    {this._currentMenu}
    ); diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 38b823cbc..a8f7faba8 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -78,6 +78,8 @@ export class TimelineOverview extends React.Component{ } render(){ + console.log("rendered"); + console.log(this.props.visibleStart); return(
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 274b215d9..3ec410216 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -32,18 +32,24 @@ export class Track extends React.Component { @observable private _onKeyframe: (Doc | undefined) = undefined; @observable private _onRegionData: (Doc | undefined) = undefined; @observable private _storedState: (Doc | undefined) = undefined; - - @computed - private get regions() { - return Cast(this.props.node.regions, listSpec(Doc)) as List; - } + @observable private filterList = [ + "regions", + "cursors", + "hidden", + "nativeHeight", + "nativeWidth", + "schemaColumns", + "baseLayout", + "backgroundLayout", + "layout", + ]; + + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} componentWillMount() { - if (!this.props.node.regions) { - this.props.node.regions = new List(); - } - - + runInAction(() => { + if (!this.props.node.regions) this.props.node.regions = new List(); + }); } componentDidMount() { @@ -54,11 +60,11 @@ export class Track extends React.Component { this.props.node.hidden = false; this.props.node.opacity = 1; }); - } componentWillUnmount() { runInAction(() => { + //disposing reactions if (this._currentBarXReaction) this._currentBarXReaction(); if (this._timelineVisibleReaction) this._timelineVisibleReaction(); }); @@ -166,17 +172,7 @@ export class Track extends React.Component { }); } - private filterList = [ - "regions", - "cursors", - "hidden", - "nativeHeight", - "nativeWidth", - "schemaColumns", - "baseLayout", - "backgroundLayout", - "layout", - ]; + @action private filterKeys = (keys: string[]): string[] => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index af2651dc8..bbfc5eb51 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -115,8 +115,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Tue, 1 Oct 2019 16:24:18 -0400 Subject: toggle button --- src/client/views/animationtimeline/Timeline.scss | 44 +++++++++++++++------ src/client/views/animationtimeline/Timeline.tsx | 45 ++++++++++++++++------ .../views/animationtimeline/TimelineOverview.tsx | 2 - 3 files changed, 65 insertions(+), 26 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 990bc681c..09fc593fc 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -1,11 +1,6 @@ @import "./../globalCssVariables.scss"; -.minimize{ - position:relative; - z-index: 1000; - height: 30px; - width: 100px; -} + .timeline-toolbox{ position:absolute; @@ -17,6 +12,8 @@ margin-left:10px; } } + + .timeline-container{ width:100%; height:300px; @@ -37,12 +34,10 @@ background-color: transparent; height: 30px; width:100%; - .tick{ height:100%; width: 1px; background-color:black; - } } .scrubber{ @@ -128,15 +123,40 @@ background-color: white; border: 2px solid purple; border-radius: 20px; + animation-fill-mode: forwards; + animation-duration: 500ms; input{ + position:absolute; opacity: 0; height: 0; width: 0; } - .slider{ - height: 40px; - width: 40px; - background-color: black; + .round-toggle-slider{ + position:absolute; + height: 35px; + width: 35px; + top: 0.5px; + background-color: white; + border:1px solid grey; border-radius: 20px; + transition: transform 500ms ease-in-out; + + } + +} +@keyframes turnon{ + from{ + background-color: white; + } + to{ + background-color: purple; + } +} +@keyframes turnoff{ + from{ + background-color: purple; + } + to{ + background-color: white; } } \ No newline at end of file diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 8f96315a0..8127e4de2 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -29,6 +29,8 @@ export class Timeline extends React.Component { @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); @observable private _infoContainer = React.createRef(); + @observable private _roundToggleRef = React.createRef(); + @observable private _roundToggleContainerRef = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @@ -331,23 +333,45 @@ export class Timeline extends React.Component { private timelineToolBox = (scale:number) => { let size = 50 * scale; //50 is default - return ( + return ( +
    -
    -
    -
    - +
    +
    +
    + +
    +
    +
    ); } + @action + private toggleChecked = (e:React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let roundToggle = this._roundToggleRef.current!; + let roundToggleContainer = this._roundToggleContainerRef.current!; + if (BoolCast(this.props.Document.isAnimating)){ + roundToggle.style.transform = "translate(0px, 0px)"; + roundToggle.style.animationName = "turnoff"; + roundToggleContainer.style.animationName = "turnoff"; + + this.props.Document.isAnimating = false; + } else { + roundToggle.style.transform = "translate(45px, 0px)"; + roundToggle.style.animationName = "turnon"; + roundToggleContainer.style.animationName = "turnon"; + this.props.Document.isAnimating = true; + } + } render() { return (
    - {this.timelineToolBox(0.5)}
    {this._ticks.map(element => { @@ -365,16 +389,13 @@ export class Timeline extends React.Component { {DocListCast(this.children).map(doc =>
    {Doc.BrushDoc(doc);}} onPointerOut={() => {Doc.UnBrushDoc(doc);}}>

    {doc.title}

    )}
    - +
    - {BoolCast(this.props.Document.isAnimating) ?
    : this.timelineToolBox(1) } + { this.timelineToolBox(1) }
    - +
    ); diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index a8f7faba8..38b823cbc 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -78,8 +78,6 @@ export class TimelineOverview extends React.Component{ } render(){ - console.log("rendered"); - console.log(this.props.visibleStart); return(
    -- cgit v1.2.3-70-g09d2 From 7ccce9564e11ede82bec01b9eea3889da4dc1bc2 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 1 Oct 2019 17:10:17 -0400 Subject: changes with toggling --- src/client/views/animationtimeline/Timeline.scss | 11 +++++------ src/client/views/animationtimeline/Timeline.tsx | 8 +++++--- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 09fc593fc..71fac876d 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -22,7 +22,7 @@ box-shadow: 0px 10px 20px; .info-container{ - margin-top: 50px; + margin-top: 80px; right:20px; position:absolute; height: calc(100% - 100px); @@ -72,7 +72,7 @@ } .title-container{ - margin-top: 80px; + margin-top: 110px; margin-left: 20px; height: calc(100% - 100px - 30px); width: 100px; @@ -117,7 +117,6 @@ } .round-toggle { - position: absolute; height: 40px; width: 80px; background-color: white; @@ -125,6 +124,7 @@ border-radius: 20px; animation-fill-mode: forwards; animation-duration: 500ms; + top: 20px; input{ position:absolute; opacity: 0; @@ -132,15 +132,14 @@ width: 0; } .round-toggle-slider{ - position:absolute; height: 35px; width: 35px; - top: 0.5px; background-color: white; border:1px solid grey; border-radius: 20px; transition: transform 500ms ease-in-out; - + margin-left: 0px; + margin-top: 0.5px; } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 8127e4de2..bc48f422a 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -18,7 +18,7 @@ import { KeyframeFunc } from "./Keyframe"; @observer export class Timeline extends React.Component { - private readonly DEFAULT_CONTAINER_HEIGHT: number = 300; + private readonly DEFAULT_CONTAINER_HEIGHT: number = 330; private readonly DEFAULT_TICK_SPACING: number = 50; private readonly MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; @@ -353,16 +353,18 @@ export class Timeline extends React.Component { e.stopPropagation(); let roundToggle = this._roundToggleRef.current!; let roundToggleContainer = this._roundToggleContainerRef.current!; + let timelineContainer = this._timelineContainer.current!; if (BoolCast(this.props.Document.isAnimating)){ roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; - + timelineContainer.style.transform = `translate(0px, ${this._containerHeight}px)`; this.props.Document.isAnimating = false; } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; + timelineContainer.style.transform = `translate(0px, ${-this._containerHeight}px)`; this.props.Document.isAnimating = true; } } @@ -371,7 +373,7 @@ export class Timeline extends React.Component {
    -
    +
    {this._ticks.map(element => { -- cgit v1.2.3-70-g09d2 From 3143c2775cdf7bdafa44f047ea9b6ebbd090b28e Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 5 Oct 2019 17:26:10 -0400 Subject: animation --- src/client/views/animationtimeline/Timeline.scss | 1 + src/client/views/animationtimeline/Timeline.tsx | 251 ++++++++++++----------- 2 files changed, 131 insertions(+), 121 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 71fac876d..fbdb2a200 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -20,6 +20,7 @@ position:absolute; background-color: $light-color-secondary; box-shadow: 0px 10px 20px; + transition: transform 500ms ease; .info-container{ margin-top: 80px; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index bc48f422a..8a41a5943 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -29,25 +29,25 @@ export class Timeline extends React.Component { @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); @observable private _infoContainer = React.createRef(); - @observable private _roundToggleRef = React.createRef(); - @observable private _roundToggleContainerRef = React.createRef(); + @observable private _roundToggleRef = React.createRef(); + @observable private _roundToggleContainerRef = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing @observable private _totalLength: number = 0; - @observable private _visibleLength: number = 0; - @observable private _visibleStart: number = 0; - @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; + @observable private _visibleLength: number = 0; + @observable private _visibleStart: number = 0; + @observable private _containerHeight: number = this.DEFAULT_CONTAINER_HEIGHT; @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; @observable private _time = 100000; //DEFAULT @observable private _ticks: number[] = []; - @observable private _playButton = faPlayCircle; - @observable private _timelineVisible = false; - @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; - @observable private _reactionDisposer:IReactionDisposer[] = []; + @observable private _playButton = faPlayCircle; + @observable private _timelineVisible = false; + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; + @observable private _reactionDisposer: IReactionDisposer[] = []; @computed @@ -65,7 +65,7 @@ export class Timeline extends React.Component { componentWillMount() { - this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; + this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; } componentDidMount() { @@ -78,29 +78,29 @@ export class Timeline extends React.Component { return NumCast(this.props.Document.curPage); }, curPage => { if (!this._isPlaying) { - this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); - this.props.Document.curPage = this._currentBarX; - this.play(); + this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); + this.props.Document.curPage = this._currentBarX; + this.play(); } })); } } runInAction(() => { this._reactionDisposer.push(reaction(() => { - return this._time; + return this._time; }, () => { this._ticks = []; for (let i = 0; i < this._time;) { this._ticks.push(i); i += 1000; } - this._totalLength = this._tickSpacing * (this._time/ this._tickIncrement); - }, {fireImmediately:true})); - this._totalLength = this._tickSpacing * (this._ticks.length/ this._tickIncrement); - this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; - this._visibleStart = this._infoContainer.current!.scrollLeft; + this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); + }, { fireImmediately: true })); + this._totalLength = this._tickSpacing * (this._ticks.length / this._tickIncrement); + this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; + this._visibleStart = this._infoContainer.current!.scrollLeft; }); - + } @@ -112,30 +112,30 @@ export class Timeline extends React.Component { //for playing @action onPlay = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.play(); + e.preventDefault(); + e.stopPropagation(); + this.play(); } @action play = () => { if (this._isPlaying) { this._isPlaying = false; - this._playButton = faPlayCircle; + this._playButton = faPlayCircle; } else { this._isPlaying = true; - this._playButton = faPauseCircle; + this._playButton = faPauseCircle; const playTimeline = () => { - if (this._isPlaying){ + if (this._isPlaying) { if (this._currentBarX >= this._totalLength) { - this.changeCurrentBarX(0); + this.changeCurrentBarX(0); } else { this.changeCurrentBarX(this._currentBarX + this._windSpeed); - } - setTimeout(playTimeline, 15); + } + setTimeout(playTimeline, 15); } - }; - playTimeline(); + }; + playTimeline(); } } @@ -143,8 +143,8 @@ export class Timeline extends React.Component { @action windForward = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); + e.preventDefault(); + e.stopPropagation(); if (this._windSpeed < 64) { //max speed is 32 this._windSpeed = this._windSpeed * 2; } @@ -152,8 +152,8 @@ export class Timeline extends React.Component { @action windBackward = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); + e.preventDefault(); + e.stopPropagation(); if (this._windSpeed > 1 / 16) { // min speed is 1/8 this._windSpeed = this._windSpeed / 2; } @@ -177,7 +177,7 @@ export class Timeline extends React.Component { let scrubberbox = this._scrubberbox.current!; let left = scrubberbox.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; - this.changeCurrentBarX(offsetX); + this.changeCurrentBarX(offsetX); } @action @@ -186,7 +186,7 @@ export class Timeline extends React.Component { e.stopPropagation(); let scrubberbox = this._scrubberbox.current!; let offsetX = (e.clientX - scrubberbox.getBoundingClientRect().left) * this.props.ScreenToLocalTransform().Scale; - this.changeCurrentBarX(offsetX); + this.changeCurrentBarX(offsetX); } @@ -195,19 +195,21 @@ export class Timeline extends React.Component { onPanDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let clientX = e.clientX; - if (this._doubleClickEnabled){ - this._doubleClickEnabled = false; + let clientX = e.clientX; + if (this._doubleClickEnabled) { + this._doubleClickEnabled = false; } else { - setTimeout(() => {if(!this._mouseToggled && this._doubleClickEnabled) this.changeCurrentBarX(this._trackbox.current!.scrollLeft + clientX - this._trackbox.current!.getBoundingClientRect().left); + setTimeout(() => { + if (!this._mouseToggled && this._doubleClickEnabled) this.changeCurrentBarX(this._trackbox.current!.scrollLeft + clientX - this._trackbox.current!.getBoundingClientRect().left); this._mouseToggled = false; - this._doubleClickEnabled = false;}, 200); - this._doubleClickEnabled = true; + this._doubleClickEnabled = false; + }, 200); + this._doubleClickEnabled = true; document.addEventListener("pointermove", this.onPanMove); document.addEventListener("pointerup", () => { document.removeEventListener("pointermove", this.onPanMove); if (!this._doubleClickEnabled) { - this._mouseToggled = false; + this._mouseToggled = false; } }); @@ -219,7 +221,7 @@ export class Timeline extends React.Component { e.preventDefault(); e.stopPropagation(); if (e.movementX !== 0 || e.movementY !== 0) { - this._mouseToggled = true; + this._mouseToggled = true; } let trackbox = this._trackbox.current!; let titleContainer = this._titleContainer.current!; @@ -227,10 +229,10 @@ export class Timeline extends React.Component { trackbox.scrollTop = trackbox.scrollTop - e.movementY; titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; } - @action - movePanX = (pixel:number) => { + @action + movePanX = (pixel: number) => { let infoContainer = this._infoContainer.current!; - infoContainer.scrollLeft = pixel; + infoContainer.scrollLeft = pixel; this._visibleStart = infoContainer.scrollLeft; } @@ -273,131 +275,138 @@ export class Timeline extends React.Component { return `${min}:${sec}`; } - timelineContextMenu = (e:MouseEvent): void => { + timelineContextMenu = (e: MouseEvent): void => { let subitems: ContextMenuProps[] = []; subitems.push({ description: this._timelineVisible ? "Hide Timeline" : "Show Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; + this._timelineVisible = !this._timelineVisible; }), icon: this._timelineVisible ? faEyeSlash : "eye" - }); - subitems.push({ description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => { - BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true;} - , icon:BoolCast(this.props.Document.isAnimating) ? "play" : "edit"}); + }); + subitems.push({ + description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => { + BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true; + } + , icon: BoolCast(this.props.Document.isAnimating) ? "play" : "edit" + }); ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems, icon: faClock }); } @action onWheelZoom = (e: React.WheelEvent) => { - e.preventDefault(); - e.stopPropagation(); - let offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; + e.preventDefault(); + e.stopPropagation(); + let offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; let prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); - let prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX,"mili", "time", this._tickSpacing, this._tickIncrement); - e.deltaY < 0 ? this.zoom(true) : this.zoom(false); - let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); - let currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); - this._infoContainer.current!.scrollLeft = currPixel - offset; + let prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + e.deltaY < 0 ? this.zoom(true) : this.zoom(false); + let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + let currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this._infoContainer.current!.scrollLeft = currPixel - offset; this._visibleStart = currPixel - offset > 0 ? currPixel - offset : 0; - this._visibleStart += this._visibleLength + this._visibleStart > this._totalLength ? this._totalLength - (this._visibleStart + this._visibleLength) :0; - this.changeCurrentBarX(currCurrent); + this._visibleStart += this._visibleLength + this._visibleStart > this._totalLength ? this._totalLength - (this._visibleStart + this._visibleLength) : 0; + this.changeCurrentBarX(currCurrent); } @action zoom = (dir: boolean) => { - let spacingChange = this._tickSpacing; - let incrementChange = this._tickIncrement; - if (dir){ - if (!(this._tickSpacing === 100 && this._tickIncrement === 1000)){ + let spacingChange = this._tickSpacing; + let incrementChange = this._tickIncrement; + if (dir) { + if (!(this._tickSpacing === 100 && this._tickIncrement === 1000)) { if (this._tickSpacing >= 100) { - incrementChange /= 2; - spacingChange = 50; + incrementChange /= 2; + spacingChange = 50; } else { - spacingChange += 5; + spacingChange += 5; } - } + } } else { if (this._tickSpacing <= 50) { - spacingChange = 100; - incrementChange *= 2; + spacingChange = 100; + incrementChange *= 2; } else { - spacingChange -= 5; + spacingChange -= 5; } } - let finalLength = spacingChange * (this._time / incrementChange); - if (finalLength >= this._infoContainer.current!.getBoundingClientRect().width){ - this._totalLength = finalLength; - this._tickSpacing = spacingChange; - this._tickIncrement = incrementChange; + let finalLength = spacingChange * (this._time / incrementChange); + if (finalLength >= this._infoContainer.current!.getBoundingClientRect().width) { + this._totalLength = finalLength; + this._tickSpacing = spacingChange; + this._tickIncrement = incrementChange; } } - private timelineToolBox = (scale:number) => { + private timelineToolBox = (scale: number) => { let size = 50 * scale; //50 is default - return ( - -
    -
    -
    -
    - -
    -
    + return ( + +
    +
    +
    +
    + +
    +
    +
    -
    ); } @action - private toggleChecked = (e:React.PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - let roundToggle = this._roundToggleRef.current!; - let roundToggleContainer = this._roundToggleContainerRef.current!; - let timelineContainer = this._timelineContainer.current!; - if (BoolCast(this.props.Document.isAnimating)){ + private toggleChecked = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + let roundToggle = this._roundToggleRef.current!; + let roundToggleContainer = this._roundToggleContainerRef.current!; + let timelineContainer = this._timelineContainer.current!; + if (BoolCast(this.props.Document.isAnimating)) { + roundToggle.style.transform = "translate(0px, 0px)"; - roundToggle.style.animationName = "turnoff"; - roundToggleContainer.style.animationName = "turnoff"; - timelineContainer.style.transform = `translate(0px, ${this._containerHeight}px)`; - this.props.Document.isAnimating = false; + roundToggle.style.animationName = "turnoff"; + roundToggleContainer.style.animationName = "turnoff"; + timelineContainer.style.transform = `translate(0px, ${0}px)`; + setTimeout(() => { + this.props.Document.isAnimating = false; + }, 500); } else { - roundToggle.style.transform = "translate(45px, 0px)"; - roundToggle.style.animationName = "turnon"; - roundToggleContainer.style.animationName = "turnon"; - timelineContainer.style.transform = `translate(0px, ${-this._containerHeight}px)`; - this.props.Document.isAnimating = true; + roundToggle.style.transform = "translate(45px, 0px)"; + roundToggle.style.animationName = "turnon"; + roundToggleContainer.style.animationName = "turnon"; + timelineContainer.style.transform = `translate(0px, ${this._containerHeight}px)`; + this.props.Document.isAnimating = true; + } } render() { return (
    -
    -
    -
    -
    -
    +
    +
    +
    +
    +
    {this._ticks.map(element => { - if(element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; + if (element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; })}
    -
    - {DocListCast(this.children).map(doc => )} +
    + {DocListCast(this.children).map(doc => )}
    -
    - {DocListCast(this.children).map(doc =>
    {Doc.BrushDoc(doc);}} onPointerOut={() => {Doc.UnBrushDoc(doc);}}>

    {doc.title}

    )} +
    + {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )}
    - +
    - { this.timelineToolBox(1) } + {this.timelineToolBox(1)}
    - +
    ); -- cgit v1.2.3-70-g09d2 From 98cc5ba95454be7d36343917c6e2c28047f109b9 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 6 Oct 2019 16:59:33 -0400 Subject: refactoring and resize right fix --- src/client/views/animationtimeline/Keyframe.tsx | 121 +++++++++++++---------- src/client/views/animationtimeline/Timeline.scss | 12 +-- src/client/views/animationtimeline/Timeline.tsx | 104 +++++-------------- 3 files changed, 98 insertions(+), 139 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 66ad6a76d..587625efa 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -288,7 +288,7 @@ export class Keyframe extends React.Component { } else if (this.regiondata.duration - offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // no keyframes, just fades this.regiondata.position -= (this.regiondata.fadeIn + this.regiondata.fadeOut - this.regiondata.duration); this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; - } else if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) { + } else if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) { let dif = this.regiondata.position - (leftRegion.position + leftRegion.duration); this.regiondata.position = leftRegion.position + leftRegion.duration; this.regiondata.duration += dif; @@ -296,8 +296,8 @@ export class Keyframe extends React.Component { this.regiondata.duration -= offset; this.regiondata.position += offset; } - this.keyframes[0].time = this.regiondata.position; - this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + // this.keyframes[0].time = this.regiondata.position; + // this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } @@ -308,14 +308,11 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); - if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut + offset <= NumCast((this.keyframes[this.keyframes.length - 1]).time)) { - let dif = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - NumCast((this.keyframes[this.keyframes.length - 1]).time); - this.regiondata.duration -= dif; - } else if (this.regiondata.duration + offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // nokeyframes, just fades - this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; - } else if (rightRegion && this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position) { - let dif = rightRegion.position - (this.regiondata.position + this.regiondata.duration); - this.regiondata.duration += dif; + console.log(offset); + console.log(this.keyframes[this.keyframes.length - 3].time); + console.log(this.regiondata.position + this.regiondata.duration - offset); + if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - offset <= NumCast(this.keyframes[this.keyframes.length - 3].time)) { + console.log("HI"); } else { this.regiondata.duration += offset; } @@ -458,6 +455,7 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } + @action checkInput = (val: any) => { return typeof(val === "number"); } @@ -471,6 +469,7 @@ export class Keyframe extends React.Component { }); } + @action onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); e.stopPropagation(); @@ -479,6 +478,7 @@ export class Keyframe extends React.Component { Doc.BrushDoc(this.props.node); } + @action onContainerOut = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); e.stopPropagation(); @@ -568,6 +568,60 @@ export class Keyframe extends React.Component { document.removeEventListener("pointerup", this.onReactionListen); } } + + @action + drawKeyframes = () => { + let keyframeDivs:JSX.Element[] = []; + this.keyframes.forEach( kf => { + if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { + keyframeDivs.push( +
    +
    +
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.makeKeyframeMenu(kf, e.nativeEvent); + }}>
    +
    + ); + } + else { + keyframeDivs.push( +
    +
    +
    + ); + } + }); + return keyframeDivs; + } + + @action + drawKeyframeDividers = () => { + let keyframeDividers:JSX.Element[] = []; + this.keyframes.forEach(kf => { + if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { + let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; + let bodyRef = React.createRef(); + let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + return ( +
    { this.onContainerOver(e, bodyRef); }} + onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} + onContextMenu={(e) => { + e.preventDefault(); + e.stopPropagation(); + this._mouseToggled = true; + this.makeRegionMenu(kf, e.nativeEvent); + }}> +
    + ); + } + }); + return keyframeDividers; + } + render() { return (
    @@ -577,49 +631,8 @@ export class Keyframe extends React.Component { onPointerDown={this.onBarPointerDown}>
    - {this.keyframes.map(kf => { - if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { - return ( -
    -
    -
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.makeKeyframeMenu(kf, e.nativeEvent); - }}>
    -
    - ); - } - else { - return ( -
    -
    -
    - ); - } - - })} - {this.keyframes.map( kf => { - if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { - let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; - let bodyRef = React.createRef(); - let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - return ( -
    { this.onContainerOver(e, bodyRef); }} - onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} - onContextMenu={(e) => { - e.preventDefault(); - e.stopPropagation(); - this._mouseToggled = true; - this.makeRegionMenu(kf, e.nativeEvent); - }}> -
    - ); - } - })} - + {this.drawKeyframes()} + {this.drawKeyframeDividers()}
    ); diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index fbdb2a200..cf6b4b3d5 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -13,7 +13,11 @@ } } - +.tick{ + height:100%; + width: 1px; + background-color:black; +} .timeline-container{ width:100%; height:300px; @@ -35,11 +39,7 @@ background-color: transparent; height: 30px; width:100%; - .tick{ - height:100%; - width: 1px; - background-color:black; - } + } .scrubber{ top:30px; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 8a41a5943..9ac5d98d2 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,12 +8,13 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes } from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; import { KeyframeFunc } from "./Keyframe"; +import { Utils } from "../../../Utils"; @observer export class Timeline extends React.Component { @@ -24,7 +25,6 @@ export class Timeline extends React.Component { private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; - @observable private _scrubberbox = React.createRef(); @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); @@ -42,13 +42,10 @@ export class Timeline extends React.Component { @observable private _tickSpacing = this.DEFAULT_TICK_SPACING; @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; @observable private _time = 100000; //DEFAULT - @observable private _ticks: number[] = []; @observable private _playButton = faPlayCircle; @observable private _timelineVisible = false; @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; - @observable private _reactionDisposer: IReactionDisposer[] = []; - + @observable private _doubleClickEnabled = false; @computed private get children(): List { @@ -63,47 +60,28 @@ export class Timeline extends React.Component { return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } - - componentWillMount() { - this.props.Document.isAnimating ? this.props.Document.isAnimating = true : this.props.Document.isAnimating = false; - } - componentDidMount() { - if (StrCast(this.props.Document.type) === "video") { - console.log("video"); - console.log(this.props.Document.duration); - if (this.props.Document.duration) { - this._time = Math.round(NumCast(this.props.Document.duration)) * 1000; - this._reactionDisposer.push(reaction(() => { - return NumCast(this.props.Document.curPage); - }, curPage => { - if (!this._isPlaying) { - this.changeCurrentBarX(curPage * this._tickIncrement / this._tickSpacing); - this.props.Document.curPage = this._currentBarX; - this.play(); - } - })); - } - } runInAction(() => { - this._reactionDisposer.push(reaction(() => { - return this._time; - }, () => { - this._ticks = []; - for (let i = 0; i < this._time;) { - this._ticks.push(i); - i += 1000; - } - this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); - }, { fireImmediately: true })); - this._totalLength = this._tickSpacing * (this._ticks.length / this._tickIncrement); + this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; this._visibleStart = this._infoContainer.current!.scrollLeft; }); + } - + /** + * React Functional Component + * Purpose: For drawing Tick marks across the timeline in authoring mode + */ + @action + drawTicks = () => { + let ticks = []; + for (let i = 0; i < this._time / this._tickIncrement; i++){ + ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); + } + return ticks; } + @action changeCurrentBarX = (pixel: number) => { pixel <= 0 ? this._currentBarX = 0 : pixel >= this._totalLength ? this._currentBarX = this._totalLength : this._currentBarX = pixel; @@ -174,23 +152,12 @@ export class Timeline extends React.Component { onScrubberMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let scrubberbox = this._scrubberbox.current!; + let scrubberbox = this._infoContainer.current!; let left = scrubberbox.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; this.changeCurrentBarX(offsetX); } - @action - onScrubberClick = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - let scrubberbox = this._scrubberbox.current!; - let offsetX = (e.clientX - scrubberbox.getBoundingClientRect().left) * this.props.ScreenToLocalTransform().Scale; - this.changeCurrentBarX(offsetX); - } - - - @action onPanDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -236,7 +203,6 @@ export class Timeline extends React.Component { this._visibleStart = infoContainer.scrollLeft; } - @action onResizeDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -261,8 +227,6 @@ export class Timeline extends React.Component { } } - - @action toReadTime = (time: number): string => { const inSeconds = time / 1000; @@ -276,21 +240,12 @@ export class Timeline extends React.Component { } timelineContextMenu = (e: MouseEvent): void => { - let subitems: ContextMenuProps[] = []; - subitems.push({ - description: this._timelineVisible ? "Hide Timeline" : "Show Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; - }), icon: this._timelineVisible ? faEyeSlash : "eye" - }); - subitems.push({ - description: BoolCast(this.props.Document.isAnimating) ? "Enter Play Mode" : "Enter Authoring Mode", event: () => { - BoolCast(this.props.Document.isAnimating) ? this.props.Document.isAnimating = false : this.props.Document.isAnimating = true; - } - , icon: BoolCast(this.props.Document.isAnimating) ? "play" : "edit" - }); - ContextMenu.Instance.addItem({ description: "Timeline Funcs...", subitems: subitems, icon: faClock }); + ContextMenu.Instance.addItem({description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { + this._timelineVisible = !this._timelineVisible; + }), icon: faTimes}); } + @action onWheelZoom = (e: React.WheelEvent) => { e.preventDefault(); @@ -339,14 +294,13 @@ export class Timeline extends React.Component { private timelineToolBox = (scale: number) => { let size = 50 * scale; //50 is default return ( -
    -
    -
    +
    +
    ); @@ -360,7 +314,6 @@ export class Timeline extends React.Component { let roundToggleContainer = this._roundToggleContainerRef.current!; let timelineContainer = this._timelineContainer.current!; if (BoolCast(this.props.Document.isAnimating)) { - roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; @@ -374,7 +327,6 @@ export class Timeline extends React.Component { roundToggleContainer.style.animationName = "turnon"; timelineContainer.style.transform = `translate(0px, ${this._containerHeight}px)`; this.props.Document.isAnimating = true; - } } render() { @@ -384,11 +336,7 @@ export class Timeline extends React.Component {
    -
    - {this._ticks.map(element => { - if (element % this._tickIncrement === 0) return

    {this.toReadTime(element)}

    ; - })} -
    + {this.drawTicks()}
    @@ -406,8 +354,6 @@ export class Timeline extends React.Component {
    {this.timelineToolBox(1)}
    - -
    ); } -- cgit v1.2.3-70-g09d2 From 7d63153af4933b480673f29ffb1331feeb965f49 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 12 Oct 2019 17:02:36 -0400 Subject: resize bug fix, more edge cases, starting interact --- src/client/views/animationtimeline/Keyframe.tsx | 64 ++++++++++--------------- 1 file changed, 25 insertions(+), 39 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 587625efa..810f9a057 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -13,6 +13,7 @@ import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { thisTypeAnnotation } from "babel-types"; export namespace KeyframeFunc { export enum KeyframeType { @@ -280,24 +281,18 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions); - let firstkf: (Doc | undefined) = this.keyframes[0]; - if (firstkf && this.regiondata.position + this.regiondata.fadeIn + offset >= NumCast(firstkf!.time)) { - let dif = NumCast(firstkf!.time) - (this.pixelPosition + this.pixelFadeIn); - this.regiondata.position = NumCast(firstkf!.time) - this.regiondata.fadeIn; - this.regiondata.duration -= dif; - } else if (this.regiondata.duration - offset < this.regiondata.fadeIn + this.regiondata.fadeOut) { // no keyframes, just fades - this.regiondata.position -= (this.regiondata.fadeIn + this.regiondata.fadeOut - this.regiondata.duration); - this.regiondata.duration = this.regiondata.fadeIn + this.regiondata.fadeOut; - } else if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) { - let dif = this.regiondata.position - (leftRegion.position + leftRegion.duration); - this.regiondata.position = leftRegion.position + leftRegion.duration; - this.regiondata.duration += dif; + if (leftRegion && this.regiondata.position + offset <= leftRegion.position + leftRegion.duration) { + this.regiondata.position = leftRegion.position + leftRegion.duration; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - (leftRegion.position + leftRegion.duration); + } else if (NumCast(this.keyframes[1].time) + offset >= NumCast(this.keyframes[2].time)) { + this.regiondata.position = NumCast(this.keyframes[2].time) - this.regiondata.fadeIn; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - NumCast(this.keyframes[2].time) + this.regiondata.fadeIn; } else { this.regiondata.duration -= offset; this.regiondata.position += offset; } - // this.keyframes[0].time = this.regiondata.position; - // this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + this.keyframes[0].time = this.regiondata.position; + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } @@ -308,17 +303,16 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); - console.log(offset); - console.log(this.keyframes[this.keyframes.length - 3].time); - console.log(this.regiondata.position + this.regiondata.duration - offset); - if (this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut - offset <= NumCast(this.keyframes[this.keyframes.length - 3].time)) { - console.log("HI"); + let 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 + this.regiondata.duration = fadeOutKeyframeTime - this.regiondata.position + this.regiondata.fadeOut; + } 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 @@ -382,10 +376,10 @@ export class Keyframe extends React.Component { @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Add Ease", () => { - // this.onContainerDown(kf, "interpolate"); + this.onContainerDown(kf, "interpolate"); }), TimelineMenu.Instance.addItem("button", "Add Path", () => { - // this.onContainerDown(kf, "path"); + this.onContainerDown(kf, "path"); }), TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{this.regions.splice(this.regions.indexOf(this.regiondata), 1);}), TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { @@ -514,16 +508,6 @@ export class Keyframe extends React.Component { onReactionListen = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let message = prompt("GRAPHING MODE: Enter gain"); - if (message) { - let messageContent = parseInt(message, 10); - if (messageContent === NaN) { - this._gain = Infinity; - } else { - this._gain = messageContent; - } - - } if (this._reac && this._plotList && this._interpolationKeyframe) { this.props.collection.backgroundColor = "#FFF"; this._reac(); @@ -605,10 +589,10 @@ export class Keyframe extends React.Component { let bodyRef = React.createRef(); let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - return ( + keyframeDividers.push (
    { this.onContainerOver(e, bodyRef); }} - onPointerOut={(e) => { this.onContainerOut(e, bodyRef); }} + 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(); @@ -625,10 +609,12 @@ export class Keyframe extends React.Component { render() { return (
    -
    +
    {this.drawKeyframes()} -- cgit v1.2.3-70-g09d2 From 9e914734438a52c5f9bb9a43421418c8ed5f903a Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 19 Oct 2019 16:59:01 -0400 Subject: lots of bug fixes --- src/client/views/animationtimeline/Keyframe.tsx | 25 +++++++++++++++---------- src/client/views/animationtimeline/Timeline.tsx | 16 +++++++++------- src/client/views/animationtimeline/Track.tsx | 1 + src/new_fields/util.ts | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 810f9a057..c872b8740 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -13,7 +13,6 @@ import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { thisTypeAnnotation } from "babel-types"; export namespace KeyframeFunc { export enum KeyframeType { @@ -167,6 +166,7 @@ export class Keyframe extends React.Component { (fadeOut.key! as Doc).opacity = 1; (start.key! as Doc).opacity = 0.1; (finish.key! as Doc).opacity = 0.1; + this.forceUpdate(); }); } @@ -315,6 +315,7 @@ export class Keyframe extends React.Component { this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; } + @action createKeyframe = async (clientX:number) => { this._mouseToggled = true; @@ -327,7 +328,7 @@ export class Keyframe extends React.Component { } } - + @action moveKeyframe = async (e: React.MouseEvent, kf: Doc) => { e.preventDefault(); @@ -346,12 +347,13 @@ export class Keyframe extends React.Component { @action makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { - runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); - CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); - }), + runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); + }), TimelineMenu.Instance.addItem("button", "Delete", () => { runInAction(() => { (this.regiondata.keyframes as List).splice(this.keyframes.indexOf(kf), 1); + this.forceUpdate(); }); }), TimelineMenu.Instance.addItem("input", "Move", (val) => { @@ -381,7 +383,10 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("button", "Add Path", () => { this.onContainerDown(kf, "path"); }), - TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{this.regions.splice(this.regions.indexOf(this.regiondata), 1);}), + TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{ + runInAction(() => { + this.regions.splice(this.regions.indexOf(this.regiondata), 1);} + );}), TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { runInAction(() => { if (this.checkInput(val)){ @@ -554,9 +559,9 @@ export class Keyframe extends React.Component { } @action - drawKeyframes = () => { + drawKeyframes = () => { let keyframeDivs:JSX.Element[] = []; - this.keyframes.forEach( kf => { + DocListCast(this.regiondata.keyframes).forEach( kf => { if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { keyframeDivs.push(
    @@ -581,9 +586,9 @@ export class Keyframe extends React.Component { } @action - drawKeyframeDividers = () => { + drawKeyframeDividers = () => { let keyframeDividers:JSX.Element[] = []; - this.keyframes.forEach(kf => { + DocListCast(this.regiondata.keyframes).forEach(kf => { if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; let bodyRef = React.createRef(); diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 9ac5d98d2..666048a54 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -155,7 +155,7 @@ export class Timeline extends React.Component { let scrubberbox = this._infoContainer.current!; let left = scrubberbox.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; - this.changeCurrentBarX(offsetX); + this.changeCurrentBarX(offsetX + this._visibleStart); } @action @@ -201,6 +201,9 @@ export class Timeline extends React.Component { let infoContainer = this._infoContainer.current!; infoContainer.scrollLeft = pixel; this._visibleStart = infoContainer.scrollLeft; + console.log(infoContainer.scrollLeft); + console.log(this._totalLength); + console.log(this._visibleLength); } @action @@ -317,15 +320,14 @@ export class Timeline extends React.Component { roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; - timelineContainer.style.transform = `translate(0px, ${0}px)`; - setTimeout(() => { - this.props.Document.isAnimating = false; - }, 500); + timelineContainer.style.top = `${-this._containerHeight}px`; + this.props.Document.isAnimating = false; + } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; - timelineContainer.style.transform = `translate(0px, ${this._containerHeight}px)`; + timelineContainer.style.top = "0px"; this.props.Document.isAnimating = true; } } @@ -334,7 +336,7 @@ export class Timeline extends React.Component {
    -
    +
    {this.drawTicks()}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 3ec410216..7a8f42ea7 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -270,6 +270,7 @@ export class Track extends React.Component { let inner = this._inner.current!; let 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.forceUpdate(); } createRegion = (position: number) => { diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 04194509c..a92b1858d 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -69,7 +69,7 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number } else { target.__fields[prop] = value; } - if (typeof value === "object" && !(value instanceof ObjectField)) debugger; + // if (typeof value === "object" && !(value instanceof ObjectField)) debugger; if (writeToServer) { if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); -- cgit v1.2.3-70-g09d2 From 8e45ed5a6705becf6708c3d9e9740ce8febe65d9 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 20 Oct 2019 17:16:52 -0400 Subject: changed ui input, and more bug fixes --- src/client/views/animationtimeline/Timeline.scss | 68 ++++++++++++++---------- src/client/views/animationtimeline/Timeline.tsx | 51 +++++++++++++++--- 2 files changed, 85 insertions(+), 34 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index cf6b4b3d5..f6a48d876 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -7,10 +7,48 @@ display:flex; align-items: flex-start; flex-direction: row; + justify-content: space-evenly; + align-items: baseline; top: 10px; div{ margin-left:10px; } + .animation-text{ + font-size: 20px; + height: auto; + width: auto; + } + .round-toggle { + height: 40px; + width: 80px; + background-color: white; + border: 2px solid purple; + border-radius: 20px; + animation-fill-mode: forwards; + animation-duration: 500ms; + top: 30px; + input{ + position:absolute; + opacity: 0; + height: 0; + width: 0; + } + .round-toggle-slider{ + height: 35px; + width: 35px; + background-color: white; + border:1px solid grey; + border-radius: 20px; + transition: transform 500ms ease-in-out; + margin-left: 0px; + margin-top: 0.5px; + } + } + .time-input{ + height: 40px; + width: 100px; + + } } .tick{ @@ -112,38 +150,12 @@ float: left 0px; top: 25%; height: 75%; - width: 100%; + width: 100%; background-color: grey; } } -.round-toggle { - height: 40px; - width: 80px; - background-color: white; - border: 2px solid purple; - border-radius: 20px; - animation-fill-mode: forwards; - animation-duration: 500ms; - top: 20px; - input{ - position:absolute; - opacity: 0; - height: 0; - width: 0; - } - .round-toggle-slider{ - height: 35px; - width: 35px; - background-color: white; - border:1px solid grey; - border-radius: 20px; - transition: transform 500ms ease-in-out; - margin-left: 0px; - margin-top: 0.5px; - } - -} + @keyframes turnon{ from{ background-color: white; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 666048a54..30fa70b12 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -31,6 +31,7 @@ export class Timeline extends React.Component { @observable private _infoContainer = React.createRef(); @observable private _roundToggleRef = React.createRef(); @observable private _roundToggleContainerRef = React.createRef(); + @observable private _timeInputRef = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @@ -62,12 +63,27 @@ export class Timeline extends React.Component { componentDidMount() { runInAction(() => { + if (!this.props.Document.AnimationLength){ + this.props.Document.AnimationLength = this._time; + } else { + this._time = NumCast(this.props.Document.AnimationLength); + console.log(this._time); + } this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; this._visibleStart = this._infoContainer.current!.scrollLeft; + this.props.Document.isAnimating = !this.props.Document.isAnimating; + this.toggleHandle(); }); } + componentWillUnmount(){ + runInAction(() => { + console.log(this._time); + this.props.Document.AnimationLength = this._time; + }); + } + /** * React Functional Component * Purpose: For drawing Tick marks across the timeline in authoring mode @@ -194,16 +210,20 @@ export class Timeline extends React.Component { let titleContainer = this._titleContainer.current!; this.movePanX(this._visibleStart - e.movementX); trackbox.scrollTop = trackbox.scrollTop - e.movementY; - titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; + titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; + if (this._visibleStart + this._visibleLength + 20>= this._totalLength){ + this._visibleStart -= e.movementX; + this._totalLength -= e.movementX; + this._time -= KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this._tickSpacing, this._tickIncrement); + this.props.Document.AnimationLength = this._time; + } + } @action movePanX = (pixel: number) => { let infoContainer = this._infoContainer.current!; infoContainer.scrollLeft = pixel; this._visibleStart = infoContainer.scrollLeft; - console.log(infoContainer.scrollLeft); - console.log(this._totalLength); - console.log(this._visibleLength); } @action @@ -300,19 +320,39 @@ export class Timeline extends React.Component {
    -
    +
    +

    Timeline Overview

    +

    Mode: {this.props.Document.isAnimating ? "Authoring" : "Play"}

    +

    Length:

    + +
    ); } + + @action + private onTimeInput = (e: React.KeyboardEvent) => { + if (e.keyCode === 13){ + let timeInput = this._timeInputRef.current!; + this._time = parseInt(timeInput.value, 10); + this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this.props.Document.AnimationLength = this._time; + + } + } @action private toggleChecked = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); + this.toggleHandle(); + } + + private toggleHandle = () => { let roundToggle = this._roundToggleRef.current!; let roundToggleContainer = this._roundToggleContainerRef.current!; let timelineContainer = this._timelineContainer.current!; @@ -322,7 +362,6 @@ export class Timeline extends React.Component { roundToggleContainer.style.animationName = "turnoff"; timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isAnimating = false; - } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; -- cgit v1.2.3-70-g09d2 From 21621ac406b7703811ac40b429c51dac752dd142 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 26 Oct 2019 16:47:42 -0400 Subject: ui changes, bug fix, icon fix --- src/client/views/animationtimeline/Keyframe.tsx | 1 + src/client/views/animationtimeline/Timeline.scss | 21 +++++++-------------- src/client/views/animationtimeline/Timeline.tsx | 10 ++++++---- 3 files changed, 14 insertions(+), 18 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index c872b8740..6a5163cde 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -125,6 +125,7 @@ interface IProps { tickSpacing: number; tickIncrement: number; time: number; + changeCurrentBarX: (x: number) => void; transform: Transform; } diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index f6a48d876..8317a3606 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -156,19 +156,12 @@ } -@keyframes turnon{ - from{ - background-color: white; - } - to{ - background-color: purple; - } -} -@keyframes turnoff{ - from{ - background-color: purple; - } - to{ - background-color: white; +.timeline-checker{ + height: auto; + width: auto; + position: absolute; + .check{ + width: 100px; + height: 100px; } } \ No newline at end of file diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 30fa70b12..0b6b06aaa 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,7 +8,7 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes } from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross} from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; @@ -265,7 +265,7 @@ export class Timeline extends React.Component { timelineContextMenu = (e: MouseEvent): void => { ContextMenu.Instance.addItem({description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { this._timelineVisible = !this._timelineVisible; - }), icon: faTimes}); + }), icon: this._timelineVisible ? faEyeSlash : faEye }); } @@ -329,7 +329,6 @@ export class Timeline extends React.Component {

    Length:

    -
    ); } @@ -341,7 +340,6 @@ export class Timeline extends React.Component { this._time = parseInt(timeInput.value, 10); this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); this.props.Document.AnimationLength = this._time; - } } @@ -392,6 +390,10 @@ export class Timeline extends React.Component {
    +
    + + +
    {this.timelineToolBox(1)}
    -- cgit v1.2.3-70-g09d2 From 2b7b564aa051db78c89d14ff48cf38ace2f42b37 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 27 Oct 2019 16:42:34 -0400 Subject: confirm box, regiondata bugfix --- src/client/views/animationtimeline/Keyframe.tsx | 24 ++++++++++------ src/client/views/animationtimeline/Timeline.scss | 16 +++++++++-- src/client/views/animationtimeline/Timeline.tsx | 36 ++++++++++++++++++++---- src/client/views/animationtimeline/Track.tsx | 3 ++ 4 files changed, 62 insertions(+), 17 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 6a5163cde..35d7afc7a 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -125,9 +125,10 @@ interface IProps { tickSpacing: number; tickIncrement: number; time: number; - + check: string; changeCurrentBarX: (x: number) => void; transform: Transform; + checkCallBack: (visible: boolean) => void; } @observer @@ -137,6 +138,7 @@ export class Keyframe extends React.Component { @observable private _gain = 20; //default @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; + @observable private _index:number = 0; @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc);} @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} @@ -386,7 +388,7 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{ runInAction(() => { - this.regions.splice(this.regions.indexOf(this.regiondata), 1);} + this.regions.splice(this.regions.indexOf(this.props.RegionData), 1);} );}), TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { runInAction(() => { @@ -492,10 +494,12 @@ export class Keyframe extends React.Component { private _plotList: ([string, StrokeData] | undefined) = undefined; private _interpolationKeyframe: (Doc | undefined) = undefined; private _type: string = ""; + @action onContainerDown = (kf: Doc, type: string) => { - let listenerCreated = false; + let listenerCreated = false; + this.props.checkCallBack(true); this._type = type; this.props.collection.backgroundColor = "rgb(0,0,0)"; this._reac = reaction(() => { @@ -504,16 +508,20 @@ export class Keyframe extends React.Component { if (!listenerCreated) { this._plotList = Array.from(data!)[data!.size - 1]!; this._interpolationKeyframe = kf; - document.addEventListener("pointerup", this.onReactionListen); listenerCreated = true; + const reac = reaction(() => { + return this.props.check; + }, () => { + if(this.props.check === "yes") this.onReactionListen(); + reac(); + this.props.checkCallBack(false); + }); } }); } @action - onReactionListen = (e: PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); + onReactionListen = () => { if (this._reac && this._plotList && this._interpolationKeyframe) { this.props.collection.backgroundColor = "#FFF"; this._reac(); @@ -554,8 +562,6 @@ export class Keyframe extends React.Component { this._reac = undefined; this._interpolationKeyframe = undefined; this._plotList = undefined; - this._type = ""; - document.removeEventListener("pointerup", this.onReactionListen); } } diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 8317a3606..0f98ed7c4 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -159,9 +159,19 @@ .timeline-checker{ height: auto; width: auto; - position: absolute; + overflow: hidden; + position: absolute; + display: flex; + padding: 10px 10px; + div{ + height: auto; + width: auto; + overflow: hidden; + margin: 0px 10px; + cursor: pointer + } .check{ - width: 100px; - height: 100px; + 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 0b6b06aaa..6028656dc 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,7 +8,7 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross} from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross, faCheckCircle, faTimesCircle} from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; @@ -368,6 +368,28 @@ export class Timeline extends React.Component { this.props.Document.isAnimating = true; } } + + + @observable private _check:string = ""; + @observable private _checkVisible:boolean = false; + @action + private onCheckClicked = (type: string) => { + if (type === "yes"){ + this._check = "yes"; + } else if (type === "no"){ + this._check = "no"; + } + } + + + @action + private checkCallBack = (visible:boolean) => { + this._checkVisible = visible; + if (!visible){ //when user confirms + this._check = ""; + } + + } render() { return (
    @@ -380,7 +402,7 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    @@ -390,9 +412,13 @@ export class Timeline extends React.Component {
    -
    - - +
    +
    {this.onCheckClicked("yes");}}> + +
    +
    {this.onCheckClicked("no");}}> + +
    {this.timelineToolBox(1)} diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 7a8f42ea7..14e309f68 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -20,7 +20,10 @@ interface IProps { tickIncrement: number; tickSpacing: number; timelineVisible: boolean; + check: string; changeCurrentBarX: (x: number) => void; + checkCallBack: (visible: boolean) => void; + } @observer -- cgit v1.2.3-70-g09d2 From 7977625e5b408d6e47432caaf7382aa315fc9832 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 3 Nov 2019 16:48:56 -0500 Subject: changes to timeline overview --- src/client/views/animationtimeline/Keyframe.tsx | 1 - src/client/views/animationtimeline/Timeline.scss | 35 +++++++---- src/client/views/animationtimeline/Timeline.tsx | 10 +-- .../views/animationtimeline/TimelineOverview.scss | 73 ++++++++++++++++++---- .../views/animationtimeline/TimelineOverview.tsx | 30 ++++++--- 5 files changed, 109 insertions(+), 40 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 35d7afc7a..55a2b2075 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -138,7 +138,6 @@ export class Keyframe extends React.Component { @observable private _gain = 20; //default @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; - @observable private _index:number = 0; @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc);} @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 0f98ed7c4..6270eed41 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -4,25 +4,33 @@ .timeline-toolbox{ position:absolute; + margin: 0px; + padding: 0px; display:flex; align-items: flex-start; - flex-direction: row; - justify-content: space-evenly; - align-items: baseline; - top: 10px; + flex-direction: row; + justify-content: space-evenly; + align-items: center; + top: 15px; div{ + padding: 0px; margin-left:10px; } .animation-text{ font-size: 20px; height: auto; width: auto; + white-space: nowrap; + font-size: 16px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; } .round-toggle { height: 40px; width: 80px; background-color: white; - border: 2px solid purple; + border: 2px solid grey; border-radius: 20px; animation-fill-mode: forwards; animation-duration: 500ms; @@ -44,13 +52,18 @@ margin-top: 0.5px; } } - .time-input{ - height: 40px; - width: 100px; - - } + +} +.time-input{ + height: 40px; + width: 100px; + white-space: nowrap; + font-size: 16px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; + } - .tick{ height:100%; width: 1px; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 6028656dc..94cd0629d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -321,14 +321,14 @@ export class Timeline extends React.Component {
    -

    Timeline Overview

    - -

    Mode: {this.props.Document.isAnimating ? "Authoring" : "Play"}

    +
    Timeline Overview
    + +
    Mode: {this.props.Document.isAnimating ? "Authoring" : "Play"}
    -

    Length:

    - +
    Length:
    +
    ); } diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index 9e69c2adf..c7f9bd059 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -1,38 +1,85 @@ @import "./../globalCssVariables.scss"; -.timeline-overview-container{ + +.timeline-overview-container{ + padding: 0px; + margin: 0px; width: 300px; height: 40px; - margin-top: 10px; - margin-left: 20px; background: white; + position: relative; border: 2px solid black; - padding: 0px; - display:inline-block; + .timeline-overview-visible{ + position: absolute; height: 100%; background: green; + display: inline-block; margin: 0px; + padding: 0px; } - .timeline-overview-scrubber-container{ + .timeline-overview-scrubber-container{ + margin: 0px; + padding: 0px; + position: absolute; height: 100%; - margin-top: -40px; - margin-left: 0px; width: 2px; + top: 0px; + left: 0px; z-index: 1001; background-color:black; display: inline-block; - .timeline-overview-scrubber-head{ + + .timeline-overview-scrubber-head{ + padding: 0px; + margin: 0px; position:absolute; height: 30px; width: 30px; background-color:transparent; border-radius: 50%; border: 5px solid black; - margin-left: -15px; - top: -15px; - + left: -15px; + top: -30px; } - } +} + + + +.timeline-play-bar{ + position: relative; + padding: 0px; + margin: 0px; + width: 300px; + height: 4px; + background-color: grey; + border-radius: 20px; + cursor: pointer; + + .timeline-play-head{ + position: absolute; + padding: 0px; + margin: 0px; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: white; + border: 3px grey solid; + left: 0px; + top: -10px; + cursor: pointer; + } +} +.timeline-play-tail{ + position: absolute; + padding: 0px; + margin: 0px; + height: 4px; + width: 0px; + z-index: 1000; + background-color: green; + border-radius: 20px; + margin-top: -4px; + cursor: pointer; } \ No newline at end of file diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 38b823cbc..4741969dc 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -6,11 +6,11 @@ import "./TimelineOverview.scss"; interface TimelineOverviewProps{ - scale: number; totalLength: number; visibleLength:number; visibleStart:number; - currentBarX:number; + currentBarX:number; + isAuthoring: boolean; changeCurrentBarX: (pixel:number) => void; movePanX: (pixel:number) => any; } @@ -37,8 +37,8 @@ export class TimelineOverview extends React.Component{ onPanX = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH * this.props.scale) + e.movementX; - this.props.movePanX((movX / (this.DEFAULT_WIDTH * this.props.scale)) * this.props.totalLength); + let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH) + e.movementX; + this.props.movePanX((movX / (this.DEFAULT_WIDTH )) * this.props.totalLength); } @action @@ -66,7 +66,7 @@ export class TimelineOverview extends React.Component{ let scrubberRef = this._scrubberRef.current!; let left = scrubberRef.getBoundingClientRect().left; let offsetX = Math.round(e.clientX - left); - this.props.changeCurrentBarX(((offsetX / (this.DEFAULT_WIDTH * this.props.scale)) * this.props.totalLength) + this.props.currentBarX); + this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); } @action @@ -78,12 +78,22 @@ export class TimelineOverview extends React.Component{ } render(){ + let timeline = this.props.isAuthoring ? [ +
    +
    , +
    +
    +
    +
    + ] : [ +
    +
    +
    , +
    + ]; return( -
    -
    -
    -
    -
    +
    + {timeline}
    ); } -- cgit v1.2.3-70-g09d2 From 4d4db3aecf54a501a981c239feacdfddfe71152c Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 12 Nov 2019 17:20:21 -0500 Subject: bug fix with ui changes --- src/client/views/animationtimeline/Keyframe.tsx | 13 ++++++++----- src/client/views/animationtimeline/Timeline.scss | 5 +++-- src/client/views/animationtimeline/Timeline.tsx | 10 ++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 55a2b2075..424f4ed8d 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -572,11 +572,11 @@ export class Keyframe extends React.Component { keyframeDivs.push(
    -
    { this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { +
    { 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(); }}>
    ); } @@ -595,7 +595,8 @@ export class Keyframe extends React.Component { drawKeyframeDividers = () => { let keyframeDividers:JSX.Element[] = []; DocListCast(this.regiondata.keyframes).forEach(kf => { - if(this.keyframes.indexOf(kf ) !== this.keyframes.length - 1) { + let index = this.keyframes.indexOf(kf); + if(index !== this.keyframes.length - 1 ) { let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; let bodyRef = React.createRef(); let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); @@ -606,8 +607,10 @@ export class Keyframe extends React.Component { onPointerOut={(e) => { e.preventDefault(); e.stopPropagation(); this.onContainerOut(e, bodyRef); }} onContextMenu={(e) => { e.preventDefault(); - e.stopPropagation(); - this._mouseToggled = true; + e.stopPropagation(); + if (index !== 0 || index !== this.keyframes.length - 2){ + this._mouseToggled = true; + } this.makeRegionMenu(kf, e.nativeEvent); }}>
    diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 6270eed41..88d602d76 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -11,7 +11,7 @@ flex-direction: row; justify-content: space-evenly; align-items: center; - top: 15px; + top: 20px; div{ padding: 0px; margin-left:10px; @@ -56,12 +56,13 @@ } .time-input{ height: 40px; - width: 100px; + width: 120px; white-space: nowrap; font-size: 16px; color: grey; letter-spacing: 2px; text-transform: uppercase; + padding-left: 5px; } .tick{ diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 94cd0629d..73e6c600f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -315,12 +315,12 @@ export class Timeline extends React.Component { } private timelineToolBox = (scale: number) => { - let size = 50 * scale; //50 is default + let size = 40 * scale; //50 is default return (
    -
    -
    -
    +
    +
    +
    Timeline Overview
    Mode: {this.props.Document.isAnimating ? "Authoring" : "Play"}
    @@ -358,12 +358,14 @@ export class Timeline extends React.Component { roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; + roundToggleContainer.style.backgroundColor = "white"; timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isAnimating = false; } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; + roundToggleContainer.style.backgroundColor = "green"; timelineContainer.style.top = "0px"; this.props.Document.isAnimating = true; } -- cgit v1.2.3-70-g09d2 From 13de65ec4ca3fbeef4a687d079e7b480bd691764 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 12 Nov 2019 18:15:32 -0500 Subject: isanimating fix --- src/client/views/animationtimeline/Timeline.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 73e6c600f..43019903e 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -72,7 +72,7 @@ export class Timeline extends React.Component { this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; this._visibleStart = this._infoContainer.current!.scrollLeft; - this.props.Document.isAnimating = !this.props.Document.isAnimating; + this.props.Document.isATOn = !this.props.Document.isATOn; this.toggleHandle(); }); } @@ -322,13 +322,13 @@ export class Timeline extends React.Component {
    Timeline Overview
    - -
    Mode: {this.props.Document.isAnimating ? "Authoring" : "Play"}
    + +
    Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}
    -
    Length:
    - +
    Length:
    +
    ); } @@ -354,20 +354,20 @@ export class Timeline extends React.Component { let roundToggle = this._roundToggleRef.current!; let roundToggleContainer = this._roundToggleContainerRef.current!; let timelineContainer = this._timelineContainer.current!; - if (BoolCast(this.props.Document.isAnimating)) { + if (BoolCast(this.props.Document.isATOn)) { roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; roundToggleContainer.style.backgroundColor = "white"; timelineContainer.style.top = `${-this._containerHeight}px`; - this.props.Document.isAnimating = false; + this.props.Document.isATOn = false; } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; roundToggleContainer.style.backgroundColor = "green"; timelineContainer.style.top = "0px"; - this.props.Document.isAnimating = true; + this.props.Document.isATOn = true; } } @@ -396,7 +396,7 @@ export class Timeline extends React.Component { return (
    -
    +
    {this.drawTicks()} -- cgit v1.2.3-70-g09d2 From d7f772d93458e7669a1d2e954ad741e1c67318a5 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 12 Nov 2019 19:01:42 -0500 Subject: undo --- src/client/views/animationtimeline/Keyframe.tsx | 456 +++++++++++++----------- src/new_fields/util.ts | 3 +- 2 files changed, 240 insertions(+), 219 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 424f4ed8d..a2d0a644e 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import "./Keyframe.scss"; import "./Timeline.scss"; import "../globalCssVariables.scss"; -import { observer} from "mobx-react"; +import { observer } from "mobx-react"; import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction } from "mobx"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; @@ -13,6 +13,7 @@ import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; export namespace KeyframeFunc { export enum KeyframeType { @@ -86,23 +87,23 @@ export namespace KeyframeFunc { regiondata.position = 0; regiondata.fadeIn = 1000; regiondata.fadeOut = 1000; - regiondata.functions = new List(); + regiondata.functions = new List(); return regiondata; }; - export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing:number, tickIncrement:number) => { - let 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) => { + let time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement; switch (unit) { case "mili": - return time; + return time; case "sec": - return dir === "pixel" ? time / 1000 : time * 1000; + return dir === "pixel" ? time / 1000 : time * 1000; case "min": - return dir === "pixel" ? time / 60000 : time * 60000; + return dir === "pixel" ? time / 60000 : time * 60000; case "hr": - return dir === "pixel" ? time / 3600000 : time * 3600000; - default: - return time; + return dir === "pixel" ? time / 3600000 : time * 3600000; + default: + return time; } }; } @@ -113,7 +114,7 @@ export const RegionDataSchema = createSchema({ keyframes: listSpec(Doc), fadeIn: defaultSpec("number", 0), fadeOut: defaultSpec("number", 0), - functions: listSpec(Doc) + functions: listSpec(Doc) }); export type RegionData = makeInterface<[typeof RegionDataSchema]>; export const RegionData = makeInterface(RegionDataSchema); @@ -122,13 +123,13 @@ interface IProps { node: Doc; RegionData: Doc; collection: Doc; - tickSpacing: number; - tickIncrement: number; - time: number; - check: string; + tickSpacing: number; + tickIncrement: number; + time: number; + check: string; changeCurrentBarX: (x: number) => void; transform: Transform; - checkCallBack: (visible: boolean) => void; + checkCallBack: (visible: boolean) => void; } @observer @@ -136,16 +137,16 @@ export class Keyframe extends React.Component { @observable private _bar = React.createRef(); @observable private _gain = 20; //default - @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; - - @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc);} - @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} - @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); } + @observable private _mouseToggled = false; + @observable private _doubleClickEnabled = false; + + @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc); } + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } + @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 pixelFadeOut() { return KeyframeFunc.convertPixelTime(this.regiondata.fadeOut, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); } @computed private get inks() { if (this.props.collection.data_ext) { @@ -168,12 +169,13 @@ export class Keyframe extends React.Component { (fadeOut.key! as Doc).opacity = 1; (start.key! as Doc).opacity = 0.1; (finish.key! as Doc).opacity = 0.1; - this.forceUpdate(); - }); + this.forceUpdate(); + }); } @action makeKeyData = async (kfpos: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + const batch = UndoManager.StartBatch("makeKeyData"); let doclist = (await DocListCastAsync(this.regiondata.keyframes))!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { @@ -183,45 +185,54 @@ export class Keyframe extends React.Component { let TK: Doc = new Doc(); TK.time = kfpos; TK.key = Doc.MakeCopy(this.props.node, true); - TK.type = type; + TK.type = type; this.regiondata.keyframes!.push(TK); - let interpolationFunctions = new Doc(); - interpolationFunctions.interpolationX = new List([0, 1]); - interpolationFunctions.interpolationY = new List([0,100]); - interpolationFunctions.pathX = new List(); - interpolationFunctions.pathY = new List(); + // myObservable++; + // UndoManager.AddEvent({ + // undo: action(() => myObservable--), + // redo: action(() => myObservable++) + // }); + + let interpolationFunctions = new Doc(); + interpolationFunctions.interpolationX = new List([0, 1]); + interpolationFunctions.interpolationY = new List([0, 100]); + interpolationFunctions.pathX = new List(); + interpolationFunctions.pathY = new List(); - this.regiondata.functions!.push(interpolationFunctions); - let found:boolean = false; + this.regiondata.functions!.push(interpolationFunctions); + let found: boolean = false; this.regiondata.keyframes!.forEach(compkf => { - compkf = compkf as Doc; + compkf = compkf as Doc; if (kfpos < NumCast(compkf.time) && !found) { runInAction(() => { this.regiondata.keyframes!.splice(doclist.indexOf(compkf as Doc), 0, TK); - this.regiondata.keyframes!.pop(); - found = true; - }); - return; + this.regiondata.keyframes!.pop(); + found = true; + }); + return; } }); + batch.end(); return TK; } - + @action onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let clientX = e.clientX; - if (this._doubleClickEnabled){ - this.createKeyframe(clientX); - this._doubleClickEnabled = false; + let clientX = e.clientX; + if (this._doubleClickEnabled) { + this.createKeyframe(clientX); + 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); - this._mouseToggled = false; - this._doubleClickEnabled = false; }, 200); - this._doubleClickEnabled = true; + setTimeout(() => { + 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); + this._doubleClickEnabled = true; document.addEventListener("pointermove", this.onBarPointerMove); document.addEventListener("pointerup", (e: PointerEvent) => { document.removeEventListener("pointermove", this.onBarPointerMove); @@ -235,7 +246,7 @@ export class Keyframe extends React.Component { e.preventDefault(); e.stopPropagation(); if (e.movementX !== 0) { - this._mouseToggled = true; + this._mouseToggled = true; } let left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; let right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions!); @@ -249,10 +260,10 @@ export class Keyframe extends React.Component { this.regiondata.position = right.position - this.regiondata.duration; } else { this.regiondata.position = futureX; - } - let movement = this.regiondata.position - prevX; + } + let movement = this.regiondata.position - prevX; this.keyframes.forEach(kf => { - kf.time = NumCast(kf.time) + movement; + kf.time = NumCast(kf.time) + movement; }); } @@ -284,17 +295,17 @@ export class Keyframe extends React.Component { let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let 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; - this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - (leftRegion.position + leftRegion.duration); + this.regiondata.position = leftRegion.position + leftRegion.duration; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - (leftRegion.position + leftRegion.duration); } else if (NumCast(this.keyframes[1].time) + offset >= NumCast(this.keyframes[2].time)) { - this.regiondata.position = NumCast(this.keyframes[2].time) - this.regiondata.fadeIn; - this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - NumCast(this.keyframes[2].time) + this.regiondata.fadeIn; + this.regiondata.position = NumCast(this.keyframes[2].time) - this.regiondata.fadeIn; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - NumCast(this.keyframes[2].time) + this.regiondata.fadeIn; } else { this.regiondata.duration -= offset; this.regiondata.position += offset; } - this.keyframes[0].time = this.regiondata.position; - this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + this.keyframes[0].time = this.regiondata.position; + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } @@ -305,22 +316,22 @@ export class Keyframe extends React.Component { let bar = this._bar.current!; let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); - let fadeOutKeyframeTime = NumCast(this.keyframes[this.keyframes.length - 3].time); + let 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 this.regiondata.duration = fadeOutKeyframeTime - this.regiondata.position + this.regiondata.fadeOut; - } else if (rightRegion && (this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position)){ - this.regiondata.duration = rightRegion.position - this.regiondata.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; + 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; + createKeyframe = async (clientX: number) => { + this._mouseToggled = true; let bar = this._bar.current!; let 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 @@ -330,7 +341,7 @@ export class Keyframe extends React.Component { } } - + @action moveKeyframe = async (e: React.MouseEvent, kf: Doc) => { e.preventDefault(); @@ -346,126 +357,134 @@ export class Keyframe extends React.Component { this.props.node.backgroundColor = "#000000"; } - @action - makeKeyframeMenu = (kf :Doc, e:MouseEvent) => { + @action + makeKeyframeMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { - runInAction(() => {let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); - CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); - }), - TimelineMenu.Instance.addItem("button", "Delete", () => { - runInAction(() => { - (this.regiondata.keyframes as List).splice(this.keyframes.indexOf(kf), 1); - this.forceUpdate(); - }); - }), - TimelineMenu.Instance.addItem("input", "Move", (val) => { runInAction(() => { - if (this.checkInput(val)){ - let cannotMove:boolean = false; - let 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; + let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); + }); + }), + TimelineMenu.Instance.addItem("button", "Delete", () => { + runInAction(() => { + (this.regiondata.keyframes as List).splice(this.keyframes.indexOf(kf), 1); + this.forceUpdate(); + }); + }), + TimelineMenu.Instance.addItem("input", "Move", (val) => { + runInAction(() => { + if (this.checkInput(val)) { + let cannotMove: boolean = false; + let 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); + TimelineMenu.Instance.addMenu("Keyframe"); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } - @action + @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Add Ease", () => { this.onContainerDown(kf, "interpolate"); }), - TimelineMenu.Instance.addItem("button", "Add Path", () => { - this.onContainerDown(kf, "path"); - }), - TimelineMenu.Instance.addItem("button", "Remove Region", ()=>{ - runInAction(() => { - this.regions.splice(this.regions.indexOf(this.props.RegionData), 1);} - );}), - TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { - runInAction(() => { - if (this.checkInput(val)){ - let cannotMove:boolean = false; - if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position){ - cannotMove = true; - } - if (!cannotMove){ - this.regiondata.fadeIn = parseInt(val, 10); - this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; - } + TimelineMenu.Instance.addItem("button", "Add Path", () => { + this.onContainerDown(kf, "path"); + }), + TimelineMenu.Instance.addItem("button", "Remove Region", () => { + runInAction(() => { + this.regions.splice(this.regions.indexOf(this.props.RegionData), 1); } - });}), - TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => { - runInAction(() => { - if (this.checkInput(val)){ - let cannotMove:boolean = false; - if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)){ - cannotMove = true; - } - if (!cannotMove){ - this.regiondata.fadeOut = parseInt(val, 10); - this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - val; + ); + }), + TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)) { + let cannotMove: boolean = false; + if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position) { + cannotMove = true; + } + if (!cannotMove) { + this.regiondata.fadeIn = parseInt(val, 10); + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + } } - } - });}), - TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => { - runInAction(() => { - if (this.checkInput(val)){ - let prevPosition = this.regiondata.position; - let cannotMove:boolean = false; - DocListCast(this.regions).forEach(region => { - if (NumCast(region.position) !== this.regiondata.position){ - if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))){ + }); + }), + TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)) { + let cannotMove: boolean = false; + if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)) { cannotMove = true; } + if (!cannotMove) { + this.regiondata.fadeOut = parseInt(val, 10); + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - val; + } } }); - if (!cannotMove) { - this.regiondata.position = parseInt(val, 10); - this.updateKeyframes(this.regiondata.position - prevPosition ); - } - } - });}), - TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { - runInAction(() => { - if (this.checkInput(val)){ - let cannotMove:boolean = false; - DocListCast(this.regions).forEach(region => { - if (NumCast(region.position) !== this.regiondata.position){ - val += this.regiondata.position; - if ((val < 0 ) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))){ - cannotMove = true; + }), + TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)) { + let prevPosition = this.regiondata.position; + let cannotMove: boolean = false; + DocListCast(this.regions).forEach(region => { + if (NumCast(region.position) !== this.regiondata.position) { + if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))) { + cannotMove = true; + } } + }); + if (!cannotMove) { + this.regiondata.position = parseInt(val, 10); + this.updateKeyframes(this.regiondata.position - prevPosition); } - }); - if (!cannotMove) { - this.regiondata.duration = parseInt(val, 10); - this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; - this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; } - } - });}), - TimelineMenu.Instance.addMenu("Region"); - TimelineMenu.Instance.openMenu(e.clientX, e.clientY); + }); + }), + TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { + runInAction(() => { + if (this.checkInput(val)) { + let cannotMove: boolean = false; + DocListCast(this.regions).forEach(region => { + if (NumCast(region.position) !== this.regiondata.position) { + val += this.regiondata.position; + if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))) { + cannotMove = true; + } + } + }); + if (!cannotMove) { + this.regiondata.duration = parseInt(val, 10); + this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; + } + } + }); + }), + TimelineMenu.Instance.addMenu("Region"); + TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } @action checkInput = (val: any) => { - return typeof(val === "number"); + return typeof (val === "number"); } @action - updateKeyframes = (incr:number, filter:number[] = []) => { + updateKeyframes = (incr: number, filter: number[] = []) => { this.keyframes.forEach(kf => { - if (!filter.includes(this.keyframes.indexOf(kf))){ - kf.time = NumCast(kf.time) + incr; + if (!filter.includes(this.keyframes.indexOf(kf))) { + kf.time = NumCast(kf.time) + incr; } }); } @@ -476,7 +495,7 @@ export class Keyframe extends React.Component { e.stopPropagation(); let div = ref.current!; div.style.opacity = "1"; - Doc.BrushDoc(this.props.node); + Doc.BrushDoc(this.props.node); } @action @@ -485,36 +504,36 @@ export class Keyframe extends React.Component { e.stopPropagation(); let div = ref.current!; div.style.opacity = "0"; - Doc.UnBrushDoc(this.props.node); + Doc.UnBrushDoc(this.props.node); } private _reac: (undefined | IReactionDisposer) = undefined; private _plotList: ([string, StrokeData] | undefined) = undefined; - private _interpolationKeyframe: (Doc | undefined) = undefined; - private _type: string = ""; - + private _interpolationKeyframe: (Doc | undefined) = undefined; + private _type: string = ""; + @action onContainerDown = (kf: Doc, type: string) => { - let listenerCreated = false; - this.props.checkCallBack(true); - this._type = type; + let listenerCreated = false; + this.props.checkCallBack(true); + this._type = type; this.props.collection.backgroundColor = "rgb(0,0,0)"; this._reac = reaction(() => { return this.inks; }, data => { if (!listenerCreated) { this._plotList = Array.from(data!)[data!.size - 1]!; - this._interpolationKeyframe = kf; - listenerCreated = true; + this._interpolationKeyframe = kf; + listenerCreated = true; const reac = reaction(() => { - return this.props.check; - }, () => { - if(this.props.check === "yes") this.onReactionListen(); - reac(); - this.props.checkCallBack(false); - }); + return this.props.check; + }, () => { + if (this.props.check === "yes") this.onReactionListen(); + reac(); + this.props.checkCallBack(false); + }); } }); } @@ -548,26 +567,26 @@ export class Keyframe extends React.Component { } } else { i++; - } + } } - let index = this.keyframes.indexOf(this._interpolationKeyframe!); - if (this._type === "interpolate"){ + let index = this.keyframes.indexOf(this._interpolationKeyframe!); + if (this._type === "interpolate") { (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationX = xPlots; (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationY = yPlots; } else if (this._type === "path") { (Cast(this.regiondata.functions![index], Doc) as Doc).pathX = xPlots; (Cast(this.regiondata.functions![index], Doc) as Doc).pathY = yPlots; } - this._reac = undefined; - this._interpolationKeyframe = undefined; - this._plotList = undefined; + this._reac = undefined; + this._interpolationKeyframe = undefined; + this._plotList = undefined; } } @action - drawKeyframes = () => { - let keyframeDivs:JSX.Element[] = []; - DocListCast(this.regiondata.keyframes).forEach( kf => { + drawKeyframes = () => { + let keyframeDivs: JSX.Element[] = []; + DocListCast(this.regiondata.keyframes).forEach(kf => { if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { keyframeDivs.push(
    @@ -575,8 +594,8 @@ export class Keyframe extends React.Component {
    { 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(); }}>
    + this.makeKeyframeMenu(kf, e.nativeEvent); + }} onDoubleClick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
    ); } @@ -588,47 +607,48 @@ export class Keyframe extends React.Component { ); } }); - return keyframeDivs; + return keyframeDivs; } - @action - drawKeyframeDividers = () => { - let keyframeDividers:JSX.Element[] = []; + @action + drawKeyframeDividers = () => { + let keyframeDividers: JSX.Element[] = []; DocListCast(this.regiondata.keyframes).forEach(kf => { - let index = this.keyframes.indexOf(kf); - if(index !== this.keyframes.length - 1 ) { - let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; - let bodyRef = React.createRef(); - let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - keyframeDividers.push ( -
    { 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); - }}> + let index = this.keyframes.indexOf(kf); + if (index !== this.keyframes.length - 1) { + let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; + let bodyRef = React.createRef(); + let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + keyframeDividers.push( +
    { 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); + }}>
    - ); - } - }); - return keyframeDividers; + ); + } + }); + return keyframeDividers; } render() { return (
    -
    + }>
    {this.drawKeyframes()} diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index a92b1858d..92e3e3f6f 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -76,7 +76,8 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number } else { DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); } - UndoManager.AddEvent({ + UndoManager. + AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue }); -- cgit v1.2.3-70-g09d2 From 5becac4b0442da73a6fe3b48e3a248f6cf2df61d Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sat, 23 Nov 2019 15:40:07 -0500 Subject: responsive ui --- src/client/views/animationtimeline/Timeline.scss | 276 ++++++++++++----------- src/client/views/animationtimeline/Timeline.tsx | 129 ++++++----- src/client/views/animationtimeline/Track.scss | 1 - src/client/views/animationtimeline/Track.tsx | 88 ++++---- src/client/views/linking/LinkFollowBox.tsx | 2 +- 5 files changed, 260 insertions(+), 236 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 88d602d76..493b084a8 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -1,191 +1,209 @@ -@import "./../globalCssVariables.scss"; +@import "./../globalCssVariables.scss"; -.timeline-toolbox{ - position:absolute; - margin: 0px; - padding: 0px; - display:flex; - align-items: flex-start; +.timeline-toolbox { + position: absolute; + margin: 0px; + padding: 0px; + display: flex; + align-items: flex-start; flex-direction: row; justify-content: space-evenly; align-items: center; top: 20px; - div{ - padding: 0px; - margin-left:10px; + + div { + padding: 0px; + margin-left: 10px; } - .animation-text{ - font-size: 20px; - height: auto; - width: auto; + + .animation-text { + font-size: 20px; + height: auto; + width: auto; white-space: nowrap; font-size: 16px; color: grey; letter-spacing: 2px; text-transform: uppercase; } + .round-toggle { height: 40px; width: 80px; background-color: white; border: 2px solid grey; border-radius: 20px; - animation-fill-mode: forwards; + animation-fill-mode: forwards; animation-duration: 500ms; - top: 30px; - input{ - position:absolute; - opacity: 0; - height: 0; - width: 0; + top: 30px; + + input { + position: absolute; + opacity: 0; + height: 0; + width: 0; } - .round-toggle-slider{ - height: 35px; - width: 35px; + + .round-toggle-slider { + height: 35px; + width: 35px; background-color: white; - border:1px solid grey; - border-radius: 20px; - transition: transform 500ms ease-in-out; - margin-left: 0px; - margin-top: 0.5px; - } + border: 1px solid grey; + border-radius: 20px; + transition: transform 500ms ease-in-out; + margin-left: 0px; + margin-top: 0.5px; + } } - + } -.time-input{ - height: 40px; - width: 120px; + +.time-input { + height: 40px; + width: 120px; white-space: nowrap; font-size: 16px; color: grey; letter-spacing: 2px; text-transform: uppercase; - padding-left: 5px; - + padding-left: 5px; + } -.tick{ - height:100%; - width: 1px; - background-color:black; -} -.timeline-container{ - width:100%; - height:300px; - position:absolute; + +.tick { + height: 100%; + width: 1px; + background-color: black; +} + +.timeline-container { + width: 100%; + height: 300px; + position: absolute; background-color: $light-color-secondary; - box-shadow: 0px 10px 20px; - transition: transform 500ms ease; - - .info-container{ - margin-top: 80px; - right:20px; - position:absolute; - height: calc(100% - 100px); - width: calc(100% - 140px); + box-shadow: 0px 10px 20px; + transition: transform 500ms ease; + + .info-container { + margin-top: 80px; + right: 20px; + position: absolute; + height: calc(100% - 100px); + width: calc(100% - 140px); overflow: hidden; - .scrubberbox{ - position:absolute; - background-color: transparent; + .scrubberbox { + position: absolute; + background-color: transparent; height: 30px; - width:100%; - + width: 100%; + } - .scrubber{ - top:30px; - height: 100%; - width: 2px; - position:absolute; + + .scrubber { + top: 30px; + height: 100%; + width: 2px; + position: absolute; z-index: 1001; - background-color:black; - .scrubberhead{ - top: -30px; - height: 30px; + background-color: black; + + .scrubberhead { + top: -30px; + height: 30px; width: 30px; - background-color:transparent; - border-radius: 50%; - border: 5px solid black; + background-color: transparent; + border-radius: 50%; + border: 5px solid black; left: -15px; - position:absolute; + position: absolute; } } - .trackbox{ - top: 30px; - height:calc(100% - 30px); - width:100%; - border:1px; - overflow:hidden; - background-color:white; - position:absolute; - box-shadow: -10px 0px 10px 10px grey; + .trackbox { + top: 30px; + height: calc(100% - 30px); + width: 100%; + border: 1px; + overflow: hidden; + background-color: white; + position: absolute; + box-shadow: -10px 0px 10px 10px grey; } - + } - .title-container{ - margin-top: 110px; - margin-left: 20px; - height: calc(100% - 100px - 30px); - width: 100px; - background-color:white; - overflow: hidden; - .datapane{ - top:0px; - width: 100px; - height: 75px; + + .title-container { + margin-top: 110px; + margin-left: 20px; + height: calc(100% - 100px - 30px); + width: 100px; + background-color: white; + overflow: hidden; + + .datapane { + top: 0px; + width: 100px; + height: 30%; border: 1px solid $dark-color; - background-color: $intermediate-color; - color: white; - position:relative; - float:left; - border-style:solid; + background-color: $intermediate-color; + color: white; + position: relative; + float: left; + border-style: solid; + overflow-y: scroll; + overflow-x: hidden; } } - .resize{ - bottom: 5px; - position:absolute; - height: 30px; - width: 50px; + + .resize { + bottom: 5px; + position: absolute; + height: 30px; + width: 50px; left: calc(50% - 25px); } } -.overview{ - position: absolute; - height: 50px; - width: 200px; - background-color: black; - .container{ - position: absolute; - float: left 0px; - top: 25%; - height: 75%; - width: 100%; - background-color: grey; +.overview { + position: absolute; + height: 50px; + width: 200px; + background-color: black; + + .container { + position: absolute; + float: left 0px; + top: 25%; + height: 75%; + width: 100%; + background-color: grey; } } -.timeline-checker{ - height: auto; - width: auto; - overflow: hidden; - position: absolute; - display: flex; - padding: 10px 10px; - div{ - height: auto; +.timeline-checker { + height: auto; + width: auto; + overflow: hidden; + position: absolute; + display: flex; + padding: 10px 10px; + + div { + height: auto; width: auto; - overflow: hidden; - margin: 0px 10px; + overflow: hidden; + margin: 0px 10px; cursor: pointer } - .check{ - width: 50px; - height: 50px; + + .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 43019903e..f8aa88755 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,7 +8,7 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross, faCheckCircle, faTimesCircle} from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross, faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; @@ -19,9 +19,9 @@ import { Utils } from "../../../Utils"; @observer export class Timeline extends React.Component { - private readonly DEFAULT_CONTAINER_HEIGHT: number = 330; + private DEFAULT_CONTAINER_HEIGHT: number = 330; private readonly DEFAULT_TICK_SPACING: number = 50; - private readonly MIN_CONTAINER_HEIGHT: number = 205; + private MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; @@ -31,7 +31,7 @@ export class Timeline extends React.Component { @observable private _infoContainer = React.createRef(); @observable private _roundToggleRef = React.createRef(); @observable private _roundToggleContainerRef = React.createRef(); - @observable private _timeInputRef = React.createRef(); + @observable private _timeInputRef = React.createRef(); @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @@ -46,8 +46,8 @@ export class Timeline extends React.Component { @observable private _playButton = faPlayCircle; @observable private _timelineVisible = false; @observable private _mouseToggled = false; - @observable private _doubleClickEnabled = false; - + @observable private _doubleClickEnabled = false; + private _titleHeight = 0; @computed private get children(): List { let extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); @@ -60,28 +60,33 @@ export class Timeline extends React.Component { } return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } + componentWillMount() { + this._titleHeight = window.innerHeight / 14; //arbitrary number, but for responsiveness + this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; + this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; + } componentDidMount() { runInAction(() => { - if (!this.props.Document.AnimationLength){ - this.props.Document.AnimationLength = this._time; + if (!this.props.Document.AnimationLength) { + this.props.Document.AnimationLength = this._time; } else { - this._time = NumCast(this.props.Document.AnimationLength); - console.log(this._time); + this._time = NumCast(this.props.Document.AnimationLength); + console.log(this._time); } this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; this._visibleStart = this._infoContainer.current!.scrollLeft; - this.props.Document.isATOn = !this.props.Document.isATOn; - this.toggleHandle(); + this.props.Document.isATOn = !this.props.Document.isATOn; + this.toggleHandle(); }); } - componentWillUnmount(){ + componentWillUnmount() { runInAction(() => { - console.log(this._time); - this.props.Document.AnimationLength = this._time; - }); + console.log(this._time); + this.props.Document.AnimationLength = this._time; + }); } /** @@ -90,11 +95,11 @@ export class Timeline extends React.Component { */ @action drawTicks = () => { - let ticks = []; - for (let i = 0; i < this._time / this._tickIncrement; i++){ - ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); + let ticks = []; + for (let i = 0; i < this._time / this._tickIncrement; i++) { + ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); } - return ticks; + return ticks; } @@ -210,14 +215,14 @@ export class Timeline extends React.Component { let titleContainer = this._titleContainer.current!; this.movePanX(this._visibleStart - e.movementX); trackbox.scrollTop = trackbox.scrollTop - e.movementY; - titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; - if (this._visibleStart + this._visibleLength + 20>= this._totalLength){ - this._visibleStart -= e.movementX; + titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; + if (this._visibleStart + this._visibleLength + 20 >= this._totalLength) { + this._visibleStart -= e.movementX; this._totalLength -= e.movementX; - this._time -= KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this._tickSpacing, this._tickIncrement); - this.props.Document.AnimationLength = this._time; + this._time -= KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this._tickSpacing, this._tickIncrement); + this.props.Document.AnimationLength = this._time; } - + } @action movePanX = (pixel: number) => { @@ -263,9 +268,11 @@ export class Timeline extends React.Component { } timelineContextMenu = (e: MouseEvent): void => { - ContextMenu.Instance.addItem({description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; - }), icon: this._timelineVisible ? faEyeSlash : faEye }); + ContextMenu.Instance.addItem({ + description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { + this._timelineVisible = !this._timelineVisible; + }), icon: this._timelineVisible ? faEyeSlash : faEye + }); } @@ -318,28 +325,28 @@ export class Timeline extends React.Component { let size = 40 * scale; //50 is default return (
    -
    -
    -
    +
    +
    +
    Timeline Overview
    - +
    Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}
    -
    Length:
    - +
    Length:
    +
    ); } - - @action + + @action private onTimeInput = (e: React.KeyboardEvent) => { - if (e.keyCode === 13){ - let timeInput = this._timeInputRef.current!; + if (e.keyCode === 13) { + let timeInput = this._timeInputRef.current!; this._time = parseInt(timeInput.value, 10); - this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); - this.props.Document.AnimationLength = this._time; + this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this.props.Document.AnimationLength = this._time; } } @@ -347,7 +354,7 @@ export class Timeline extends React.Component { private toggleChecked = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - this.toggleHandle(); + this.toggleHandle(); } private toggleHandle = () => { @@ -358,36 +365,36 @@ export class Timeline extends React.Component { roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; - roundToggleContainer.style.backgroundColor = "white"; + roundToggleContainer.style.backgroundColor = "white"; timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isATOn = false; } else { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; - roundToggleContainer.style.backgroundColor = "green"; - timelineContainer.style.top = "0px"; + roundToggleContainer.style.backgroundColor = "green"; + timelineContainer.style.top = "0px"; this.props.Document.isATOn = true; } } - @observable private _check:string = ""; - @observable private _checkVisible:boolean = false; + @observable private _check: string = ""; + @observable private _checkVisible: boolean = false; @action private onCheckClicked = (type: string) => { - if (type === "yes"){ - this._check = "yes"; - } else if (type === "no"){ + if (type === "yes") { + this._check = "yes"; + } else if (type === "no") { this._check = "no"; } } - @action - private checkCallBack = (visible:boolean) => { - this._checkVisible = visible; - if (!visible){ //when user confirms + @action + private checkCallBack = (visible: boolean) => { + this._checkVisible = visible; + if (!visible) { //when user confirms this._check = ""; } @@ -404,22 +411,22 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    - {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )} + {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )}
    -
    -
    {this.onCheckClicked("yes");}}> - +
    +
    { this.onCheckClicked("yes"); }}> +
    -
    {this.onCheckClicked("no");}}> - +
    { this.onCheckClicked("no"); }}> +
    diff --git a/src/client/views/animationtimeline/Track.scss b/src/client/views/animationtimeline/Track.scss index c8d56edf6..61a8e0b88 100644 --- a/src/client/views/animationtimeline/Track.scss +++ b/src/client/views/animationtimeline/Track.scss @@ -5,7 +5,6 @@ .track { .inner { top:0px; - height: 75px; width: calc(100%); background-color: $light-color; border: 1px solid $dark-color; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index e66b42690..bee9933b0 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -19,10 +19,10 @@ interface IProps { time: number; tickIncrement: number; tickSpacing: number; - timelineVisible: boolean; - check: string; + timelineVisible: boolean; + check: string; changeCurrentBarX: (x: number) => void; - checkCallBack: (visible: boolean) => void; + checkCallBack: (visible: boolean) => void; } @@ -36,35 +36,35 @@ export class Track extends React.Component { @observable private _onRegionData: (Doc | undefined) = undefined; @observable private _storedState: (Doc | undefined) = undefined; @observable private filterList = [ - "regions", - "cursors", - "hidden", - "nativeHeight", - "nativeWidth", - "schemaColumns", - "baseLayout", - "backgroundLayout", - "layout", - ]; - - @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List;} + "regions", + "cursors", + "hidden", + "nativeHeight", + "nativeWidth", + "schemaColumns", + "baseLayout", + "backgroundLayout", + "layout", + ]; + private _trackHeight = 0; + + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } componentWillMount() { runInAction(() => { - if (!this.props.node.regions) this.props.node.regions = new List(); - console.log("hi"); - console.log("HELLO"); - console.log("hi"); + if (!this.props.node.regions) this.props.node.regions = new List(); + this._trackHeight = window.innerHeight / 14; //for responsiveness + }); } componentDidMount() { runInAction(async () => { - this._timelineVisibleReaction = this.timelineVisibleReaction(); + this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); - this.props.node.hidden = false; - this.props.node.opacity = 1; + this.props.node.hidden = false; + this.props.node.opacity = 1; }); } @@ -72,7 +72,7 @@ export class Track extends React.Component { runInAction(() => { //disposing reactions if (this._currentBarXReaction) this._currentBarXReaction(); - if (this._timelineVisibleReaction) this._timelineVisibleReaction(); + if (this._timelineVisibleReaction) this._timelineVisibleReaction(); }); } @@ -81,7 +81,7 @@ export class Track extends React.Component { let keyframes: List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); let kfIndex: number = keyframes.indexOf(ref); let kf = keyframes[kfIndex] as Doc; - if (!kf) return; + if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists @@ -107,13 +107,13 @@ export class Track extends React.Component { this._isOnKeyframe = false; } - @action + @action revertState = () => { - let copyDoc = Doc.MakeCopy(this.props.node, true); + let copyDoc = Doc.MakeCopy(this.props.node, true); if (this._storedState) this.applyKeys(this._storedState); - let newState = new Doc(); - newState.key = copyDoc; - this._storedState = newState; + let newState = new Doc(); + newState.key = copyDoc; + this._storedState = newState; } @action @@ -129,13 +129,13 @@ export class Track extends React.Component { } }); } - @action + @action timelineVisibleReaction = () => { return reaction(() => { - return this.props.timelineVisible; + return this.props.timelineVisible; }, isVisible => { - this.revertState(); - }); + this.revertState(); + }); } @action @@ -162,28 +162,28 @@ export class Track extends React.Component { @action private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; - let docFromApply = kfNode; + let docFromApply = kfNode; if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { if (!kfNode[key]) { this.props.node[key] = undefined; } else { let stored = kfNode[key]; - if(stored instanceof ObjectField){ - this.props.node[key] = stored[Copy](); + if (stored instanceof ObjectField) { + this.props.node[key] = stored[Copy](); } else { - this.props.node[key] = stored; + this.props.node[key] = stored; } } }); } - + @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { - if (!this.filterList.includes(key)) acc.push(key); + if (!this.filterList.includes(key)) acc.push(key); return acc; }, []); } @@ -249,10 +249,10 @@ export class Track extends React.Component { } } else { let stored = leftNode[key]; - if(stored instanceof ObjectField){ - this.props.node[key] = stored[Copy](); + if (stored instanceof ObjectField) { + this.props.node[key] = stored[Copy](); } else { - this.props.node[key] = stored; + this.props.node[key] = stored; } } }); @@ -276,7 +276,7 @@ export class Track extends React.Component { let inner = this._inner.current!; let 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.forceUpdate(); + this.forceUpdate(); } createRegion = (position: number) => { @@ -297,7 +297,7 @@ export class Track extends React.Component { return (
    -
    {Doc.BrushDoc(this.props.node);}}onPointerOut={() => {Doc.UnBrushDoc(this.props.node);}}> +
    { Doc.BrushDoc(this.props.node); }} onPointerOut={() => { Doc.UnBrushDoc(this.props.node); }} style={{ height: `${this._trackHeight}px` }}> {DocListCast(this.regions).map((region) => { return ; })} diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index efe2c7f2a..f3193896f 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -21,7 +21,7 @@ import { docs_v1 } from "googleapis"; import { Utils } from "../../../Utils"; import { Link } from "@react-pdf/renderer"; -enum FollowModes { +export enum FollowModes { OPENTAB = "Open in Tab", OPENRIGHT = "Open in Right Split", OPENFULL = "Open Full Screen", -- cgit v1.2.3-70-g09d2 From 8af45ed7f376981ce8f8b1c6d1b2fd3b1546a00e Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 23 Nov 2019 16:08:44 -0500 Subject: responsive update --- src/client/views/animationtimeline/Timeline.tsx | 4 +++- src/client/views/animationtimeline/Track.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index f8aa88755..64822542d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -21,6 +21,7 @@ export class Timeline extends React.Component { private DEFAULT_CONTAINER_HEIGHT: number = 330; private readonly DEFAULT_TICK_SPACING: number = 50; + private readonly MAX_TITLE_HEIGHT = 75; private MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; @@ -61,7 +62,8 @@ export class Timeline extends React.Component { return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } componentWillMount() { - this._titleHeight = window.innerHeight / 14; //arbitrary number, but for responsiveness + let relativeHeight = window.innerHeight / 14; + this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index bee9933b0..a3aa62a31 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -46,6 +46,7 @@ export class Track extends React.Component { "backgroundLayout", "layout", ]; + private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } @@ -53,7 +54,8 @@ export class Track extends React.Component { componentWillMount() { runInAction(() => { if (!this.props.node.regions) this.props.node.regions = new List(); - this._trackHeight = window.innerHeight / 14; //for responsiveness + let relativeHeight = window.innerHeight / 14; + this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness }); } -- cgit v1.2.3-70-g09d2 From 5bf4dfa43e07a21bc5cb96b3b98f1a6ddb75b903 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 23 Nov 2019 16:31:15 -0500 Subject: another change --- src/client/views/animationtimeline/Timeline.tsx | 3 +-- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 64822542d..2b960cc88 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,8 +8,7 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines, faArrowUp, faArrowDown, faClock, faPauseCircle, faEyeSlash, faTimes, faEye, faCheck, faCross, faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; -import { ContextMenuProps } from "../ContextMenuItem"; +import { faPlayCircle, faBackward, faForward, faGripLines,faPauseCircle, faEyeSlash,faEye,faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9fbfffc82..e2b4716ce 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -637,7 +637,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } private viewDefToJSX(viewDef: any): Opt { - if (viewDef.type === "text") { + if (viewDef.type === "text") { const text = Cast(viewDef.text, "string"); // don't use NumCast, StrCast, etc since we want to test for undefined below const x = Cast(viewDef.x, "number"); const y = Cast(viewDef.y, "number"); -- cgit v1.2.3-70-g09d2 From be753f6c952d8f1fc324d2c076095416b6d98a35 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 7 Dec 2019 17:04:29 -0500 Subject: bug fixes --- src/client/views/animationtimeline/Keyframe.tsx | 5 ++++- src/client/views/animationtimeline/Track.tsx | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index a2d0a644e..e8b75eef4 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -300,7 +300,10 @@ export class Keyframe extends React.Component { } else if (NumCast(this.keyframes[1].time) + offset >= NumCast(this.keyframes[2].time)) { this.regiondata.position = NumCast(this.keyframes[2].time) - this.regiondata.fadeIn; this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - NumCast(this.keyframes[2].time) + this.regiondata.fadeIn; - } else { + } else if (NumCast(this.keyframes[0].time) + offset <= 0){ + this.regiondata.position = 0; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time); + }else { this.regiondata.duration -= offset; this.regiondata.position += offset; } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index a3aa62a31..22b83f055 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -45,6 +45,17 @@ export class Track extends React.Component { "baseLayout", "backgroundLayout", "layout", + "title", + "AnimationLength", + "author", + "baseProto", + "creationDate", + "isATOn", + "isPrototype", + "lastOpened", + "proto", + "type", + "zIndex" ]; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; -- cgit v1.2.3-70-g09d2 From a24f9da758415c60dbcb56b1cb488bec02d5b1a0 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 10 Dec 2019 17:55:13 -0500 Subject: some changes --- src/client/views/animationtimeline/Keyframe.tsx | 5 ++- src/client/views/animationtimeline/Timeline.tsx | 45 ++++++++++++++++++++----- src/client/views/animationtimeline/Track.tsx | 25 ++++++++++++-- src/client/views/nodes/DocumentView.tsx | 4 +-- 4 files changed, 64 insertions(+), 15 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index e8b75eef4..c3e018112 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -88,6 +88,7 @@ export namespace KeyframeFunc { regiondata.fadeIn = 1000; regiondata.fadeOut = 1000; regiondata.functions = new List(); + regiondata.hasData = false; return regiondata; }; @@ -114,7 +115,8 @@ export const RegionDataSchema = createSchema({ keyframes: listSpec(Doc), fadeIn: defaultSpec("number", 0), fadeOut: defaultSpec("number", 0), - functions: listSpec(Doc) + functions: listSpec(Doc), + hasData: defaultSpec("boolean", false) }); export type RegionData = makeInterface<[typeof RegionDataSchema]>; export const RegionData = makeInterface(RegionDataSchema); @@ -340,6 +342,7 @@ export class Keyframe extends React.Component { if (offset > this.regiondata.fadeIn && offset < this.regiondata.duration - this.regiondata.fadeOut) { //make sure keyframe is not created inbetween fades and ends let position = this.regiondata.position; await this.makeKeyData(Math.round(position + offset)); + 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 } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 2b960cc88..c13a039a5 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -3,7 +3,7 @@ import "./Timeline.scss"; import { listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, observe, toJS } from "mobx"; +import { observable, action, computed, runInAction } from "mobx"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; @@ -17,14 +17,18 @@ import { Utils } from "../../../Utils"; @observer export class Timeline extends React.Component { - - private DEFAULT_CONTAINER_HEIGHT: number = 330; + + //readonly constants private readonly DEFAULT_TICK_SPACING: number = 50; private readonly MAX_TITLE_HEIGHT = 75; - private MIN_CONTAINER_HEIGHT: number = 205; private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; + //height variables + private DEFAULT_CONTAINER_HEIGHT: number = 330; + private MIN_CONTAINER_HEIGHT: number = 205; + + //react refs @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); @observable private _timelineContainer = React.createRef(); @@ -33,6 +37,7 @@ export class Timeline extends React.Component { @observable private _roundToggleContainerRef = React.createRef(); @observable private _timeInputRef = React.createRef(); + //boolean vars and instance vars @observable private _currentBarX: number = 0; @observable private _windSpeed: number = 1; @observable private _isPlaying: boolean = false; //scrubber playing @@ -47,7 +52,11 @@ export class Timeline extends React.Component { @observable private _timelineVisible = false; @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; - private _titleHeight = 0; + @observable private _titleHeight = 0; + + /** + * collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit. + */ @computed private get children(): List { let extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); @@ -60,6 +69,10 @@ export class Timeline extends React.Component { } return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } + + /** + * + */ componentWillMount() { let relativeHeight = window.innerHeight / 14; this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; @@ -140,16 +153,21 @@ export class Timeline extends React.Component { } - + /** + * fast forward the timeline scrubbing + */ @action windForward = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - if (this._windSpeed < 64) { //max speed is 32 + if (this._windSpeed < 64) { //max speed is 32 this._windSpeed = this._windSpeed * 2; } } + /** + * rewind the timeline scrubbing + */ @action windBackward = (e: React.MouseEvent) => { e.preventDefault(); @@ -159,7 +177,7 @@ export class Timeline extends React.Component { } } - //for scrubber action + @action onScrubberDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -392,6 +410,7 @@ export class Timeline extends React.Component { } + @action private checkCallBack = (visible: boolean) => { this._checkVisible = visible; @@ -400,10 +419,18 @@ export class Timeline extends React.Component { } } + + + + + + + + render() { return (
    -
    +
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 22b83f055..d0bcdd655 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -65,9 +65,8 @@ export class Track extends React.Component { componentWillMount() { runInAction(() => { if (!this.props.node.regions) this.props.node.regions = new List(); - let relativeHeight = window.innerHeight / 14; + let relativeHeight = window.innerHeight / 14; this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness - }); } @@ -145,12 +144,32 @@ export class Track extends React.Component { @action timelineVisibleReaction = () => { return reaction(() => { - return this.props.timelineVisible; + return this.props.timelineVisible; }, isVisible => { this.revertState(); + if (isVisible){ + DocListCast(this.regions).forEach(region => { + if (!BoolCast((Cast(region, Doc) as Doc).hasData)){ + for (let i = 0; i < 4; i++){ + DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); + if (i === 0 || i === 3){ + DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key.opacity = 0.1; + } + } + console.log("saving keyframes"); + } + }); + } }); } + @action + /** + * Simple loop through all the regions to update the keyframes. Only applies to timelineVisibleReaction + */ + updateAllRegions = () => { + + } @action timeChange = async (time: number) => { if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 467fd4b32..6c3dd2051 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -669,10 +669,10 @@ export class DocumentView extends DocComponent(Docu return
    { - console.log("Brush" + this.props.Document.title); + //console.log("Brush" + this.props.Document.title); Doc.BrushDoc(this.props.Document); }} onPointerLeave={e => { - console.log("UnBrush" + this.props.Document.title); + //console.log("UnBrush" + this.props.Document.title); Doc.UnBrushDoc(this.props.Document); }} -- cgit v1.2.3-70-g09d2 From aa5b205e3d5239457fd224da37fe32421a4f3b3c Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Thu, 9 Jan 2020 21:45:00 +0900 Subject: documentation --- src/client/views/animationtimeline/Keyframe.tsx | 65 ++++++++++++ src/client/views/animationtimeline/Timeline.tsx | 127 ++++++++++++++++++------ src/client/views/animationtimeline/Track.tsx | 62 ++++++++++-- 3 files changed, 218 insertions(+), 36 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index c3e018112..c3c1f5f8c 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -15,6 +15,11 @@ import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { undoBatch, UndoManager } from "../../util/UndoManager"; + + +/** + * 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 { fade = "fade", @@ -134,6 +139,30 @@ interface IProps { checkCallBack: (visible: boolean) => void; } + +/** + * + * This class handles the green region stuff + * Key facts: + * + * Structure looks like this + * + * region as a whole + * <------------------------------REGION-------------------------------> + * + * 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 + */ @observer export class Keyframe extends React.Component { @@ -363,6 +392,10 @@ export class Keyframe extends React.Component { this.props.node.backgroundColor = "#000000"; } + + /** + * custom keyframe context menu items (when clicking on the keyframe circle) + */ @action makeKeyframeMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { @@ -396,6 +429,9 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } + /** + * context menu for region (anywhere on the green region). + */ @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Add Ease", () => { @@ -481,6 +517,10 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } + + /** + * checking if input is correct (might have to use external module) + */ @action checkInput = (val: any) => { return typeof (val === "number"); @@ -495,6 +535,9 @@ export class Keyframe extends React.Component { }); } + /** + * hovering effect when hovered (hidden div darkens) + */ @action onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); @@ -504,6 +547,9 @@ export class Keyframe extends React.Component { Doc.BrushDoc(this.props.node); } + /** + * hovering effect when hovered out (hidden div becomes invisible) + */ @action onContainerOut = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); @@ -520,6 +566,9 @@ export class Keyframe extends React.Component { private _type: string = ""; + /** + * Need to fix this. skip + */ @action onContainerDown = (kf: Doc, type: string) => { let listenerCreated = false; @@ -544,6 +593,9 @@ export class Keyframe extends React.Component { }); } + /** + * for custom draw interpolation. Need to be refactored + */ @action onReactionListen = () => { if (this._reac && this._plotList && this._interpolationKeyframe) { @@ -589,6 +641,13 @@ export class Keyframe extends React.Component { } } + ///////////////////////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) + */ @action drawKeyframes = () => { let keyframeDivs: JSX.Element[] = []; @@ -616,6 +675,9 @@ export class Keyframe extends React.Component { return keyframeDivs; } + /** + * drawing the hidden divs that partition different intervals within a region. + */ @action drawKeyframeDividers = () => { let keyframeDividers: JSX.Element[] = []; @@ -645,6 +707,9 @@ export class Keyframe extends React.Component { return keyframeDividers; } + /** + * rendering that green region + */ render() { return (
    diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index c13a039a5..9cf600b5f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -15,9 +15,32 @@ import { FieldViewProps } from "../nodes/FieldView"; import { KeyframeFunc } from "./Keyframe"; import { Utils } from "../../../Utils"; + +/** + * Timeline class controls most of timeline functions besides individual keyframe and track mechanism. Main functions are + * zooming, panning, currentBarX (scrubber movement). Most of the UI stuff is also handled here. You shouldn't really make + * any logical changes here. Most work is needed on UI. + * + * The hierarchy works this way: + * + * Timeline.tsx --> Track.tsx --> Keyframe.tsx + | | + | TimelineMenu.tsx (timeline's custom contextmenu) + | + | + TimelineOverview.tsx (youtube like dragging thing is play mode, complex dragging thing in editing mode) + + + Most style changes are in SCSS file. + If you have any questions, email me or text me. + @author Andrew Kim + */ + + @observer export class Timeline extends React.Component { - + + //readonly constants private readonly DEFAULT_TICK_SPACING: number = 50; private readonly MAX_TITLE_HEIGHT = 75; @@ -70,38 +93,35 @@ export class Timeline extends React.Component { return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List; } - /** - * - */ + /////////lifecycle functions//////////// componentWillMount() { - let relativeHeight = window.innerHeight / 14; - this._titleHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; - this.MIN_CONTAINER_HEIGHT = this._titleHeight + 130; - this.DEFAULT_CONTAINER_HEIGHT = this._titleHeight * 2 + 130; + let relativeHeight = window.innerHeight / 14; //sets height to arbitrary size, relative to innerHeight + 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 } componentDidMount() { runInAction(() => { - if (!this.props.Document.AnimationLength) { - this.props.Document.AnimationLength = this._time; + if (!this.props.Document.AnimationLength) { //if animation length did not exist + this.props.Document.AnimationLength = this._time; //set it to default time } else { - this._time = NumCast(this.props.Document.AnimationLength); - console.log(this._time); + this._time = NumCast(this.props.Document.AnimationLength); //else, set time to animationlength stored from before } - this._totalLength = this._tickSpacing * (this._time / this._tickIncrement); - this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; - this._visibleStart = this._infoContainer.current!.scrollLeft; - this.props.Document.isATOn = !this.props.Document.isATOn; + 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.toggleHandle(); }); } componentWillUnmount() { runInAction(() => { - console.log(this._time); - this.props.Document.AnimationLength = this._time; + this.props.Document.AnimationLength = this._time; //save animation length }); } + ///////////////////////////////////////////////// /** * React Functional Component @@ -116,7 +136,9 @@ export class Timeline extends React.Component { return ticks; } - + /** + * changes the scrubber to actual pixel position + */ @action changeCurrentBarX = (pixel: number) => { pixel <= 0 ? this._currentBarX = 0 : pixel >= this._totalLength ? this._currentBarX = this._totalLength : this._currentBarX = pixel; @@ -130,6 +152,9 @@ export class Timeline extends React.Component { this.play(); } + /** + * when playbutton is clicked + */ @action play = () => { if (this._isPlaying) { @@ -177,7 +202,9 @@ export class Timeline extends React.Component { } } - + /** + * scrubber down + */ @action onScrubberDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -188,16 +215,22 @@ export class Timeline extends React.Component { }); } + /** + * when there is any scrubber movement + */ @action onScrubberMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); let scrubberbox = this._infoContainer.current!; let left = scrubberbox.getBoundingClientRect().left; - let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; - this.changeCurrentBarX(offsetX + this._visibleStart); + let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; + this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position } + /** + * when panning the timeline (in editing mode) + */ @action onPanDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -223,6 +256,9 @@ export class Timeline extends React.Component { } } + /** + * when moving the timeline (in editing mode) + */ @action onPanMove = (e: PointerEvent) => { e.preventDefault(); @@ -243,6 +279,8 @@ export class Timeline extends React.Component { } } + + @action movePanX = (pixel: number) => { let infoContainer = this._infoContainer.current!; @@ -250,6 +288,9 @@ export class Timeline extends React.Component { this._visibleStart = infoContainer.scrollLeft; } + /** + * resizing timeline (in editing mode) (the hamburger drag icon) + */ @action onResizeDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -274,6 +315,9 @@ export class Timeline extends React.Component { } } + /** + * for displaying time to standard min:sec + */ @action toReadTime = (time: number): string => { const inSeconds = time / 1000; @@ -286,6 +330,11 @@ export class Timeline extends React.Component { return `${min}:${sec}`; } + + /** + * context menu function. + * opens the timeline or closes the timeline. + */ timelineContextMenu = (e: MouseEvent): void => { ContextMenu.Instance.addItem({ description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { @@ -295,6 +344,10 @@ export class Timeline extends React.Component { } + /** + * timeline zoom function + * use mouse middle button to zoom in/out the timeline + */ @action onWheelZoom = (e: React.WheelEvent) => { e.preventDefault(); @@ -311,6 +364,9 @@ export class Timeline extends React.Component { this.changeCurrentBarX(currCurrent); } + /** + * zooming mechanism (increment and spacing changes) + */ @action zoom = (dir: boolean) => { let spacingChange = this._tickSpacing; @@ -340,6 +396,9 @@ export class Timeline extends React.Component { } } + /** + * tool box includes the toggle buttons at the top of the timeline (both editing mode and play mode) + */ private timelineToolBox = (scale: number) => { let size = 40 * scale; //50 is default return ( @@ -359,6 +418,9 @@ export class Timeline extends React.Component { ); } + /** + * manual time input (kinda broken right now) + */ @action private onTimeInput = (e: React.KeyboardEvent) => { if (e.keyCode === 13) { @@ -369,6 +431,10 @@ export class Timeline extends React.Component { } } + + /** + * when the user decides to click the toggle button (either user wants to enter editing mode or play mode) + */ @action private toggleChecked = (e: React.PointerEvent) => { e.preventDefault(); @@ -376,6 +442,9 @@ export class Timeline extends React.Component { this.toggleHandle(); } + /** + * turns on the toggle button (the purple slide button that changes from editing mode and play mode + */ private toggleHandle = () => { let roundToggle = this._roundToggleRef.current!; let roundToggleContainer = this._roundToggleContainerRef.current!; @@ -410,7 +479,9 @@ export class Timeline extends React.Component { } - + /** + * check mark thing that needs to be fixed. Do not edit this, because it most likely change. + */ @action private checkCallBack = (visible: boolean) => { this._checkVisible = visible; @@ -421,12 +492,10 @@ export class Timeline extends React.Component { } - - - - - - + /** + * if you have any question here, just shoot me an email or text. + * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) + */ render() { return (
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index d0bcdd655..d9b8026c5 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -62,9 +62,11 @@ export class Track extends React.Component { @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } + ////////// life cycle functions/////////////// componentWillMount() { runInAction(() => { - if (!this.props.node.regions) this.props.node.regions = new List(); + if (!this.props.node.regions) this.props.node.regions = new List(); //if there is no region, then create new doc to store stuff + //these two lines are exactly same from timeline.tsx let relativeHeight = window.innerHeight / 14; this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness }); @@ -80,6 +82,9 @@ export class Track extends React.Component { }); } + /** + * mainly for disposing reactions + */ componentWillUnmount() { runInAction(() => { //disposing reactions @@ -87,7 +92,11 @@ export class Track extends React.Component { if (this._timelineVisibleReaction) this._timelineVisibleReaction(); }); } + //////////////////////////////// + /** + * keyframe save logic. Needs to be changed so it's more efficient + */ @action saveKeyframe = async (ref: Doc, regiondata: Doc) => { let keyframes: List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); @@ -119,6 +128,9 @@ export class Track extends React.Component { this._isOnKeyframe = false; } + /** + * reverting back to previous state before editing on AT + */ @action revertState = () => { let copyDoc = Doc.MakeCopy(this.props.node, true); @@ -128,6 +140,10 @@ export class Track extends React.Component { this._storedState = newState; } + /** + * Reaction when scrubber bar changes + * made into function so it's easier to dispose later + */ @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { @@ -141,6 +157,10 @@ export class Track extends React.Component { } }); } + + /** + * when timeline is visible, reaction is ran so states are reverted + */ @action timelineVisibleReaction = () => { return reaction(() => { @@ -163,13 +183,9 @@ export class Track extends React.Component { }); } - @action - /** - * Simple loop through all the regions to update the keyframes. Only applies to timelineVisibleReaction + /**w + * when scrubber position changes. Need to edit the logic */ - updateAllRegions = () => { - - } @action timeChange = async (time: number) => { if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { @@ -191,6 +207,10 @@ export class Track extends React.Component { } } + /** + * applying changes (when saving the keyframe) + * need to change the logic here + */ @action private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; @@ -212,6 +232,9 @@ export class Track extends React.Component { + /** + * changing the filter here + */ @action private filterKeys = (keys: string[]): string[] => { return keys.reduce((acc: string[], key: string) => { @@ -220,6 +243,10 @@ export class Track extends React.Component { }, []); } + + /** + * calculating current keyframe, if the scrubber is right on the keyframe + */ @action calcCurrent = async (region: Doc) => { let currentkf: (Doc | undefined) = undefined; @@ -231,6 +258,10 @@ export class Track extends React.Component { } + /** + * interpolation. definetely needs to be changed. (currently involves custom linear splicing interpolations). + * Too complex right now. Also need to apply quadratic spline later on (for smoothness, instead applying "gains") + */ @action interpolate = async (left: Doc, right: Doc, regiondata: Doc) => { let leftNode = left.key as Doc; @@ -290,6 +321,10 @@ export class Track extends React.Component { }); } + /** + * 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?) + */ @action findRegion = async (time: number) => { let foundRegion: (Doc | undefined) = undefined; @@ -303,6 +338,10 @@ export class Track extends React.Component { return foundRegion; } + + /** + * double click on track. Signalling keyframe creation. Problem with phantom regions + */ @action onInnerDoubleClick = (e: React.MouseEvent) => { let inner = this._inner.current!; @@ -311,6 +350,10 @@ export class Track extends React.Component { this.forceUpdate(); } + + /** + * creates a region (KEYFRAME.TSX stuff). + */ createRegion = (position: number) => { let regiondata = KeyframeFunc.defaultKeyframe(); regiondata.position = position; @@ -325,6 +368,11 @@ export class Track extends React.Component { } } + + + /** + * UI sstuff here. Not really much to change + */ render() { return (
    -- cgit v1.2.3-70-g09d2 From b25276d9442f5ae9196a72b4af05849b9e69ef2f Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sat, 11 Jan 2020 15:42:58 +0900 Subject: phantom region fix, scrubber double click, fade kf --- src/client/views/animationtimeline/Keyframe.tsx | 104 +++++++---------------- src/client/views/animationtimeline/Timeline.scss | 2 + src/client/views/animationtimeline/Timeline.tsx | 4 +- src/client/views/animationtimeline/Track.tsx | 26 +++--- 4 files changed, 51 insertions(+), 85 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index c3c1f5f8c..62528483b 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -22,6 +22,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager"; */ export namespace KeyframeFunc { export enum KeyframeType { + end = "end", fade = "fade", default = "default", } @@ -194,8 +195,8 @@ export class Keyframe extends React.Component { if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); let fadeIn = await this.makeKeyData(this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade)!; let fadeOut = await this.makeKeyData(this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade)!; - let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.fade)!; - let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.fade)!; + let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.end)!; + let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end)!; (fadeIn.key! as Doc).opacity = 1; (fadeOut.key! as Doc).opacity = 1; (start.key! as Doc).opacity = 0.1; @@ -206,7 +207,6 @@ export class Keyframe extends React.Component { @action makeKeyData = async (kfpos: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - const batch = UndoManager.StartBatch("makeKeyData"); let doclist = (await DocListCastAsync(this.regiondata.keyframes))!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { @@ -218,19 +218,11 @@ export class Keyframe extends React.Component { TK.key = Doc.MakeCopy(this.props.node, true); TK.type = type; this.regiondata.keyframes!.push(TK); - - // myObservable++; - // UndoManager.AddEvent({ - // undo: action(() => myObservable--), - // redo: action(() => myObservable++) - // }); - let interpolationFunctions = new Doc(); interpolationFunctions.interpolationX = new List([0, 1]); interpolationFunctions.interpolationY = new List([0, 100]); interpolationFunctions.pathX = new List(); interpolationFunctions.pathY = new List(); - this.regiondata.functions!.push(interpolationFunctions); let found: boolean = false; this.regiondata.keyframes!.forEach(compkf => { @@ -244,7 +236,6 @@ export class Keyframe extends React.Component { return; } }); - batch.end(); return TK; } @@ -384,15 +375,6 @@ export class Keyframe extends React.Component { this.props.changeCurrentBarX(KeyframeFunc.convertPixelTime(NumCast(kf.time!), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement)); } - - @action - onKeyframeOver = (e: React.PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.props.node.backgroundColor = "#000000"; - } - - /** * custom keyframe context menu items (when clicking on the keyframe circle) */ @@ -412,7 +394,6 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("input", "Move", (val) => { runInAction(() => { - if (this.checkInput(val)) { let cannotMove: boolean = false; let kfIndex: number = this.keyframes.indexOf(kf); if (val < 0 || (val < NumCast(this.keyframes[kfIndex - 1].time) || val > NumCast(this.keyframes[kfIndex + 1].time))) { @@ -422,7 +403,6 @@ export class Keyframe extends React.Component { this.keyframes[kfIndex].time = parseInt(val, 10); this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } - } }); }); TimelineMenu.Instance.addMenu("Keyframe"); @@ -448,7 +428,6 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("input", `fadeIn: ${this.regiondata.fadeIn}ms`, (val) => { runInAction(() => { - if (this.checkInput(val)) { let cannotMove: boolean = false; if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position) { cannotMove = true; @@ -457,59 +436,52 @@ export class Keyframe extends React.Component { this.regiondata.fadeIn = parseInt(val, 10); this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; } - } }); }), TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => { runInAction(() => { - if (this.checkInput(val)) { - let cannotMove: boolean = false; - if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)) { - cannotMove = true; - } - if (!cannotMove) { - this.regiondata.fadeOut = parseInt(val, 10); - this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - val; - } + let cannotMove: boolean = false; + if (val < 0 || val > this.regiondata.position + this.regiondata.duration - NumCast(this.keyframes[this.keyframes.length - 3].time)) { + cannotMove = true; + } + if (!cannotMove) { + this.regiondata.fadeOut = parseInt(val, 10); + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - val; } }); }), TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => { runInAction(() => { - if (this.checkInput(val)) { - let prevPosition = this.regiondata.position; - let cannotMove: boolean = false; - DocListCast(this.regions).forEach(region => { - if (NumCast(region.position) !== this.regiondata.position) { - if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))) { - cannotMove = true; - } + let prevPosition = this.regiondata.position; + let cannotMove: boolean = false; + DocListCast(this.regions).forEach(region => { + if (NumCast(region.position) !== this.regiondata.position) { + if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))) { + cannotMove = true; } - }); - if (!cannotMove) { - this.regiondata.position = parseInt(val, 10); - this.updateKeyframes(this.regiondata.position - prevPosition); } + }); + if (!cannotMove) { + this.regiondata.position = parseInt(val, 10); + this.updateKeyframes(this.regiondata.position - prevPosition); } }); }), TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { runInAction(() => { - if (this.checkInput(val)) { - let cannotMove: boolean = false; - DocListCast(this.regions).forEach(region => { - if (NumCast(region.position) !== this.regiondata.position) { - val += this.regiondata.position; - if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))) { - cannotMove = true; - } + let cannotMove: boolean = false; + DocListCast(this.regions).forEach(region => { + if (NumCast(region.position) !== this.regiondata.position) { + val += this.regiondata.position; + if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))) { + cannotMove = true; } - }); - if (!cannotMove) { - this.regiondata.duration = parseInt(val, 10); - this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; - this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; } + }); + if (!cannotMove) { + this.regiondata.duration = parseInt(val, 10); + this.keyframes[this.keyframes.length - 1].time = this.regiondata.position + this.regiondata.duration; + this.keyframes[this.keyframes.length - 2].time = this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut; } }); }), @@ -517,15 +489,6 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.openMenu(e.clientX, e.clientY); } - - /** - * checking if input is correct (might have to use external module) - */ - @action - checkInput = (val: any) => { - return typeof (val === "number"); - } - @action updateKeyframes = (incr: number, filter: number[] = []) => { this.keyframes.forEach(kf => { @@ -652,7 +615,7 @@ export class Keyframe extends React.Component { drawKeyframes = () => { let keyframeDivs: JSX.Element[] = []; DocListCast(this.regiondata.keyframes).forEach(kf => { - if (kf.type as KeyframeFunc.KeyframeType === KeyframeFunc.KeyframeType.default) { + if (kf.type as KeyframeFunc.KeyframeType !== KeyframeFunc.KeyframeType.end) { keyframeDivs.push(
    @@ -663,8 +626,7 @@ export class Keyframe extends React.Component { }} onDoubleClick={(e) => { e.preventDefault(); e.stopPropagation(); }}>
    ); - } - else { + } else { keyframeDivs.push(
    diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 493b084a8..76c8475d1 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -109,6 +109,7 @@ position: absolute; z-index: 1001; background-color: black; + pointer-events: none; .scrubberhead { top: -30px; @@ -119,6 +120,7 @@ border: 5px solid black; left: -15px; position: absolute; + pointer-events: all; } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 9cf600b5f..df25f709a 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -504,8 +504,8 @@ export class Timeline extends React.Component {
    {this.drawTicks()} -
    -
    +
    +
    {DocListCast(this.children).map(doc => )} diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index d9b8026c5..2ea3d168f 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -96,6 +96,7 @@ export class Track extends React.Component { /** * keyframe save logic. Needs to be changed so it's more efficient + * */ @action saveKeyframe = async (ref: Doc, regiondata: Doc) => { @@ -354,19 +355,20 @@ export class Track extends React.Component { /** * creates a region (KEYFRAME.TSX stuff). */ - createRegion = (position: number) => { - let regiondata = KeyframeFunc.defaultKeyframe(); - regiondata.position = position; - let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); - - if (rightRegion && rightRegion.position - regiondata.position <= 4000) { - regiondata.duration = rightRegion.position - regiondata.position; - } - if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { - this.regions.push(regiondata); - return regiondata; + createRegion = async (time: number) => { + if (await this.findRegion(time) === undefined){ //check if there is a region where double clicking (prevents phantom regions) + let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data + regiondata.position = time; //set position + let 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 + regiondata.duration = rightRegion.position - regiondata.position; + } + if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { + this.regions.push(regiondata); + return regiondata; + } } - } -- cgit v1.2.3-70-g09d2 From f7123e343024cf5760386c8e872e34e582d2d79e Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sat, 11 Jan 2020 23:36:36 +0900 Subject: autocreate keyframe UNSTABLE --- src/client/views/animationtimeline/Keyframe.tsx | 80 +++++++++++++------------ src/client/views/animationtimeline/Track.tsx | 36 ++++++++++- 2 files changed, 77 insertions(+), 39 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 62528483b..5e4676f56 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -98,6 +98,41 @@ export namespace KeyframeFunc { return regiondata; }; + export const makeKeyData = async (regiondata:RegionData, time: number, badNode:Doc, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + runInAction(async () => { + let doclist = (await DocListCastAsync(regiondata.keyframes))!; + let existingkf: (Doc | undefined) = undefined; + doclist.forEach(TK => { + if (TK.time === time) existingkf = TK; + }); + if (existingkf) return existingkf; + let TK: Doc = new Doc(); + TK.time = time; + TK.key = Doc.MakeCopy(badNode, true); + TK.type = type; + regiondata.keyframes!.push(TK); + let interpolationFunctions = new Doc(); + interpolationFunctions.interpolationX = new List([0, 1]); + interpolationFunctions.interpolationY = new List([0, 100]); + interpolationFunctions.pathX = new List(); + interpolationFunctions.pathY = new List(); + regiondata.functions!.push(interpolationFunctions); + let found: boolean = false; + regiondata.keyframes!.forEach(compkf => { + compkf = compkf as Doc; + if (time < NumCast(compkf.time) && !found) { + runInAction(() => { + regiondata.keyframes!.splice(doclist.indexOf(compkf as Doc), 0, TK); + regiondata.keyframes!.pop(); + found = true; + }); + return; + } + }); + return TK; + }); + }; + export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing: number, tickIncrement: number) => { let time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement; switch (unit) { @@ -193,10 +228,10 @@ export class Keyframe extends React.Component { componentWillMount() { runInAction(async () => { if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - let fadeIn = await this.makeKeyData(this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade)!; - let fadeOut = await this.makeKeyData(this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade)!; - let start = await this.makeKeyData(this.regiondata.position, KeyframeFunc.KeyframeType.end)!; - let finish = await this.makeKeyData(this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end)!; + let fadeIn = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, this.props.node, KeyframeFunc.KeyframeType.fade))! as any as Doc; + let fadeOut = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, this.props.node, KeyframeFunc.KeyframeType.fade))! as any as Doc; + let start = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position, this.props.node, KeyframeFunc.KeyframeType.end))! as any as Doc; + let finish = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, this.props.node, KeyframeFunc.KeyframeType.end))! as any as Doc; (fadeIn.key! as Doc).opacity = 1; (fadeOut.key! as Doc).opacity = 1; (start.key! as Doc).opacity = 0.1; @@ -205,39 +240,7 @@ export class Keyframe extends React.Component { }); } - @action - makeKeyData = async (kfpos: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - let doclist = (await DocListCastAsync(this.regiondata.keyframes))!; - let existingkf: (Doc | undefined) = undefined; - doclist.forEach(TK => { - if (TK.time === kfpos) existingkf = TK; - }); - if (existingkf) return existingkf; - let TK: Doc = new Doc(); - TK.time = kfpos; - TK.key = Doc.MakeCopy(this.props.node, true); - TK.type = type; - this.regiondata.keyframes!.push(TK); - let interpolationFunctions = new Doc(); - interpolationFunctions.interpolationX = new List([0, 1]); - interpolationFunctions.interpolationY = new List([0, 100]); - interpolationFunctions.pathX = new List(); - interpolationFunctions.pathY = new List(); - this.regiondata.functions!.push(interpolationFunctions); - let found: boolean = false; - this.regiondata.keyframes!.forEach(compkf => { - compkf = compkf as Doc; - if (kfpos < NumCast(compkf.time) && !found) { - runInAction(() => { - this.regiondata.keyframes!.splice(doclist.indexOf(compkf as Doc), 0, TK); - this.regiondata.keyframes!.pop(); - found = true; - }); - return; - } - }); - return TK; - } + @action @@ -361,9 +364,10 @@ export class Keyframe extends React.Component { let 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 let position = this.regiondata.position; - await this.makeKeyData(Math.round(position + offset)); + await KeyframeFunc.makeKeyData(this.regiondata, Math.round(position + offset), this.props.node); 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 + } } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 2ea3d168f..c27a24ecf 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun } from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun , toJS} from "mobx"; import "./Track.scss"; import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; @@ -57,6 +57,19 @@ export class Track extends React.Component { "type", "zIndex" ]; + + private whiteList = [ + "data", + "height", + "opacity", + "width", + "x", + "y" + ] + + @observable private whitelist = [ + + ]; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; @@ -79,6 +92,7 @@ export class Track extends React.Component { if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); this.props.node.hidden = false; this.props.node.opacity = 1; + this.autoCreateKeyframe(); }); } @@ -129,6 +143,26 @@ export class Track extends React.Component { this._isOnKeyframe = false; } + /** + * autocreates keyframe + */ + @action + autoCreateKeyframe = async () => { + return reaction(() => [this.props.node.data, this.props.node.height, this.props.node.width, this.props.node.x, this.props.node.y, this.props.node.opacity], async changed => { + console.log("RAN!"); + //convert scrubber pos(pixel) to time + let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + //check for region + let region:(Doc | undefined) = await this.findRegion(time); + if (region !== undefined){ //if region at scrub time exist + if (DocListCast(region!.keyframes).find(kf => {return kf.time === time}) === undefined ){ + console.log("change has occured"); + } + } + + }); + } + /** * reverting back to previous state before editing on AT */ -- cgit v1.2.3-70-g09d2 From 04defabf37c5d3d9165c0ce07fefa43050e70584 Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Wed, 15 Jan 2020 01:38:06 +0900 Subject: autokeyframe still doesn't work --- src/client/views/animationtimeline/Keyframe.tsx | 103 +----------------------- src/client/views/animationtimeline/Timeline.tsx | 2 +- src/client/views/animationtimeline/Track.tsx | 50 ++++++------ 3 files changed, 28 insertions(+), 127 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 5e4676f56..2f2639c76 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -9,7 +9,6 @@ import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; import { Transform } from "../../util/Transform"; -import { InkField, StrokeData } from "../../../new_fields/InkField"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -172,7 +171,6 @@ interface IProps { check: string; changeCurrentBarX: (x: number) => void; transform: Transform; - checkCallBack: (visible: boolean) => void; } @@ -214,17 +212,7 @@ export class Keyframe extends React.Component { @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 inks() { - if (this.props.collection.data_ext) { - let data_ext = Cast(this.props.collection.data_ext, Doc) as Doc; - let ink = Cast(data_ext.ink, InkField) as InkField; - if (ink) { - return ink.inkData; - } - } - } - + componentWillMount() { runInAction(async () => { if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); @@ -418,12 +406,6 @@ export class Keyframe extends React.Component { */ @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { - TimelineMenu.Instance.addItem("button", "Add Ease", () => { - this.onContainerDown(kf, "interpolate"); - }), - TimelineMenu.Instance.addItem("button", "Add Path", () => { - this.onContainerDown(kf, "path"); - }), TimelineMenu.Instance.addItem("button", "Remove Region", () => { runInAction(() => { this.regions.splice(this.regions.indexOf(this.props.RegionData), 1); @@ -525,88 +507,7 @@ export class Keyframe extends React.Component { div.style.opacity = "0"; Doc.UnBrushDoc(this.props.node); } - - - private _reac: (undefined | IReactionDisposer) = undefined; - private _plotList: ([string, StrokeData] | undefined) = undefined; - private _interpolationKeyframe: (Doc | undefined) = undefined; - private _type: string = ""; - - - /** - * Need to fix this. skip - */ - @action - onContainerDown = (kf: Doc, type: string) => { - let listenerCreated = false; - this.props.checkCallBack(true); - this._type = type; - this.props.collection.backgroundColor = "rgb(0,0,0)"; - this._reac = reaction(() => { - return this.inks; - }, data => { - if (!listenerCreated) { - this._plotList = Array.from(data!)[data!.size - 1]!; - this._interpolationKeyframe = kf; - listenerCreated = true; - const reac = reaction(() => { - return this.props.check; - }, () => { - if (this.props.check === "yes") this.onReactionListen(); - reac(); - this.props.checkCallBack(false); - }); - } - }); - } - - /** - * for custom draw interpolation. Need to be refactored - */ - @action - onReactionListen = () => { - if (this._reac && this._plotList && this._interpolationKeyframe) { - this.props.collection.backgroundColor = "#FFF"; - this._reac(); - let xPlots = new List(); - let yPlots = new List(); - let maxY = 0; - let minY = Infinity; - let pathData = this._plotList![1].pathData; - for (let i = 0; i < pathData.length - 1;) { - let val = pathData[i]; - if (val.y > maxY) { - maxY = val.y; - } - if (val.y < minY) { - minY = val.y; - } - xPlots.push(val.x); - yPlots.push(val.y); - let increment = Math.floor(pathData.length / this._gain); - if (pathData.length > this._gain) { - if (i + increment < pathData.length) { - i = i + increment; - } else { - i = pathData.length - 1; - } - } else { - i++; - } - } - let index = this.keyframes.indexOf(this._interpolationKeyframe!); - if (this._type === "interpolate") { - (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationX = xPlots; - (Cast(this.regiondata.functions![index], Doc) as Doc).interpolationY = yPlots; - } else if (this._type === "path") { - (Cast(this.regiondata.functions![index], Doc) as Doc).pathX = xPlots; - (Cast(this.regiondata.functions![index], Doc) as Doc).pathY = yPlots; - } - this._reac = undefined; - this._interpolationKeyframe = undefined; - this._plotList = undefined; - } - } + ///////////////////////UI STUFF ///////////////////////// diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index df25f709a..fedffe8c1 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -508,7 +508,7 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index c27a24ecf..fc8d0852f 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun , toJS} from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun , toJS, isObservableArray, IObservableArray} from "mobx"; import "./Track.scss"; import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; @@ -22,8 +22,6 @@ interface IProps { timelineVisible: boolean; check: string; changeCurrentBarX: (x: number) => void; - checkCallBack: (visible: boolean) => void; - } @observer @@ -58,18 +56,6 @@ export class Track extends React.Component { "zIndex" ]; - private whiteList = [ - "data", - "height", - "opacity", - "width", - "x", - "y" - ] - - @observable private whitelist = [ - - ]; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; @@ -143,24 +129,38 @@ export class Track extends React.Component { this._isOnKeyframe = false; } + + private whitelist = [ + "x", + "y", + "width", + "height", + "data" + ] /** * autocreates keyframe */ @action - autoCreateKeyframe = async () => { - return reaction(() => [this.props.node.data, this.props.node.height, this.props.node.width, this.props.node.x, this.props.node.y, this.props.node.opacity], async changed => { - console.log("RAN!"); + autoCreateKeyframe = async () => { + return reaction(async () => { + return this.whitelist.map(key => this.props.node[key]); + }, (changed, reaction) => { //convert scrubber pos(pixel) to time let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); //check for region - let region:(Doc | undefined) = await this.findRegion(time); - if (region !== undefined){ //if region at scrub time exist - if (DocListCast(region!.keyframes).find(kf => {return kf.time === time}) === undefined ){ - console.log("change has occured"); - } - } + //let region:(Doc | undefined) = await this.findRegion(time); + console.log(this.props.node.x); + console.log(this.props.node.y); + console.log(changed); + // if (region !== undefined){ //if region at scrub time exist + // if (DocListCast(region!.keyframes).find(kf => {return kf.time === time}) === undefined ){ + // console.log("change has occured"); + // } + // } + //reaction.dispose(); }); + } /** @@ -185,7 +185,7 @@ export class Track extends React.Component { let regiondata: (Doc | undefined) = await this.findRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); if (regiondata) { this.props.node.hidden = false; - await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); + //await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } else { this.props.node.hidden = true; this.props.node.opacity = 0; -- cgit v1.2.3-70-g09d2 From b481a3a3d95a7481c785373b9a088c442488dfde Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 14 Jan 2020 17:27:26 -0500 Subject: initial stylistic changes --- src/client/views/animationtimeline/Timeline.scss | 30 +++-- src/client/views/animationtimeline/Timeline.tsx | 18 +-- .../views/animationtimeline/TimelineOverview.scss | 138 +++++++++++---------- 3 files changed, 97 insertions(+), 89 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 76c8475d1..83988e324 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -1,6 +1,6 @@ @import "./../globalCssVariables.scss"; - +$timelineColor: #9acedf; .timeline-toolbox { position: absolute; @@ -13,6 +13,10 @@ align-items: center; top: 20px; + .timeline-icon { + color: $timelineColor; + } + div { padding: 0px; margin-left: 10px; @@ -24,7 +28,7 @@ width: auto; white-space: nowrap; font-size: 16px; - color: grey; + color: black; letter-spacing: 2px; text-transform: uppercase; } @@ -33,7 +37,7 @@ height: 40px; width: 80px; background-color: white; - border: 2px solid grey; + border: 2px solid black; border-radius: 20px; animation-fill-mode: forwards; animation-duration: 500ms; @@ -50,7 +54,7 @@ height: 35px; width: 35px; background-color: white; - border: 1px solid grey; + border: 1px solid black; border-radius: 20px; transition: transform 500ms ease-in-out; margin-left: 0px; @@ -65,7 +69,7 @@ width: 120px; white-space: nowrap; font-size: 16px; - color: grey; + color: black; letter-spacing: 2px; text-transform: uppercase; padding-left: 5px; @@ -112,13 +116,13 @@ pointer-events: none; .scrubberhead { - top: -30px; - height: 30px; - width: 30px; - background-color: transparent; + top: -20px; + height: 20px; + width: 20px; + background-color: white; border-radius: 50%; - border: 5px solid black; - left: -15px; + border: 3px solid black; + left: -9px; position: absolute; pointer-events: all; } @@ -132,7 +136,7 @@ overflow: hidden; background-color: white; position: absolute; - box-shadow: -10px 0px 10px 10px grey; + // box-shadow: -10px 0px 10px 10px red; } } @@ -156,7 +160,7 @@ float: left; border-style: solid; overflow-y: scroll; - overflow-x: hidden; + overflow-x: hidden; } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index fedffe8c1..589470111 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -8,7 +8,7 @@ import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faPlayCircle, faBackward, faForward, faGripLines,faPauseCircle, faEyeSlash,faEye,faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; +import { faPlayCircle, faBackward, faForward, faGripLines, faPauseCircle, faEyeSlash, faEye, faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; import { ContextMenu } from "../ContextMenu"; import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; @@ -43,14 +43,14 @@ export class Timeline extends React.Component { //readonly constants private readonly DEFAULT_TICK_SPACING: number = 50; - private readonly MAX_TITLE_HEIGHT = 75; + private readonly MAX_TITLE_HEIGHT = 75; private readonly MAX_CONTAINER_HEIGHT: number = 800; private readonly DEFAULT_TICK_INCREMENT: number = 1000; //height variables private DEFAULT_CONTAINER_HEIGHT: number = 330; private MIN_CONTAINER_HEIGHT: number = 205; - + //react refs @observable private _trackbox = React.createRef(); @observable private _titleContainer = React.createRef(); @@ -224,7 +224,7 @@ export class Timeline extends React.Component { e.stopPropagation(); let scrubberbox = this._infoContainer.current!; let left = scrubberbox.getBoundingClientRect().left; - let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; + let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position } @@ -403,9 +403,9 @@ export class Timeline extends React.Component { let size = 40 * scale; //50 is default return (
    -
    -
    -
    +
    +
    +
    Timeline Overview
    Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}
    @@ -460,7 +460,7 @@ export class Timeline extends React.Component { roundToggle.style.transform = "translate(45px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; - roundToggleContainer.style.backgroundColor = "green"; + roundToggleContainer.style.backgroundColor = "#9acedf"; timelineContainer.style.top = "0px"; this.props.Document.isATOn = true; } @@ -499,7 +499,7 @@ export class Timeline extends React.Component { render() { return (
    -
    +
    diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index c7f9bd059..c643b978b 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -1,85 +1,89 @@ -@import "./../globalCssVariables.scss"; +@import "./../globalCssVariables.scss"; +$timelineColor: #9acedf; -.timeline-overview-container{ - padding: 0px; - margin: 0px; - width: 300px; +.timeline-overview-container { + padding: 0px; + margin: 0px; + width: 300px; height: 40px; - background: white; - position: relative; - border: 2px solid black; - - .timeline-overview-visible{ - position: absolute; - height: 100%; - background: green; + background: white; + position: relative; + border: 2px solid black; + + .timeline-overview-visible { + position: absolute; + height: 98%; + background: $timelineColor; display: inline-block; - margin: 0px; - padding: 0px; + margin: 0px; + padding: 0px; } - .timeline-overview-scrubber-container{ - margin: 0px; - padding: 0px; - position: absolute; + + .timeline-overview-scrubber-container { + margin: 0px; + padding: 0px; + position: absolute; height: 100%; - width: 2px; - top: 0px; - left: 0px; + width: 2px; + top: 0px; + left: 0px; z-index: 1001; - background-color:black; - display: inline-block; + background-color: black; + display: inline-block; - .timeline-overview-scrubber-head{ - padding: 0px; - margin: 0px; - position:absolute; - height: 30px; - width: 30px; - background-color:transparent; - border-radius: 50%; - border: 5px solid black; - left: -15px; - top: -30px; + .timeline-overview-scrubber-head { + padding: 0px; + margin: 0px; + position: absolute; + height: 10px; + width: 10px; + // background-color: black; + border-radius: 50%; + // border: 3px solid black; + left: -4px; + // top: -30px; + top: -10px; } } } -.timeline-play-bar{ - position: relative; - padding: 0px; - margin: 0px; - width: 300px; - height: 4px; - background-color: grey; +.timeline-play-bar { + position: relative; + padding: 0px; + margin: 0px; + width: 300px; + height: 4px; + background-color: $timelineColor; border-radius: 20px; - cursor: pointer; - - .timeline-play-head{ - position: absolute; - padding: 0px; - margin: 0px; - width: 20px; - height: 20px; - border-radius: 50%; - background-color: white; - border: 3px grey solid; - left: 0px; - top: -10px; - cursor: pointer; + cursor: pointer; + + .timeline-play-head { + position: absolute; + padding: 0px; + margin: 0px; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: white; + border: 3px $timelineColor; + left: 0px; + top: -10px; + cursor: pointer; } -} -.timeline-play-tail{ - position: absolute; - padding: 0px; - margin: 0px; - height: 4px; - width: 0px; - z-index: 1000; - background-color: green; +} + +.timeline-play-tail { + position: absolute; + padding: 0px; + margin: 0px; + height: 4px; + width: 0px; + z-index: 1000; + background-color: $timelineColor; border-radius: 20px; - margin-top: -4px; - cursor: pointer; + margin-top: -4px; + cursor: pointer; } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 95e321930a5e6f5a6fd86047542615dff49813f2 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 14 Jan 2020 19:35:47 -0500 Subject: color fixes --- src/client/views/animationtimeline/Timeline.scss | 9 ++++++++- src/client/views/animationtimeline/Timeline.tsx | 4 ++-- src/client/views/animationtimeline/TimelineOverview.scss | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 83988e324..060627c17 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -54,7 +54,7 @@ $timelineColor: #9acedf; height: 35px; width: 35px; background-color: white; - border: 1px solid black; + border: 3px solid black; border-radius: 20px; transition: transform 500ms ease-in-out; margin-left: 0px; @@ -80,6 +80,13 @@ $timelineColor: #9acedf; height: 100%; width: 1px; background-color: black; + color: black; +} + +.number-label { + color: black; + padding-left: 5px; + } .timeline-container { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 589470111..2332b4d5f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -131,7 +131,7 @@ export class Timeline extends React.Component { drawTicks = () => { let ticks = []; for (let i = 0; i < this._time / this._tickIncrement; i++) { - ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); + ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); } return ticks; } @@ -457,7 +457,7 @@ export class Timeline extends React.Component { timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isATOn = false; } else { - roundToggle.style.transform = "translate(45px, 0px)"; + roundToggle.style.transform = "translate(40px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; roundToggleContainer.style.backgroundColor = "#9acedf"; diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index c643b978b..3517d3f39 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -38,7 +38,7 @@ $timelineColor: #9acedf; position: absolute; height: 10px; width: 10px; - // background-color: black; + background-color: black; border-radius: 50%; // border: 3px solid black; left: -4px; @@ -68,9 +68,9 @@ $timelineColor: #9acedf; height: 20px; border-radius: 50%; background-color: white; - border: 3px $timelineColor; + border: 3px solid $timelineColor; left: 0px; - top: -10px; + top: -8px; cursor: pointer; } } -- cgit v1.2.3-70-g09d2 From da6ce86f604ad5a6e7857f073ebba0095fc5d467 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 14 Jan 2020 20:02:57 -0500 Subject: more minor changes --- src/client/views/animationtimeline/Timeline.scss | 20 ++++++++++++-------- src/client/views/animationtimeline/Timeline.tsx | 7 ++++--- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 060627c17..02c1bdb16 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -1,6 +1,7 @@ @import "./../globalCssVariables.scss"; $timelineColor: #9acedf; +$timelineDark: #77a1aa; .timeline-toolbox { position: absolute; @@ -78,15 +79,15 @@ $timelineColor: #9acedf; .tick { height: 100%; - width: 1px; + width: 2px; background-color: black; color: black; } .number-label { color: black; - padding-left: 5px; - + transform: rotate(-90deg) translate(-15px, 8px); + font-size: .85em; } .timeline-container { @@ -94,7 +95,7 @@ $timelineColor: #9acedf; height: 300px; position: absolute; background-color: $light-color-secondary; - box-shadow: 0px 10px 20px; + border-bottom: 2px solid $timelineDark; transition: transform 500ms ease; .info-container { @@ -139,7 +140,7 @@ $timelineColor: #9acedf; top: 30px; height: calc(100% - 30px); width: 100%; - border: 1px; + border: 2px solid black; overflow: hidden; background-color: white; position: absolute; @@ -155,6 +156,9 @@ $timelineColor: #9acedf; width: 100px; background-color: white; overflow: hidden; + border-left: 2px solid black; + border-top: 2px solid black; + border-bottom: 2px solid black; .datapane { top: 0px; @@ -172,10 +176,10 @@ $timelineColor: #9acedf; } .resize { - bottom: 5px; + bottom: 0px; position: absolute; - height: 30px; - width: 50px; + height: 20px; + width: 40px; left: calc(50% - 25px); } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 2332b4d5f..37d93f6c1 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -401,11 +401,12 @@ export class Timeline extends React.Component { */ private timelineToolBox = (scale: number) => { let size = 40 * scale; //50 is default + let iconSize = 25; return (
    -
    -
    -
    +
    +
    +
    Timeline Overview
    Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}
    -- cgit v1.2.3-70-g09d2 From 68a8c2bdbeafc7bc799884a6c1dcea86dbfd9f27 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Fri, 24 Jan 2020 15:04:59 -0500 Subject: change branch --- src/client/views/animationtimeline/Timeline.scss | 92 ++++++++--- src/client/views/animationtimeline/Timeline.tsx | 88 ++++++++-- .../views/animationtimeline/TimelineOverview.scss | 29 ++-- .../views/animationtimeline/TimelineOverview.tsx | 180 ++++++++++++++------- 4 files changed, 284 insertions(+), 105 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 02c1bdb16..a8dd9b9e7 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -10,39 +10,79 @@ $timelineDark: #77a1aa; display: flex; align-items: flex-start; flex-direction: row; - justify-content: space-evenly; + // justify-content: space-evenly; align-items: center; - top: 20px; + top: 3px; + width: 100%; - .timeline-icon { - color: $timelineColor; + .overview-tool { + display: flex; + justify-content: center; } - div { - padding: 0px; + .playbackControls { + display: flex; + margin-left: 30px; + max-width: 84px; + width: 84px; + + .timeline-icon { + color: $timelineColor; + margin-left: 3px; + } + + } + + .grid-box { + display: grid; + grid-template-columns: [first] 50% [line2] 25% [line3] 25%; + width: calc(100% - 150px); + // width: 100%; margin-left: 10px; + + .time-box { + margin-left: 5px; + display: flex; + } + + .mode-box { + display: flex; + margin-left: 5px; + } + + .overview-box { + width: 100%; + display: flex; + } + + div { + padding: 0px; + // margin-left: 10px; + } } .animation-text { - font-size: 20px; + // font-size: 16px; height: auto; width: auto; white-space: nowrap; - font-size: 16px; + font-size: 14px; color: black; letter-spacing: 2px; text-transform: uppercase; } .round-toggle { - height: 40px; - width: 80px; + height: 20px; + width: 40px; + min-width: 40px; background-color: white; - border: 2px solid black; + border: 2px solid $timelineDark; border-radius: 20px; animation-fill-mode: forwards; animation-duration: 500ms; top: 30px; + margin-left: 5px; input { position: absolute; @@ -52,29 +92,30 @@ $timelineDark: #77a1aa; } .round-toggle-slider { - height: 35px; - width: 35px; + height: 17px; + width: 17px; background-color: white; - border: 3px solid black; - border-radius: 20px; + border: 2px solid $timelineDark; + border-radius: 50%; transition: transform 500ms ease-in-out; margin-left: 0px; - margin-top: 0.5px; + // margin-top: 0.5px; } } } .time-input { - height: 40px; - width: 120px; + height: 20px; + // width: 120px; + width: 100%; white-space: nowrap; - font-size: 16px; + font-size: 12px; color: black; letter-spacing: 2px; text-transform: uppercase; padding-left: 5px; - + margin-left: 5px; } .tick { @@ -99,7 +140,7 @@ $timelineDark: #77a1aa; transition: transform 500ms ease; .info-container { - margin-top: 80px; + margin-top: 50px; right: 20px; position: absolute; height: calc(100% - 100px); @@ -138,9 +179,12 @@ $timelineDark: #77a1aa; .trackbox { top: 30px; + // TODO: where is this 30px coming from? height: calc(100% - 30px); + // height: 100%; width: 100%; - border: 2px solid black; + border-top: 2px solid black; + border-bottom: 2px solid black; overflow: hidden; background-color: white; position: absolute; @@ -150,7 +194,7 @@ $timelineDark: #77a1aa; } .title-container { - margin-top: 110px; + margin-top: 80px; margin-left: 20px; height: calc(100% - 100px - 30px); width: 100px; @@ -159,6 +203,7 @@ $timelineDark: #77a1aa; border-left: 2px solid black; border-top: 2px solid black; border-bottom: 2px solid black; + border-right: 2px solid $timelineDark; .datapane { top: 0px; @@ -181,6 +226,7 @@ $timelineDark: #77a1aa; height: 20px; width: 40px; left: calc(50% - 25px); + color: $timelineDark; } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 37d93f6c1..e6201d431 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -3,7 +3,7 @@ import "./Timeline.scss"; import { listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, action, computed, runInAction } from "mobx"; +import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; @@ -77,6 +77,11 @@ export class Timeline extends React.Component { @observable private _doubleClickEnabled = false; @observable private _titleHeight = 0; + // so a reaction can be made + @observable public _isAuthoring = this.props.Document.isATOn; + @observable private _resizeReaction?: IReactionDisposer; + @observable private _panelWidth = 0; + /** * collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit. */ @@ -114,6 +119,19 @@ export class Timeline extends React.Component { this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on this.toggleHandle(); }); + + this._resizeReaction = reaction( + () => this.props.PanelWidth, + () => { + // if (!this.props.parent._isAuthoring) { + // runInAction(() => { + console.log("resizing"); + // this.setOverviewWidth(); + // }); + // } + }, + ); + } componentWillUnmount() { @@ -402,19 +420,58 @@ export class Timeline extends React.Component { private timelineToolBox = (scale: number) => { let size = 40 * scale; //50 is default let iconSize = 25; + + //decides if information should be omitted because the timeline is very small + // if its less than 950 pixels then it's going to be overlapping + let shouldCompress = false; + let width: number = this.props.PanelWidth(); + if (width < 850) { + shouldCompress = true; + } + + let modeString, overviewString, lengthString; + let modeType = this.props.Document.isATOn ? "Author" : "Play"; + + if (!shouldCompress) { + modeString = "Mode: " + modeType; + overviewString = "Overview:"; + lengthString = "Length: "; + } + else { + modeString = modeType; + overviewString = ""; + lengthString = ""; + } + + + // let modeType: string = this.props.Document.isATOn ? "Author" : "Play"; + // let modeString: string = "Mode: " + modeType; + // let overviewString: string = "Overview:"; + // let lengthString: string = "Length: "; + return (
    -
    -
    -
    -
    Timeline Overview
    - -
    Mode: {this.props.Document.isATOn ? "Authoring" : "Play"}
    -
    -
    +
    +
    +
    +
    +
    +
    +
    +
    {overviewString}
    + +
    +
    +
    {modeString}
    +
    +
    +
    +
    +
    +
    {lengthString}
    + +
    -
    Length:
    -
    ); } @@ -457,13 +514,15 @@ export class Timeline extends React.Component { roundToggleContainer.style.backgroundColor = "white"; timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isATOn = false; + this._isAuthoring = false; } else { - roundToggle.style.transform = "translate(40px, 0px)"; + roundToggle.style.transform = "translate(20px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; roundToggleContainer.style.backgroundColor = "#9acedf"; timelineContainer.style.top = "0px"; this.props.Document.isATOn = true; + this._isAuthoring = true; } } @@ -498,6 +557,11 @@ export class Timeline extends React.Component { * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { + console.log(this.props.PanelWidth()); + runInAction(() => { + this._panelWidth = this.props.PanelWidth(); + console.log("changing!!") + }); return (
    diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index 3517d3f39..a0b9d462b 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -1,23 +1,34 @@ @import "./../globalCssVariables.scss"; $timelineColor: #9acedf; +$timelineDark: #77a1aa; + +.timelineOverview-bounding { + width: 100%; + margin-right: 10px; +} .timeline-overview-container { - padding: 0px; - margin: 0px; - width: 300px; - height: 40px; + // padding: 0px; + margin-right: 5px; + // margin: 0px; + margin-left: 5px; + // width: 300px; + width: 100%; + height: 25px; background: white; position: relative; - border: 2px solid black; + border: 2px solid $timelineDark; + // width: 100%; .timeline-overview-visible { position: absolute; - height: 98%; + height: 21px; background: $timelineColor; display: inline-block; margin: 0px; padding: 0px; + // top: 1px; } .timeline-overview-scrubber-container { @@ -38,9 +49,9 @@ $timelineColor: #9acedf; position: absolute; height: 10px; width: 10px; - background-color: black; + background-color: white; border-radius: 50%; - // border: 3px solid black; + border: 2px solid black; left: -4px; // top: -30px; top: -10px; @@ -54,7 +65,7 @@ $timelineColor: #9acedf; position: relative; padding: 0px; margin: 0px; - width: 300px; + width: 100%; height: 4px; background-color: $timelineColor; border-radius: 20px; diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 4741969dc..4907a1ae1 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -1,101 +1,159 @@ -import * as React from "react"; -import {observable, action} from "mobx"; -import {observer} from "mobx-react"; -import "./TimelineOverview.scss"; +import * as React from "react"; +import { observable, action, computed, runInAction, reaction, IReactionDisposer } from "mobx"; +import { observer } from "mobx-react"; +import "./TimelineOverview.scss"; +import * as $ from 'jquery'; +import { Timeline } from "./Timeline"; - -interface TimelineOverviewProps{ - totalLength: number; - visibleLength:number; - visibleStart:number; - currentBarX:number; - isAuthoring: boolean; - changeCurrentBarX: (pixel:number) => void; - movePanX: (pixel:number) => any; +interface TimelineOverviewProps { + totalLength: number; + visibleLength: number; + visibleStart: number; + currentBarX: number; + isAuthoring: boolean; + parent: Timeline; + changeCurrentBarX: (pixel: number) => void; + movePanX: (pixel: number) => any; } @observer export class TimelineOverview extends React.Component{ - @observable private _visibleRef = React.createRef(); - @observable private _scrubberRef = React.createRef(); - private readonly DEFAULT_HEIGHT = 50; - private readonly DEFAULT_WIDTH = 300; + @observable private _visibleRef = React.createRef(); + @observable private _scrubberRef = React.createRef(); + @observable private overviewBarWidth: number = 0; + @observable private _authoringReaction?: IReactionDisposer; + @observable private _resizeReaction?: IReactionDisposer; + private readonly DEFAULT_HEIGHT = 50; + private readonly DEFAULT_WIDTH = 300; + + componentDidMount = () => { + this.setOverviewWidth(); + + this._authoringReaction = reaction( + () => this.props.parent._isAuthoring, + () => { + if (!this.props.parent._isAuthoring) { + runInAction(() => { + this.setOverviewWidth(); + }); + } + }, + ); + // this._resizeReaction = reaction( + // () => this.props.parent.props.PanelWidth, + // () => { + // // if (!this.props.parent._isAuthoring) { + // // runInAction(() => { + // console.log("resizing"); + // this.setOverviewWidth(); + // // }); + // // } + // }, + // ); + } + + componentWillUnmount = () => { + this._authoringReaction && this._authoringReaction(); + this._resizeReaction && this._resizeReaction(); + } @action - onPointerDown = (e:React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - document.removeEventListener("pointermove", this.onPanX); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointermove", this.onPanX); - document.addEventListener("pointerup", this.onPointerUp); + setOverviewWidth() { + let width = $("#timelineOverview").width(); + if (width) this.overviewBarWidth = width; + else this.overviewBarWidth = 0; + } + + @action + onPointerDown = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + document.removeEventListener("pointermove", this.onPanX); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointermove", this.onPanX); + document.addEventListener("pointerup", this.onPointerUp); } @action onPanX = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - let movX = (this.props.visibleStart / this.props.totalLength)* (this.DEFAULT_WIDTH) + e.movementX; - this.props.movePanX((movX / (this.DEFAULT_WIDTH )) * this.props.totalLength); + e.stopPropagation(); + e.preventDefault(); + let movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX; + // let movX = (this.props.visibleStart / this.props.totalLength) * (this.overviewWidth) + e.movementX; + this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength); + // this.props.movePanX((movX / (this.overviewWidth) * this.props.totalLength); + + // console.log(this.props.totalLength); } @action onPointerUp = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - document.removeEventListener("pointermove", this.onPanX); - document.removeEventListener("pointerup", this.onPointerUp); + e.stopPropagation(); + e.preventDefault(); + document.removeEventListener("pointermove", this.onPanX); + document.removeEventListener("pointerup", this.onPointerUp); } @action - onScrubberDown = ( e:React.PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - document.removeEventListener("pointermove", this.onScrubberMove); - document.removeEventListener("pointerup", this.onScrubberUp); - document.addEventListener("pointermove", this.onScrubberMove); + onScrubberDown = (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.removeEventListener("pointermove", this.onScrubberMove); + document.removeEventListener("pointerup", this.onScrubberUp); + document.addEventListener("pointermove", this.onScrubberMove); document.addEventListener("pointerup", this.onScrubberUp); } @action onScrubberMove = (e: PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - let scrubberRef = this._scrubberRef.current!; - let left = scrubberRef.getBoundingClientRect().left; - let offsetX = Math.round(e.clientX - left); - this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); + e.preventDefault(); + e.stopPropagation(); + let scrubberRef = this._scrubberRef.current!; + let left = scrubberRef.getBoundingClientRect().left; + let offsetX = Math.round(e.clientX - left); + this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); } @action - onScrubberUp = (e:PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - document.removeEventListener("pointermove", this.onScrubberMove); + onScrubberUp = (e: PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + document.removeEventListener("pointermove", this.onScrubberMove); document.removeEventListener("pointerup", this.onScrubberUp); } - render(){ + render() { + // calculates where everything should fall based on its size + let percentVisible = this.props.visibleLength / this.props.totalLength; + let visibleBarWidth = percentVisible * this.overviewBarWidth; + + let percentScrubberStart = this.props.currentBarX / this.props.totalLength; + let scrubberStart = percentScrubberStart * this.overviewBarWidth; + + let percentBarStart = this.props.visibleStart / this.props.totalLength; + let barStart = percentBarStart * this.overviewBarWidth; + let timeline = this.props.isAuthoring ? [ -
    -
    , -
    + +
    +
    , +
    -
    +
    ] : [ -
    -
    -
    , -
    - ]; - return( -
    +
    +
    +
    , +
    + ]; + return ( +
    {timeline}
    - ); + ); } } -- cgit v1.2.3-70-g09d2 From e73bc263f7e0b6bc8efc62302785c5e3d82ce799 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 29 Jan 2020 16:43:14 -0500 Subject: switch --- src/client/views/animationtimeline/Track.tsx | 79 +++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- 2 files changed, 41 insertions(+), 40 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index fc8d0852f..1ca8022a1 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun , toJS, isObservableArray, IObservableArray} from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun, toJS, isObservableArray, IObservableArray, trace } from "mobx"; import "./Track.scss"; import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; @@ -43,20 +43,20 @@ export class Track extends React.Component { "baseLayout", "backgroundLayout", "layout", - "title", - "AnimationLength", - "author", - "baseProto", - "creationDate", - "isATOn", - "isPrototype", - "lastOpened", - "proto", - "type", + "title", + "AnimationLength", + "author", + "baseProto", + "creationDate", + "isATOn", + "isPrototype", + "lastOpened", + "proto", + "type", "zIndex" ]; - private readonly MAX_TITLE_HEIGHT = 75; + private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } @@ -78,7 +78,7 @@ export class Track extends React.Component { if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); this.props.node.hidden = false; this.props.node.opacity = 1; - this.autoCreateKeyframe(); + this.autoCreateKeyframe(); }); } @@ -131,28 +131,29 @@ export class Track extends React.Component { private whitelist = [ - "x", - "y", - "width", - "height", + "x", + "y", + "width", + "height", "data" ] /** * autocreates keyframe */ - @action - autoCreateKeyframe = async () => { - return reaction(async () => { - return this.whitelist.map(key => this.props.node[key]); - }, (changed, reaction) => { + @action + autoCreateKeyframe = () => { + const { node } = this.props; + return reaction(() => { + return this.whitelist.map(key => node[key]); + }, (changed, reaction) => { //convert scrubber pos(pixel) to time - let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); //check for region - //let region:(Doc | undefined) = await this.findRegion(time); - console.log(this.props.node.x); - console.log(this.props.node.y); - console.log(changed); - + this.findRegion(time).then((region) => { + console.log(changed); + }); + + // if (region !== undefined){ //if region at scrub time exist // if (DocListCast(region!.keyframes).find(kf => {return kf.time === time}) === undefined ){ // console.log("change has occured"); @@ -160,7 +161,7 @@ export class Track extends React.Component { // } //reaction.dispose(); }); - + } /** @@ -199,21 +200,21 @@ export class Track extends React.Component { @action timelineVisibleReaction = () => { return reaction(() => { - return this.props.timelineVisible; + return this.props.timelineVisible; }, isVisible => { this.revertState(); - if (isVisible){ + if (isVisible) { DocListCast(this.regions).forEach(region => { - if (!BoolCast((Cast(region, Doc) as Doc).hasData)){ - for (let i = 0; i < 4; i++){ - DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); - if (i === 0 || i === 3){ + if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { + for (let i = 0; i < 4; i++) { + DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); + if (i === 0 || i === 3) { DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key.opacity = 0.1; } } - console.log("saving keyframes"); + console.log("saving keyframes"); } - }); + }); } }); } @@ -390,11 +391,11 @@ export class Track extends React.Component { * creates a region (KEYFRAME.TSX stuff). */ createRegion = async (time: number) => { - if (await this.findRegion(time) === undefined){ //check if there is a region where double clicking (prevents phantom regions) + if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data regiondata.position = time; //set position let 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 regiondata.duration = rightRegion.position - regiondata.position; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c85b59488..81d176efd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -26,7 +26,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { _disposer: IReactionDisposer | undefined = undefined; get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive - get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } + get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px)`; } get X() { return this._animPos !== undefined ? this._animPos[0] : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } get Y() { return this._animPos !== undefined ? this._animPos[1] : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.dataProvider && this.dataProvider ? this.dataProvider.width : this.layoutDoc[WidthSym](); } -- cgit v1.2.3-70-g09d2 From 2320240229cd8e89e8f5abe917053caad7bf38c2 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sat, 1 Feb 2020 13:50:32 -0500 Subject: overveiw resize --- src/client/views/animationtimeline/Timeline.tsx | 18 ++++++++++++++++-- .../views/animationtimeline/TimelineOverview.tsx | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e6201d431..8b943f209 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -449,6 +449,9 @@ export class Timeline extends React.Component { // let overviewString: string = "Overview:"; // let lengthString: string = "Length: "; + console.log("visible: " + this._visibleLength) + console.log("total: " + this._totalLength) + return (
    @@ -459,7 +462,7 @@ export class Timeline extends React.Component {
    {overviewString}
    - +
    {modeString}
    @@ -551,17 +554,28 @@ export class Timeline extends React.Component { } + @action.bound + changeLenths() { + if (this._infoContainer.current) { + 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 + } + } + /** * if you have any question here, just shoot me an email or text. * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { - console.log(this.props.PanelWidth()); + // console.log(this.props.PanelWidth()); runInAction(() => { this._panelWidth = this.props.PanelWidth(); + this.changeLenths(); console.log("changing!!") }); + + // change visible and total width return (
    diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 4907a1ae1..caa97bb70 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -15,6 +15,7 @@ interface TimelineOverviewProps { parent: Timeline; changeCurrentBarX: (pixel: number) => void; movePanX: (pixel: number) => any; + panelWidth: number; } @@ -125,8 +126,11 @@ export class TimelineOverview extends React.Component{ } render() { + + console.log("helo") // calculates where everything should fall based on its size let percentVisible = this.props.visibleLength / this.props.totalLength; + console.log(this.props.visibleLength) let visibleBarWidth = percentVisible * this.overviewBarWidth; let percentScrubberStart = this.props.currentBarX / this.props.totalLength; -- cgit v1.2.3-70-g09d2 From a23aa80dcb4c0278091de6a619a195072a564a7c Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 1 Feb 2020 13:50:37 -0500 Subject: some cleanup --- src/client/views/animationtimeline/Keyframe.tsx | 1 + src/client/views/animationtimeline/Track.tsx | 162 +++++++++--------------- 2 files changed, 64 insertions(+), 99 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 2f2639c76..9f4d80d2b 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -99,6 +99,7 @@ export namespace KeyframeFunc { export const makeKeyData = async (regiondata:RegionData, time: number, badNode:Doc, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time runInAction(async () => { + console.log("ran"); let doclist = (await DocListCastAsync(regiondata.keyframes))!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 1ca8022a1..6d9cfe55c 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -33,33 +33,17 @@ export class Track extends React.Component { @observable private _onKeyframe: (Doc | undefined) = undefined; @observable private _onRegionData: (Doc | undefined) = undefined; @observable private _storedState: (Doc | undefined) = undefined; - @observable private filterList = [ - "regions", - "cursors", - "hidden", - "nativeHeight", - "nativeWidth", - "schemaColumns", - "baseLayout", - "backgroundLayout", - "layout", - "title", - "AnimationLength", - "author", - "baseProto", - "creationDate", - "isATOn", - "isPrototype", - "lastOpened", - "proto", - "type", - "zIndex" - ]; - private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; - + private whitelist = [ + "x", + "y", + "width", + "height", + "data" + ]; @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } + // @computed private get time() {} ////////// life cycle functions/////////////// componentWillMount() { @@ -78,7 +62,7 @@ export class Track extends React.Component { if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); this.props.node.hidden = false; this.props.node.opacity = 1; - this.autoCreateKeyframe(); + // this.autoCreateKeyframe(); }); } @@ -130,13 +114,6 @@ export class Track extends React.Component { } - private whitelist = [ - "x", - "y", - "width", - "height", - "data" - ] /** * autocreates keyframe */ @@ -146,22 +123,20 @@ export class Track extends React.Component { return reaction(() => { return this.whitelist.map(key => node[key]); }, (changed, reaction) => { + console.log(changed); //convert scrubber pos(pixel) to time let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); //check for region this.findRegion(time).then((region) => { - console.log(changed); + if (region !== undefined){ //if region at scrub time exist + let r = region as any as RegionData; //for some region is returning undefined... which is not the case + if (DocListCast(r.keyframes).find(kf => kf.time === time) === undefined ){ //basically when there is no additional keyframe at that timespot + KeyframeFunc.makeKeyData(r, time, this.props.node, KeyframeFunc.KeyframeType.default); + } + } + // reaction.dispose(); }); - - - // if (region !== undefined){ //if region at scrub time exist - // if (DocListCast(region!.keyframes).find(kf => {return kf.time === time}) === undefined ){ - // console.log("change has occured"); - // } - // } - //reaction.dispose(); }); - } /** @@ -186,7 +161,7 @@ export class Track extends React.Component { let regiondata: (Doc | undefined) = await this.findRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); if (regiondata) { this.props.node.hidden = false; - //await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); + await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } else { this.props.node.hidden = true; this.props.node.opacity = 0; @@ -267,19 +242,6 @@ export class Track extends React.Component { } - - /** - * changing the filter here - */ - @action - private filterKeys = (keys: string[]): string[] => { - return keys.reduce((acc: string[], key: string) => { - if (!this.filterList.includes(key)) acc.push(key); - return acc; - }, []); - } - - /** * calculating current keyframe, if the scrubber is right on the keyframe */ @@ -302,50 +264,52 @@ export class Track extends React.Component { interpolate = async (left: Doc, right: Doc, regiondata: Doc) => { let leftNode = left.key as Doc; let rightNode = right.key as Doc; - const dif_time = NumCast(right.time) - NumCast(left.time); - const timeratio = (KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement) - NumCast(left.time)) / dif_time; //linear - let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; - let indexLeft = keyframes.indexOf(left); - let interY: List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; - let realIndex = (interY.length - 1) * timeratio; - let xIndex = Math.floor(realIndex); - let yValue = interY[xIndex]; - let secondYOffset: number = yValue; - let minY = interY[0]; // for now - let maxY = interY[interY.length - 1]; //for now - if (interY.length !== 1) { - secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; - } - let finalRatio = secondYOffset / (maxY - minY); - let pathX: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; - let pathY: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; - let proposedX = 0; - let proposedY = 0; - if (pathX.length !== 0) { - let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); - let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); - if (pathCorrespondingIndex >= pathX.length - 1) { - proposedX = pathX[pathX.length - 1]; - proposedY = pathY[pathY.length - 1]; - } else if (pathCorrespondingIndex < 0) { - proposedX = pathX[0]; - proposedY = pathY[0]; - } else { - proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); - proposedY = pathY[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathY[pathCorrespondingIndex + 1] - pathY[pathCorrespondingIndex]); - } - - } - this.filterKeys(Doc.allKeys(leftNode)).forEach(key => { + // const dif_time = NumCast(right.time) - NumCast(left.time); + // const timeratio = (KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement) - NumCast(left.time)) / dif_time; //linear + // let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; + // let indexLeft = keyframes.indexOf(left); + // let interY: List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; + // let realIndex = (interY.length - 1) * timeratio; + // let xIndex = Math.floor(realIndex); + // let yValue = interY[xIndex]; + // let secondYOffset: number = yValue; + // let minY = interY[0]; // for now + // let maxY = interY[interY.length - 1]; //for now + // if (interY.length !== 1) { + // secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; + // } + // let finalRatio = secondYOffset / (maxY - minY); + // let pathX: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; + // let pathY: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; + // let proposedX = 0; + // let proposedY = 0; + // if (pathX.length !== 0) { + // let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); + // let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); + // if (pathCorrespondingIndex >= pathX.length - 1) { + // proposedX = pathX[pathX.length - 1]; + // proposedY = pathY[pathY.length - 1]; + // } else if (pathCorrespondingIndex < 0) { + // proposedX = pathX[0]; + // proposedY = pathY[0]; + // } else { + // proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); + // proposedY = pathY[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathY[pathCorrespondingIndex + 1] - pathY[pathCorrespondingIndex]); + // } + + // } + this.whitelist.forEach(key => { if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate - if ((key === "x" || key === "y") && pathX.length !== 0) { - if (key === "x") this.props.node[key] = proposedX; - if (key === "y") this.props.node[key] = proposedY; - } else { - const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); - const adjusted = diff * finalRatio; - this.props.node[key] = NumCast(leftNode[key]) + adjusted; - } + // if ((key === "x" || key === "y") && pathX.length !== 0) { + // if (key === "x") this.props.node[key] = proposedX; + // if (key === "y") this.props.node[key] = proposedY; + // } else { + // const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); + // const adjusted = diff * finalRatio; + // this.props.node[key] = NumCast(leftNode[key]) + adjusted; + // } + let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); + } else { let stored = leftNode[key]; if (stored instanceof ObjectField) { -- cgit v1.2.3-70-g09d2 From 648aaeda9255f944275cb7c5ecbbceb669fa6c57 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 1 Feb 2020 13:52:55 -0500 Subject: another set of changes --- src/client/views/animationtimeline/Track.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 6d9cfe55c..e5e7a364c 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -226,8 +226,7 @@ export class Track extends React.Component { private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; let docFromApply = kfNode; - if (this.filterKeys(Doc.allKeys(this.props.node)).length > this.filterKeys(Doc.allKeys(kfNode)).length) docFromApply = this.props.node; - this.filterKeys(Doc.allKeys(docFromApply)).forEach(key => { + this.whitelist.forEach(key => { if (!kfNode[key]) { this.props.node[key] = undefined; } else { -- cgit v1.2.3-70-g09d2 From 78810a40e22510eefe747c099e73fa3f2c4860a9 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sat, 1 Feb 2020 15:03:15 -0500 Subject: ui changes cl.ose to done --- src/client/views/animationtimeline/Keyframe.scss | 138 ++++++++++----------- src/client/views/animationtimeline/Keyframe.tsx | 79 ++++++------ src/client/views/animationtimeline/Timeline.scss | 24 ++-- src/client/views/animationtimeline/Timeline.tsx | 24 +--- .../views/animationtimeline/TimelineOverview.tsx | 51 ++++---- src/client/views/animationtimeline/Track.tsx | 2 +- 6 files changed, 153 insertions(+), 165 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.scss b/src/client/views/animationtimeline/Keyframe.scss index b1e8b0b65..8ff1c53f5 100644 --- a/src/client/views/animationtimeline/Keyframe.scss +++ b/src/client/views/animationtimeline/Keyframe.scss @@ -1,94 +1,94 @@ -@import "./../globalCssVariables.scss"; +@import "./../globalCssVariables.scss"; + + +$timelineColor: #9acedf; +$timelineDark: #77a1aa; .bar { height: 100%; width: 5px; position: absolute; - + // pointer-events: none; .menubox { - width: 200px; - height:200px; + width: 200px; + height: 200px; top: 50%; - position: relative; - background-color: $light-color; - .menutable{ - tr:nth-child(odd){ - background-color:$light-color-secondary; + position: relative; + background-color: $light-color; + + .menutable { + tr:nth-child(odd) { + background-color: $light-color-secondary; } } } - .leftResize{ - left:-12.5px; - height:25px; - width:25px; - border-radius: 50%; - background-color: white; - border:3px solid black; - top: calc(50% - 12.5px); - z-index: 1000; - position:absolute; + .leftResize { + left: -10px; + border: 3px solid black; + } + + .rightResize { + right: -10px; + border: 3px solid black; } - .rightResize{ - right:-12.5px; - height:25px; - width:25px; - border-radius: 50%; - top:calc(50% - 12.5px); - background-color:white; - border:3px solid black; - z-index: 1000; - position:absolute; + + .keyframe-indicator { + height: 20px; + width: 20px; + top: calc(50% - 10px); + background-color: white; + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + z-index: 1000; + position: absolute; } - .fadeLeft{ - left:0px; - height:100%; - position:absolute; - pointer-events: none; - background: linear-gradient(to left, #4d9900 10%, $light-color); + + .keyframeCircle { + left: -10px; + border: 3px solid $timelineDark; } - .fadeRight{ - right:0px; - height:100%; - position:absolute; - pointer-events: none; - background: linear-gradient(to right, #4d9900 10%, $light-color); + .fadeLeft { + left: 0px; + height: 100%; + position: absolute; + pointer-events: none; + background: linear-gradient(to left, $timelineColor 10%, $light-color); } - .divider{ - height:100%; - width: 1px; - position: absolute; - background-color:black; - cursor: col-resize; - pointer-events:none; + + .fadeRight { + right: 0px; + height: 100%; + position: absolute; + pointer-events: none; + background: linear-gradient(to right, $timelineColor 10%, $light-color); } - .keyframe{ - height:100%; - position:absolute; + + .divider { + height: 100%; + width: 1px; + position: absolute; + background-color: black; + cursor: col-resize; + pointer-events: none; } - .keyframeCircle{ - left:-15px; - height:30px; - width:30px; - border-radius: 50%; - top:calc(50% - 15px); - background-color:white; - border:3px solid green; - z-index: 1000; - position:absolute; + + .keyframe { + height: 100%; + position: absolute; } - .fadeIn-container, .fadeOut-container, .body-container{ - position:absolute; - height:100%; + .fadeIn-container, + .fadeOut-container, + .body-container { + position: absolute; + height: 100%; background-color: rgba(0, 0, 0, 0.5); - opacity: 0; + opacity: 0; } - - -} - +} \ No newline at end of file diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 2f2639c76..9c486a6d6 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -93,11 +93,11 @@ export namespace KeyframeFunc { regiondata.fadeIn = 1000; regiondata.fadeOut = 1000; regiondata.functions = new List(); - regiondata.hasData = false; + regiondata.hasData = false; return regiondata; }; - export const makeKeyData = async (regiondata:RegionData, time: number, badNode:Doc, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + export const makeKeyData = async (regiondata: RegionData, time: number, badNode: Doc, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time runInAction(async () => { let doclist = (await DocListCastAsync(regiondata.keyframes))!; let existingkf: (Doc | undefined) = undefined; @@ -155,7 +155,7 @@ export const RegionDataSchema = createSchema({ keyframes: listSpec(Doc), fadeIn: defaultSpec("number", 0), fadeOut: defaultSpec("number", 0), - functions: listSpec(Doc), + functions: listSpec(Doc), hasData: defaultSpec("boolean", false) }); export type RegionData = makeInterface<[typeof RegionDataSchema]>; @@ -212,7 +212,7 @@ export class Keyframe extends React.Component { @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); } - + componentWillMount() { runInAction(async () => { if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); @@ -228,7 +228,7 @@ export class Keyframe extends React.Component { }); } - + @action @@ -313,10 +313,10 @@ export class Keyframe extends React.Component { } else if (NumCast(this.keyframes[1].time) + offset >= NumCast(this.keyframes[2].time)) { this.regiondata.position = NumCast(this.keyframes[2].time) - this.regiondata.fadeIn; this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - NumCast(this.keyframes[2].time) + this.regiondata.fadeIn; - } else if (NumCast(this.keyframes[0].time) + offset <= 0){ - this.regiondata.position = 0; - this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time); - }else { + } else if (NumCast(this.keyframes[0].time) + offset <= 0) { + this.regiondata.position = 0; + this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time); + } else { this.regiondata.duration -= offset; this.regiondata.position += offset; } @@ -353,9 +353,9 @@ export class Keyframe extends React.Component { if (offset > this.regiondata.fadeIn && offset < this.regiondata.duration - this.regiondata.fadeOut) { //make sure keyframe is not created inbetween fades and ends let position = this.regiondata.position; await KeyframeFunc.makeKeyData(this.regiondata, Math.round(position + offset), this.props.node); - this.regiondata.hasData = true; + 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 - + } } @@ -386,15 +386,15 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("input", "Move", (val) => { runInAction(() => { - let cannotMove: boolean = false; - let 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; - } + let cannotMove: boolean = false; + let 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"); @@ -406,22 +406,22 @@ export class Keyframe extends React.Component { */ @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { - TimelineMenu.Instance.addItem("button", "Remove Region", () => { - runInAction(() => { - this.regions.splice(this.regions.indexOf(this.props.RegionData), 1); - } - ); - }), + TimelineMenu.Instance.addItem("button", "Remove Region", () => { + runInAction(() => { + this.regions.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) { - cannotMove = true; - } - if (!cannotMove) { - this.regiondata.fadeIn = parseInt(val, 10); - this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; - } + let cannotMove: boolean = false; + if (val < 0 || val > NumCast(this.keyframes[2].time) - this.regiondata.position) { + cannotMove = true; + } + if (!cannotMove) { + this.regiondata.fadeIn = parseInt(val, 10); + this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn; + } }); }), TimelineMenu.Instance.addItem("input", `fadeOut: ${this.regiondata.fadeOut}ms`, (val) => { @@ -507,7 +507,7 @@ export class Keyframe extends React.Component { div.style.opacity = "0"; Doc.UnBrushDoc(this.props.node); } - + ///////////////////////UI STUFF ///////////////////////// @@ -524,7 +524,7 @@ export class Keyframe extends React.Component { keyframeDivs.push(
    -
    { e.preventDefault(); e.stopPropagation(); this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { +
    { e.preventDefault(); e.stopPropagation(); this.moveKeyframe(e, kf); }} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); this.makeKeyframeMenu(kf, e.nativeEvent); @@ -577,18 +577,19 @@ export class Keyframe extends React.Component { /** * rendering that green region */ + //154, 206, 223 render() { return (
    -
    -
    +
    +
    {this.drawKeyframes()} {this.drawKeyframeDividers()}
    diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index a8dd9b9e7..40479559d 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -206,18 +206,18 @@ $timelineDark: #77a1aa; border-right: 2px solid $timelineDark; .datapane { - top: 0px; - width: 100px; - height: 30%; - border: 1px solid $dark-color; - background-color: $intermediate-color; - color: white; - position: relative; - float: left; - border-style: solid; - overflow-y: scroll; - overflow-x: hidden; - } + top: 0px; + width: 100px; + height: 30%; + border: 1px solid $dark-color; + background-color: $intermediate-color; + color: white; + position: relative; + float: left; + border-style: solid; + overflow-y: scroll; + overflow-x: hidden; +} } .resize { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 8b943f209..5ff721ebb 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -120,18 +120,6 @@ export class Timeline extends React.Component { this.toggleHandle(); }); - this._resizeReaction = reaction( - () => this.props.PanelWidth, - () => { - // if (!this.props.parent._isAuthoring) { - // runInAction(() => { - console.log("resizing"); - // this.setOverviewWidth(); - // }); - // } - }, - ); - } componentWillUnmount() { @@ -443,15 +431,6 @@ export class Timeline extends React.Component { lengthString = ""; } - - // let modeType: string = this.props.Document.isATOn ? "Author" : "Play"; - // let modeString: string = "Mode: " + modeType; - // let overviewString: string = "Overview:"; - // let lengthString: string = "Length: "; - - console.log("visible: " + this._visibleLength) - console.log("total: " + this._totalLength) - return (
    @@ -462,7 +441,7 @@ export class Timeline extends React.Component {
    {overviewString}
    - +
    {modeString}
    @@ -572,7 +551,6 @@ export class Timeline extends React.Component { runInAction(() => { this._panelWidth = this.props.PanelWidth(); this.changeLenths(); - console.log("changing!!") }); // change visible and total width diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index caa97bb70..9a881264f 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -4,6 +4,7 @@ import { observer } from "mobx-react"; import "./TimelineOverview.scss"; import * as $ from 'jquery'; import { Timeline } from "./Timeline"; +import { Keyframe, KeyframeFunc } from "./Keyframe"; interface TimelineOverviewProps { @@ -15,7 +16,9 @@ interface TimelineOverviewProps { parent: Timeline; changeCurrentBarX: (pixel: number) => void; movePanX: (pixel: number) => any; - panelWidth: number; + time: number; + tickSpacing: number; + tickIncrement: number; } @@ -25,7 +28,9 @@ export class TimelineOverview extends React.Component{ @observable private _scrubberRef = React.createRef(); @observable private overviewBarWidth: number = 0; @observable private _authoringReaction?: IReactionDisposer; - @observable private _resizeReaction?: IReactionDisposer; + @observable private visibleTime: number = 0; + @observable private currentX: number = 0; + @observable private visibleStart: number = 0; private readonly DEFAULT_HEIGHT = 50; private readonly DEFAULT_WIDTH = 300; @@ -42,22 +47,10 @@ export class TimelineOverview extends React.Component{ } }, ); - // this._resizeReaction = reaction( - // () => this.props.parent.props.PanelWidth, - // () => { - // // if (!this.props.parent._isAuthoring) { - // // runInAction(() => { - // console.log("resizing"); - // this.setOverviewWidth(); - // // }); - // // } - // }, - // ); } componentWillUnmount = () => { this._authoringReaction && this._authoringReaction(); - this._resizeReaction && this._resizeReaction(); } @action @@ -85,8 +78,6 @@ export class TimelineOverview extends React.Component{ // let movX = (this.props.visibleStart / this.props.totalLength) * (this.overviewWidth) + e.movementX; this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength); // this.props.movePanX((movX / (this.overviewWidth) * this.props.totalLength); - - // console.log(this.props.totalLength); } @action @@ -125,18 +116,36 @@ export class TimelineOverview extends React.Component{ document.removeEventListener("pointerup", this.onScrubberUp); } + @action + getTimes() { + let vis = KeyframeFunc.convertPixelTime(this.props.visibleLength, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + let x = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + let start = KeyframeFunc.convertPixelTime(this.props.visibleStart, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + this.visibleTime = vis; + this.currentX = x; + this.visibleStart = start; + } + render() { - console.log("helo") + this.getTimes(); // calculates where everything should fall based on its size - let percentVisible = this.props.visibleLength / this.props.totalLength; - console.log(this.props.visibleLength) + // let percentVisible = this.props.visibleLength / this.props.totalLength; + // let visibleBarWidth = percentVisible * this.overviewBarWidth; + + // let percentScrubberStart = this.props.currentBarX / this.props.totalLength; + // let scrubberStart = percentScrubberStart * this.overviewBarWidth; + + // let percentBarStart = this.props.visibleStart / this.props.totalLength; + // let barStart = percentBarStart * this.overviewBarWidth; + + let percentVisible = this.visibleTime / this.props.time; let visibleBarWidth = percentVisible * this.overviewBarWidth; - let percentScrubberStart = this.props.currentBarX / this.props.totalLength; + let percentScrubberStart = this.currentX / this.props.time; let scrubberStart = percentScrubberStart * this.overviewBarWidth; - let percentBarStart = this.props.visibleStart / this.props.totalLength; + let percentBarStart = this.visibleStart / this.props.time; let barStart = percentBarStart * this.overviewBarWidth; let timeline = this.props.isAuthoring ? [ diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 1ca8022a1..3ea34a2f3 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -66,7 +66,7 @@ export class Track extends React.Component { runInAction(() => { if (!this.props.node.regions) this.props.node.regions = new List(); //if there is no region, then create new doc to store stuff //these two lines are exactly same from timeline.tsx - let relativeHeight = window.innerHeight / 14; + let relativeHeight = window.innerHeight / 20; this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness }); } -- cgit v1.2.3-70-g09d2 From c12573ba5e45271493acf01ee7d63ce9387ac606 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sat, 1 Feb 2020 16:23:51 -0500 Subject: lots of changes --- src/client/views/animationtimeline/Keyframe.tsx | 95 ++++++++-------- src/client/views/animationtimeline/Timeline.tsx | 4 - .../views/animationtimeline/TimelineOverview.tsx | 2 - src/client/views/animationtimeline/Track.tsx | 120 +++++++-------------- 4 files changed, 79 insertions(+), 142 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 9f4d80d2b..4f6ba728d 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -20,15 +20,18 @@ import { undoBatch, UndoManager } from "../../util/UndoManager"; * 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", } + export enum Direction { left = "left", right = "right" } + export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: List): (RegionData | undefined) => { let leftMost: (RegionData | undefined) = undefined; let rightMost: (RegionData | undefined) = undefined; @@ -97,41 +100,6 @@ export namespace KeyframeFunc { return regiondata; }; - export const makeKeyData = async (regiondata:RegionData, time: number, badNode:Doc, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - runInAction(async () => { - console.log("ran"); - let doclist = (await DocListCastAsync(regiondata.keyframes))!; - let existingkf: (Doc | undefined) = undefined; - doclist.forEach(TK => { - if (TK.time === time) existingkf = TK; - }); - if (existingkf) return existingkf; - let TK: Doc = new Doc(); - TK.time = time; - TK.key = Doc.MakeCopy(badNode, true); - TK.type = type; - regiondata.keyframes!.push(TK); - let interpolationFunctions = new Doc(); - interpolationFunctions.interpolationX = new List([0, 1]); - interpolationFunctions.interpolationY = new List([0, 100]); - interpolationFunctions.pathX = new List(); - interpolationFunctions.pathY = new List(); - regiondata.functions!.push(interpolationFunctions); - let found: boolean = false; - regiondata.keyframes!.forEach(compkf => { - compkf = compkf as Doc; - if (time < NumCast(compkf.time) && !found) { - runInAction(() => { - regiondata.keyframes!.splice(doclist.indexOf(compkf as Doc), 0, TK); - regiondata.keyframes!.pop(); - found = true; - }); - return; - } - }); - return TK; - }); - }; export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing: number, tickIncrement: number) => { let time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement; @@ -202,7 +170,6 @@ interface IProps { export class Keyframe extends React.Component { @observable private _bar = React.createRef(); - @observable private _gain = 20; //default @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; @@ -215,18 +182,15 @@ export class Keyframe extends React.Component { @computed private get pixelFadeOut() { return KeyframeFunc.convertPixelTime(this.regiondata.fadeOut, "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); } componentWillMount() { - runInAction(async () => { - if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - let fadeIn = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, this.props.node, KeyframeFunc.KeyframeType.fade))! as any as Doc; - let fadeOut = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, this.props.node, KeyframeFunc.KeyframeType.fade))! as any as Doc; - let start = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position, this.props.node, KeyframeFunc.KeyframeType.end))! as any as Doc; - let finish = (await KeyframeFunc.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, this.props.node, KeyframeFunc.KeyframeType.end))! as any as Doc; - (fadeIn.key! as Doc).opacity = 1; - (fadeOut.key! as Doc).opacity = 1; - (start.key! as Doc).opacity = 0.1; - (finish.key! as Doc).opacity = 0.1; - this.forceUpdate(); - }); + if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); + let start = this.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); + let fadeIn = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); + let fadeOut = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); + let finish = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); + (fadeIn.key as Doc).opacity = 1; + (fadeOut.key as Doc).opacity = 1; + (start.key as Doc).opacity = 0.1; + (finish.key as Doc).opacity = 0.1; } @@ -253,7 +217,32 @@ export class Keyframe extends React.Component { }); } } - + private makeKeyData = (regiondata:RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + let doclist = DocListCast(regiondata.keyframes)!; + let existingkf: (Doc | undefined) = undefined; + doclist.forEach(TK => { + if (TK.time === time) existingkf = TK; + }); + if (existingkf) return existingkf; + //else creates a new doc. + let TK: Doc = new Doc(); + TK.time = time; + TK.key = Doc.MakeCopy(this.props.node, true); + TK.type = type; + //assuming there are already keyframes (for keeping keyframes in order, sorted by time) + console.log("making..."); + if (doclist.length === 0) regiondata.keyframes!.push(TK); + doclist.forEach(kf => { + let index = doclist.indexOf(kf); + let kfTime = NumCast(kf.time); + console.log(kfTime); + if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))){ + regiondata.keyframes!.splice(index + 1, 0, TK); + return; + } + }); + return TK; + } @action onBarPointerMove = (e: PointerEvent) => { @@ -353,7 +342,7 @@ export class Keyframe extends React.Component { let 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 let position = this.regiondata.position; - await KeyframeFunc.makeKeyData(this.regiondata, Math.round(position + offset), this.props.node); + this.makeKeyData(this.regiondata, Math.round(position + offset)); 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 @@ -552,12 +541,12 @@ export class Keyframe extends React.Component { DocListCast(this.regiondata.keyframes).forEach(kf => { let index = this.keyframes.indexOf(kf); if (index !== this.keyframes.length - 1) { - let left = this.keyframes[this.keyframes.indexOf(kf) + 1]; + let right = this.keyframes[index + 1]; let bodyRef = React.createRef(); let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - let leftPos = KeyframeFunc.convertPixelTime(NumCast(left!.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + let rightPos = KeyframeFunc.convertPixelTime(NumCast(right.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); keyframeDividers.push( -
    { e.preventDefault(); e.stopPropagation(); this.onContainerOver(e, bodyRef); }} onPointerOut={(e) => { e.preventDefault(); e.stopPropagation(); this.onContainerOut(e, bodyRef); }} onContextMenu={(e) => { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 8b943f209..604827213 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -449,9 +449,6 @@ export class Timeline extends React.Component { // let overviewString: string = "Overview:"; // let lengthString: string = "Length: "; - console.log("visible: " + this._visibleLength) - console.log("total: " + this._totalLength) - return (
    @@ -572,7 +569,6 @@ export class Timeline extends React.Component { runInAction(() => { this._panelWidth = this.props.PanelWidth(); this.changeLenths(); - console.log("changing!!") }); // change visible and total width diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index caa97bb70..553ba890d 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -127,10 +127,8 @@ export class TimelineOverview extends React.Component{ render() { - console.log("helo") // calculates where everything should fall based on its size let percentVisible = this.props.visibleLength / this.props.totalLength; - console.log(this.props.visibleLength) let visibleBarWidth = percentVisible * this.overviewBarWidth; let percentScrubberStart = this.props.currentBarX / this.props.totalLength; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index e5e7a364c..17466bd1a 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -10,6 +10,7 @@ import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { Transform } from "../../util/Transform"; import { Copy } from "../../../new_fields/FieldSymbols"; import { ObjectField } from "../../../new_fields/ObjectField"; +import { fromCallback } from "bluebird"; interface IProps { node: Doc; @@ -40,10 +41,12 @@ export class Track extends React.Component { "y", "width", "height", - "data" + "data", + "opacity" ]; + @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } - // @computed private get time() {} + @computed private get time() {return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement));} ////////// life cycle functions/////////////// componentWillMount() { @@ -59,7 +62,7 @@ export class Track extends React.Component { runInAction(async () => { this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); - if (this.regions.length === 0) this.createRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); + if (this.regions.length === 0) this.createRegion(this.time); this.props.node.hidden = false; this.props.node.opacity = 1; // this.autoCreateKeyframe(); @@ -90,17 +93,17 @@ export class Track extends React.Component { if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = Doc.MakeCopy(this.props.node, true); - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), kf); //right keyframe, if it exists + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.time, kf); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.time, kf); //right keyframe, if it exists if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), leftkf!); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.time, leftkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; } if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement), rightkf!); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.time, rightkf!); edge!.key = Doc.MakeCopy(kf.key as Doc, true); rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; @@ -124,14 +127,12 @@ export class Track extends React.Component { return this.whitelist.map(key => node[key]); }, (changed, reaction) => { console.log(changed); - //convert scrubber pos(pixel) to time - let time = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); //check for region - this.findRegion(time).then((region) => { + this.findRegion(this.time).then((region) => { if (region !== undefined){ //if region at scrub time exist let r = region as any as RegionData; //for some region is returning undefined... which is not the case - if (DocListCast(r.keyframes).find(kf => kf.time === time) === undefined ){ //basically when there is no additional keyframe at that timespot - KeyframeFunc.makeKeyData(r, time, this.props.node, KeyframeFunc.KeyframeType.default); + if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined ){ //basically when there is no additional keyframe at that timespot + KeyframeFunc.makeKeyData(r, this.time, this.props.node, KeyframeFunc.KeyframeType.default); } } // reaction.dispose(); @@ -158,10 +159,10 @@ export class Track extends React.Component { @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, async () => { - let regiondata: (Doc | undefined) = await this.findRegion(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); + let regiondata: (Doc | undefined) = await this.findRegion(this.time); if (regiondata) { this.props.node.hidden = false; - await this.timeChange(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); + await this.timeChange(); } else { this.props.node.hidden = true; this.props.node.opacity = 0; @@ -198,14 +199,14 @@ export class Track extends React.Component { * when scrubber position changes. Need to edit the logic */ @action - timeChange = async (time: number) => { + timeChange = async () => { if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { await this.saveKeyframe(this._onKeyframe, this._onRegionData); } - let regiondata = await this.findRegion(Math.round(time)); //finds a region that the scrubber is on + let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on if (regiondata) { - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); //right keyframe, if it exists + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); @@ -213,7 +214,7 @@ export class Track extends React.Component { this._onKeyframe = currentkf; this._onRegionData = regiondata; } else if (leftkf && rightkf) { - await this.interpolate(leftkf, rightkf, regiondata); + await this.interpolate(leftkf, rightkf); } } } @@ -225,17 +226,12 @@ export class Track extends React.Component { @action private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; - let docFromApply = kfNode; this.whitelist.forEach(key => { if (!kfNode[key]) { this.props.node[key] = undefined; } else { let stored = kfNode[key]; - if (stored instanceof ObjectField) { - this.props.node[key] = stored[Copy](); - } else { - this.props.node[key] = stored; - } + this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); } @@ -245,77 +241,35 @@ export class Track extends React.Component { * calculating current keyframe, if the scrubber is right on the keyframe */ @action - calcCurrent = async (region: Doc) => { + calcCurrent = (region: Doc) => { let currentkf: (Doc | undefined) = undefined; - let keyframes = await DocListCastAsync(region.keyframes!); - keyframes!.forEach((kf) => { - if (NumCast(kf.time) === Math.round(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement))) currentkf = kf; + let keyframes = DocListCast(region.keyframes!); + keyframes.forEach((kf) => { + if (NumCast(kf.time) === Math.round(this.time)) currentkf = kf; }); return currentkf; } /** - * interpolation. definetely needs to be changed. (currently involves custom linear splicing interpolations). - * Too complex right now. Also need to apply quadratic spline later on (for smoothness, instead applying "gains") + * basic linear interpolation function */ @action - interpolate = async (left: Doc, right: Doc, regiondata: Doc) => { - let leftNode = left.key as Doc; - let rightNode = right.key as Doc; - // const dif_time = NumCast(right.time) - NumCast(left.time); - // const timeratio = (KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement) - NumCast(left.time)) / dif_time; //linear - // let keyframes = (await DocListCastAsync(regiondata.keyframes!))!; - // let indexLeft = keyframes.indexOf(left); - // let interY: List = (await ((regiondata.functions as List)[indexLeft] as Doc).interpolationY as List)!; - // let realIndex = (interY.length - 1) * timeratio; - // let xIndex = Math.floor(realIndex); - // let yValue = interY[xIndex]; - // let secondYOffset: number = yValue; - // let minY = interY[0]; // for now - // let maxY = interY[interY.length - 1]; //for now - // if (interY.length !== 1) { - // secondYOffset = interY[xIndex] + ((realIndex - xIndex) / 1) * (interY[xIndex + 1] - interY[xIndex]) - minY; - // } - // let finalRatio = secondYOffset / (maxY - minY); - // let pathX: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathX as List; - // let pathY: List = await ((regiondata.functions as List)[indexLeft] as Doc).pathY as List; - // let proposedX = 0; - // let proposedY = 0; - // if (pathX.length !== 0) { - // let realPathCorrespondingIndex = finalRatio * (pathX.length - 1); - // let pathCorrespondingIndex = Math.floor(realPathCorrespondingIndex); - // if (pathCorrespondingIndex >= pathX.length - 1) { - // proposedX = pathX[pathX.length - 1]; - // proposedY = pathY[pathY.length - 1]; - // } else if (pathCorrespondingIndex < 0) { - // proposedX = pathX[0]; - // proposedY = pathY[0]; - // } else { - // proposedX = pathX[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathX[pathCorrespondingIndex + 1] - pathX[pathCorrespondingIndex]); - // proposedY = pathY[pathCorrespondingIndex] + ((realPathCorrespondingIndex - pathCorrespondingIndex) / 1) * (pathY[pathCorrespondingIndex + 1] - pathY[pathCorrespondingIndex]); - // } - - // } + interpolate = async (left: Doc, right: Doc) => { + let leftNode = await(left.key) as Doc; + let rightNode = await(right.key) as Doc; this.whitelist.forEach(key => { + console.log(key); + console.log(leftNode[key]); + console.log(rightNode[key]); if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate - // if ((key === "x" || key === "y") && pathX.length !== 0) { - // if (key === "x") this.props.node[key] = proposedX; - // if (key === "y") this.props.node[key] = proposedY; - // } else { - // const diff = NumCast(rightNode[key]) - NumCast(leftNode[key]); - // const adjusted = diff * finalRatio; - // this.props.node[key] = NumCast(leftNode[key]) + adjusted; - // } let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); - - } else { + let deltaLeft = this.time - NumCast(left.time); + let ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); + this.props.node[key] = NumCast(leftNode[key]) + (dif * ratio); + } else { // case data let stored = leftNode[key]; - if (stored instanceof ObjectField) { - this.props.node[key] = stored[Copy](); - } else { - this.props.node[key] = stored; - } + this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); } -- cgit v1.2.3-70-g09d2 From ad15ebb5f1572702894ba96caf9a66be278e1e81 Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sun, 2 Feb 2020 00:08:59 -0500 Subject: kinda unstable (will fix it in the morning) --- src/client/views/animationtimeline/Keyframe.tsx | 37 +----- src/client/views/animationtimeline/Track.tsx | 164 +++++++++++++++--------- 2 files changed, 106 insertions(+), 95 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 4f6ba728d..d53000460 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -140,6 +140,7 @@ interface IProps { check: string; changeCurrentBarX: (x: number) => void; transform: Transform; + makeKeyData: (region:RegionData, pos: number, kftype:KeyframeFunc.KeyframeType) => Doc; } @@ -183,10 +184,10 @@ export class Keyframe extends React.Component { componentWillMount() { if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - let start = this.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); - let fadeIn = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); - let fadeOut = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); - let finish = this.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); + let start = this.props.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); + let fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); + let fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); + let finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); (fadeIn.key as Doc).opacity = 1; (fadeOut.key as Doc).opacity = 1; (start.key as Doc).opacity = 0.1; @@ -217,32 +218,6 @@ export class Keyframe extends React.Component { }); } } - private makeKeyData = (regiondata:RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - let doclist = DocListCast(regiondata.keyframes)!; - let existingkf: (Doc | undefined) = undefined; - doclist.forEach(TK => { - if (TK.time === time) existingkf = TK; - }); - if (existingkf) return existingkf; - //else creates a new doc. - let TK: Doc = new Doc(); - TK.time = time; - TK.key = Doc.MakeCopy(this.props.node, true); - TK.type = type; - //assuming there are already keyframes (for keeping keyframes in order, sorted by time) - console.log("making..."); - if (doclist.length === 0) regiondata.keyframes!.push(TK); - doclist.forEach(kf => { - let index = doclist.indexOf(kf); - let kfTime = NumCast(kf.time); - console.log(kfTime); - if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))){ - regiondata.keyframes!.splice(index + 1, 0, TK); - return; - } - }); - return TK; - } @action onBarPointerMove = (e: PointerEvent) => { @@ -342,7 +317,7 @@ export class Keyframe extends React.Component { let 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 let position = this.regiondata.position; - this.makeKeyData(this.regiondata, Math.round(position + offset)); + 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 diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 17466bd1a..40350bc7a 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -60,12 +60,12 @@ export class Track extends React.Component { componentDidMount() { runInAction(async () => { - this._timelineVisibleReaction = this.timelineVisibleReaction(); + // this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); if (this.regions.length === 0) this.createRegion(this.time); this.props.node.hidden = false; this.props.node.opacity = 1; - // this.autoCreateKeyframe(); + //this.autoCreateKeyframe(); }); } @@ -86,34 +86,34 @@ export class Track extends React.Component { * */ @action - saveKeyframe = async (ref: Doc, regiondata: Doc) => { - let keyframes: List = (Cast(regiondata.keyframes, listSpec(Doc)) as List); - let kfIndex: number = keyframes.indexOf(ref); - let kf = keyframes[kfIndex] as Doc; + saveKeyframe = async () => { + console.log("saving keyframe"); + let keyframes: List = (Cast(this.saveStateRegion!.keyframes, listSpec(Doc)) as List); + let kfIndex: number = keyframes.indexOf(this.saveStateKf!); + let kf = keyframes[kfIndex] as Doc; //index in the keyframe if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades - kf.key = Doc.MakeCopy(this.props.node, true); - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.time, kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.time, kf); //right keyframe, if it exists + kf.key = this.makeCopy(); + let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists + let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata!, this.time, leftkf!); - edge!.key = Doc.MakeCopy(kf.key as Doc, true); - leftkf!.key = Doc.MakeCopy(kf.key as Doc, true); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf!); + edge!.key = this.makeCopy(); + leftkf!.key = this.makeCopy(); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; } if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata!, this.time, rightkf!); - edge!.key = Doc.MakeCopy(kf.key as Doc, true); - rightkf!.key = Doc.MakeCopy(kf.key as Doc, true); + let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf!); + edge!.key = this.makeCopy(); + rightkf!.key = this.makeCopy(); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; } } keyframes[kfIndex] = kf; - this._onKeyframe = undefined; - this._onRegionData = undefined; - this._isOnKeyframe = false; + this.saveStateKf = undefined; + this.saveStateRegion = undefined; } @@ -126,13 +126,13 @@ export class Track extends React.Component { return reaction(() => { return this.whitelist.map(key => node[key]); }, (changed, reaction) => { - console.log(changed); + console.log("autocreated"); //check for region this.findRegion(this.time).then((region) => { if (region !== undefined){ //if region at scrub time exist let r = region as any 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 - KeyframeFunc.makeKeyData(r, this.time, this.props.node, KeyframeFunc.KeyframeType.default); + this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default); } } // reaction.dispose(); @@ -140,17 +140,17 @@ export class Track extends React.Component { }); } - /** - * reverting back to previous state before editing on AT - */ - @action - revertState = () => { - let copyDoc = Doc.MakeCopy(this.props.node, true); - if (this._storedState) this.applyKeys(this._storedState); - let newState = new Doc(); - newState.key = copyDoc; - this._storedState = newState; - } + // /** + // * reverting back to previous state before editing on AT + // */ + // @action + // revertState = () => { + // let copyDoc = Doc.MakeCopy(this.props.node, true); + // if (this._storedState) this.applyKeys(this._storedState); + // let newState = new Doc(); + // newState.key = copyDoc; + // this._storedState = newState; + // } /** * Reaction when scrubber bar changes @@ -170,38 +170,41 @@ export class Track extends React.Component { }); } - /** - * when timeline is visible, reaction is ran so states are reverted - */ - @action - timelineVisibleReaction = () => { - return reaction(() => { - return this.props.timelineVisible; - }, isVisible => { - this.revertState(); - if (isVisible) { - DocListCast(this.regions).forEach(region => { - if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { - for (let i = 0; i < 4; i++) { - DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); - if (i === 0 || i === 3) { - DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key.opacity = 0.1; - } - } - console.log("saving keyframes"); - } - }); - } - }); - } + // /** + // * when timeline is visible, reaction is ran so states are reverted + // */ + // @action + // timelineVisibleReaction = () => { + // return reaction(() => { + // return this.props.timelineVisible; + // }, isVisible => { + // this.revertState(); + // if (isVisible) { + // DocListCast(this.regions).forEach(region => { + // if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { + // for (let i = 0; i < 4; i++) { + // DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); + // if (i === 0 || i === 3) { + // DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key.opacity = 0.1; + // } + // } + // console.log("saving keyframes"); + // } + // }); + // } + // }); + // } + + @observable private saveStateKf:(Doc | undefined) = undefined; + @observable private saveStateRegion: (Doc|undefined) = undefined; /**w * when scrubber position changes. Need to edit the logic */ @action timeChange = async () => { - if (this._isOnKeyframe && this._onKeyframe && this._onRegionData) { - await this.saveKeyframe(this._onKeyframe, this._onRegionData); + if (this.saveStateKf !== undefined) { + await this.saveKeyframe(); } let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on if (regiondata) { @@ -210,9 +213,8 @@ export class Track extends React.Component { let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { await this.applyKeys(currentkf); - this._isOnKeyframe = true; - this._onKeyframe = currentkf; - this._onRegionData = regiondata; + this.saveStateKf = currentkf; + this.saveStateRegion = regiondata; } else if (leftkf && rightkf) { await this.interpolate(leftkf, rightkf); } @@ -259,9 +261,6 @@ export class Track extends React.Component { let leftNode = await(left.key) as Doc; let rightNode = await(right.key) as Doc; this.whitelist.forEach(key => { - console.log(key); - console.log(leftNode[key]); - console.log(rightNode[key]); if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); let deltaLeft = this.time - NumCast(left.time); @@ -307,6 +306,7 @@ export class Track extends React.Component { /** * creates a region (KEYFRAME.TSX stuff). */ + @action createRegion = async (time: number) => { if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data @@ -323,6 +323,42 @@ export class Track extends React.Component { } } + @action + makeKeyData = (regiondata:RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + console.log("KEYDATA GENERATING"); + let doclist = DocListCast(regiondata.keyframes)!; + let existingkf: (Doc | undefined) = undefined; + doclist.forEach(TK => { + if (TK.time === time) existingkf = TK; + }); + if (existingkf) return existingkf; + //else creates a new doc. + let TK: Doc = new Doc(); + TK.time = time; + TK.key = this.makeCopy(); + TK.type = type; + //assuming there are already keyframes (for keeping keyframes in order, sorted by time) + if (doclist.length === 0) regiondata.keyframes!.push(TK); + doclist.forEach(kf => { + let index = doclist.indexOf(kf); + let kfTime = NumCast(kf.time); + if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))){ + regiondata.keyframes!.splice(index + 1, 0, TK); + return; + } + }); + return TK; + } + + @action + makeCopy = () => { + let doc = new Doc(); + this.whitelist.forEach(key => { + let originalVal = this.props.node[key]; + doc.key = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; + }); + return doc; + } /** * UI sstuff here. Not really much to change @@ -333,7 +369,7 @@ export class Track extends React.Component {
    { Doc.BrushDoc(this.props.node); }} onPointerOut={() => { Doc.UnBrushDoc(this.props.node); }} style={{ height: `${this._trackHeight}px` }}> {DocListCast(this.regions).map((region) => { - return ; + return ; })}
    -- cgit v1.2.3-70-g09d2 From 0688541300ad0fa5cda7543d5bdc2e2c56246fbc Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sun, 2 Feb 2020 10:40:45 -0500 Subject: cleanup (unstable) --- src/client/views/animationtimeline/Keyframe.tsx | 1 - src/client/views/animationtimeline/Timeline.tsx | 48 +------------------------ src/client/views/animationtimeline/Track.tsx | 5 --- 3 files changed, 1 insertion(+), 53 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index d53000460..482d066ba 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -137,7 +137,6 @@ interface IProps { tickSpacing: number; tickIncrement: number; time: number; - check: string; changeCurrentBarX: (x: number) => void; transform: Transform; makeKeyData: (region:RegionData, pos: number, kftype:KeyframeFunc.KeyframeType) => Doc; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 604827213..da9c361da 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -79,7 +79,6 @@ export class Timeline extends React.Component { // so a reaction can be made @observable public _isAuthoring = this.props.Document.isATOn; - @observable private _resizeReaction?: IReactionDisposer; @observable private _panelWidth = 0; /** @@ -119,19 +118,6 @@ export class Timeline extends React.Component { this.props.Document.isATOn = !this.props.Document.isATOn; //turns the boolean on, saying AT (animation timeline) is on this.toggleHandle(); }); - - this._resizeReaction = reaction( - () => this.props.PanelWidth, - () => { - // if (!this.props.parent._isAuthoring) { - // runInAction(() => { - console.log("resizing"); - // this.setOverviewWidth(); - // }); - // } - }, - ); - } componentWillUnmount() { @@ -527,30 +513,6 @@ export class Timeline extends React.Component { } - @observable private _check: string = ""; - @observable private _checkVisible: boolean = false; - @action - private onCheckClicked = (type: string) => { - if (type === "yes") { - this._check = "yes"; - } else if (type === "no") { - this._check = "no"; - } - } - - - /** - * check mark thing that needs to be fixed. Do not edit this, because it most likely change. - */ - @action - private checkCallBack = (visible: boolean) => { - this._checkVisible = visible; - if (!visible) { //when user confirms - this._check = ""; - } - - } - @action.bound changeLenths() { if (this._infoContainer.current) { @@ -583,7 +545,7 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => )}
    @@ -593,14 +555,6 @@ export class Timeline extends React.Component {
    -
    -
    { this.onCheckClicked("yes"); }}> - -
    -
    { this.onCheckClicked("no"); }}> - -
    -
    {this.timelineToolBox(1)}
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 40350bc7a..d260792e1 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -21,7 +21,6 @@ interface IProps { tickIncrement: number; tickSpacing: number; timelineVisible: boolean; - check: string; changeCurrentBarX: (x: number) => void; } @@ -30,10 +29,6 @@ export class Track extends React.Component { @observable private _inner = React.createRef(); @observable private _currentBarXReaction: any; @observable private _timelineVisibleReaction: any; - @observable private _isOnKeyframe: boolean = false; - @observable private _onKeyframe: (Doc | undefined) = undefined; - @observable private _onRegionData: (Doc | undefined) = undefined; - @observable private _storedState: (Doc | undefined) = undefined; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; private whitelist = [ -- cgit v1.2.3-70-g09d2 From 7284810ee039c8baa456d0579fefba59eef444ca Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sun, 2 Feb 2020 13:18:39 -0500 Subject: stable --- src/client/views/animationtimeline/Keyframe.tsx | 31 ++++++++++++------------ src/client/views/animationtimeline/Track.tsx | 32 +++++++++++++------------ 2 files changed, 32 insertions(+), 31 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 482d066ba..393168ac3 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -60,9 +60,7 @@ export namespace KeyframeFunc { let keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { let compTime = currentBarX; - if (ref) { - compTime = NumCast(ref.time); - } + if (ref) compTime = NumCast(ref.time); if (NumCast(kf.time) < compTime && NumCast(kf.time) >= time) { leftKf = kf; time = NumCast(kf.time); @@ -78,9 +76,7 @@ export namespace KeyframeFunc { let keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { let compTime = currentBarX; - if (ref) { - compTime = NumCast(ref.time); - } + if (ref) compTime = NumCast(ref.time); if (NumCast(kf.time) > compTime && NumCast(kf.time) <= NumCast(time)) { rightKf = kf; time = NumCast(kf.time); @@ -181,16 +177,19 @@ export class Keyframe extends React.Component { @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); } - componentWillMount() { - if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - let start = this.props.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); - let fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); - let fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); - let finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); - (fadeIn.key as Doc).opacity = 1; - (fadeOut.key as Doc).opacity = 1; - (start.key as Doc).opacity = 0.1; - (finish.key as Doc).opacity = 0.1; + componentDidMount() { + setTimeout(() => { //giving it a temporary 1sec delay... + if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); + let start = this.props.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); + let fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); + let fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); + let finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); + (fadeIn.key as Doc).opacity = 1; + (fadeOut.key as Doc).opacity = 1; + (start.key as Doc).opacity = 0.1; + (finish.key as Doc).opacity = 0.1; + this.forceUpdate(); //not needed, if setTimeout is gone... + }, 1000); } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index d260792e1..a20769142 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -10,7 +10,6 @@ import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import { Transform } from "../../util/Transform"; import { Copy } from "../../../new_fields/FieldSymbols"; import { ObjectField } from "../../../new_fields/ObjectField"; -import { fromCallback } from "bluebird"; interface IProps { node: Doc; @@ -153,15 +152,16 @@ export class Track extends React.Component { */ @action currentBarXReaction = () => { - return reaction(() => this.props.currentBarX, async () => { - let regiondata: (Doc | undefined) = await this.findRegion(this.time); - if (regiondata) { - this.props.node.hidden = false; - await this.timeChange(); - } else { - this.props.node.hidden = true; - this.props.node.opacity = 0; - } + return reaction(() => this.props.currentBarX, () => { + this.findRegion(this.time).then((regiondata: (Doc | undefined)) => { + if (regiondata) { + this.props.node.hidden = false; + this.timeChange(); + } else { + this.props.node.hidden = true; + this.props.node.opacity = 0; + } + }); }); } @@ -207,10 +207,12 @@ export class Track extends React.Component { let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { + console.log("on a keyframe"); await this.applyKeys(currentkf); this.saveStateKf = currentkf; this.saveStateRegion = regiondata; } else if (leftkf && rightkf) { + console.log("interpolating!"); await this.interpolate(leftkf, rightkf); } } @@ -228,6 +230,8 @@ export class Track extends React.Component { this.props.node[key] = undefined; } else { let stored = kfNode[key]; + console.log(key); + console.log(stored); this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); @@ -287,14 +291,13 @@ export class Track extends React.Component { /** - * double click on track. Signalling keyframe creation. Problem with phantom regions + * double click on track. Signalling keyframe creation. */ @action onInnerDoubleClick = (e: React.MouseEvent) => { let inner = this._inner.current!; let 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.forceUpdate(); } @@ -320,7 +323,6 @@ export class Track extends React.Component { @action makeKeyData = (regiondata:RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - console.log("KEYDATA GENERATING"); let doclist = DocListCast(regiondata.keyframes)!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { @@ -349,8 +351,8 @@ export class Track extends React.Component { makeCopy = () => { let doc = new Doc(); this.whitelist.forEach(key => { - let originalVal = this.props.node[key]; - doc.key = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; + let originalVal = this.props.node[key]; + doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; }); return doc; } -- cgit v1.2.3-70-g09d2 From d5cda7cf9a67d0e47908dd510fbc8d43a3920f15 Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Sun, 2 Feb 2020 13:45:01 -0500 Subject: autokeyframing problem --- src/client/views/animationtimeline/Track.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index a20769142..24a5d2b6c 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -28,6 +28,7 @@ export class Track extends React.Component { @observable private _inner = React.createRef(); @observable private _currentBarXReaction: any; @observable private _timelineVisibleReaction: any; + @observable private _autoKfReaction: any; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; private whitelist = [ @@ -59,7 +60,7 @@ export class Track extends React.Component { if (this.regions.length === 0) this.createRegion(this.time); this.props.node.hidden = false; this.props.node.opacity = 1; - //this.autoCreateKeyframe(); + this.autoCreateKeyframe(); }); } @@ -71,6 +72,7 @@ export class Track extends React.Component { //disposing reactions if (this._currentBarXReaction) this._currentBarXReaction(); if (this._timelineVisibleReaction) this._timelineVisibleReaction(); + //if (this._autoKfReaction) this._autoKfReaction(); }); } //////////////////////////////// @@ -121,6 +123,7 @@ export class Track extends React.Component { return this.whitelist.map(key => node[key]); }, (changed, reaction) => { console.log("autocreated"); + console.log(changed); //check for region this.findRegion(this.time).then((region) => { if (region !== undefined){ //if region at scrub time exist @@ -129,9 +132,8 @@ export class Track extends React.Component { this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default); } } - // reaction.dispose(); }); - }); + }, {fireImmediately: false}); } // /** @@ -156,10 +158,15 @@ export class Track extends React.Component { this.findRegion(this.time).then((regiondata: (Doc | undefined)) => { if (regiondata) { this.props.node.hidden = false; + if (!this._autoKfReaction){ + // console.log("creating another reaction"); + // this._autoKfReaction = this.autoCreateKeyframe(); + } this.timeChange(); } else { this.props.node.hidden = true; this.props.node.opacity = 0; + //if (this._autoKfReaction) this._autoKfReaction(); } }); }); @@ -207,12 +214,10 @@ export class Track extends React.Component { let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { - console.log("on a keyframe"); await this.applyKeys(currentkf); this.saveStateKf = currentkf; this.saveStateRegion = regiondata; } else if (leftkf && rightkf) { - console.log("interpolating!"); await this.interpolate(leftkf, rightkf); } } @@ -229,9 +234,7 @@ export class Track extends React.Component { if (!kfNode[key]) { this.props.node[key] = undefined; } else { - let stored = kfNode[key]; - console.log(key); - console.log(stored); + let stored = kfNode[key]; this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); -- cgit v1.2.3-70-g09d2 From 4fd68c0ec41f2871ae24a87d8e5316d093bdb505 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sun, 2 Feb 2020 15:10:34 -0500 Subject: changes --- src/client/views/animationtimeline/Keyframe.scss | 15 +++++++++++ src/client/views/animationtimeline/Keyframe.tsx | 8 +++++- src/client/views/animationtimeline/Timeline.scss | 32 +++++++++++++++--------- src/client/views/animationtimeline/Timeline.tsx | 2 +- src/client/views/animationtimeline/Track.scss | 17 +++++++------ 5 files changed, 52 insertions(+), 22 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.scss b/src/client/views/animationtimeline/Keyframe.scss index 8ff1c53f5..f0685943b 100644 --- a/src/client/views/animationtimeline/Keyframe.scss +++ b/src/client/views/animationtimeline/Keyframe.scss @@ -46,6 +46,21 @@ $timelineDark: #77a1aa; position: absolute; } + .keyframe:hover~.keyframe-information { + display: flex; + } + + .keyframe-information { + display: none; + position: relative; + // z-index: 100000; + // background: $timelineDark; + width: 100px; + // left: -50px; + height: 100px; + // top: 40px; + } + .keyframeCircle { left: -10px; border: 3px solid $timelineDark; diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 9c486a6d6..2348da813 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -522,14 +522,18 @@ export class Keyframe extends React.Component { DocListCast(this.regiondata.keyframes).forEach(kf => { if (kf.type as KeyframeFunc.KeyframeType !== KeyframeFunc.KeyframeType.end) { keyframeDivs.push( -
    + <>
    { 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(); }}>
    +
    +
    + + ); } else { keyframeDivs.push( @@ -589,7 +593,9 @@ export class Keyframe extends React.Component { onPointerDown={this.onBarPointerDown }>
    + {/*
    */}
    + {/*
    */} {this.drawKeyframes()} {this.drawKeyframeDividers()}
    diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index 40479559d..dbdade03f 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -206,18 +206,26 @@ $timelineDark: #77a1aa; border-right: 2px solid $timelineDark; .datapane { - top: 0px; - width: 100px; - height: 30%; - border: 1px solid $dark-color; - background-color: $intermediate-color; - color: white; - position: relative; - float: left; - border-style: solid; - overflow-y: scroll; - overflow-x: hidden; -} + top: 0px; + width: 100px; + height: 30%; + border: 1px solid $dark-color; + font-size: 12px; + line-height: 11px; + background-color: $timelineDark; + color: white; + position: relative; + float: left; + padding: 3px; + border-style: solid; + overflow-y: scroll; + overflow-x: hidden; + + p { + hyphens: auto; + } + + } } .resize { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 5ff721ebb..f0ca1c0ab 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -100,7 +100,7 @@ export class Timeline extends React.Component { /////////lifecycle functions//////////// componentWillMount() { - let relativeHeight = window.innerHeight / 14; //sets height to arbitrary size, relative to innerHeight + let relativeHeight = window.innerHeight / 20; //sets height to arbitrary size, relative to innerHeight 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 diff --git a/src/client/views/animationtimeline/Track.scss b/src/client/views/animationtimeline/Track.scss index 61a8e0b88..aec587a79 100644 --- a/src/client/views/animationtimeline/Track.scss +++ b/src/client/views/animationtimeline/Track.scss @@ -1,14 +1,15 @@ -@import "./../globalCssVariables.scss"; +@import "./../globalCssVariables.scss"; -.track-container{ +.track-container { .track { - .inner { - top:0px; - width: calc(100%); - background-color: $light-color; - border: 1px solid $dark-color; - position:relative; + .inner { + top: 0px; + width: calc(100%); + background-color: $light-color; + border: 1px solid $dark-color; + position: relative; + z-index: 100; } } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 84d5d8808bc0a51ae7a45f6415d9bd926c78bf6c Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 2 Feb 2020 15:56:16 -0500 Subject: changes --- src/client/views/animationtimeline/Track.tsx | 105 ++++++++++++++------------- 1 file changed, 56 insertions(+), 49 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 24a5d2b6c..e352cdbb5 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun, toJS, isObservableArray, IObservableArray, trace } from "mobx"; +import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun, toJS, isObservableArray, IObservableArray, trace, observe, intercept } from "mobx"; import "./Track.scss"; import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; @@ -28,20 +28,22 @@ export class Track extends React.Component { @observable private _inner = React.createRef(); @observable private _currentBarXReaction: any; @observable private _timelineVisibleReaction: any; - @observable private _autoKfReaction: any; + @observable private _autoKfReaction: any; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; - private whitelist = [ + private primitiveWhitelist = [ "x", "y", "width", "height", - "data", "opacity" ]; + private objectWhitelist = [ + "data" + ] @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } - @computed private get time() {return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement));} + @computed private get time() { return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } ////////// life cycle functions/////////////// componentWillMount() { @@ -55,7 +57,7 @@ export class Track extends React.Component { componentDidMount() { runInAction(async () => { - // this._timelineVisibleReaction = this.timelineVisibleReaction(); + // this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); if (this.regions.length === 0) this.createRegion(this.time); this.props.node.hidden = false; @@ -72,7 +74,7 @@ export class Track extends React.Component { //disposing reactions if (this._currentBarXReaction) this._currentBarXReaction(); if (this._timelineVisibleReaction) this._timelineVisibleReaction(); - //if (this._autoKfReaction) this._autoKfReaction(); + if (this._autoKfReaction) this._autoKfReaction(); }); } //////////////////////////////// @@ -89,12 +91,12 @@ export class Track extends React.Component { let kf = keyframes[kfIndex] as Doc; //index in the keyframe if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades - kf.key = this.makeCopy(); + kf.key = this.makeCopy(); let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf!); - edge!.key = this.makeCopy(); + edge!.key = this.makeCopy(); leftkf!.key = this.makeCopy(); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; @@ -102,13 +104,13 @@ export class Track extends React.Component { if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf!); edge!.key = this.makeCopy(); - rightkf!.key = this.makeCopy(); + rightkf!.key = this.makeCopy(); (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; } } keyframes[kfIndex] = kf; - this.saveStateKf = undefined; + this.saveStateKf = undefined; this.saveStateRegion = undefined; } @@ -119,21 +121,26 @@ export class Track extends React.Component { @action autoCreateKeyframe = () => { const { node } = this.props; + const objects = this.objectWhitelist.map(key => node[key]); + intercept(this.props.node, change => { + console.log(change); + return change; + }); return reaction(() => { - return this.whitelist.map(key => node[key]); + return [...this.primitiveWhitelist.map(key => node[key]), ...objects]; }, (changed, reaction) => { - console.log("autocreated"); + console.log("autocreated"); console.log(changed); //check for region this.findRegion(this.time).then((region) => { - if (region !== undefined){ //if region at scrub time exist + if (region !== undefined) { //if region at scrub time exist let r = region as any 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); - } + 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 }); } // /** @@ -158,10 +165,10 @@ export class Track extends React.Component { this.findRegion(this.time).then((regiondata: (Doc | undefined)) => { if (regiondata) { this.props.node.hidden = false; - if (!this._autoKfReaction){ - // console.log("creating another reaction"); - // this._autoKfReaction = this.autoCreateKeyframe(); - } + if (!this._autoKfReaction) { + // console.log("creating another reaction"); + // this._autoKfReaction = this.autoCreateKeyframe(); + } this.timeChange(); } else { this.props.node.hidden = true; @@ -197,8 +204,8 @@ export class Track extends React.Component { // }); // } - @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 @@ -215,8 +222,8 @@ export class Track extends React.Component { let 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; - this.saveStateRegion = regiondata; + this.saveStateKf = currentkf; + this.saveStateRegion = regiondata; } else if (leftkf && rightkf) { await this.interpolate(leftkf, rightkf); } @@ -230,12 +237,12 @@ export class Track extends React.Component { @action private applyKeys = async (kf: Doc) => { let kfNode = await Cast(kf.key, Doc) as Doc; - this.whitelist.forEach(key => { + this.primitiveWhitelist.forEach(key => { if (!kfNode[key]) { this.props.node[key] = undefined; } else { - let stored = kfNode[key]; - this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; + let stored = kfNode[key]; + this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); } @@ -260,17 +267,17 @@ export class Track extends React.Component { */ @action interpolate = async (left: Doc, right: Doc) => { - let leftNode = await(left.key) as Doc; - let rightNode = await(right.key) as Doc; - this.whitelist.forEach(key => { + let leftNode = await (left.key) as Doc; + let rightNode = await (right.key) as Doc; + this.primitiveWhitelist.forEach(key => { if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate - let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); + let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); let deltaLeft = this.time - NumCast(left.time); - let ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); - this.props.node[key] = NumCast(leftNode[key]) + (dif * ratio); + let ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); + this.props.node[key] = NumCast(leftNode[key]) + (dif * ratio); } else { // case data let stored = leftNode[key]; - this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; + this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); } @@ -325,8 +332,8 @@ export class Track extends React.Component { } @action - makeKeyData = (regiondata:RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - let doclist = DocListCast(regiondata.keyframes)!; + makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time + let doclist = DocListCast(regiondata.keyframes)!; let existingkf: (Doc | undefined) = undefined; doclist.forEach(TK => { if (TK.time === time) existingkf = TK; @@ -338,26 +345,26 @@ export class Track extends React.Component { TK.key = this.makeCopy(); TK.type = type; //assuming there are already keyframes (for keeping keyframes in order, sorted by time) - if (doclist.length === 0) regiondata.keyframes!.push(TK); + if (doclist.length === 0) regiondata.keyframes!.push(TK); doclist.forEach(kf => { - let index = doclist.indexOf(kf); + let index = doclist.indexOf(kf); let kfTime = NumCast(kf.time); - if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))){ - regiondata.keyframes!.splice(index + 1, 0, TK); - return; + if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))) { + regiondata.keyframes!.splice(index + 1, 0, TK); + return; } }); - return TK; + return TK; } - @action + @action makeCopy = () => { - let doc = new Doc(); - this.whitelist.forEach(key => { + let doc = new Doc(); + this.primitiveWhitelist.forEach(key => { let originalVal = this.props.node[key]; - doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; + doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; }); - return doc; + return doc; } /** -- cgit v1.2.3-70-g09d2 From 6b8060dd969b314728a86fcd2fefc0e667ba079b Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Wed, 5 Feb 2020 00:22:54 -0500 Subject: everything works except data tracking --- src/client/views/animationtimeline/Track.tsx | 76 ++++++++++++++++------------ 1 file changed, 45 insertions(+), 31 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index e352cdbb5..32fa1d9ca 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -29,6 +29,7 @@ export class Track extends React.Component { @observable private _currentBarXReaction: any; @observable private _timelineVisibleReaction: any; @observable private _autoKfReaction: any; + @observable private _newKeyframe: boolean = false; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; private primitiveWhitelist = [ @@ -36,11 +37,12 @@ export class Track extends React.Component { "y", "width", "height", - "opacity" + "opacity", + "data", ]; private objectWhitelist = [ "data" - ] + ]; @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } @computed private get time() { return NumCast(KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } @@ -57,12 +59,12 @@ export class Track extends React.Component { componentDidMount() { runInAction(async () => { - // this._timelineVisibleReaction = this.timelineVisibleReaction(); + this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); if (this.regions.length === 0) this.createRegion(this.time); this.props.node.hidden = false; this.props.node.opacity = 1; - this.autoCreateKeyframe(); + // this.autoCreateKeyframe(); }); } @@ -108,10 +110,21 @@ export class Track extends React.Component { (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; } + } else if (this._newKeyframe) { + // console.log("new keyframe registering"); + // let kfList = DocListCast(this.saveStateRegion!.keyframes); + // kfList.forEach(kf => { + // kf.key = this.makeCopy(); + // if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3){ + // (kf.key as Doc).opacity = 0.1; + // } + // }); + } keyframes[kfIndex] = kf; this.saveStateKf = undefined; this.saveStateRegion = undefined; + this._newKeyframe = false; } @@ -129,8 +142,6 @@ export class Track extends React.Component { return reaction(() => { return [...this.primitiveWhitelist.map(key => node[key]), ...objects]; }, (changed, reaction) => { - console.log("autocreated"); - console.log(changed); //check for region this.findRegion(this.time).then((region) => { if (region !== undefined) { //if region at scrub time exist @@ -179,30 +190,28 @@ export class Track extends React.Component { }); } - // /** - // * when timeline is visible, reaction is ran so states are reverted - // */ - // @action - // timelineVisibleReaction = () => { - // return reaction(() => { - // return this.props.timelineVisible; - // }, isVisible => { - // this.revertState(); - // if (isVisible) { - // DocListCast(this.regions).forEach(region => { - // if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { - // for (let i = 0; i < 4; i++) { - // DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = Doc.MakeCopy(this.props.node, true); - // if (i === 0 || i === 3) { - // DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key.opacity = 0.1; - // } - // } - // console.log("saving keyframes"); - // } - // }); - // } - // }); - // } + /** + * when timeline is visible, reaction is ran so states are reverted + */ + @action + timelineVisibleReaction = () => { + return reaction(() => { + return this.props.timelineVisible; + }, isVisible => { + if (isVisible) { + DocListCast(this.regions).forEach(region => { + if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { + for (let i = 0; i < 4; i++) { + DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = this.makeCopy(); + if (i === 0 || i === 3) { //manually inputing fades + (DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key! as Doc).opacity = 0.1; + } + } + } + }); + } + }); + } @observable private saveStateKf: (Doc | undefined) = undefined; @observable private saveStateRegion: (Doc | undefined) = undefined; @@ -214,7 +223,7 @@ export class Track extends React.Component { timeChange = async () => { if (this.saveStateKf !== undefined) { await this.saveKeyframe(); - } + } let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on if (regiondata) { let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists @@ -318,6 +327,8 @@ export class Track extends React.Component { createRegion = async (time: number) => { if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data + this._newKeyframe = true; + this.saveStateRegion = regiondata; regiondata.position = time; //set position let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); @@ -362,6 +373,9 @@ export class Track extends React.Component { let doc = new Doc(); this.primitiveWhitelist.forEach(key => { let originalVal = this.props.node[key]; + if (key === "data"){ + console.log(originalVal); + } doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; }); return doc; -- cgit v1.2.3-70-g09d2 From c1846375f87b82ea2391f0e56bd1606e34a8f69b Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Wed, 5 Feb 2020 01:01:54 -0500 Subject: major changes --- src/client/views/animationtimeline/Track.tsx | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 32fa1d9ca..09ebbab14 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -91,6 +91,17 @@ export class Track extends React.Component { let keyframes: List = (Cast(this.saveStateRegion!.keyframes, listSpec(Doc)) as List); let kfIndex: number = keyframes.indexOf(this.saveStateKf!); let kf = keyframes[kfIndex] as Doc; //index in the keyframe + if (this._newKeyframe) { + console.log("new keyframe registering"); + let kfList = DocListCast(this.saveStateRegion!.keyframes); + kfList.forEach(kf => { + kf.key = this.makeCopy(); + if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3){ + (kf.key as Doc).opacity = 0.1; + } + }); + this._newKeyframe = false; + } if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades kf.key = this.makeCopy(); @@ -110,21 +121,10 @@ export class Track extends React.Component { (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; } - } else if (this._newKeyframe) { - // console.log("new keyframe registering"); - // let kfList = DocListCast(this.saveStateRegion!.keyframes); - // kfList.forEach(kf => { - // kf.key = this.makeCopy(); - // if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3){ - // (kf.key as Doc).opacity = 0.1; - // } - // }); - } keyframes[kfIndex] = kf; this.saveStateKf = undefined; this.saveStateRegion = undefined; - this._newKeyframe = false; } @@ -223,7 +223,10 @@ export class Track extends React.Component { timeChange = async () => { if (this.saveStateKf !== undefined) { await this.saveKeyframe(); - } + } else if (this._newKeyframe){ + console.log("CALLED"); + await this.saveKeyframe(); + } let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on if (regiondata) { let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists -- cgit v1.2.3-70-g09d2 From 10432453db7890696eb5c9b1c4572d4cff63b0b1 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Wed, 5 Feb 2020 08:46:21 -0500 Subject: about to merge --- src/client/views/animationtimeline/Keyframe.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.scss b/src/client/views/animationtimeline/Keyframe.scss index f0685943b..8dcf71994 100644 --- a/src/client/views/animationtimeline/Keyframe.scss +++ b/src/client/views/animationtimeline/Keyframe.scss @@ -46,9 +46,9 @@ $timelineDark: #77a1aa; position: absolute; } - .keyframe:hover~.keyframe-information { - display: flex; - } + // .keyframe:hover~.keyframe-information { + // display: flex; + // } .keyframe-information { display: none; -- cgit v1.2.3-70-g09d2 From 9e4d644c5977c781b4822ba065cec6e92977de10 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Wed, 5 Feb 2020 10:16:42 -0500 Subject: about to pull --- src/client/views/animationtimeline/Timeline.scss | 28 ++++++++++++++++++++-- src/client/views/animationtimeline/Timeline.tsx | 21 +++++++++++++--- .../views/animationtimeline/TimelineOverview.scss | 9 ++++++- .../views/animationtimeline/TimelineOverview.tsx | 19 +++++++-------- 4 files changed, 61 insertions(+), 16 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index dbdade03f..ce8c845df 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -43,6 +43,8 @@ $timelineDark: #77a1aa; .time-box { margin-left: 5px; display: flex; + justify-content: center; + align-items: center; } .mode-box { @@ -61,6 +63,12 @@ $timelineDark: #77a1aa; } } + .overview-tool { + display: flex; + justify-content: center; + align-items: center; + } + .animation-text { // font-size: 16px; height: auto; @@ -179,13 +187,14 @@ $timelineDark: #77a1aa; .trackbox { top: 30px; - // TODO: where is this 30px coming from? height: calc(100% - 30px); // height: 100%; + // height: 100%; width: 100%; border-top: 2px solid black; border-bottom: 2px solid black; overflow: hidden; + // overflow-y: scroll; background-color: white; position: absolute; // box-shadow: -10px 0px 10px 10px red; @@ -193,10 +202,25 @@ $timelineDark: #77a1aa; } + .currentTime { + // background: red; + font-size: 12px; + display: flex; + justify-content: center; + align-items: center; + height: 40px; + top: 40px; + position: relative; + width: 100px; + margin-left: 20px; + } + .title-container { - margin-top: 80px; + // margin-top: 80px; + margin-top: 40px; margin-left: 20px; height: calc(100% - 100px - 30px); + // height: 100%; width: 100px; background-color: white; overflow: hidden; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index f0ca1c0ab..ae2dfafc9 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -312,6 +312,7 @@ export class Timeline extends React.Component { e.preventDefault(); e.stopPropagation(); let offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; + // let offset = 0; if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT) { this._containerHeight = this.MIN_CONTAINER_HEIGHT; } else if (this._containerHeight + offset >= this.MAX_CONTAINER_HEIGHT) { @@ -326,7 +327,10 @@ export class Timeline extends React.Component { */ @action toReadTime = (time: number): string => { - const inSeconds = time / 1000; + time = time / 1000; + var inSeconds = Math.round((time * 100)) / 100; + // var inSeconds = parseFloat(time.toFixed(2)); + // const inSeconds = (Math.floor(time) / 1000); let min: (string | number) = Math.floor(inSeconds / 60); let sec: (string | number) = inSeconds % 60; @@ -451,7 +455,8 @@ export class Timeline extends React.Component {
    {lengthString}
    - + +
    Hello there
    @@ -541,13 +546,22 @@ export class Timeline extends React.Component { } } + // @computed + getCurrentTime = () => { + let current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + // console.log(this._currentBarX) + return this.toReadTime(current); `` + // return (Math.floor(current) / 1000) + // return current / 1000.0; + } + /** * if you have any question here, just shoot me an email or text. * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { - // console.log(this.props.PanelWidth()); + console.log(this.props.Document.isATOn); runInAction(() => { this._panelWidth = this.props.PanelWidth(); this.changeLenths(); @@ -568,6 +582,7 @@ export class Timeline extends React.Component { {DocListCast(this.children).map(doc => )}
    +
    Current: {this.getCurrentTime()}
    {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )}
    diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index a0b9d462b..283163ea7 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -8,6 +8,13 @@ $timelineDark: #77a1aa; margin-right: 10px; } +.timeline-flex { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} + .timeline-overview-container { // padding: 0px; margin-right: 5px; @@ -93,7 +100,7 @@ $timelineDark: #77a1aa; height: 4px; width: 0px; z-index: 1000; - background-color: $timelineColor; + background-color: $timelineDark; border-radius: 20px; margin-top: -4px; cursor: pointer; diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 9a881264f..65fd8ff62 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -56,8 +56,11 @@ export class TimelineOverview extends React.Component{ @action setOverviewWidth() { let width = $("#timelineOverview").width(); + // console.log($("timelineOverview")) if (width) this.overviewBarWidth = width; else this.overviewBarWidth = 0; + + // console.log(this.overviewBarWidth) } @action @@ -124,20 +127,14 @@ export class TimelineOverview extends React.Component{ this.visibleTime = vis; this.currentX = x; this.visibleStart = start; + // console.log("getting times") + // console.log(x) + // console.log(start) } render() { - + this.setOverviewWidth(); this.getTimes(); - // calculates where everything should fall based on its size - // let percentVisible = this.props.visibleLength / this.props.totalLength; - // let visibleBarWidth = percentVisible * this.overviewBarWidth; - - // let percentScrubberStart = this.props.currentBarX / this.props.totalLength; - // let scrubberStart = percentScrubberStart * this.overviewBarWidth; - - // let percentBarStart = this.props.visibleStart / this.props.totalLength; - // let barStart = percentBarStart * this.overviewBarWidth; let percentVisible = this.visibleTime / this.props.time; let visibleBarWidth = percentVisible * this.overviewBarWidth; @@ -163,9 +160,11 @@ export class TimelineOverview extends React.Component{
    ]; return ( +
    {timeline}
    +
    ); } -- cgit v1.2.3-70-g09d2 From 4cc2472c5e2d16ac5bc60a919150d1df5d6f4129 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Wed, 5 Feb 2020 10:25:23 -0500 Subject: ready --- src/client/views/animationtimeline/Timeline.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 68b0ce80c..f74d4c71e 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -454,7 +454,7 @@ export class Timeline extends React.Component {
    {lengthString}
    -
    {this.getCurrentTime()}
    +
    Current: {this.getCurrentTime()}
    -- cgit v1.2.3-70-g09d2 From 0c8f7a70dfa954e74c886d89fadf79ee75c26029 Mon Sep 17 00:00:00 2001 From: Andrew Kim Date: Wed, 5 Feb 2020 11:45:03 -0500 Subject: fixed --- src/client/views/animationtimeline/Track.tsx | 31 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 09ebbab14..287e4a04f 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -38,7 +38,6 @@ export class Track extends React.Component { "width", "height", "opacity", - "data", ]; private objectWhitelist = [ "data" @@ -98,6 +97,8 @@ export class Track extends React.Component { kf.key = this.makeCopy(); if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3){ (kf.key as Doc).opacity = 0.1; + } else{ + (kf.key as Doc).opacity = 1; } }); this._newKeyframe = false; @@ -154,18 +155,18 @@ export class Track extends React.Component { }, { fireImmediately: false }); } + + + // @observable private _storedState:(Doc | undefined) = undefined; // /** // * reverting back to previous state before editing on AT // */ // @action // revertState = () => { - // let copyDoc = Doc.MakeCopy(this.props.node, true); // if (this._storedState) this.applyKeys(this._storedState); - // let newState = new Doc(); - // newState.key = copyDoc; - // this._storedState = newState; // } + /** * Reaction when scrubber bar changes * made into function so it's easier to dispose later @@ -176,10 +177,10 @@ export class Track extends React.Component { this.findRegion(this.time).then((regiondata: (Doc | undefined)) => { if (regiondata) { this.props.node.hidden = false; - if (!this._autoKfReaction) { - // console.log("creating another reaction"); - // this._autoKfReaction = this.autoCreateKeyframe(); - } + // if (!this._autoKfReaction) { + // // console.log("creating another reaction"); + // // this._autoKfReaction = this.autoCreateKeyframe(); + // } this.timeChange(); } else { this.props.node.hidden = true; @@ -209,6 +210,9 @@ export class Track extends React.Component { } } }); + } else { + console.log("reverting state"); + //this.revertState(); } }); } @@ -224,7 +228,6 @@ export class Track extends React.Component { if (this.saveStateKf !== undefined) { await this.saveKeyframe(); } else if (this._newKeyframe){ - console.log("CALLED"); await this.saveKeyframe(); } let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on @@ -233,6 +236,7 @@ export class Track extends React.Component { let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { + console.log("is current"); await this.applyKeys(currentkf); this.saveStateKf = currentkf; this.saveStateRegion = regiondata; @@ -330,8 +334,7 @@ export class Track extends React.Component { createRegion = async (time: number) => { if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data - this._newKeyframe = true; - this.saveStateRegion = regiondata; + regiondata.position = time; //set position let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); @@ -339,7 +342,9 @@ export class Track extends React.Component { regiondata.duration = rightRegion.position - regiondata.position; } if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { - this.regions.push(regiondata); + this.regions.push(regiondata); + this._newKeyframe = true; + this.saveStateRegion = regiondata; return regiondata; } } -- cgit v1.2.3-70-g09d2 From e310c0fdcef6ac71ee492470d4ac689cbb094167 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sat, 8 Feb 2020 12:54:07 -0500 Subject: small changes --- src/client/views/animationtimeline/Timeline.tsx | 15 +++++++-------- src/client/views/animationtimeline/TimelineOverview.scss | 2 +- src/client/views/animationtimeline/TimelineOverview.tsx | 8 ++++++-- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index f74d4c71e..5d5e78652 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -453,7 +453,7 @@ export class Timeline extends React.Component {
    {lengthString}
    - +
    Current: {this.getCurrentTime()}
    @@ -466,12 +466,12 @@ export class Timeline extends React.Component { */ @action private onTimeInput = (e: React.KeyboardEvent) => { - if (e.keyCode === 13) { - let timeInput = this._timeInputRef.current!; - this._time = parseInt(timeInput.value, 10); - this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); - this.props.Document.AnimationLength = this._time; - } + // if (e.keyCode === 13) { + // let timeInput = this._timeInputRef.current!; + // this._time = parseInt(timeInput.value, 10); + // this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); + // this.props.Document.AnimationLength = this._time; + // } } @@ -535,7 +535,6 @@ export class Timeline extends React.Component { * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { - console.log(this.props.Document.isATOn); runInAction(() => { this._panelWidth = this.props.PanelWidth(); this.changeLenths(); diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index 283163ea7..b54399307 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -72,7 +72,7 @@ $timelineDark: #77a1aa; position: relative; padding: 0px; margin: 0px; - width: 100%; + // width: 100%; height: 4px; background-color: $timelineColor; border-radius: 20px; diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 7ff78955e..5d6378068 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -58,7 +58,7 @@ export class TimelineOverview extends React.Component{ let width = $("#timelineOverview").width(); // console.log($("timelineOverview")) if (width) this.overviewBarWidth = width; - else this.overviewBarWidth = 0; + // else this.overviewBarWidth = 0; // console.log(this.overviewBarWidth) } @@ -95,10 +95,12 @@ export class TimelineOverview extends React.Component{ onScrubberDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); + if (!this.props.isAuthoring) { document.removeEventListener("pointermove", this.onScrubberMove); document.removeEventListener("pointerup", this.onScrubberUp); document.addEventListener("pointermove", this.onScrubberMove); document.addEventListener("pointerup", this.onScrubberUp); + } } @action @@ -107,8 +109,10 @@ export class TimelineOverview extends React.Component{ e.stopPropagation(); let scrubberRef = this._scrubberRef.current!; let left = scrubberRef.getBoundingClientRect().left; + // left = e.screenX; let offsetX = Math.round(e.clientX - left); this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); + // this.props.changeCurrentBarX(e.screenX) } @action @@ -154,7 +158,7 @@ export class TimelineOverview extends React.Component{
    ] : [ -
    +
    ,
    -- cgit v1.2.3-70-g09d2 From 92068acedc3d6f5bed25dc1a0dacbe19d0338829 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 9 Feb 2020 14:06:54 -0500 Subject: reformatted --- package-lock.json | 8 ++++- package.json | 2 +- src/client/views/animationtimeline/Timeline.tsx | 2 +- .../views/animationtimeline/TimelineOverview.scss | 2 +- .../views/animationtimeline/TimelineOverview.tsx | 35 +++++++++++----------- .../collectionFreeForm/CollectionFreeFormView.tsx | 33 ++++++++++---------- 6 files changed, 46 insertions(+), 36 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/package-lock.json b/package-lock.json index 379cd3337..1f87e1493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14244,7 +14244,8 @@ "fsevents": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==" + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "optional": true }, "get-caller-file": { "version": "2.0.5", @@ -16134,6 +16135,11 @@ "setimmediate": "^1.0.4" } }, + "tiny-timer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/tiny-timer/-/tiny-timer-1.4.0.tgz", + "integrity": "sha512-NZCayn+Y2OaDaBtVQmx8Lx/SggG9qGGINYoPNmXpqvj8ue7E24H9ZgI+02I9BZSMWCW8keOXsw2R3hSzk7aALQ==" + }, "tinycolor2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", diff --git a/package.json b/package.json index b6beb5a3a..155026d2c 100644 --- a/package.json +++ b/package.json @@ -237,4 +237,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} \ No newline at end of file +} diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 5d5e78652..2ac7e6c92 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -343,7 +343,7 @@ export class Timeline extends React.Component { * context menu function. * opens the timeline or closes the timeline. */ - timelineContextMenu = (e: MouseEvent): void => { + timelineContextMenu = (e: React.MouseEvent): void => { ContextMenu.Instance.addItem({ description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { this._timelineVisible = !this._timelineVisible; diff --git a/src/client/views/animationtimeline/TimelineOverview.scss b/src/client/views/animationtimeline/TimelineOverview.scss index b54399307..283163ea7 100644 --- a/src/client/views/animationtimeline/TimelineOverview.scss +++ b/src/client/views/animationtimeline/TimelineOverview.scss @@ -72,7 +72,7 @@ $timelineDark: #77a1aa; position: relative; padding: 0px; margin: 0px; - // width: 100%; + width: 100%; height: 4px; background-color: $timelineColor; border-radius: 20px; diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 5d6378068..6358982c4 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -55,7 +55,7 @@ export class TimelineOverview extends React.Component{ @action setOverviewWidth() { - let width = $("#timelineOverview").width(); + const width = $("#timelineOverview").width(); // console.log($("timelineOverview")) if (width) this.overviewBarWidth = width; // else this.overviewBarWidth = 0; @@ -77,7 +77,7 @@ export class TimelineOverview extends React.Component{ onPanX = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - let movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX; + const movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX; // let movX = (this.props.visibleStart / this.props.totalLength) * (this.overviewWidth) + e.movementX; this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength); // this.props.movePanX((movX / (this.overviewWidth) * this.props.totalLength); @@ -95,22 +95,22 @@ export class TimelineOverview extends React.Component{ onScrubberDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - if (!this.props.isAuthoring) { + // if (!this.props.isAuthoring) { document.removeEventListener("pointermove", this.onScrubberMove); document.removeEventListener("pointerup", this.onScrubberUp); document.addEventListener("pointermove", this.onScrubberMove); document.addEventListener("pointerup", this.onScrubberUp); - } + // } } @action onScrubberMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let scrubberRef = this._scrubberRef.current!; - let left = scrubberRef.getBoundingClientRect().left; + const scrubberRef = this._scrubberRef.current!; + const left = scrubberRef.getBoundingClientRect().left; // left = e.screenX; - let offsetX = Math.round(e.clientX - left); + const offsetX = Math.round(e.clientX - left); this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); // this.props.changeCurrentBarX(e.screenX) } @@ -125,9 +125,9 @@ export class TimelineOverview extends React.Component{ @action getTimes() { - let vis = KeyframeFunc.convertPixelTime(this.props.visibleLength, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); - let x = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); - let start = KeyframeFunc.convertPixelTime(this.props.visibleStart, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + const vis = KeyframeFunc.convertPixelTime(this.props.visibleLength, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + const x = KeyframeFunc.convertPixelTime(this.props.currentBarX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + const start = KeyframeFunc.convertPixelTime(this.props.visibleStart, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); this.visibleTime = vis; this.currentX = x; this.visibleStart = start; @@ -137,19 +137,20 @@ export class TimelineOverview extends React.Component{ } render() { + console.log("RERENDERED!"); this.setOverviewWidth(); this.getTimes(); - let percentVisible = this.visibleTime / this.props.time; - let visibleBarWidth = percentVisible * this.overviewBarWidth; + const percentVisible = this.visibleTime / this.props.time; + const visibleBarWidth = percentVisible * this.overviewBarWidth; - let percentScrubberStart = this.currentX / this.props.time; - let scrubberStart = percentScrubberStart * this.overviewBarWidth; + const percentScrubberStart = this.currentX / this.props.time; + const scrubberStart = percentScrubberStart * this.overviewBarWidth; - let percentBarStart = this.visibleStart / this.props.time; - let barStart = percentBarStart * this.overviewBarWidth; + const percentBarStart = this.visibleStart / this.props.time; + const barStart = percentBarStart * this.overviewBarWidth; - let timeline = this.props.isAuthoring ? [ + const timeline = this.props.isAuthoring ? [
    , diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c61dcd21f..56b3b3bc0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -966,7 +966,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); @@ -1019,6 +1018,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { icon: "eye" }); ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" }); + this._timelineRef.current!.timelineContextMenu(e); } @@ -1070,21 +1070,24 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if isAnnotationOverlay is set, then children will be stored in the extension document for the fieldKey. // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document // let lodarea = this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale; - return
    - {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ? - this.placeholder : this.marqueeView} + return
    +
    + {/* */} + {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ? + this.placeholder : this.marqueeView} + +
    -
    ; } } -- cgit v1.2.3-70-g09d2 From 4eb94980caad8fb98863e140189a9f77b67cf354 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 9 Feb 2020 14:46:05 -0500 Subject: fixed scrubber --- src/client/views/animationtimeline/Keyframe.tsx | 2 +- src/client/views/animationtimeline/TimelineOverview.tsx | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index a2add3ae8..fd4a3f281 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -337,7 +337,7 @@ export class Keyframe extends React.Component { makeKeyframeMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => { - let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { width: 300, height: 300 }); + let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { _width: 300, _height: 300 }); CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); }), diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 6358982c4..4d1d1cf88 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -109,10 +109,8 @@ export class TimelineOverview extends React.Component{ e.stopPropagation(); const scrubberRef = this._scrubberRef.current!; const left = scrubberRef.getBoundingClientRect().left; - // left = e.screenX; const offsetX = Math.round(e.clientX - left); - this.props.changeCurrentBarX((offsetX / (this.DEFAULT_WIDTH) * this.props.totalLength) + this.props.currentBarX); - // this.props.changeCurrentBarX(e.screenX) + this.props.changeCurrentBarX((((offsetX) / this.overviewBarWidth) * this.props.totalLength) + this.props.currentBarX); } @action @@ -154,7 +152,7 @@ export class TimelineOverview extends React.Component{
    , -
    +
    -- cgit v1.2.3-70-g09d2 From 7d2e05ca34d28d49d9272668091bfce7e6b47f22 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 9 Feb 2020 14:51:26 -0500 Subject: fixed --- src/client/views/animationtimeline/TimelineOverview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 4d1d1cf88..66f6a9482 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -158,9 +158,9 @@ export class TimelineOverview extends React.Component{
    ] : [
    -
    +
    , -
    +
    ]; return (
    -- cgit v1.2.3-70-g09d2 From fb9cbca164800c26baee2d0bde171e9e052b7866 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sun, 9 Feb 2020 14:55:25 -0500 Subject: taking out right information --- package-lock.json | 142 +++++++++++++++--------- package.json | 4 +- src/client/views/animationtimeline/Timeline.tsx | 23 +++- 3 files changed, 111 insertions(+), 58 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/package-lock.json b/package-lock.json index 1f87e1493..5684789c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6533,9 +6533,9 @@ "dev": true }, "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -8844,9 +8844,9 @@ "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" }, "npm": { - "version": "6.13.6", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.6.tgz", - "integrity": "sha512-NomC08kv7HIl1FOyLOe9Hp89kYsOsvx52huVIJ7i8hFW8Xp65lDwe/8wTIrh9q9SaQhA8hTrfXPh3BEL3TmMpw==", + "version": "6.13.7", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.7.tgz", + "integrity": "sha512-X967EKTT407CvgrWFjXusnPh0VLERcmR9hZFSVgkEquOomZkvpwLJ5zrQ3qrG9SpPLKJE4bPLUu76exKQ4a3Cg==", "requires": { "JSONStream": "^1.3.5", "abbrev": "~1.1.1", @@ -8854,7 +8854,7 @@ "ansistyles": "~0.1.3", "aproba": "^2.0.0", "archy": "~1.0.0", - "bin-links": "^1.1.6", + "bin-links": "^1.1.7", "bluebird": "^3.5.5", "byte-size": "^5.0.1", "cacache": "^12.0.3", @@ -8897,7 +8897,7 @@ "libnpmorg": "^1.0.1", "libnpmsearch": "^2.0.2", "libnpmteam": "^1.0.2", - "libnpx": "^10.2.0", + "libnpx": "^10.2.2", "lock-verify": "^2.1.0", "lockfile": "^1.0.4", "lodash._baseindexof": "*", @@ -8916,7 +8916,7 @@ "mississippi": "^3.0.0", "mkdirp": "~0.5.1", "move-concurrently": "^1.0.1", - "node-gyp": "^5.0.5", + "node-gyp": "^5.0.7", "nopt": "~4.0.1", "normalize-package-data": "^2.5.0", "npm-audit-report": "^1.3.2", @@ -9113,7 +9113,7 @@ } }, "bin-links": { - "version": "1.1.6", + "version": "1.1.7", "bundled": true, "requires": { "bluebird": "^3.5.3", @@ -9593,7 +9593,7 @@ } }, "env-paths": { - "version": "1.0.0", + "version": "2.2.0", "bundled": true }, "err-code": { @@ -9896,7 +9896,7 @@ } }, "get-caller-file": { - "version": "1.0.2", + "version": "1.0.3", "bundled": true }, "get-stream": { @@ -10091,7 +10091,7 @@ } }, "invert-kv": { - "version": "1.0.0", + "version": "2.0.0", "bundled": true }, "ip": { @@ -10249,10 +10249,10 @@ "bundled": true }, "lcid": { - "version": "1.0.0", + "version": "2.0.0", "bundled": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "^2.0.0" } }, "libcipm": { @@ -10411,7 +10411,7 @@ } }, "libnpx": { - "version": "10.2.0", + "version": "10.2.2", "bundled": true, "requires": { "dotenv": "^5.0.1", @@ -10541,15 +10541,30 @@ "ssri": "^6.0.0" } }, + "map-age-cleaner": { + "version": "0.1.3", + "bundled": true, + "requires": { + "p-defer": "^1.0.0" + } + }, "meant": { "version": "1.0.1", "bundled": true }, "mem": { - "version": "1.1.0", + "version": "4.3.0", "bundled": true, "requires": { - "mimic-fn": "^1.0.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "bundled": true + } } }, "mime-db": { @@ -10563,10 +10578,6 @@ "mime-db": "~1.35.0" } }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, "minimatch": { "version": "3.0.4", "bundled": true, @@ -10644,6 +10655,10 @@ "version": "0.0.7", "bundled": true }, + "nice-try": { + "version": "1.0.5", + "bundled": true + }, "node-fetch-npm": { "version": "2.0.2", "bundled": true, @@ -10654,33 +10669,20 @@ } }, "node-gyp": { - "version": "5.0.5", + "version": "5.0.7", "bundled": true, "requires": { - "env-paths": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", "tar": "^4.4.12", - "which": "1" - }, - "dependencies": { - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "5.3.0", - "bundled": true - } + "which": "^1.3.1" } }, "nopt": { @@ -10874,12 +10876,38 @@ "bundled": true }, "os-locale": { - "version": "2.1.0", + "version": "3.1.0", "bundled": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "bundled": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "bundled": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } } }, "os-tmpdir": { @@ -10894,10 +10922,18 @@ "os-tmpdir": "^1.0.0" } }, + "p-defer": { + "version": "1.0.0", + "bundled": true + }, "p-finally": { "version": "1.0.0", "bundled": true }, + "p-is-promise": { + "version": "2.1.0", + "bundled": true + }, "p-limit": { "version": "1.2.0", "bundled": true, @@ -11872,14 +11908,14 @@ "bundled": true }, "yargs": { - "version": "11.0.0", + "version": "11.1.1", "bundled": true, "requires": { "cliui": "^4.0.0", "decamelize": "^1.1.1", "find-up": "^2.1.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", @@ -17955,7 +17991,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/package.json b/package.json index 155026d2c..5b2818c33 100644 --- a/package.json +++ b/package.json @@ -176,7 +176,7 @@ "nodemailer": "^5.1.1", "nodemon": "^1.19.4", "normalize.css": "^8.0.1", - "npm": "^6.13.6", + "npm": "^6.13.7", "p-limit": "^2.2.0", "passport": "^0.4.0", "passport-google-oauth20": "^2.0.0", @@ -226,8 +226,8 @@ "socket.io": "^2.3.0", "socket.io-client": "^2.3.0", "solr-node": "^1.2.1", - "tiny-timer": "^1.3.0", "standard-http-error": "^2.0.1", + "tiny-timer": "^1.3.0", "typescript-collections": "^1.3.3", "url-loader": "^1.1.2", "uuid": "^3.4.0", diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 2ac7e6c92..e4af43e0a 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -433,6 +433,8 @@ export class Timeline extends React.Component { lengthString = ""; } + // let rightInfo = this.timeIndicator; + return (
    @@ -452,15 +454,30 @@ export class Timeline extends React.Component {
    -
    {lengthString}
    - -
    Current: {this.getCurrentTime()}
    + {this.timeIndicator(lengthString)} + {/* {rightInfo} */}
    ); } + timeIndicator(lengthString: string) { + if (this.props.Document.isATOn) { + return ( + <> +
    {lengthString}
    + + + ); + } + else { + return ( +
    Current: {this.getCurrentTime()}
    + ); + } + } + /** * manual time input (kinda broken right now) */ -- cgit v1.2.3-70-g09d2 From eea67eb24b944f13e307915d386f7745078e7d23 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 9 Feb 2020 15:06:45 -0500 Subject: const to let --- src/client/views/animationtimeline/Keyframe.tsx | 74 +++++++++++----------- src/client/views/animationtimeline/Timeline.tsx | 56 ++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- 3 files changed, 67 insertions(+), 67 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index fd4a3f281..bb557289e 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -36,7 +36,7 @@ export namespace KeyframeFunc { let leftMost: (RegionData | undefined) = undefined; let rightMost: (RegionData | undefined) = undefined; DocListCast(regions).forEach(region => { - let neighbor = RegionData(region); + const neighbor = RegionData(region); if (currentRegion.position! > neighbor.position) { if (!leftMost || neighbor.position > leftMost.position) { leftMost = neighbor; @@ -57,7 +57,7 @@ export namespace KeyframeFunc { export const calcMinLeft = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closet keyframe to the left let leftKf: (Doc | undefined) = undefined; let time: number = 0; - let keyframes = await DocListCastAsync(region.keyframes!); + const keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { let compTime = currentBarX; if (ref) compTime = NumCast(ref.time); @@ -73,7 +73,7 @@ export namespace KeyframeFunc { export const calcMinRight = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closest keyframe to the right let rightKf: (Doc | undefined) = undefined; let time: number = Infinity; - let keyframes = await DocListCastAsync(region.keyframes!); + const keyframes = await DocListCastAsync(region.keyframes!); keyframes!.forEach((kf) => { let compTime = currentBarX; if (ref) compTime = NumCast(ref.time); @@ -86,7 +86,7 @@ export namespace KeyframeFunc { }; export const defaultKeyframe = () => { - let regiondata = new Doc(); //creating regiondata in MILI + const regiondata = new Doc(); //creating regiondata in MILI regiondata.duration = 4000; regiondata.position = 0; regiondata.fadeIn = 1000; @@ -98,7 +98,7 @@ export namespace KeyframeFunc { export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing: number, tickIncrement: number) => { - let time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement; + const time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement; switch (unit) { case "mili": return time; @@ -180,10 +180,10 @@ export class Keyframe extends React.Component { componentDidMount() { setTimeout(() => { //giving it a temporary 1sec delay... if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - let start = this.props.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); - let fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); - let fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); - let finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); + 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); + const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); + const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); (fadeIn.key as Doc).opacity = 1; (fadeOut.key as Doc).opacity = 1; (start.key as Doc).opacity = 0.1; @@ -199,7 +199,7 @@ export class Keyframe extends React.Component { onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let clientX = e.clientX; + const clientX = e.clientX; if (this._doubleClickEnabled) { this.createKeyframe(clientX); this._doubleClickEnabled = false; @@ -224,10 +224,10 @@ export class Keyframe extends React.Component { if (e.movementX !== 0) { this._mouseToggled = true; } - let left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; - let right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions!); - let prevX = this.regiondata.position; - let futureX = this.regiondata.position + KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + 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); if (futureX <= 0) { this.regiondata.position = 0; } else if ((left && left.position + left.duration >= futureX)) { @@ -237,7 +237,7 @@ export class Keyframe extends React.Component { } else { this.regiondata.position = futureX; } - let movement = this.regiondata.position - prevX; + const movement = this.regiondata.position - prevX; this.keyframes.forEach(kf => { kf.time = NumCast(kf.time) + movement; }); @@ -267,9 +267,9 @@ export class Keyframe extends React.Component { onDragResizeLeft = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let bar = this._bar.current!; - let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); - let leftRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions); + 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 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; this.regiondata.duration = NumCast(this.keyframes[this.keyframes.length - 1].time) - (leftRegion.position + leftRegion.duration); @@ -292,10 +292,10 @@ export class Keyframe extends React.Component { onDragResizeRight = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let bar = this._bar.current!; - let offset = KeyframeFunc.convertPixelTime(Math.round((e.clientX - bar.getBoundingClientRect().right) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); - let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, this.regiondata, this.regions); - let fadeOutKeyframeTime = NumCast(this.keyframes[this.keyframes.length - 3].time); + 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 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 this.regiondata.duration = fadeOutKeyframeTime - this.regiondata.position + this.regiondata.fadeOut; } else if (rightRegion && (this.regiondata.position + this.regiondata.duration + offset >= rightRegion.position)) { @@ -311,10 +311,10 @@ export class Keyframe extends React.Component { @action createKeyframe = async (clientX: number) => { this._mouseToggled = true; - let bar = this._bar.current!; - let offset = KeyframeFunc.convertPixelTime(Math.round((clientX - bar.getBoundingClientRect().left) * this.props.transform.Scale), "mili", "time", this.props.tickSpacing, this.props.tickIncrement); + 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 - let position = this.regiondata.position; + 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 @@ -337,7 +337,7 @@ export class Keyframe extends React.Component { makeKeyframeMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => { - let kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { _width: 300, _height: 300 }); + const kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { _width: 300, _height: 300 }); CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); }); }), @@ -350,7 +350,7 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("input", "Move", (val) => { runInAction(() => { let cannotMove: boolean = false; - let kfIndex: number = this.keyframes.indexOf(kf); + 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; } @@ -401,7 +401,7 @@ export class Keyframe extends React.Component { }), TimelineMenu.Instance.addItem("input", `position: ${this.regiondata.position}ms`, (val) => { runInAction(() => { - let prevPosition = this.regiondata.position; + const prevPosition = this.regiondata.position; let cannotMove: boolean = false; DocListCast(this.regions).forEach(region => { if (NumCast(region.position) !== this.regiondata.position) { @@ -454,7 +454,7 @@ export class Keyframe extends React.Component { onContainerOver = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); e.stopPropagation(); - let div = ref.current!; + const div = ref.current!; div.style.opacity = "1"; Doc.BrushDoc(this.props.node); } @@ -466,7 +466,7 @@ export class Keyframe extends React.Component { onContainerOut = (e: React.PointerEvent, ref: React.RefObject) => { e.preventDefault(); e.stopPropagation(); - let div = ref.current!; + const div = ref.current!; div.style.opacity = "0"; Doc.UnBrushDoc(this.props.node); } @@ -481,7 +481,7 @@ export class Keyframe extends React.Component { */ @action drawKeyframes = () => { - let keyframeDivs: JSX.Element[] = []; + const keyframeDivs: JSX.Element[] = []; DocListCast(this.regiondata.keyframes).forEach(kf => { if (kf.type as KeyframeFunc.KeyframeType !== KeyframeFunc.KeyframeType.end) { keyframeDivs.push( @@ -514,14 +514,14 @@ export class Keyframe extends React.Component { */ @action drawKeyframeDividers = () => { - let keyframeDividers: JSX.Element[] = []; + const keyframeDividers: JSX.Element[] = []; DocListCast(this.regiondata.keyframes).forEach(kf => { - let index = this.keyframes.indexOf(kf); + const index = this.keyframes.indexOf(kf); if (index !== this.keyframes.length - 1) { - let right = this.keyframes[index + 1]; - let bodyRef = React.createRef(); - let kfPos = KeyframeFunc.convertPixelTime(NumCast(kf.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); - let rightPos = KeyframeFunc.convertPixelTime(NumCast(right.time), "mili", "pixel", this.props.tickSpacing, this.props.tickIncrement); + const right = this.keyframes[index + 1]; + const bodyRef = React.createRef(); + 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(
    { e.preventDefault(); e.stopPropagation(); this.onContainerOver(e, bodyRef); }} diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 2ac7e6c92..dc381609e 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -86,7 +86,7 @@ export class Timeline extends React.Component { */ @computed private get children(): List { - let extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); + const extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); if (extendedDocument) { if (this.props.Document.data_ext) { return Cast((Cast(this.props.Document.data_ext, Doc) as Doc).annotations, listSpec(Doc)) as List; @@ -99,7 +99,7 @@ export class Timeline extends React.Component { /////////lifecycle functions//////////// componentWillMount() { - let relativeHeight = window.innerHeight / 20; //sets height to arbitrary size, relative to innerHeight + const relativeHeight = window.innerHeight / 20; //sets height to arbitrary size, relative to innerHeight 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 @@ -133,7 +133,7 @@ export class Timeline extends React.Component { */ @action drawTicks = () => { - let ticks = []; + const ticks = []; for (let i = 0; i < this._time / this._tickIncrement; i++) { ticks.push(

    {this.toReadTime(i * this._tickIncrement)}

    ); } @@ -226,9 +226,9 @@ export class Timeline extends React.Component { onScrubberMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let scrubberbox = this._infoContainer.current!; - let left = scrubberbox.getBoundingClientRect().left; - let offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; + const scrubberbox = this._infoContainer.current!; + const left = scrubberbox.getBoundingClientRect().left; + const offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale; this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position } @@ -239,7 +239,7 @@ export class Timeline extends React.Component { onPanDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let clientX = e.clientX; + const clientX = e.clientX; if (this._doubleClickEnabled) { this._doubleClickEnabled = false; } else { @@ -270,8 +270,8 @@ export class Timeline extends React.Component { if (e.movementX !== 0 || e.movementY !== 0) { this._mouseToggled = true; } - let trackbox = this._trackbox.current!; - let titleContainer = this._titleContainer.current!; + const trackbox = this._trackbox.current!; + const titleContainer = this._titleContainer.current!; this.movePanX(this._visibleStart - e.movementX); trackbox.scrollTop = trackbox.scrollTop - e.movementY; titleContainer.scrollTop = titleContainer.scrollTop - e.movementY; @@ -287,7 +287,7 @@ export class Timeline extends React.Component { @action movePanX = (pixel: number) => { - let infoContainer = this._infoContainer.current!; + const infoContainer = this._infoContainer.current!; infoContainer.scrollLeft = pixel; this._visibleStart = infoContainer.scrollLeft; } @@ -309,7 +309,7 @@ export class Timeline extends React.Component { onResizeMove = (e: PointerEvent) => { e.preventDefault(); e.stopPropagation(); - let offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; + const offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom; // let offset = 0; if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT) { this._containerHeight = this.MIN_CONTAINER_HEIGHT; @@ -326,10 +326,10 @@ export class Timeline extends React.Component { @action toReadTime = (time: number): string => { time = time / 1000; - var inSeconds = Math.round((time * 100)) / 100; + const inSeconds = Math.round((time * 100)) / 100; // var inSeconds = parseFloat(time.toFixed(2)); // const inSeconds = (Math.floor(time) / 1000); - let min: (string | number) = Math.floor(inSeconds / 60); + const min: (string | number) = Math.floor(inSeconds / 60); let sec: (string | number) = inSeconds % 60; if (Math.floor(sec / 10) === 0) { @@ -360,12 +360,12 @@ export class Timeline extends React.Component { onWheelZoom = (e: React.WheelEvent) => { e.preventDefault(); e.stopPropagation(); - let offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; - let prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); - let prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + const offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left; + const prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement); + const prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); e.deltaY < 0 ? this.zoom(true) : this.zoom(false); - let currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); - let currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); + const currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + const currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement); this._infoContainer.current!.scrollLeft = currPixel - offset; this._visibleStart = currPixel - offset > 0 ? currPixel - offset : 0; this._visibleStart += this._visibleLength + this._visibleStart > this._totalLength ? this._totalLength - (this._visibleStart + this._visibleLength) : 0; @@ -396,7 +396,7 @@ export class Timeline extends React.Component { spacingChange -= 5; } } - let finalLength = spacingChange * (this._time / incrementChange); + const finalLength = spacingChange * (this._time / incrementChange); if (finalLength >= this._infoContainer.current!.getBoundingClientRect().width) { this._totalLength = finalLength; this._tickSpacing = spacingChange; @@ -408,19 +408,19 @@ export class Timeline extends React.Component { * tool box includes the toggle buttons at the top of the timeline (both editing mode and play mode) */ private timelineToolBox = (scale: number) => { - let size = 40 * scale; //50 is default - let iconSize = 25; + const size = 40 * scale; //50 is default + const iconSize = 25; //decides if information should be omitted because the timeline is very small // if its less than 950 pixels then it's going to be overlapping let shouldCompress = false; - let width: number = this.props.PanelWidth(); + const width: number = this.props.PanelWidth(); if (width < 850) { shouldCompress = true; } let modeString, overviewString, lengthString; - let modeType = this.props.Document.isATOn ? "Author" : "Play"; + const modeType = this.props.Document.isATOn ? "Author" : "Play"; if (!shouldCompress) { modeString = "Mode: " + modeType; @@ -489,9 +489,9 @@ export class Timeline extends React.Component { * turns on the toggle button (the purple slide button that changes from editing mode and play mode */ private toggleHandle = () => { - let roundToggle = this._roundToggleRef.current!; - let roundToggleContainer = this._roundToggleContainerRef.current!; - let timelineContainer = this._timelineContainer.current!; + const roundToggle = this._roundToggleRef.current!; + const roundToggleContainer = this._roundToggleContainerRef.current!; + const timelineContainer = this._timelineContainer.current!; if (BoolCast(this.props.Document.isATOn)) { roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; @@ -522,9 +522,9 @@ export class Timeline extends React.Component { // @computed getCurrentTime = () => { - let current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); // console.log(this._currentBarX) - return this.toReadTime(current); `` + return this.toReadTime(current); // return (Math.floor(current) / 1000) // return current / 1000.0; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 56b3b3bc0..ef1ec5e78 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -809,7 +809,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { doFreeformLayout(poolData: Map) { const layoutDocs = this.childLayoutPairs.map(pair => pair.layout); const initResult = this.Document.arrangeInit && this.Document.arrangeInit.script.run({ docs: layoutDocs, collection: this.Document }, console.log); - let state = initResult && initResult.success ? initResult.result.scriptState : undefined; + const state = initResult && initResult.success ? initResult.result.scriptState : undefined; const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { @@ -1001,7 +1001,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } }); //@ts-ignore - let subitems: ContextMenuProps[] = + const subitems: ContextMenuProps[] = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data).map((note, i) => ({ description: (i + 1) + ": " + StrCast(note.title), event: () => console.log("Hi"), -- cgit v1.2.3-70-g09d2 From 61d4938de06a09687eca4a1549d48b1009aa4134 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sun, 9 Feb 2020 15:07:55 -0500 Subject: rounding fix --- src/client/views/animationtimeline/Timeline.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e4af43e0a..cbdbd07b149 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -326,15 +326,18 @@ export class Timeline extends React.Component { @action toReadTime = (time: number): string => { time = time / 1000; - var inSeconds = Math.round((time * 100)) / 100; + const inSeconds = Math.round(time * 100) / 100; + + // console.log(inSeconds) // var inSeconds = parseFloat(time.toFixed(2)); // const inSeconds = (Math.floor(time) / 1000); - let min: (string | number) = Math.floor(inSeconds / 60); - let sec: (string | number) = inSeconds % 60; + const min: (string | number) = Math.floor(inSeconds / 60); + let sec: (string | number) = (Math.round((inSeconds % 60) * 100) / 100); if (Math.floor(sec / 10) === 0) { sec = "0" + sec; } + // sec = Number.parseFloat(sec).toFixed(2); return `${min}:${sec}`; } -- cgit v1.2.3-70-g09d2 From ba835bbe5b31e2ad0badc9f960b75f639e0b02e0 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Sun, 9 Feb 2020 15:50:43 -0500 Subject: moving... --- src/client/views/animationtimeline/Timeline.tsx | 23 ++++++++++++++++++++-- .../views/animationtimeline/TimelineOverview.tsx | 1 - src/client/views/animationtimeline/Track.tsx | 7 +++++++ 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index dc381609e..42bb02e85 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -342,6 +342,7 @@ export class Timeline extends React.Component { /** * context menu function. * opens the timeline or closes the timeline. + * Used in: Freeform */ timelineContextMenu = (e: React.MouseEvent): void => { ContextMenu.Instance.addItem({ @@ -493,6 +494,7 @@ export class Timeline extends React.Component { const roundToggleContainer = this._roundToggleContainerRef.current!; const timelineContainer = this._timelineContainer.current!; if (BoolCast(this.props.Document.isATOn)) { + //turning on playmode... roundToggle.style.transform = "translate(0px, 0px)"; roundToggle.style.animationName = "turnoff"; roundToggleContainer.style.animationName = "turnoff"; @@ -500,7 +502,9 @@ export class Timeline extends React.Component { timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isATOn = false; this._isAuthoring = false; + this.tracks(); } else { + //turning on authoring mode... roundToggle.style.transform = "translate(20px, 0px)"; roundToggle.style.animationName = "turnon"; roundToggleContainer.style.animationName = "turnon"; @@ -524,12 +528,24 @@ export class Timeline extends React.Component { getCurrentTime = () => { const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); // console.log(this._currentBarX) - return this.toReadTime(current); + return this.toReadTime(current); // return (Math.floor(current) / 1000) // return current / 1000.0; } + @observable private mapOfTracks: (Track | null)[] = []; + @action + tracks = () => { + console.log(this.mapOfTracks.length); + this.mapOfTracks.forEach(track => { + if (track !== null) { + track.getLastRegion(); + } else { + + } + }); + } /** * if you have any question here, just shoot me an email or text. * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) @@ -552,7 +568,10 @@ export class Timeline extends React.Component {
    - {DocListCast(this.children).map(doc => )} + {DocListCast(this.children).map(doc => { + const track = { this.mapOfTracks.push(ref); }} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={this._timelineVisible} /> + return track; + })}
    Current: {this.getCurrentTime()}
    diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 66f6a9482..b8c639825 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -135,7 +135,6 @@ export class TimelineOverview extends React.Component{ } render() { - console.log("RERENDERED!"); this.setOverviewWidth(); this.getTimes(); diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 84edc6e0a..620668db7 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -80,6 +80,13 @@ export class Track extends React.Component { } //////////////////////////////// + + getLastRegion = () => { + + console.log((this.regions[this.regions.length - 1] as Doc).time); + return this.regions[this.regions.length - 1] as Doc; + } + /** * keyframe save logic. Needs to be changed so it's more efficient * -- cgit v1.2.3-70-g09d2 From 79f70eebe0a29f8f3d759eff82dd3446ac3d5ed1 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sun, 9 Feb 2020 16:14:04 -0500 Subject: done with ui bugs --- src/client/views/animationtimeline/Timeline.scss | 3 ++ src/client/views/animationtimeline/Timeline.tsx | 11 +++--- .../views/animationtimeline/TimelineOverview.tsx | 45 +++++++++++----------- 3 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index ce8c845df..a99d017f4 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -42,14 +42,17 @@ $timelineDark: #77a1aa; .time-box { margin-left: 5px; + min-width: 140px; display: flex; justify-content: center; align-items: center; + // grid-column-start: line2; } .mode-box { display: flex; margin-left: 5px; + // grid-column-start: line3; } .overview-box { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e0f70dd43..3c4c5c93f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -458,7 +458,6 @@ export class Timeline extends React.Component {
    {this.timeIndicator(lengthString)} - {/* {rightInfo} */}
    @@ -470,13 +469,16 @@ export class Timeline extends React.Component { return ( <>
    {lengthString}
    - +
    1:40.07
    ); } else { return ( -
    Current: {this.getCurrentTime()}
    +
    +
    {`Current: ${this.getCurrentTime()}`}
    +
    {`Total: 1:40.07`}
    +
    ); } } @@ -543,10 +545,7 @@ export class Timeline extends React.Component { // @computed getCurrentTime = () => { const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); - // console.log(this._currentBarX) return this.toReadTime(current); - // return (Math.floor(current) / 1000) - // return current / 1000.0; } diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 66f6a9482..94bbe7074 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -27,6 +27,8 @@ export class TimelineOverview extends React.Component{ @observable private _visibleRef = React.createRef(); @observable private _scrubberRef = React.createRef(); @observable private overviewBarWidth: number = 0; + @observable private playbarWidth: number = 0; + @observable private activeOverviewWidth: number = 0; @observable private _authoringReaction?: IReactionDisposer; @observable private visibleTime: number = 0; @observable private currentX: number = 0; @@ -55,12 +57,17 @@ export class TimelineOverview extends React.Component{ @action setOverviewWidth() { - const width = $("#timelineOverview").width(); - // console.log($("timelineOverview")) - if (width) this.overviewBarWidth = width; - // else this.overviewBarWidth = 0; - - // console.log(this.overviewBarWidth) + const width1 = $("#timelineOverview").width(); + const width2 = $("#timelinePlay").width(); + if (width1 && width1 !== 0) this.overviewBarWidth = width1; + if (width2 && width2 !== 0) this.playbarWidth = width2; + + if (this.props.isAuthoring) { + this.activeOverviewWidth = this.overviewBarWidth; + } + else { + this.activeOverviewWidth = this.playbarWidth; + } } @action @@ -78,9 +85,7 @@ export class TimelineOverview extends React.Component{ e.stopPropagation(); e.preventDefault(); const movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX; - // let movX = (this.props.visibleStart / this.props.totalLength) * (this.overviewWidth) + e.movementX; this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength); - // this.props.movePanX((movX / (this.overviewWidth) * this.props.totalLength); } @action @@ -95,12 +100,10 @@ export class TimelineOverview extends React.Component{ onScrubberDown = (e: React.PointerEvent) => { e.preventDefault(); e.stopPropagation(); - // if (!this.props.isAuthoring) { document.removeEventListener("pointermove", this.onScrubberMove); document.removeEventListener("pointerup", this.onScrubberUp); document.addEventListener("pointermove", this.onScrubberMove); document.addEventListener("pointerup", this.onScrubberUp); - // } } @action @@ -110,7 +113,7 @@ export class TimelineOverview extends React.Component{ const scrubberRef = this._scrubberRef.current!; const left = scrubberRef.getBoundingClientRect().left; const offsetX = Math.round(e.clientX - left); - this.props.changeCurrentBarX((((offsetX) / this.overviewBarWidth) * this.props.totalLength) + this.props.currentBarX); + this.props.changeCurrentBarX((((offsetX) / this.activeOverviewWidth) * this.props.totalLength) + this.props.currentBarX); } @action @@ -129,38 +132,34 @@ export class TimelineOverview extends React.Component{ this.visibleTime = vis; this.currentX = x; this.visibleStart = start; - // console.log("getting times") - // console.log(x) - // console.log(start) } render() { - console.log("RERENDERED!"); this.setOverviewWidth(); this.getTimes(); const percentVisible = this.visibleTime / this.props.time; - const visibleBarWidth = percentVisible * this.overviewBarWidth; + const visibleBarWidth = percentVisible * this.activeOverviewWidth; const percentScrubberStart = this.currentX / this.props.time; - const scrubberStart = percentScrubberStart * this.overviewBarWidth; + const scrubberStart = this.props.currentBarX / this.props.totalLength * this.activeOverviewWidth; const percentBarStart = this.visibleStart / this.props.time; - const barStart = percentBarStart * this.overviewBarWidth; + const barStart = percentBarStart * this.activeOverviewWidth; const timeline = this.props.isAuthoring ? [ -
    +
    , -
    +
    ] : [ -
    -
    +
    +
    , -
    +
    ]; return (
    -- cgit v1.2.3-70-g09d2 From 8d28c35bb9cf6ec190dbfed2e2cda8b5d1454efb Mon Sep 17 00:00:00 2001 From: ab Date: Sun, 9 Feb 2020 16:15:28 -0500 Subject: some changes --- src/client/views/animationtimeline/Timeline.tsx | 6 ++++-- src/client/views/animationtimeline/Track.tsx | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 42bb02e85..9e90cc764 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -539,8 +539,10 @@ export class Timeline extends React.Component { tracks = () => { console.log(this.mapOfTracks.length); this.mapOfTracks.forEach(track => { - if (track !== null) { - track.getLastRegion(); + console.log(track); + if (track) { + const region = track.getLastRegion(); + console.log(region.time); } else { } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 620668db7..9f63b3562 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -82,7 +82,7 @@ export class Track extends React.Component { getLastRegion = () => { - + console.log(this.regions.length); console.log((this.regions[this.regions.length - 1] as Doc).time); return this.regions[this.regions.length - 1] as Doc; } -- cgit v1.2.3-70-g09d2 From d3f9765c98595788eaeb8b5c0ef52af1cd3adab3 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Sun, 9 Feb 2020 17:01:37 -0500 Subject: reset view done --- src/client/views/animationtimeline/Keyframe.scss | 4 ---- src/client/views/animationtimeline/Timeline.scss | 27 +++++++++++++++++----- src/client/views/animationtimeline/Timeline.tsx | 11 +++++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 25 ++++++++++++++++---- src/new_fields/Doc.ts | 19 +++++++++++++++ 5 files changed, 68 insertions(+), 18 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.scss b/src/client/views/animationtimeline/Keyframe.scss index 8dcf71994..84c8de287 100644 --- a/src/client/views/animationtimeline/Keyframe.scss +++ b/src/client/views/animationtimeline/Keyframe.scss @@ -46,10 +46,6 @@ $timelineDark: #77a1aa; position: absolute; } - // .keyframe:hover~.keyframe-information { - // display: flex; - // } - .keyframe-information { display: none; position: relative; diff --git a/src/client/views/animationtimeline/Timeline.scss b/src/client/views/animationtimeline/Timeline.scss index a99d017f4..f90249771 100644 --- a/src/client/views/animationtimeline/Timeline.scss +++ b/src/client/views/animationtimeline/Timeline.scss @@ -34,29 +34,44 @@ $timelineDark: #77a1aa; } .grid-box { - display: grid; - grid-template-columns: [first] 50% [line2] 25% [line3] 25%; + display: flex; + // grid-template-columns: [first] 20% [line2] 20% [line3] 60%; width: calc(100% - 150px); // width: 100%; margin-left: 10px; .time-box { - margin-left: 5px; + margin-left: 10px; min-width: 140px; display: flex; justify-content: center; align-items: center; - // grid-column-start: line2; + + .resetView-tool { + width: 30px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + margin: 3px; + color: $timelineDark; + } + + .resetView-tool:hover { + -webkit-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); + transition: .2s ease; + } } .mode-box { display: flex; margin-left: 5px; - // grid-column-start: line3; } .overview-box { - width: 100%; + width: 80%; display: flex; } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 3942499c9..256b98ffa 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -459,6 +459,9 @@ export class Timeline extends React.Component {
    {this.timeIndicator(lengthString)} +
    Doc.resetView(this.props.Document)}>
    +
    Doc.setView(this.props.Document)}>
    +
    @@ -477,8 +480,8 @@ export class Timeline extends React.Component { else { return (
    -
    {`Current: ${this.getCurrentTime()}`}
    -
    {`Total: 1:40.07`}
    +
    {`Current: ${this.getCurrentTime()}`}
    +
    {`Total: 1:40.07`}
    ); } @@ -539,7 +542,7 @@ export class Timeline extends React.Component { @action.bound - changeLenths() { + changeLengths() { if (this._infoContainer.current) { 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 @@ -572,7 +575,7 @@ export class Timeline extends React.Component { render() { runInAction(() => { this._panelWidth = this.props.PanelWidth(); - this.changeLenths(); + this.changeLengths(); }); // change visible and total width diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ef1ec5e78..81fca3b54 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -966,7 +966,24 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + const { Document } = this.props; + + layoutItems.push({ + description: "reset view", event: () => { + Doc.resetView(Document); + }, icon: "compress-arrows-alt" + }); + layoutItems.push({ + description: "set view origin", event: () => { + Doc.setView(Document); + }, icon: "expand-arrows-alt" + }); + layoutItems.push({ + description: "reset view to origin", event: () => { + Doc.resetViewToOrigin(Document); + }, icon: "expand-arrows-alt" + }); + layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); @@ -1018,7 +1035,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { icon: "eye" }); ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" }); - this._timelineRef.current!.timelineContextMenu(e); + this._timelineRef.current!.timelineContextMenu(e); } @@ -1081,12 +1098,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { transformOrigin: this.contentScaling ? "left top" : "", width: this.contentScaling ? `${100 / this.contentScaling}%` : "", height: this.contentScaling ? `${100 / this.contentScaling}%` : this.isAnnotationOverlay ? (this.props.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight() - }}> + }}> {/* */} {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ? this.placeholder : this.marqueeView} -
    +
    ; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index f230abaf4..216005697 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -255,6 +255,25 @@ export namespace Doc { // return Cast(field, ctor); // }); // } + + export function resetView(doc: Doc) { + doc._panX = doc._customOriginX ?? 0; + doc._panY = doc._customOriginY ?? 0; + doc.scale = doc._customOriginScale ?? 1; + } + + export function resetViewToOrigin(doc: Doc) { + doc._panX = 0; + doc._panY = 0; + doc.scale = 1; + } + + export function setView(doc: Doc) { + doc._customOriginX = doc._panX; + doc._customOriginY = doc._panY; + doc._customOriginScale = doc.scale; + } + export function RunCachedUpdate(doc: Doc, field: string) { const update = doc[CachedUpdates][field]; if (update) { -- cgit v1.2.3-70-g09d2 From cb140cb5387836de1e2287ed9519a132f0f9d28f Mon Sep 17 00:00:00 2001 From: ab Date: Sun, 9 Feb 2020 18:10:26 -0500 Subject: kinda works --- src/client/views/animationtimeline/Timeline.tsx | 42 +++++++++++++++++----- .../views/animationtimeline/TimelineOverview.tsx | 8 +++-- src/client/views/animationtimeline/Track.tsx | 15 +++++--- 3 files changed, 50 insertions(+), 15 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index fc1a0ec3b..c52669879 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -14,6 +14,7 @@ import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; import { KeyframeFunc } from "./Keyframe"; import { Utils } from "../../../Utils"; +import { createPromiseCapability } from "../../../../deploy/assets/pdf.worker"; /** @@ -470,7 +471,7 @@ export class Timeline extends React.Component { return ( <>
    {lengthString}
    -
    1:40.07
    +
    {this.toReadTime(this._time)}
    ); } @@ -478,7 +479,7 @@ export class Timeline extends React.Component { return (
    {`Current: ${this.getCurrentTime()}`}
    -
    {`Total: 1:40.07`}
    +
    {`Total: ${this.toReadTime(this._time)}`}
    ); } @@ -524,7 +525,7 @@ export class Timeline extends React.Component { timelineContainer.style.top = `${-this._containerHeight}px`; this.props.Document.isATOn = false; this._isAuthoring = false; - this.tracks(); + this.toPlay(); } else { //turning on authoring mode... roundToggle.style.transform = "translate(20px, 0px)"; @@ -534,6 +535,7 @@ export class Timeline extends React.Component { timelineContainer.style.top = "0px"; this.props.Document.isATOn = true; this._isAuthoring = true; + this.toAuthoring(); } } @@ -555,18 +557,40 @@ export class Timeline extends React.Component { @observable private mapOfTracks: (Track | null)[] = []; @action - tracks = () => { - console.log(this.mapOfTracks.length); + findLongestTime = () => { + let longestTime:number = 0; this.mapOfTracks.forEach(track => { - console.log(track); if (track) { - const region = track.getLastRegion(); - console.log(region.time); + const lastTime = track.getLastRegionTime(); + if (this.children.length !== 0 ){ + if (longestTime <= lastTime){ + longestTime = lastTime; + } + } } else { - + //TODO: remove undefineds and duplicates } }); + return longestTime; + } + + @action + toAuthoring = () => { + let longestTime = this.findLongestTime(); + if (longestTime === 0) longestTime = 1; + const adjustedTime = Math.ceil(longestTime / 100000) * 100000; + console.log(adjustedTime); + this._totalLength = KeyframeFunc.convertPixelTime(adjustedTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this._time = adjustedTime; + } + + @action + toPlay = () => { + const longestTime = this.findLongestTime(); + this._time = longestTime; + this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); } + /** * if you have any question here, just shoot me an email or text. * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 94bbe7074..a587e1138 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -142,11 +142,15 @@ export class TimelineOverview extends React.Component{ const visibleBarWidth = percentVisible * this.activeOverviewWidth; const percentScrubberStart = this.currentX / this.props.time; - const scrubberStart = this.props.currentBarX / this.props.totalLength * this.activeOverviewWidth; + let scrubberStart = this.props.currentBarX / this.props.totalLength * this.activeOverviewWidth; + if (scrubberStart > this.activeOverviewWidth) scrubberStart = this.activeOverviewWidth; const percentBarStart = this.visibleStart / this.props.time; const barStart = percentBarStart * this.activeOverviewWidth; + let playWidth = (this.props.currentBarX / this.props.totalLength) * this.activeOverviewWidth; + if (playWidth > this.activeOverviewWidth) playWidth = this.activeOverviewWidth; + const timeline = this.props.isAuthoring ? [
    @@ -159,7 +163,7 @@ export class TimelineOverview extends React.Component{
    , -
    +
    ]; return (
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 9f63b3562..69e65fbcf 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -81,10 +81,17 @@ export class Track extends React.Component { //////////////////////////////// - getLastRegion = () => { - console.log(this.regions.length); - console.log((this.regions[this.regions.length - 1] as Doc).time); - return this.regions[this.regions.length - 1] as Doc; + getLastRegionTime = () => { + let lastTime:number = 0; + let lastRegion:(Doc | undefined); + DocListCast(this.regions).forEach(region => { + const time = NumCast(region.time); + if (lastTime <= time) { + lastTime = time; + lastRegion = region; + } + }); + return lastRegion ? lastTime + NumCast(lastRegion.duration) : 0; } /** -- cgit v1.2.3-70-g09d2 From d9990be832185b31375aaeb458c21addb389c32e Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Mon, 10 Feb 2020 20:30:59 -0500 Subject: fixed time --- package-lock.json | 2 +- src/client/views/animationtimeline/Timeline.tsx | 1 + src/client/views/animationtimeline/Track.tsx | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/package-lock.json b/package-lock.json index 5684789c1..0ae430be9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17991,7 +17991,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 914c19b53..d27990bd6 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -574,6 +574,7 @@ export class Timeline extends React.Component { //TODO: remove undefineds and duplicates } }); + console.log(longestTime); return longestTime; } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 69e65fbcf..705cc33a2 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -85,7 +85,7 @@ export class Track extends React.Component { let lastTime:number = 0; let lastRegion:(Doc | undefined); DocListCast(this.regions).forEach(region => { - const time = NumCast(region.time); + const time = NumCast(region.position); if (lastTime <= time) { lastTime = time; lastRegion = region; -- cgit v1.2.3-70-g09d2 From 77ddee9b0d5697522894badc9df1d54a0a7f08c9 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Mon, 10 Feb 2020 20:38:37 -0500 Subject: fixed width --- src/client/views/animationtimeline/Timeline.tsx | 32 +++++++++++----------- .../views/animationtimeline/TimelineOverview.tsx | 16 ++++++----- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index d27990bd6..b1777bfa0 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -538,7 +538,7 @@ export class Timeline extends React.Component { timelineContainer.style.top = "0px"; this.props.Document.isATOn = true; this._isAuthoring = true; - this.toAuthoring(); + this.toAuthoring(); } } @@ -561,37 +561,37 @@ export class Timeline extends React.Component { @action findLongestTime = () => { - let longestTime:number = 0; + let longestTime: number = 0; this.mapOfTracks.forEach(track => { if (track) { const lastTime = track.getLastRegionTime(); - if (this.children.length !== 0 ){ - if (longestTime <= lastTime){ - longestTime = lastTime; + if (this.children.length !== 0) { + if (longestTime <= lastTime) { + longestTime = lastTime; } } } else { //TODO: remove undefineds and duplicates } }); - console.log(longestTime); - return longestTime; + // console.log(longestTime); + return longestTime; } - @action + @action toAuthoring = () => { - let longestTime = this.findLongestTime(); + let longestTime = this.findLongestTime(); if (longestTime === 0) longestTime = 1; - const adjustedTime = Math.ceil(longestTime / 100000) * 100000; - console.log(adjustedTime); - this._totalLength = KeyframeFunc.convertPixelTime(adjustedTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); - this._time = adjustedTime; + const adjustedTime = Math.ceil(longestTime / 100000) * 100000; + // console.log(adjustedTime); + this._totalLength = KeyframeFunc.convertPixelTime(adjustedTime, "mili", "pixel", this._tickSpacing, this._tickIncrement); + this._time = adjustedTime; } - @action + @action toPlay = () => { - const longestTime = this.findLongestTime(); - this._time = longestTime; + const longestTime = this.findLongestTime(); + this._time = longestTime; this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); } diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index a587e1138..e3a276737 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -26,6 +26,8 @@ interface TimelineOverviewProps { export class TimelineOverview extends React.Component{ @observable private _visibleRef = React.createRef(); @observable private _scrubberRef = React.createRef(); + @observable private authoringContainer = React.createRef(); + @observable private playbackContainer = React.createRef(); @observable private overviewBarWidth: number = 0; @observable private playbarWidth: number = 0; @observable private activeOverviewWidth: number = 0; @@ -57,8 +59,8 @@ export class TimelineOverview extends React.Component{ @action setOverviewWidth() { - const width1 = $("#timelineOverview").width(); - const width2 = $("#timelinePlay").width(); + const width1 = this.authoringContainer.current?.clientWidth; + const width2 = this.playbackContainer.current?.clientWidth; if (width1 && width1 !== 0) this.overviewBarWidth = width1; if (width2 && width2 !== 0) this.playbarWidth = width2; @@ -143,24 +145,24 @@ export class TimelineOverview extends React.Component{ const percentScrubberStart = this.currentX / this.props.time; let scrubberStart = this.props.currentBarX / this.props.totalLength * this.activeOverviewWidth; - if (scrubberStart > this.activeOverviewWidth) scrubberStart = this.activeOverviewWidth; + if (scrubberStart > this.activeOverviewWidth) scrubberStart = this.activeOverviewWidth; const percentBarStart = this.visibleStart / this.props.time; const barStart = percentBarStart * this.activeOverviewWidth; - let playWidth = (this.props.currentBarX / this.props.totalLength) * this.activeOverviewWidth; - if (playWidth > this.activeOverviewWidth) playWidth = this.activeOverviewWidth; + let playWidth = (this.props.currentBarX / this.props.totalLength) * this.activeOverviewWidth; + if (playWidth > this.activeOverviewWidth) playWidth = this.activeOverviewWidth; const timeline = this.props.isAuthoring ? [ -
    +
    ,
    ] : [ -
    +
    ,
    -- cgit v1.2.3-70-g09d2 From 02c8bdb41bc7daf8268fde3fe85a9e2f237c772d Mon Sep 17 00:00:00 2001 From: monikahedman Date: Mon, 10 Feb 2020 20:53:45 -0500 Subject: time fixed --- src/client/views/animationtimeline/Timeline.tsx | 38 +++++++++++-------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index b1777bfa0..2b0525c6e 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -412,7 +412,7 @@ export class Timeline extends React.Component { /** * tool box includes the toggle buttons at the top of the timeline (both editing mode and play mode) */ - private timelineToolBox = (scale: number) => { + private timelineToolBox = (scale: number, totalTime: number) => { const size = 40 * scale; //50 is default const iconSize = 25; @@ -459,7 +459,7 @@ export class Timeline extends React.Component {
    - {this.timeIndicator(lengthString)} + {this.timeIndicator(lengthString, totalTime)}
    Doc.resetView(this.props.Document)}>
    Doc.setView(this.props.Document)}>
    @@ -469,12 +469,11 @@ export class Timeline extends React.Component { ); } - timeIndicator(lengthString: string) { + timeIndicator(lengthString: string, totalTime: number) { if (this.props.Document.isATOn) { return ( <> -
    {lengthString}
    -
    {this.toReadTime(this._time)}
    +
    {`Total: ${this.toReadTime(totalTime)}`}
    ); } @@ -482,26 +481,12 @@ export class Timeline extends React.Component { return (
    {`Current: ${this.getCurrentTime()}`}
    -
    {`Total:${this.toReadTime(this._time)}`}
    +
    {`Total: ${this.toReadTime(this._time)}`}
    ); } } - /** - * manual time input (kinda broken right now) - */ - @action - private onTimeInput = (e: React.KeyboardEvent) => { - // if (e.keyCode === 13) { - // let timeInput = this._timeInputRef.current!; - // this._time = parseInt(timeInput.value, 10); - // this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement); - // this.props.Document.AnimationLength = this._time; - // } - } - - /** * when the user decides to click the toggle button (either user wants to enter editing mode or play mode) */ @@ -553,7 +538,10 @@ export class Timeline extends React.Component { // @computed getCurrentTime = () => { - const current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + let current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement); + if (current > this._time) { + current = this._time; + } return this.toReadTime(current); } @@ -603,8 +591,14 @@ export class Timeline extends React.Component { runInAction(() => { this._panelWidth = this.props.PanelWidth(); this.changeLengths(); + // this.toPlay(); + + + // this._time = longestTime; }); + const longestTime = this.findLongestTime(); + // change visible and total width return (
    @@ -632,7 +626,7 @@ export class Timeline extends React.Component {
    - {this.timelineToolBox(1)} + {this.timelineToolBox(1, longestTime)}
    ); -- cgit v1.2.3-70-g09d2 From 4ecf08b5c5cdc4ddb3a997e2f3a2188e921ff430 Mon Sep 17 00:00:00 2001 From: monikahedman Date: Tue, 11 Feb 2020 19:29:19 -0500 Subject: number jitter fixed --- src/client/views/animationtimeline/Timeline.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 2b0525c6e..e9caa2b2a 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -329,17 +329,15 @@ export class Timeline extends React.Component { time = time / 1000; const inSeconds = Math.round(time * 100) / 100; - // console.log(inSeconds) - // var inSeconds = parseFloat(time.toFixed(2)); - // const inSeconds = (Math.floor(time) / 1000); const min: (string | number) = Math.floor(inSeconds / 60); - let sec: (string | number) = (Math.round((inSeconds % 60) * 100) / 100); + const sec: (string | number) = (Math.round((inSeconds % 60) * 100) / 100); + let secString = sec.toFixed(2); if (Math.floor(sec / 10) === 0) { - sec = "0" + sec; + secString = "0" + secString; } - // sec = Number.parseFloat(sec).toFixed(2); - return `${min}:${sec}`; + + return `${min}:${secString}`; } -- cgit v1.2.3-70-g09d2 From 0fb0341287cfed4c5b846f6bc7126623599b34f5 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 28 Apr 2020 20:16:45 -0400 Subject: small timeline fixes --- src/client/views/animationtimeline/Keyframe.tsx | 103 ++++++++++----------- src/client/views/animationtimeline/Timeline.tsx | 16 +--- .../views/animationtimeline/TimelineOverview.tsx | 8 +- src/client/views/animationtimeline/Track.tsx | 60 ++++++------ 4 files changed, 92 insertions(+), 95 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index bb557289e..76c3e63be 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -3,7 +3,7 @@ import "./Keyframe.scss"; import "./Timeline.scss"; import "../globalCssVariables.scss"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction } from "mobx"; +import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction, trace } from "mobx"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; @@ -13,6 +13,7 @@ import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { undoBatch, UndoManager } from "../../util/UndoManager"; +import { emptyPath } from "../../../Utils"; @@ -32,10 +33,10 @@ export namespace KeyframeFunc { right = "right" } - export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: List): (RegionData | undefined) => { + export const findAdjacentRegion = (dir: KeyframeFunc.Direction, currentRegion: Doc, regions: Doc[]): (RegionData | undefined) => { let leftMost: (RegionData | undefined) = undefined; let rightMost: (RegionData | undefined) = undefined; - DocListCast(regions).forEach(region => { + regions.forEach(region => { const neighbor = RegionData(region); if (currentRegion.position! > neighbor.position) { if (!leftMost || neighbor.position > leftMost.position) { @@ -135,7 +136,7 @@ interface IProps { time: number; changeCurrentBarX: (x: number) => void; transform: Transform; - makeKeyData: (region:RegionData, pos: number, kftype:KeyframeFunc.KeyframeType) => Doc; + makeKeyData: (region: RegionData, pos: number, kftype: KeyframeFunc.KeyframeType) => Doc; } @@ -169,21 +170,24 @@ export class Keyframe extends React.Component { @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; - @computed private get regiondata() { return RegionData(this.regions[this.regions.indexOf(this.props.RegionData)] as Doc); } - @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } + @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... - if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); - const start = this.props.makeKeyData(this.regiondata, this.regiondata.position, KeyframeFunc.KeyframeType.end); + if (!this.regiondata.keyframes) this.regiondata.keyframes = new List(); + 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); const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); - const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration,KeyframeFunc.KeyframeType.end); + const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end); (fadeIn.key as Doc).opacity = 1; (fadeOut.key as Doc).opacity = 1; (start.key as Doc).opacity = 0.1; @@ -192,9 +196,6 @@ export class Keyframe extends React.Component { }, 1000); } - - - @action onBarPointerDown = (e: React.PointerEvent) => { e.preventDefault(); @@ -316,7 +317,7 @@ export class Keyframe extends React.Component { 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.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 } @@ -338,7 +339,7 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => { const kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { _width: 300, _height: 300 }); - CollectionDockingView.AddRightSplit(kvp, (kf.key as Doc).data as Doc); + CollectionDockingView.AddRightSplit(kvp, emptyPath); }); }), TimelineMenu.Instance.addItem("button", "Delete", () => { @@ -403,7 +404,7 @@ export class Keyframe extends React.Component { runInAction(() => { const prevPosition = this.regiondata.position; let cannotMove: boolean = false; - DocListCast(this.regions).forEach(region => { + this.regions.forEach(region => { if (NumCast(region.position) !== this.regiondata.position) { if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))) { cannotMove = true; @@ -419,7 +420,7 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { runInAction(() => { let cannotMove: boolean = false; - DocListCast(this.regions).forEach(region => { + this.regions.forEach(region => { if (NumCast(region.position) !== this.regiondata.position) { val += this.regiondata.position; if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))) { @@ -479,34 +480,31 @@ export class Keyframe extends React.Component { * 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) */ - @action drawKeyframes = () => { const keyframeDivs: JSX.Element[] = []; - DocListCast(this.regiondata.keyframes).forEach(kf => { + return DocListCast(this.regiondata.keyframes).map(kf => { if (kf.type as KeyframeFunc.KeyframeType !== KeyframeFunc.KeyframeType.end) { - keyframeDivs.push( - <>
    -
    -
    { 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(); }}>
    - -
    -
    - - - ); - } else { - keyframeDivs.push( + return <>
    +
    { 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(); }}> +
    - ); +
    + ; + } else { + return
    +
    +
    } }); - return keyframeDivs; } /** @@ -546,22 +544,23 @@ export class Keyframe extends React.Component { */ //154, 206, 223 render() { + trace(); + console.log(this.props.RegionData.position); + console.log(this.regiondata.position); + console.log(this.pixelPosition); return ( -
    -
    -
    - {/*
    */} -
    - {/*
    */} - {this.drawKeyframes()} - {this.drawKeyframeDividers()} -
    +
    +
    + {/*
    */} +
    + {/*
    */} + {this.drawKeyframes()} + {this.drawKeyframeDividers()}
    ); } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e9caa2b2a..7d245ab6f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -3,7 +3,7 @@ import "./Timeline.scss"; import { listSpec } from "../../../new_fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; -import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx"; +import { observable, action, computed, runInAction, IReactionDisposer, reaction, trace } from "mobx"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc, DocListCast } from "../../../new_fields/Doc"; @@ -14,8 +14,6 @@ import { TimelineOverview } from "./TimelineOverview"; import { FieldViewProps } from "../nodes/FieldView"; import { KeyframeFunc } from "./Keyframe"; import { Utils } from "../../../Utils"; -import { createPromiseCapability } from "../../../../deploy/assets/pdf.worker"; - /** * Timeline class controls most of timeline functions besides individual keyframe and track mechanism. Main functions are @@ -80,7 +78,6 @@ export class Timeline extends React.Component { // so a reaction can be made @observable public _isAuthoring = this.props.Document.isATOn; - @observable private _panelWidth = 0; /** * collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit. @@ -90,7 +87,7 @@ export class Timeline extends React.Component { const extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type)); if (extendedDocument) { if (this.props.Document.data_ext) { - return Cast((Cast(this.props.Document.data_ext, Doc) as Doc).annotations, listSpec(Doc)) as List; + return Cast((Cast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + "-annotations"], Doc) as Doc).annotations, listSpec(Doc)) as List; } else { return new List(); } @@ -586,17 +583,14 @@ export class Timeline extends React.Component { * basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region) */ render() { - runInAction(() => { - this._panelWidth = this.props.PanelWidth(); + setTimeout(() => { this.changeLengths(); // this.toPlay(); - - // this._time = longestTime; - }); + }, 0); const longestTime = this.findLongestTime(); - + trace(); // change visible and total width return (
    diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index e3a276737..31e248823 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -156,16 +156,16 @@ export class TimelineOverview extends React.Component{ const timeline = this.props.isAuthoring ? [
    -
    , -
    +
    , +
    ] : [ -
    +
    , -
    +
    ]; return (
    diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 705cc33a2..0e3c209dc 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -29,7 +29,7 @@ export class Track extends React.Component { @observable private _currentBarXReaction: any; @observable private _timelineVisibleReaction: any; @observable private _autoKfReaction: any; - @observable private _newKeyframe: boolean = false; + @observable private _newKeyframe: boolean = false; private readonly MAX_TITLE_HEIGHT = 75; private _trackHeight = 0; private primitiveWhitelist = [ @@ -37,7 +37,7 @@ export class Track extends React.Component { "y", "width", "height", - "opacity", + "opacity", ]; private objectWhitelist = [ "data" @@ -81,17 +81,17 @@ export class Track extends React.Component { //////////////////////////////// - getLastRegionTime = () => { - let lastTime:number = 0; - let lastRegion:(Doc | undefined); + getLastRegionTime = () => { + let lastTime: number = 0; + let lastRegion: (Doc | undefined); DocListCast(this.regions).forEach(region => { - const time = NumCast(region.position); + const time = NumCast(region.position); if (lastTime <= time) { - lastTime = time; - lastRegion = region; + lastTime = time; + lastRegion = region; } - }); - return lastRegion ? lastTime + NumCast(lastRegion.duration) : 0; + }); + return lastRegion ? lastTime + NumCast(lastRegion.duration) : 0; } /** @@ -106,16 +106,16 @@ export class Track extends React.Component { let kf = keyframes[kfIndex] as Doc; //index in the keyframe if (this._newKeyframe) { console.log("new keyframe registering"); - let kfList = DocListCast(this.saveStateRegion!.keyframes); + let kfList = DocListCast(this.saveStateRegion!.keyframes); kfList.forEach(kf => { - kf.key = this.makeCopy(); - if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3){ - (kf.key as Doc).opacity = 0.1; - } else{ - (kf.key as Doc).opacity = 1; + kf.key = this.makeCopy(); + if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3) { + (kf.key as Doc).opacity = 0.1; + } else { + (kf.key as Doc).opacity = 1; } }); - this._newKeyframe = false; + this._newKeyframe = false; } if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades @@ -225,7 +225,7 @@ export class Track extends React.Component { } }); } else { - console.log("reverting state"); + console.log("reverting state"); //this.revertState(); } }); @@ -241,7 +241,7 @@ export class Track extends React.Component { timeChange = async () => { if (this.saveStateKf !== undefined) { await this.saveKeyframe(); - } else if (this._newKeyframe){ + } else if (this._newKeyframe) { await this.saveKeyframe(); } let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on @@ -250,7 +250,7 @@ export class Track extends React.Component { let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { - console.log("is current"); + console.log("is current"); await this.applyKeys(currentkf); this.saveStateKf = currentkf; this.saveStateRegion = regiondata; @@ -348,7 +348,7 @@ export class Track extends React.Component { createRegion = async (time: number) => { if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data - + regiondata.position = time; //set position let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); @@ -356,9 +356,9 @@ export class Track extends React.Component { regiondata.duration = rightRegion.position - regiondata.position; } if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { - this.regions.push(regiondata); - this._newKeyframe = true; - this.saveStateRegion = regiondata; + this.regions.push(regiondata); + this._newKeyframe = true; + this.saveStateRegion = regiondata; return regiondata; } } @@ -395,7 +395,7 @@ export class Track extends React.Component { let doc = new Doc(); this.primitiveWhitelist.forEach(key => { let originalVal = this.props.node[key]; - if (key === "data"){ + if (key === "data") { console.log(originalVal); } doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; @@ -407,12 +407,16 @@ export class Track extends React.Component { * UI sstuff here. Not really much to change */ render() { + trace(); return (
    -
    { Doc.BrushDoc(this.props.node); }} onPointerOut={() => { Doc.UnBrushDoc(this.props.node); }} style={{ height: `${this._trackHeight}px` }}> - {DocListCast(this.regions).map((region) => { - return ; +
    Doc.BrushDoc(this.props.node)} + onPointerOut={() => Doc.UnBrushDoc(this.props.node)} > + {DocListCast(this.regions).map((region, i) => { + return ; })}
    -- cgit v1.2.3-70-g09d2 From ab4297e59e142f70b420831a73c3f3e4506eee15 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 28 Apr 2020 23:00:15 -0400 Subject: more animation timeline cleanup --- src/client/views/animationtimeline/Keyframe.tsx | 43 ++--- src/client/views/animationtimeline/Timeline.tsx | 41 ++-- src/client/views/animationtimeline/Track.tsx | 239 ++++++++++-------------- 3 files changed, 135 insertions(+), 188 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 76c3e63be..a3407f653 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -4,7 +4,7 @@ import "./Timeline.scss"; import "../globalCssVariables.scss"; import { observer } from "mobx-react"; import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction, trace } from "mobx"; -import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; @@ -55,11 +55,11 @@ export namespace KeyframeFunc { } }; - export const calcMinLeft = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closet keyframe to the left - let leftKf: (Doc | undefined) = undefined; + export const calcMinLeft = (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closet keyframe to the left + let leftKf: Opt; let time: number = 0; - const keyframes = await DocListCastAsync(region.keyframes!); - keyframes!.forEach((kf) => { + const keyframes = DocListCast(region.keyframes!); + keyframes.map((kf) => { let compTime = currentBarX; if (ref) compTime = NumCast(ref.time); if (NumCast(kf.time) < compTime && NumCast(kf.time) >= time) { @@ -71,11 +71,10 @@ export namespace KeyframeFunc { }; - export const calcMinRight = async (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closest keyframe to the right - let rightKf: (Doc | undefined) = undefined; + export const calcMinRight = (region: Doc, currentBarX: number, ref?: Doc) => { //returns the time of the closest keyframe to the right + let rightKf: Opt; let time: number = Infinity; - const keyframes = await DocListCastAsync(region.keyframes!); - 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)) { @@ -239,9 +238,7 @@ export class Keyframe extends React.Component { 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 @@ -338,7 +335,7 @@ export class Keyframe extends React.Component { makeKeyframeMenu = (kf: Doc, e: MouseEvent) => { TimelineMenu.Instance.addItem("button", "Show Data", () => { runInAction(() => { - const kvp = Docs.Create.KVPDocument(Cast(kf.key, Doc) as Doc, { _width: 300, _height: 300 }); + const kvp = Docs.Create.KVPDocument(kf, { _width: 300, _height: 300 }); CollectionDockingView.AddRightSplit(kvp, emptyPath); }); }), @@ -370,12 +367,8 @@ export class Keyframe extends React.Component { */ @action makeRegionMenu = (kf: Doc, e: MouseEvent) => { - TimelineMenu.Instance.addItem("button", "Remove Region", () => { - runInAction(() => { - this.regions.splice(this.regions.indexOf(this.props.RegionData), 1); - } - ); - }), + 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; @@ -404,9 +397,9 @@ export class Keyframe extends React.Component { runInAction(() => { const prevPosition = this.regiondata.position; let cannotMove: boolean = false; - this.regions.forEach(region => { - if (NumCast(region.position) !== this.regiondata.position) { - if ((val < 0) || (val > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration) || (this.regiondata.duration + val > NumCast(region.position) && this.regiondata.duration + val < NumCast(region.position) + NumCast(region.duration)))) { + 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; } } @@ -420,10 +413,10 @@ export class Keyframe extends React.Component { TimelineMenu.Instance.addItem("input", `duration: ${this.regiondata.duration}ms`, (val) => { runInAction(() => { let cannotMove: boolean = false; - this.regions.forEach(region => { - if (NumCast(region.position) !== this.regiondata.position) { + 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 > NumCast(region.position) && val < NumCast(region.position) + NumCast(region.duration))) { + if ((val < 0) || (val > pos && val < pos + dur)) { cannotMove = true; } } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 7d245ab6f..234d560f1 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -593,33 +593,30 @@ export class Timeline extends React.Component { trace(); // change visible and total width return ( -
    -
    -
    -
    -
    - {this.drawTicks()} -
    -
    -
    -
    - {DocListCast(this.children).map(doc => { - const track = { this.mapOfTracks.push(ref); }} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={this._timelineVisible} /> - return track; - })} -
    +
    +
    +
    +
    + {this.drawTicks()} +
    +
    -
    Current: {this.getCurrentTime()}
    -
    - {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )} -
    -
    - +
    + {DocListCast(this.children).map(doc => + this.mapOfTracks.push(ref)} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={this._timelineVisible} /> + )}
    +
    Current: {this.getCurrentTime()}
    +
    + {DocListCast(this.children).map(doc =>
    { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

    {doc.title}

    )} +
    +
    + +
    - {this.timelineToolBox(1, longestTime)}
    + {this.timelineToolBox(1, longestTime)}
    ); } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 0e3c209dc..9e2ec8886 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,15 +1,15 @@ -import * as React from "react"; +import { action, computed, intercept, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { observable, reaction, action, IReactionDisposer, computed, runInAction, autorun, toJS, isObservableArray, IObservableArray, trace, observe, intercept } from "mobx"; -import "./Track.scss"; -import { Doc, DocListCastAsync, DocListCast, Field } from "../../../new_fields/Doc"; -import { listSpec } from "../../../new_fields/Schema"; -import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; -import { Transform } from "../../util/Transform"; +import * as React from "react"; +import { Doc, DocListCast, Opt } from "../../../new_fields/Doc"; import { Copy } from "../../../new_fields/FieldSymbols"; +import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; +import { listSpec } from "../../../new_fields/Schema"; +import { Cast, NumCast } from "../../../new_fields/Types"; +import { Transform } from "../../util/Transform"; +import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; +import "./Track.scss"; interface IProps { node: Doc; @@ -43,48 +43,41 @@ export class Track extends React.Component { "data" ]; - @computed private get regions() { return Cast(this.props.node.regions, listSpec(Doc)) as List; } + @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)); } ////////// life cycle functions/////////////// componentWillMount() { - runInAction(() => { - if (!this.props.node.regions) this.props.node.regions = new List(); //if there is no region, then create new doc to store stuff - //these two lines are exactly same from timeline.tsx - let relativeHeight = window.innerHeight / 20; - this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness - }); + if (!this.props.node.regions) this.props.node.regions = new List(); //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; + this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness } componentDidMount() { - runInAction(async () => { - this._timelineVisibleReaction = this.timelineVisibleReaction(); - this._currentBarXReaction = this.currentBarXReaction(); - if (this.regions.length === 0) this.createRegion(this.time); - this.props.node.hidden = false; - this.props.node.opacity = 1; - // this.autoCreateKeyframe(); - }); + this._timelineVisibleReaction = this.timelineVisibleReaction(); + this._currentBarXReaction = this.currentBarXReaction(); + if (this.regions.length === 0) this.createRegion(this.time); + this.props.node.hidden = false; + this.props.node.opacity = 1; + // this.autoCreateKeyframe(); } /** * mainly for disposing reactions */ componentWillUnmount() { - runInAction(() => { - //disposing reactions - if (this._currentBarXReaction) this._currentBarXReaction(); - if (this._timelineVisibleReaction) this._timelineVisibleReaction(); - if (this._autoKfReaction) this._autoKfReaction(); - }); + this._currentBarXReaction?.(); + this._timelineVisibleReaction?.(); + this._autoKfReaction?.(); } //////////////////////////////// getLastRegionTime = () => { let lastTime: number = 0; - let lastRegion: (Doc | undefined); - DocListCast(this.regions).forEach(region => { + let lastRegion: Opt; + this.regions.forEach(region => { const time = NumCast(region.position); if (lastTime <= time) { lastTime = time; @@ -100,41 +93,34 @@ export class Track extends React.Component { */ @action saveKeyframe = async () => { - console.log("saving keyframe"); - let keyframes: List = (Cast(this.saveStateRegion!.keyframes, listSpec(Doc)) as List); - let kfIndex: number = keyframes.indexOf(this.saveStateKf!); + let keyframes = Cast(this.saveStateRegion?.keyframes, listSpec(Doc)) as List; + let kfIndex = keyframes.indexOf(this.saveStateKf!); let kf = keyframes[kfIndex] as Doc; //index in the keyframe if (this._newKeyframe) { - console.log("new keyframe registering"); - let kfList = DocListCast(this.saveStateRegion!.keyframes); - kfList.forEach(kf => { - kf.key = this.makeCopy(); - if (kfList.indexOf(kf) === 0 || kfList.indexOf(kf) === 3) { - (kf.key as Doc).opacity = 0.1; - } else { - (kf.key as Doc).opacity = 1; - } + DocListCast(this.saveStateRegion?.keyframes).forEach((kf, index) => { + this.copyDocDataToKeyFrame(kf); + 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 - kf.key = this.makeCopy(); - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists - if (leftkf!.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge: (Doc | undefined) = await KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf!); - edge!.key = this.makeCopy(); - leftkf!.key = this.makeCopy(); - (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; - (Cast(leftkf!.key, Doc)! as Doc).opacity = 1; + this.copyDocDataToKeyFrame(kf); + let leftkf = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists + let rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists + if (leftkf?.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades + let edge = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf); + edge && this.copyDocDataToKeyFrame(edge); + leftkf && this.copyDocDataToKeyFrame(leftkf); + edge && (edge!.opacity = 0.1); + leftkf && (leftkf!.opacity = 1); } - if (rightkf!.type === KeyframeFunc.KeyframeType.fade) { - let edge: (Doc | undefined) = await KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf!); - edge!.key = this.makeCopy(); - rightkf!.key = this.makeCopy(); - (Cast(edge!.key, Doc)! as Doc).opacity = 0.1; - (Cast(rightkf!.key, Doc)! as Doc).opacity = 1; + if (rightkf?.type === KeyframeFunc.KeyframeType.fade) { + let edge = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf); + edge && this.copyDocDataToKeyFrame(edge); + rightkf && this.copyDocDataToKeyFrame(rightkf); + edge && (edge.opacity = 0.1); + rightkf && (rightkf.opacity = 1); } } keyframes[kfIndex] = kf; @@ -148,24 +134,22 @@ export class Track extends React.Component { */ @action autoCreateKeyframe = () => { - const { node } = this.props; - const objects = this.objectWhitelist.map(key => node[key]); + const objects = this.objectWhitelist.map(key => this.props.node[key]); intercept(this.props.node, change => { console.log(change); return change; }); return reaction(() => { - return [...this.primitiveWhitelist.map(key => node[key]), ...objects]; + return [...this.primitiveWhitelist.map(key => this.props.node[key]), ...objects]; }, (changed, reaction) => { //check for region - this.findRegion(this.time).then((region) => { - if (region !== undefined) { //if region at scrub time exist - let r = region as any 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); - } + const region = this.findRegion(this.time); + if (region !== undefined) { //if region at scrub time exist + let 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 }); } @@ -188,20 +172,19 @@ export class Track extends React.Component { @action currentBarXReaction = () => { return reaction(() => this.props.currentBarX, () => { - this.findRegion(this.time).then((regiondata: (Doc | undefined)) => { - if (regiondata) { - this.props.node.hidden = false; - // if (!this._autoKfReaction) { - // // console.log("creating another reaction"); - // // this._autoKfReaction = this.autoCreateKeyframe(); - // } - this.timeChange(); - } else { - this.props.node.hidden = true; - this.props.node.opacity = 0; - //if (this._autoKfReaction) this._autoKfReaction(); - } - }); + const regiondata = this.findRegion(this.time); + if (regiondata) { + this.props.node.hidden = false; + // if (!this._autoKfReaction) { + // // console.log("creating another reaction"); + // // this._autoKfReaction = this.autoCreateKeyframe(); + // } + this.timeChange(); + } else { + this.props.node.hidden = true; + this.props.node.opacity = 0; + //if (this._autoKfReaction) this._autoKfReaction(); + } }); } @@ -214,13 +197,11 @@ export class Track extends React.Component { return this.props.timelineVisible; }, isVisible => { if (isVisible) { - DocListCast(this.regions).forEach(region => { - if (!BoolCast((Cast(region, Doc) as Doc).hasData)) { - for (let i = 0; i < 4; i++) { - DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key = this.makeCopy(); - if (i === 0 || i === 3) { //manually inputing fades - (DocListCast(((Cast(region, Doc) as Doc).keyframes as List))[i].key! as Doc).opacity = 0.1; - } + 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; } } }); @@ -266,12 +247,11 @@ export class Track extends React.Component { */ @action private applyKeys = async (kf: Doc) => { - let kfNode = await Cast(kf.key, Doc) as Doc; this.primitiveWhitelist.forEach(key => { - if (!kfNode[key]) { + if (!kf[key]) { this.props.node[key] = undefined; } else { - let stored = kfNode[key]; + let stored = kf[key]; this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); @@ -297,16 +277,14 @@ export class Track extends React.Component { */ @action interpolate = async (left: Doc, right: Doc) => { - let leftNode = await (left.key) as Doc; - let rightNode = await (right.key) as Doc; this.primitiveWhitelist.forEach(key => { - if (leftNode[key] && rightNode[key] && typeof (leftNode[key]) === "number" && typeof (rightNode[key]) === "number") { //if it is number, interpolate - let dif = NumCast(rightNode[key]) - NumCast(leftNode[key]); + if (left[key] && right[key] && typeof (left[key]) === "number" && typeof (right[key]) === "number") { //if it is number, interpolate + let dif = NumCast(right[key]) - NumCast(left[key]); let deltaLeft = this.time - NumCast(left.time); let ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); - this.props.node[key] = NumCast(leftNode[key]) + (dif * ratio); + this.props.node[key] = NumCast(left[key]) + (dif * ratio); } else { // case data - let stored = leftNode[key]; + let stored = left[key]; this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); @@ -316,17 +294,8 @@ export class Track extends React.Component { * 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?) */ - @action - findRegion = async (time: number) => { - let foundRegion: (Doc | undefined) = undefined; - let regions = await DocListCastAsync(this.regions); - regions!.forEach(region => { - region = region as RegionData; - if (time >= NumCast(region.position) && time <= (NumCast(region.position) + NumCast(region.duration))) { - foundRegion = region; - } - }); - return foundRegion; + findRegion = (time: number) => { + return this.regions?.find(rd => (time >= NumCast(rd.position) && time <= (NumCast(rd.position) + NumCast(rd.duration)))); } @@ -345,8 +314,8 @@ export class Track extends React.Component { * creates a region (KEYFRAME.TSX stuff). */ @action - createRegion = async (time: number) => { - if (await this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) + createRegion = (time: number) => { + if (this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data regiondata.position = time; //set position @@ -356,7 +325,7 @@ export class Track extends React.Component { regiondata.duration = rightRegion.position - regiondata.position; } if (this.regions.length === 0 || !rightRegion || (rightRegion && rightRegion.position - regiondata.position >= NumCast(regiondata.fadeIn) + NumCast(regiondata.fadeOut))) { - this.regions.push(regiondata); + Cast(this.props.node.regions, listSpec(Doc))?.push(regiondata); this._newKeyframe = true; this.saveStateRegion = regiondata; return regiondata; @@ -366,48 +335,36 @@ export class Track extends React.Component { @action makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - let doclist = DocListCast(regiondata.keyframes)!; - let existingkf: (Doc | undefined) = undefined; - doclist.forEach(TK => { - if (TK.time === time) existingkf = TK; - }); + const trackKeyFrames = DocListCast(regiondata.keyframes)!; + const existingkf = trackKeyFrames.find(TK => TK.time === time); if (existingkf) return existingkf; //else creates a new doc. - let TK: Doc = new Doc(); - TK.time = time; - TK.key = this.makeCopy(); - TK.type = type; + 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 (doclist.length === 0) regiondata.keyframes!.push(TK); - doclist.forEach(kf => { - let index = doclist.indexOf(kf); - let kfTime = NumCast(kf.time); - if ((kfTime < time && index === doclist.length - 1) || (kfTime < time && time < NumCast(doclist[index + 1].time))) { - regiondata.keyframes!.splice(index + 1, 0, TK); - return; + 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); } }); - return TK; + return newKeyFrame; } @action - makeCopy = () => { - let doc = new Doc(); - this.primitiveWhitelist.forEach(key => { - let originalVal = this.props.node[key]; - if (key === "data") { - console.log(originalVal); - } - doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : this.props.node[key]; + copyDocDataToKeyFrame = (doc: Doc) => { + this.primitiveWhitelist.map(key => { + const originalVal = this.props.node[key]; + doc[key] = originalVal instanceof ObjectField ? originalVal[Copy]() : originalVal; }); - return doc; } /** * UI sstuff here. Not really much to change */ render() { - trace(); return (
    @@ -415,7 +372,7 @@ export class Track extends React.Component { onDoubleClick={this.onInnerDoubleClick} onPointerOver={() => Doc.BrushDoc(this.props.node)} onPointerOut={() => Doc.UnBrushDoc(this.props.node)} > - {DocListCast(this.regions).map((region, i) => { + {this.regions?.map((region, i) => { return ; })}
    -- cgit v1.2.3-70-g09d2 From c0ec0efe6fb03096c9abbee9e5d72e8cab54bf6b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 28 Apr 2020 23:02:23 -0400 Subject: from last --- src/client/views/animationtimeline/Timeline.tsx | 4 +--- src/client/views/animationtimeline/Track.tsx | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 234d560f1..295c1e18c 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -467,9 +467,7 @@ export class Timeline extends React.Component { timeIndicator(lengthString: string, totalTime: number) { if (this.props.Document.isATOn) { return ( - <> -
    {`Total: ${this.toReadTime(totalTime)}`}
    - +
    {`Total: ${this.toReadTime(totalTime)}`}
    ); } else { diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 9e2ec8886..382bf9b64 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -35,8 +35,8 @@ export class Track extends React.Component { private primitiveWhitelist = [ "x", "y", - "width", - "height", + "_width", + "_height", "opacity", ]; private objectWhitelist = [ -- cgit v1.2.3-70-g09d2 From 182aa5efffd0d68af7cf57e51fd54c889d7564ae Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 29 Apr 2020 00:40:09 -0400 Subject: fixed timeline's Track initialization --- src/client/views/animationtimeline/Track.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 382bf9b64..79eb60fae 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,7 +1,7 @@ import { action, computed, intercept, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast, Opt } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../new_fields/Doc"; import { Copy } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; @@ -46,18 +46,15 @@ export class Track extends React.Component { @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)); } - ////////// life cycle functions/////////////// - componentWillMount() { - if (!this.props.node.regions) this.props.node.regions = new List(); //if there is no region, then create new doc to store stuff + async componentDidMount() { + const regions = await DocListCastAsync(this.props.node.regions); + if (!regions) this.props.node.regions = new List(); //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; this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness - } - - componentDidMount() { this._timelineVisibleReaction = this.timelineVisibleReaction(); this._currentBarXReaction = this.currentBarXReaction(); - if (this.regions.length === 0) this.createRegion(this.time); + if (DocListCast(this.props.node.regions).length === 0) this.createRegion(this.time); this.props.node.hidden = false; this.props.node.opacity = 1; // this.autoCreateKeyframe(); -- cgit v1.2.3-70-g09d2 From f78d614f99fed4555f7a1211e522e34efc19f809 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 29 Apr 2020 11:53:55 -0400 Subject: cleanup of timeline before merge --- src/client/views/animationtimeline/Timeline.tsx | 16 +- src/client/views/linking/LinkFollowBox.tsx | 571 ------------------------ src/new_fields/Doc.ts | 18 - 3 files changed, 14 insertions(+), 591 deletions(-) delete mode 100644 src/client/views/linking/LinkFollowBox.tsx (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 295c1e18c..677267ca0 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -372,6 +372,18 @@ export class Timeline extends React.Component { this.changeCurrentBarX(currCurrent); } + + resetView(doc: Doc) { + doc._panX = doc._customOriginX ?? 0; + doc._panY = doc._customOriginY ?? 0; + doc.scale = doc._customOriginScale ?? 1; + } + + setView(doc: Doc) { + doc._customOriginX = doc._panX; + doc._customOriginY = doc._panY; + doc._customOriginScale = doc.scale; + } /** * zooming mechanism (increment and spacing changes) */ @@ -455,8 +467,8 @@ export class Timeline extends React.Component {
    {this.timeIndicator(lengthString, totalTime)} -
    Doc.resetView(this.props.Document)}>
    -
    Doc.setView(this.props.Document)}>
    +
    this.resetView(this.props.Document)}>
    +
    this.setView(this.props.Document)}>
    diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx deleted file mode 100644 index 705469fd2..000000000 --- a/src/client/views/linking/LinkFollowBox.tsx +++ /dev/null @@ -1,571 +0,0 @@ -import { observable, computed, action, runInAction, reaction, IReactionDisposer } from "mobx"; -import React = require("react"); -import { observer } from "mobx-react"; -import { FieldViewProps, FieldView } from "../nodes/FieldView"; -import { Doc, DocListCastAsync, Opt } from "../../../new_fields/Doc"; -import { undoBatch } from "../../util/UndoManager"; -import { NumCast, FieldValue, Cast, StrCast } from "../../../new_fields/Types"; -import { CollectionViewType } from "../collections/CollectionView"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { SelectionManager } from "../../util/SelectionManager"; -import { DocumentManager } from "../../util/DocumentManager"; -import { DocumentView } from "../nodes/DocumentView"; -import "./LinkFollowBox.scss"; -import { SearchUtil } from "../../util/SearchUtil"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { listSpec } from "../../../new_fields/Schema"; -import { DocServer } from "../../DocServer"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faTimes } from '@fortawesome/free-solid-svg-icons'; -import { docs_v1 } from "googleapis"; -import { Utils } from "../../../Utils"; -import { Link } from "@react-pdf/renderer"; - -export enum FollowModes { - OPENTAB = "Open in Tab", - OPENRIGHT = "Open in Right Split", - OPENFULL = "Open Full Screen", - PAN = "Pan to Document", - INPLACE = "Open In Place" -} - -enum FollowOptions { - ZOOM = "Zoom", - NOZOOM = "No Zoom", -} - -@observer -export class LinkFollowBox extends React.Component { - - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkFollowBox, fieldKey); } - public static Instance: LinkFollowBox | undefined; - @observable static linkDoc: Doc | undefined = undefined; - @observable static destinationDoc: Doc | undefined = undefined; - @observable static sourceDoc: Doc | undefined = undefined; - @observable selectedMode: string = ""; - @observable selectedContext: Doc | undefined = undefined; - @observable selectedContextAliases: Doc[] | undefined = undefined; - @observable selectedOption: string = ""; - @observable selectedContextString: string = ""; - @observable sourceView: DocumentView | undefined = undefined; - @observable canPan: boolean = false; - @observable shouldUseOnlyParentContext = false; - _contextDisposer?: IReactionDisposer; - - @observable private _docs: { col: Doc, target: Doc }[] = []; - @observable private _otherDocs: { col: Doc, target: Doc }[] = []; - - constructor(props: FieldViewProps) { - super(props); - LinkFollowBox.Instance = this; - this.resetVars(); - this.props.Document.isBackground = true; - } - - componentDidMount = () => { - this.resetVars(); - - this._contextDisposer = reaction( - () => this.selectedContextString, - async () => { - const ref = await DocServer.GetRefField(this.selectedContextString); - runInAction(() => { - if (ref instanceof Doc) { - this.selectedContext = ref; - } - }); - if (this.selectedContext instanceof Doc) { - const aliases = await SearchUtil.GetViewsOfDocument(this.selectedContext); - runInAction(() => { this.selectedContextAliases = aliases; }); - } - } - ); - } - - componentWillUnmount = () => { - this._contextDisposer && this._contextDisposer(); - } - - async resetPan() { - if (LinkFollowBox.destinationDoc && this.sourceView && this.sourceView.props.ContainingCollectionDoc) { - runInAction(() => this.canPan = false); - if (this.sourceView.props.ContainingCollectionDoc._viewType === CollectionViewType.Freeform) { - const docs = Cast(this.sourceView.props.ContainingCollectionDoc.data, listSpec(Doc), []); - const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(LinkFollowBox.destinationDoc)); - - aliases.forEach(alias => { - if (docs.filter(doc => doc === alias).length > 0) { - runInAction(() => { this.canPan = true; }); - } - }); - } - } - } - - @action - resetVars = () => { - this.selectedContext = undefined; - this.selectedContextString = ""; - this.selectedMode = ""; - this.selectedOption = ""; - LinkFollowBox.linkDoc = undefined; - LinkFollowBox.sourceDoc = undefined; - LinkFollowBox.destinationDoc = undefined; - this.sourceView = undefined; - this.canPan = false; - this.shouldUseOnlyParentContext = false; - } - - async fetchDocuments() { - if (LinkFollowBox.destinationDoc) { - const dest: Doc = LinkFollowBox.destinationDoc; - const aliases = await SearchUtil.GetViewsOfDocument(Doc.GetProto(dest)); - const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${dest[Id]}"` }); - const map: Map = new Map; - const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs))); - allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index]))); - docs.forEach(doc => map.delete(doc)); - runInAction(async () => { - this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: dest })); - this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target })); - const tcontext = LinkFollowBox.linkDoc && (await Cast(LinkFollowBox.linkDoc.anchor2Context, Doc)) as Doc; - runInAction(() => tcontext && this._docs.splice(0, 0, { col: tcontext, target: dest })); - }); - } - } - - @action - setLinkDocs = (linkDoc: Doc, source: Doc, dest: Doc) => { - this.resetVars(); - - LinkFollowBox.linkDoc = linkDoc; - LinkFollowBox.sourceDoc = source; - LinkFollowBox.destinationDoc = dest; - this.fetchDocuments(); - - SelectionManager.SelectedDocuments().forEach(dv => { - if (dv.props.Document === LinkFollowBox.sourceDoc) { - this.sourceView = dv; - } - }); - - this.resetPan(); - } - - highlightDoc = () => LinkFollowBox.destinationDoc && Doc.linkFollowHighlight(LinkFollowBox.destinationDoc); - - @undoBatch - openFullScreen = () => { - if (LinkFollowBox.destinationDoc) { - const view = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc); - view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view); - } - } - - @undoBatch - openColFullScreen = (options: { context: Doc }) => { - if (LinkFollowBox.destinationDoc) { - if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2; - options.context._panX = newPanX; - options.context._panY = newPanY; - } - const view = DocumentManager.Instance.getDocumentView(options.context); - view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view); - this.highlightDoc(); - } - } - - // should container be a doc or documentview or what? This one needs work and is more long term - @undoBatch - openInContainer = (options: { container: Doc }) => { - - } - - static _addDocTab: (undefined | ((doc: Doc, dataDoc: Opt, where: string) => boolean)); - - static setAddDocTab = (addFunc: (doc: Doc, dataDoc: Opt, where: string) => boolean) => { - LinkFollowBox._addDocTab = addFunc; - } - - @undoBatch - openLinkColRight = (options: { context: Doc, shouldZoom: boolean }) => { - if (LinkFollowBox.destinationDoc) { - options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context; - if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2; - options.context._panX = newPanX; - options.context._panY = newPanY; - } - (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "onRight"); - - if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom }); - - this.highlightDoc(); - SelectionManager.DeselectAll(); - } - } - - @undoBatch - openLinkRight = () => { - if (LinkFollowBox.destinationDoc) { - const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc); - (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, undefined, "onRight"); - this.highlightDoc(); - SelectionManager.DeselectAll(); - } - - } - - @undoBatch - jumpToLink = async (options: { shouldZoom: boolean }) => { - if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) { - const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); }; - //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)); - - DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined); - } - } - - @undoBatch - openLinkTab = () => { - if (LinkFollowBox.destinationDoc) { - const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc); - // this.prosp.addDocTab is empty -- use the link source's addDocTab - (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, undefined, "inTab"); - - this.highlightDoc(); - SelectionManager.DeselectAll(); - } - } - - @undoBatch - openLinkColTab = (options: { context: Doc, shouldZoom: boolean }) => { - if (LinkFollowBox.destinationDoc) { - options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context; - if (NumCast(options.context._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc._width) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc._height) / 2; - options.context._panX = newPanX; - options.context._panY = newPanY; - } - (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "inTab"); - if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom }); - - this.highlightDoc(); - SelectionManager.DeselectAll(); - } - } - - @undoBatch - openLinkInPlace = (options: { shouldZoom: boolean }) => { - - if (LinkFollowBox.destinationDoc && LinkFollowBox.sourceDoc) { - if (this.sourceView && this.sourceView.props.addDocument) { - const destViews = DocumentManager.Instance.getDocumentViews(LinkFollowBox.destinationDoc); - if (!destViews.find(dv => dv.props.ContainingCollectionView === this.sourceView!.props.ContainingCollectionView)) { - const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc); - const y = NumCast(LinkFollowBox.sourceDoc.y); - const x = NumCast(LinkFollowBox.sourceDoc.x); - - const width = NumCast(LinkFollowBox.sourceDoc._width); - const height = NumCast(LinkFollowBox.sourceDoc._height); - - alias.x = x + width + 30; - alias.y = y; - alias._width = width; - alias._height = height; - - this.sourceView.props.addDocument(alias); - } - } - - this.jumpToLink({ shouldZoom: options.shouldZoom }); - - this.highlightDoc(); - SelectionManager.DeselectAll(); - } - } - - //set this to be the default link behavior, can be any of the above - public defaultLinkBehavior: (options?: any) => void = this.jumpToLink; - - @action - currentLinkBehavior = () => { - // this.resetPan(); - if (LinkFollowBox.destinationDoc) { - if (this.selectedContextString === "") { - this.selectedContextString = "self"; - this.selectedContext = LinkFollowBox.destinationDoc; - } - if (this.selectedOption === "") this.selectedOption = FollowOptions.NOZOOM; - const shouldZoom: boolean = this.selectedOption === FollowOptions.NOZOOM ? false : true; - const notOpenInContext: boolean = this.selectedContextString === "self" || this.selectedContextString === LinkFollowBox.destinationDoc[Id]; - - if (this.selectedMode === FollowModes.INPLACE) { - if (shouldZoom !== undefined) this.openLinkInPlace({ shouldZoom: shouldZoom }); - } - else if (this.selectedMode === FollowModes.OPENFULL) { - if (notOpenInContext) this.openFullScreen(); - else this.selectedContext && this.openColFullScreen({ context: this.selectedContext }); - } - else if (this.selectedMode === FollowModes.OPENRIGHT) { - if (notOpenInContext) this.openLinkRight(); - else this.selectedContext && this.openLinkColRight({ context: this.selectedContext, shouldZoom: shouldZoom }); - } - else if (this.selectedMode === FollowModes.OPENTAB) { - if (notOpenInContext) this.openLinkTab(); - else this.selectedContext && this.openLinkColTab({ context: this.selectedContext, shouldZoom: shouldZoom }); - } - else if (this.selectedMode === FollowModes.PAN) { - this.jumpToLink({ shouldZoom: shouldZoom }); - } - else return; - } - } - - @action - handleModeChange = (e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - this.selectedMode = target.value; - this.selectedContext = undefined; - this.selectedContextString = ""; - - this.shouldUseOnlyParentContext = (this.selectedMode === FollowModes.INPLACE || this.selectedMode === FollowModes.PAN); - - if (this.shouldUseOnlyParentContext) { - if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) { - this.selectedContext = this.sourceView.props.ContainingCollectionDoc; - this.selectedContextString = (StrCast(this.sourceView.props.ContainingCollectionDoc.title)); - } - } - } - - @action - handleOptionChange = (e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - this.selectedOption = target.value; - } - - @action - handleContextChange = (e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - this.selectedContextString = target.value; - // selectedContext is updated in reaction - this.selectedOption = ""; - } - - @computed - get canOpenInPlace() { - if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) { - const colDoc = this.sourceView.props.ContainingCollectionDoc; - if (colDoc._viewType === CollectionViewType.Freeform) return true; - } - return false; - } - - @computed - get availableModes() { - return ( -
    -
    -
    -
    -
    -
    -
    - ); - } - - @computed - get parentName() { - if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) { - return this.sourceView.props.ContainingCollectionDoc.title; - } - } - - @computed - get parentID(): string { - if (this.sourceView && this.sourceView.props.ContainingCollectionDoc) { - return StrCast(this.sourceView.props.ContainingCollectionDoc[Id]); - } - return "col"; - } - - @computed - get availableContexts() { - return ( - this.shouldUseOnlyParentContext ? - - : -
    -
    - {[...this._docs, ...this._otherDocs].map(doc => { - if (doc && doc.target && doc.col.title !== "Recently Closed") { - return

    ; - } - })} -
    - ); - } - - @computed - get shouldShowZoom(): boolean { - if (this.selectedMode === FollowModes.OPENFULL) return false; - if (this.shouldUseOnlyParentContext) return true; - if (LinkFollowBox.destinationDoc ? this.selectedContextString === LinkFollowBox.destinationDoc[Id] : "self") return false; - - let contextMatch: boolean = false; - if (this.selectedContextAliases) { - this.selectedContextAliases.forEach(alias => { - if (alias._viewType === CollectionViewType.Freeform) contextMatch = true; - }); - } - if (contextMatch) return true; - - return false; - } - - @computed - get availableOptions() { - if (LinkFollowBox.destinationDoc) { - return ( - this.shouldShowZoom ? -
    -
    -
    -
    - : -
    No Available Options
    - ); - } - return null; - } - - render() { - return ( -
    -
    -
    - {LinkFollowBox.linkDoc ? "Link Title: " + StrCast(LinkFollowBox.linkDoc.title) : "No Link Selected"} -
    this.props.Document.isMinimized = true} className="closeDocument">
    -
    -
    {LinkFollowBox.linkDoc ? - LinkFollowBox.sourceDoc && LinkFollowBox.destinationDoc ? "Source: " + StrCast(LinkFollowBox.sourceDoc.title) + ", Destination: " + StrCast(LinkFollowBox.destinationDoc.title) - : "" : ""}
    -
    -
    -
    -
    Mode
    -
    - {LinkFollowBox.linkDoc ? this.availableModes : "Please select a link to view modes"} -
    -
    -
    -
    Context
    -
    - {this.selectedMode !== "" ? this.availableContexts : "Please select a mode to view contexts"} -
    -
    -
    -
    Options
    -
    - {this.selectedContextString !== "" ? this.availableOptions : "Please select a context to view options"} -
    -
    -
    -
    - -
    - -
    -
    - ); - } -} \ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5eaaa3bae..153af933a 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -255,24 +255,6 @@ export namespace Doc { // }); // } - export function resetView(doc: Doc) { - doc._panX = doc._customOriginX ?? 0; - doc._panY = doc._customOriginY ?? 0; - doc.scale = doc._customOriginScale ?? 1; - } - - export function resetViewToOrigin(doc: Doc) { - doc._panX = 0; - doc._panY = 0; - doc.scale = 1; - } - - export function setView(doc: Doc) { - doc._customOriginX = doc._panX; - doc._customOriginY = doc._panY; - doc._customOriginScale = doc.scale; - } - export function RunCachedUpdate(doc: Doc, field: string) { const update = doc[CachedUpdates][field]; if (update) { -- cgit v1.2.3-70-g09d2 From d66aaffc27405f4231a29cd6edda3477077ae946 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 29 Apr 2020 13:48:13 -0400 Subject: fixes for text layout strings. --- src/client/views/animationtimeline/Keyframe.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentBox.tsx | 27 ++- .../views/nodes/formattedText/DashDocView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 5 +- .../views/nodes/formattedText/RichTextSchema.tsx | 181 --------------------- .../authentication/models/current_user_utils.ts | 14 +- 7 files changed, 28 insertions(+), 207 deletions(-) (limited to 'src/client/views/animationtimeline') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index a3407f653..bbd7b2676 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -225,7 +225,7 @@ export class Keyframe extends React.Component { this._mouseToggled = true; } const left = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.left, this.regiondata, this.regions)!; - const right = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, 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); if (futureX <= 0) { @@ -495,7 +495,7 @@ export class Keyframe extends React.Component { } else { return
    -
    +
    ; } }); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2d3bb6f3c..c70301b2f 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -113,7 +113,7 @@ export class MarqueeView extends React.Component; @@ -28,7 +27,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent this.contentDoc[this.props.fieldKey], (data) => { + this._prevSelectionDisposer = reaction(() => this.layoutDoc[this.props.fieldKey], (data) => { if (data instanceof Doc && !this.isSelectionLocked()) { this._selections.indexOf(data) !== -1 && this._selections.splice(this._selections.indexOf(data), 1); this._selections.push(data); @@ -42,22 +41,20 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { const funcs: ContextMenuProps[] = []; funcs.push({ description: (this.isSelectionLocked() ? "Show" : "Lock") + " Selection", event: () => this.toggleLockSelection, icon: "expand-arrows-alt" }); - funcs.push({ description: (this.props.Document.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" }); - funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" }); + funcs.push({ description: (this.layoutDoc.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => this.layoutDoc.excludeCollections = !this.layoutDoc.excludeCollections, icon: "expand-arrows-alt" }); + funcs.push({ description: `${this.layoutDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.layoutDoc.forceActive = !this.layoutDoc.forceActive, icon: "project-diagram" }); + funcs.push({ description: `Show ${this.layoutDoc.childTemplateName !== "keyValue" ? "key values" : "contents"}`, event: () => this.layoutDoc.childTemplateName = this.layoutDoc.childTemplateName ? undefined : "keyValue", icon: "project-diagram" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } - @computed get contentDoc() { - return (this.props.Document.isTemplateDoc || this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document)); - } lockSelection = () => { - this.contentDoc[this.props.fieldKey] = this.props.Document[this.props.fieldKey]; + this.layoutDoc[this.props.fieldKey] = this.layoutDoc[this.props.fieldKey]; } showSelection = () => { - this.contentDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`); + this.layoutDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`); } isSelectionLocked = () => { - const kvpstring = Field.toKeyValueString(this.contentDoc, this.props.fieldKey); + const kvpstring = Field.toKeyValueString(this.layoutDoc, this.props.fieldKey); return !kvpstring || kvpstring.includes("DOC"); } toggleLockSelection = () => { @@ -67,13 +64,13 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { this.lockSelection(); if (this._curSelection > 0) { - this.contentDoc[this.props.fieldKey] = this._selections[--this._curSelection]; + this.layoutDoc[this.props.fieldKey] = this._selections[--this._curSelection]; return true; } } nextSelection = () => { if (this._curSelection < this._selections.length - 1 && this._selections.length) { - this.contentDoc[this.props.fieldKey] = this._selections[++this._curSelection]; + this.layoutDoc[this.props.fieldKey] = this._selections[++this._curSelection]; return true; } } @@ -107,8 +104,8 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent this.props.PanelHeight() - 2 * this.yPad; getTransform = () => this.props.ScreenToLocalTransform().translate(-this.xPad, -this.yPad); get renderContents() { - const containedDoc = Cast(this.contentDoc[this.props.fieldKey], Doc, null); - const childTemplateName = StrCast(this.props.Document.childTemplateName); + const containedDoc = Cast(this.dataDoc[this.props.fieldKey], Doc, null); + const childTemplateName = StrCast(this.layoutDoc.childTemplateName); if (containedDoc && childTemplateName && !containedDoc["layout_" + childTemplateName]) { setTimeout(() => { Doc.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName); @@ -145,7 +142,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { if (dashDocBase instanceof Doc) { const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias); aliasedDoc.layoutKey = "layout"; - node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); + node.attrs.fieldKey && Doc.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined); this._dashDoc = aliasedDoc; // self.doRender(aliasedDoc, removeDoc, node, view, getPos); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c4e387e5a..782a91547 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -418,9 +418,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const cm = ContextMenu.Instance; const funcs: ContextMenuProps[] = []; - this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); + this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); + !this.rootDoc.isTemplateDoc && funcs.push({ description: "Show Template", event: async () => this.props.addDocTab(Doc.GetProto(this.layoutDoc), "onRight"), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); - !this.props.Document.rootDocument && funcs.push({ + !this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = makeTemplate(this.props.Document); Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document); diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index 33caf5751..cdb7374f8 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -342,187 +342,6 @@ export class DashDocView { } } -export class DashFieldView { - _fieldWrapper: HTMLDivElement; // container for label and value - _labelSpan: HTMLSpanElement; // field label - _fieldSpan: HTMLSpanElement; // field value - _fieldCheck: HTMLInputElement; - _enumerables: HTMLDivElement; // field value - _reactionDisposer: IReactionDisposer | undefined; - _textBoxDoc: Doc; - @observable _dashDoc: Doc | undefined; - _fieldKey: string; - _options: Doc[] = []; - - constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { - this._fieldKey = node.attrs.fieldKey; - this._textBoxDoc = tbox.props.Document; - this._fieldWrapper = document.createElement("p"); - this._fieldWrapper.style.width = node.attrs.width; - this._fieldWrapper.style.height = node.attrs.height; - this._fieldWrapper.style.fontWeight = "bold"; - this._fieldWrapper.style.position = "relative"; - this._fieldWrapper.style.display = "inline-block"; - - const self = this; - - this._enumerables = document.createElement("div"); - this._enumerables.style.width = "10px"; - this._enumerables.style.height = "10px"; - this._enumerables.style.position = "relative"; - this._enumerables.style.display = "none"; - - //Moved - this._enumerables.onpointerdown = async (e) => { - e.stopPropagation(); - const collview = await Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, [{ title: self._fieldSpan.innerText }]); - collview instanceof Doc && tbox.props.addDocTab(collview, "onRight"); - }; - //Moved - const updateText = (forceMatch: boolean) => { - self._enumerables.style.display = "none"; - const newText = self._fieldSpan.innerText.startsWith(":=") || self._fieldSpan.innerText.startsWith("=:=") ? ":=-computed-" : self._fieldSpan.innerText; - - // look for a document whose id === the fieldKey being displayed. If there's a match, then that document - // holds the different enumerated values for the field in the titles of its collected documents. - // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. - DocServer.GetRefField(self._fieldKey).then(options => { - let modText = ""; - (options instanceof Doc) && DocListCast(options.data).forEach(opt => (forceMatch ? StrCast(opt.title).startsWith(newText) : StrCast(opt.title) === newText) && (modText = StrCast(opt.title))); - if (modText) { - self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = modText; - Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, []); - } // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key - else if (self._fieldSpan.innerText.startsWith(":=")) { - self._dashDoc![self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2)); - } else if (self._fieldSpan.innerText.startsWith("=:=")) { - Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(3)); - } else { - self._dashDoc![self._fieldKey] = newText; - } - }); - }; - - //Moved - this._fieldCheck = document.createElement("input"); - this._fieldCheck.id = Utils.GenerateGuid(); - this._fieldCheck.type = "checkbox"; - this._fieldCheck.style.position = "relative"; - this._fieldCheck.style.display = "none"; - this._fieldCheck.style.minWidth = "12px"; - this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)"; - this._fieldCheck.onchange = function (e: any) { - self._dashDoc![self._fieldKey] = e.target.checked; - }; - - this._fieldSpan = document.createElement("span"); - this._fieldSpan.id = Utils.GenerateGuid(); - this._fieldSpan.contentEditable = "true"; - this._fieldSpan.style.position = "relative"; - this._fieldSpan.style.display = "none"; - this._fieldSpan.style.minWidth = "12px"; - this._fieldSpan.style.fontSize = "large"; - this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); }; - this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); self._enumerables.style.display = "inline-block"; }; - this._fieldSpan.onblur = function (e: any) { updateText(false); }; - - // MOVED - const setDashDoc = (doc: Doc) => { - self._dashDoc = doc; - if (self._options?.length && !self._dashDoc[self._fieldKey]) { - self._dashDoc[self._fieldKey] = StrCast(self._options[0].title); - } - this._labelSpan.innerHTML = `${self._fieldKey}: `; - const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); - this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; - this._fieldSpan.style.display = !(fieldVal === true || fieldVal === false) ? StrCast(this._dashDoc?.[self._fieldKey]) ? "" : "inline-block" : "none"; - }; - - //Moved - this._fieldSpan.onkeydown = function (e: any) { - e.stopPropagation(); - if ((e.key === "a" && e.ctrlKey) || (e.key === "a" && e.metaKey)) { - if (window.getSelection) { - const range = document.createRange(); - range.selectNodeContents(self._fieldSpan); - window.getSelection()!.removeAllRanges(); - window.getSelection()!.addRange(range); - } - e.preventDefault(); - } - if (e.key === "Enter") { - e.preventDefault(); - e.ctrlKey && Doc.addFieldEnumerations(self._textBoxDoc, self._fieldKey, [{ title: self._fieldSpan.innerText }]); - updateText(true); - } - }; - - this._labelSpan = document.createElement("span"); - this._labelSpan.style.position = "relative"; - this._labelSpan.style.fontSize = "small"; - this._labelSpan.title = "click to see related tags"; - this._labelSpan.style.fontSize = "x-small"; - this._labelSpan.onpointerdown = function (e: any) { - e.stopPropagation(); - let container = tbox.props.ContainingCollectionView; - while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) { - container = container.props.ContainingCollectionView; - } - if (container) { - const alias = Doc.MakeAlias(container.props.Document); - alias.viewType = CollectionViewType.Time; - let list = Cast(alias.schemaColumns, listSpec(SchemaHeaderField)); - if (!list) { - alias.schemaColumns = list = new List(); - } - list.map(c => c.heading).indexOf(self._fieldKey) === -1 && list.push(new SchemaHeaderField(self._fieldKey, "#f1efeb")); - list.map(c => c.heading).indexOf("text") === -1 && list.push(new SchemaHeaderField("text", "#f1efeb")); - alias._pivotField = self._fieldKey; - tbox.props.addDocTab(alias, "onRight"); - } - }; - this._labelSpan.innerHTML = `${self._fieldKey}: `; - //MOVED - if (node.attrs.docid) { - DocServer.GetRefField(node.attrs.docid). - then(async dashDoc => dashDoc instanceof Doc && runInAction(() => setDashDoc(dashDoc))); - } else { - setDashDoc(tbox.props.DataDoc || tbox.dataDoc); - } - - //Moved - this._reactionDisposer?.(); - this._reactionDisposer = reaction(() => { // this reaction will update the displayed text whenever the document's fieldKey's value changes - const dashVal = this._dashDoc?.[self._fieldKey]; - return StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(tbox.props.Document)[self._fieldKey] : dashVal; - }, fval => { - const boolVal = Cast(fval, "boolean", null); - if (boolVal === true || boolVal === false) { - this._fieldCheck.checked = boolVal; - } else { - this._fieldSpan.innerHTML = Field.toString(fval as Field) || ""; - } - this._fieldCheck.style.display = (boolVal === true || boolVal === false) ? "inline-block" : "none"; - this._fieldSpan.style.display = !(fval === true || fval === false) ? (StrCast(fval) ? "" : "inline-block") : "none"; - }, { fireImmediately: true }); - - //MOVED IN ORDER - this._fieldWrapper.appendChild(this._labelSpan); - this._fieldWrapper.appendChild(this._fieldCheck); - this._fieldWrapper.appendChild(this._fieldSpan); - this._fieldWrapper.appendChild(this._enumerables); - (this as any).dom = this._fieldWrapper; - //updateText(false); - } - //MOVED - destroy() { - this._reactionDisposer?.(); - } - //moved - selectNode() { } -} - export class FootnoteView { innerView: any; outerView: any; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 08dc21460..4b2aafac1 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -72,8 +72,8 @@ export class CurrentUserUtils { } if (doc["template-button-description"] === undefined) { - const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" }); - Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description"); + const descriptionTemplate = Docs.Create.TextDocument("", { title: "header", _height: 100 }); + Doc.GetProto(descriptionTemplate).layout = "
    "; descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); doc["template-button-description"] = CurrentUserUtils.ficon({ @@ -181,9 +181,13 @@ export class CurrentUserUtils { doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc], { title: "Note Layouts", _height: 75 })); } else { - const noteTypes = Cast(doc["template-notes"], Doc, null); - DocListCastAsync(noteTypes).then(list => noteTypes.data = new List([doc["template-note-Note"] as any as Doc, - doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc])); + const curNoteTypes = Cast(doc["template-notes"], Doc, null); + const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, + doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc]; + DocListCastAsync(curNoteTypes.data).then(async curNotes => { + await Promise.all(curNotes!); + requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype)); + }); } return doc["template-notes"] as Doc; -- cgit v1.2.3-70-g09d2