diff options
| author | Andy Rickert <andrew_rickert@brown.edu> | 2020-04-29 16:23:30 -0700 | 
|---|---|---|
| committer | Andy Rickert <andrew_rickert@brown.edu> | 2020-04-29 16:23:30 -0700 | 
| commit | ddf0902be470f6557695627fc65103c2d10e42f7 (patch) | |
| tree | 38311ac28f3f253462b9f867220fdee732f7a336 /src/client/views/animationtimeline/TimelineOverview.tsx | |
| parent | 9aab1f5e7dc7438dfa8a93afe03bd5746315c994 (diff) | |
| parent | dadbb74ffa56a0dc55745ce972e7b13925629b7b (diff) | |
merge w master
Diffstat (limited to 'src/client/views/animationtimeline/TimelineOverview.tsx')
| -rw-r--r-- | src/client/views/animationtimeline/TimelineOverview.tsx | 181 | 
1 files changed, 181 insertions, 0 deletions
| diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx new file mode 100644 index 000000000..31e248823 --- /dev/null +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -0,0 +1,181 @@ +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"; +import { Keyframe, KeyframeFunc } from "./Keyframe"; + + +interface TimelineOverviewProps { +    totalLength: number; +    visibleLength: number; +    visibleStart: number; +    currentBarX: number; +    isAuthoring: boolean; +    parent: Timeline; +    changeCurrentBarX: (pixel: number) => void; +    movePanX: (pixel: number) => any; +    time: number; +    tickSpacing: number; +    tickIncrement: number; +} + + +@observer +export class TimelineOverview extends React.Component<TimelineOverviewProps>{ +    @observable private _visibleRef = React.createRef<HTMLDivElement>(); +    @observable private _scrubberRef = React.createRef<HTMLDivElement>(); +    @observable private authoringContainer = React.createRef<HTMLDivElement>(); +    @observable private playbackContainer = React.createRef<HTMLDivElement>(); +    @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; +    @observable private visibleStart: number = 0; +    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(); +                    }); +                } +            }, +        ); +    } + +    componentWillUnmount = () => { +        this._authoringReaction && this._authoringReaction(); +    } + +    @action +    setOverviewWidth() { +        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; + +        if (this.props.isAuthoring) { +            this.activeOverviewWidth = this.overviewBarWidth; +        } +        else { +            this.activeOverviewWidth = this.playbarWidth; +        } +    } + +    @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(); +        const movX = (this.props.visibleStart / this.props.totalLength) * (this.DEFAULT_WIDTH) + e.movementX; +        this.props.movePanX((movX / (this.DEFAULT_WIDTH)) * this.props.totalLength); +    } + +    @action +    onPointerUp = (e: PointerEvent) => { +        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); +        document.addEventListener("pointerup", this.onScrubberUp); +    } + +    @action +    onScrubberMove = (e: PointerEvent) => { +        e.preventDefault(); +        e.stopPropagation(); +        const scrubberRef = this._scrubberRef.current!; +        const left = scrubberRef.getBoundingClientRect().left; +        const offsetX = Math.round(e.clientX - left); +        this.props.changeCurrentBarX((((offsetX) / this.activeOverviewWidth) * this.props.totalLength) + this.props.currentBarX); +    } + +    @action +    onScrubberUp = (e: PointerEvent) => { +        e.preventDefault(); +        e.stopPropagation(); +        document.removeEventListener("pointermove", this.onScrubberMove); +        document.removeEventListener("pointerup", this.onScrubberUp); +    } + +    @action +    getTimes() { +        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; +    } + +    render() { +        this.setOverviewWidth(); +        this.getTimes(); + +        const percentVisible = this.visibleTime / this.props.time; +        const visibleBarWidth = percentVisible * this.activeOverviewWidth; + +        const percentScrubberStart = this.currentX / this.props.time; +        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 ? [ + +            <div key="timeline-overview-container" className="timeline-overview-container overviewBar" id="timelineOverview" ref={this.authoringContainer}> +                <div ref={this._visibleRef} key="1" className="timeline-overview-visible" style={{ left: `${barStart}px`, width: `${visibleBarWidth}px` }} onPointerDown={this.onPointerDown}></div>, +                <div ref={this._scrubberRef} key="2" className="timeline-overview-scrubber-container" style={{ left: `${scrubberStart}px` }} onPointerDown={this.onScrubberDown}> +                    <div key="timeline-overview-scrubber-head" className="timeline-overview-scrubber-head"></div> +                </div> +            </div> +        ] : [ +                <div key="1" className="timeline-play-bar overviewBar" id="timelinePlay" ref={this.playbackContainer}> +                    <div ref={this._scrubberRef} className="timeline-play-head" style={{ left: `${scrubberStart}px` }} onPointerDown={this.onScrubberDown}></div> +                </div>, +                <div key="2" className="timeline-play-tail" style={{ width: `${playWidth}px` }}></div> +            ]; +        return ( +            <div className="timeline-flex"> +                <div className="timelineOverview-bounding"> +                    {timeline} +                </div> +            </div> +        ); +    } + +} + + | 
