Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move frame bar on ACE to the top of the window #12590

Merged
merged 6 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export class Context {

onSelectToActivated = new Observable<{ from: number; to: number }>();

onRangeFrameBarResized = new Observable<number>();
onPlayheadMoved = new Observable<number>();

lockLastFrameValue: boolean = false;
lockLastFrameFrame: boolean = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export class CanvasComponent extends React.Component<ICanvasComponentProps, ICan
public render() {
return (
<div id="canvas-zone">
<GraphComponent globalState={this.props.globalState} context={this.props.context} />
<FrameBarComponent globalState={this.props.globalState} context={this.props.context} />
<GraphComponent globalState={this.props.globalState} context={this.props.context} />
<PlayHeadComponent context={this.props.context} globalState={this.props.globalState} />
<RangeFrameBarComponent context={this.props.context} globalState={this.props.globalState} />
{this.props.context.activeAnimations.length > 0 && <div id="angle-mode" />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ interface IPlayHeadComponentProps {
context: Context;
}

interface IPlayHeadPixelLocator {
minFrame: number;
maxFrame: number;
width: number;
offset: number;
scale: number;
}

interface IPlayHeadComponentState {}

export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps, IPlayHeadComponentState> {
Expand All @@ -18,8 +26,15 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
private _playHeadCircle: React.RefObject<HTMLDivElement>;
private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
private _onActiveAnimationChangedObserver: Nullable<Observer<IActiveAnimationChangedOptions>>;
private _onRangeFrameBarResizedObserver: Nullable<Observer<number>>;
private _onMoveToFrameRequiredObserver: Nullable<Observer<number>>;
private _onGraphMovedObserver: Nullable<Observer<number>>;
private _onGraphScaledObserver: Nullable<Observer<number>>;
private _viewScale = 1;
private _offsetX = 0;
private _offsetRange = 10;
private _viewWidth = 748;
private readonly _rangeWidthToPlayheadWidth = 40;

private _pointerIsDown: boolean;

Expand All @@ -35,6 +50,10 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
this.forceUpdate();
});

this._onRangeFrameBarResizedObserver = this.props.context.onRangeFrameBarResized.add((width) => {
this._viewWidth = width - this._rangeWidthToPlayheadWidth;
});

this._onBeforeRenderObserver = this.props.context.scene.onBeforeRenderObservable.add(() => {
if (this.props.context.activeAnimations.length === 0) {
return;
Expand All @@ -54,19 +73,19 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
}
});

this.props.context.onMoveToFrameRequired.add((frame) => {
this._onMoveToFrameRequiredObserver = this.props.context.onMoveToFrameRequired.add((frame) => {
this.props.context.moveToFrame(frame);
this._moveHead(frame);
});

this.props.context.onGraphMoved.add((x) => {
this._onGraphMovedObserver = this.props.context.onGraphMoved.add((x) => {
this._offsetX = x;
this.forceUpdate();

this._moveHead(this.props.context.activeFrame);
});

this.props.context.onGraphScaled.add((scale) => {
this._onGraphScaledObserver = this.props.context.onGraphScaled.add((scale) => {
this._viewScale = 1 / scale;
this.forceUpdate();

Expand All @@ -83,6 +102,7 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
this._playHeadCircle.current.innerHTML = frame.toFixed(0);

this.props.context.activeFrame = frame;
this.props.context.onPlayheadMoved.notifyObservers(frame);
}

private _frameToPixel(frame: number) {
Expand All @@ -92,13 +112,12 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
return (((frame - minFrame) / (maxFrame - minFrame)) * this._graphAbsoluteWidth + this._offsetX) * this._viewScale;
}

private _pixelToFrame(pixel: number) {
private _pixelToFrame(pixel: number, locator: IPlayHeadPixelLocator) {
const { minFrame, maxFrame, width, offset, scale } = locator;
const animation = this.props.context.activeAnimations[0];
const keys = animation.getKeys();
const minFrame = this.props.context.referenceMinFrame;
const maxFrame = this.props.context.referenceMaxFrame;

return Math.max(((pixel / this._viewScale - this._offsetX) / this._graphAbsoluteWidth) * (maxFrame - minFrame) + minFrame, keys[0].frame);
return Math.max(((pixel / scale - offset) / width) * (maxFrame - minFrame) + minFrame, keys[0].frame);
}

componentWillUnmount() {
Expand All @@ -110,26 +129,62 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
if (this._onActiveAnimationChangedObserver) {
this.props.context.onActiveAnimationChanged.remove(this._onActiveAnimationChangedObserver);
}

if (this._onRangeFrameBarResizedObserver) {
this.props.context.onRangeFrameBarResized.remove(this._onRangeFrameBarResizedObserver);
}

if (this._onMoveToFrameRequiredObserver) {
this.props.context.onMoveToFrameRequired.remove(this._onMoveToFrameRequiredObserver);
}

if (this._onGraphMovedObserver) {
this.props.context.onGraphMoved.remove(this._onGraphMovedObserver);
}

if (this._onGraphScaledObserver) {
this.props.context.onGraphScaled.remove(this._onGraphScaledObserver);
}
}

private _getPixelValues(isRange: boolean): IPlayHeadPixelLocator {
let minFrame, maxFrame, width, offset, scale;
if (isRange) {
minFrame = this.props.context.fromKey;
maxFrame = this.props.context.toKey;
width = this._viewWidth;
offset = this._offsetRange;
scale = 1;
} else {
minFrame = this.props.context.referenceMinFrame;
maxFrame = this.props.context.referenceMaxFrame;
width = this._graphAbsoluteWidth;
offset = this._offsetX;
scale = this._viewScale;
}
return { minFrame, maxFrame, width, offset, scale };
}

private _onPointerDown(evt: React.PointerEvent<HTMLDivElement>) {
private _onPointerDown(evt: React.PointerEvent<HTMLDivElement>, isRange: boolean) {
evt.preventDefault();

this._pointerIsDown = true;
evt.currentTarget.setPointerCapture(evt.pointerId);

const frame = this._pixelToFrame(evt.nativeEvent.offsetX);
const locator = this._getPixelValues(isRange);
const frame = this._pixelToFrame(evt.nativeEvent.offsetX, locator);
this.props.context.moveToFrame(frame);

this._moveHead(frame);
}

private _onPointerMove(evt: React.PointerEvent<HTMLDivElement>) {
private _onPointerMove(evt: React.PointerEvent<HTMLDivElement>, isRange: boolean) {
if (!this._pointerIsDown) {
return;
}

const frame = this._pixelToFrame(evt.nativeEvent.offsetX);
const locator = this._getPixelValues(isRange);
const frame = this._pixelToFrame(evt.nativeEvent.offsetX, locator);
this.props.context.moveToFrame(frame);

this._moveHead(frame);
Expand All @@ -153,8 +208,14 @@ export class PlayHeadComponent extends React.Component<IPlayHeadComponentProps,
</div>
<div
id="play-head-control"
onPointerDown={(evt) => this._onPointerDown(evt)}
onPointerMove={(evt) => this._onPointerMove(evt)}
onPointerDown={(evt) => this._onPointerDown(evt, false)}
onPointerMove={(evt) => this._onPointerMove(evt, false)}
onPointerUp={(evt) => this._onPointerUp(evt)}
></div>
<div
id="play-head-control-2"
onPointerDown={(evt) => this._onPointerDown(evt, true)}
onPointerMove={(evt) => this._onPointerMove(evt, true)}
onPointerUp={(evt) => this._onPointerUp(evt)}
></div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
private _isMounted = false;

private _onActiveAnimationChangedObserver: Nullable<Observer<IActiveAnimationChangedOptions>>;
private _onPlayheadMovedObserver: Nullable<Observer<number>>;
private _onFrameManuallyEnteredObserver: Nullable<Observer<number>>;

constructor(props: IRangeFrameBarComponentProps) {
super(props);
Expand All @@ -42,6 +44,10 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
this.forceUpdate();
});

this._onPlayheadMovedObserver = this.props.context.onPlayheadMoved.add(() => {
this.forceUpdate();
});

this.props.context.onFrameSet.add(() => {
if (!this._isMounted) {
return;
Expand All @@ -50,6 +56,14 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
this.forceUpdate();
});

this._onFrameManuallyEnteredObserver = this.props.context.onFrameManuallyEntered.add(() => {
if (!this._isMounted) {
return;
}

this.forceUpdate();
});

this.props.context.onRangeUpdated.add(() => {
if (!this._isMounted) {
return;
Expand All @@ -67,6 +81,12 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
if (this._onActiveAnimationChangedObserver) {
this.props.context.onActiveAnimationChanged.remove(this._onActiveAnimationChangedObserver);
}
if (this._onPlayheadMovedObserver) {
this.props.context.onPlayheadMoved.remove(this._onPlayheadMovedObserver);
}
if (this._onFrameManuallyEnteredObserver) {
this.props.context.onFrameManuallyEntered.remove(this._onFrameManuallyEnteredObserver);
}

this._isMounted = false;
}
Expand All @@ -77,6 +97,7 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
}

this._viewWidth = this._svgHost.current.clientWidth;
this.props.context.onRangeFrameBarResized.notifyObservers(this._viewWidth);
this.forceUpdate();
}

Expand Down Expand Up @@ -106,6 +127,34 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
});
}

private _buildActiveFrame() {
if (this.props.context.activeFrame !== null && this.props.context.activeFrame !== undefined) {
return null;
}

const from = this.props.context.fromKey;
const to = this.props.context.toKey;

const range = to - from;
const convertRatio = range / this._viewWidth;

const x = (this.props.context.activeFrame - from) / convertRatio;

return (
<line
key={"line-activeFrame"}
x1={x}
y1="0px"
x2={x}
y2="40px"
style={{
stroke: "#ffffff",
strokeWidth: 0.5,
}}
></line>
);
}

private _buildFrames() {
if (this.props.context.activeAnimations.length === 0) {
return null;
Expand Down Expand Up @@ -178,6 +227,7 @@ export class RangeFrameBarComponent extends React.Component<IRangeFrameBarCompon
{this.props.context.activeAnimations.map((a) => {
return this._dropKeyFrames(a);
})}
{this._buildActiveFrame()}
</svg>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#canvas-zone {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 1fr 30px 10px 40px;
grid-template-rows: 30px 1fr 10px 40px;
overflow: hidden;
position: relative;

#graph {
grid-column: 1;
grid-row: 1;
grid-row: 2;
width: 100%;
height: 100%;
background: #222222;
Expand Down Expand Up @@ -115,7 +115,7 @@

#frame-bar {
grid-column: 1;
grid-row: 2;
grid-row: 1;
width: 100%;
height: 100%;
background: #222222;
Expand Down Expand Up @@ -153,13 +153,22 @@

#play-head-control {
grid-column: 1;
grid-row: 2;
grid-row: 1;
position: absolute;
height: 30px;
left: 40px;
width: calc(100% - 40px);
}

#play-head-control-2 {
grid-column: 1;
grid-row: 4;
position: absolute;
height: 30px;
left: 0px;
width: 100%;
}

#play-head {
grid-column: 1;
grid-row: 1 / 3;
Expand All @@ -170,13 +179,13 @@
margin-left: 40px;
display: grid;
grid-template-columns: 100%;
grid-template-rows: 1fr 22px;
grid-template-rows: 22px 1fr;
transform: translateX(-50%);
pointer-events: none;
z-index: 3;

#play-head-bar {
grid-row: 1;
grid-row: 2;
grid-column: 1;
justify-self: center;
width: 1.5px;
Expand All @@ -186,7 +195,7 @@
}

#play-head-circle {
grid-row: 2;
grid-row: 1;
grid-column: 1;
width: 22px;
height: 22px;
Expand All @@ -204,7 +213,7 @@

#angle-mode {
grid-column: 1;
grid-row: 2;
grid-row: 1;
width: 40px;
height: 100%;
z-index: 1;
Expand Down