浏览代码

Canvas Axis

Alejandro Toledo 5 年之前
父节点
当前提交
31e381715a

+ 32 - 38
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -24,17 +24,23 @@ interface IAnimationCurveEditorComponentProps {
     entity: IAnimatable;
     entity: IAnimatable;
 }
 }
 
 
-export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, { animations: Animation[], animationName: string, animationTargetProperty: string, isOpen: boolean, selected: Animation, currentPathData: string | undefined, svgKeyframes: IKeyframeSvgPoint[] | undefined, currentFrame: number }> {
+interface ICanvasAxis {
+    value: number;
+}
+
+export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, { animations: Animation[], animationName: string, animationTargetProperty: string, isOpen: boolean, selected: Animation, currentPathData: string | undefined, svgKeyframes: IKeyframeSvgPoint[] | undefined, currentFrame: number, frameAxisLength: ICanvasAxis[] }> {
 
 
     readonly _heightScale: number = 100;
     readonly _heightScale: number = 100;
+    readonly _canvasLength: number = 100;
     private _newAnimations: Animation[] = [];
     private _newAnimations: Animation[] = [];
     private _svgKeyframes: IKeyframeSvgPoint[] = [];
     private _svgKeyframes: IKeyframeSvgPoint[] = [];
     private _frames: Vector2[] = [];
     private _frames: Vector2[] = [];
     private _isPlaying: boolean = false;
     private _isPlaying: boolean = false;
+    private _graphCanvas: React.RefObject<HTMLDivElement>;
     constructor(props: IAnimationCurveEditorComponentProps) {
     constructor(props: IAnimationCurveEditorComponentProps) {
         super(props);
         super(props);
-        this.state = { animations: this._newAnimations, selected: this.props.animations[0], isOpen: true, currentPathData: this.getPathData(this.props.animations[0]), svgKeyframes: this._svgKeyframes, animationTargetProperty: 'position.x', animationName: "", currentFrame: 0 }
-
+        this._graphCanvas = React.createRef();
+        this.state = { animations: this._newAnimations, selected: this.props.animations[0], isOpen: true, currentPathData: this.getPathData(this.props.animations[0]), svgKeyframes: this._svgKeyframes, animationTargetProperty: 'position.x', animationName: "", currentFrame: 0, frameAxisLength: (new Array(this._canvasLength)).fill(0).map((s, i) => { return { value: i * 10 } }) }
     }
     }
 
 
     handleNameChange(event: React.ChangeEvent<HTMLInputElement>) {
     handleNameChange(event: React.ChangeEvent<HTMLInputElement>) {
@@ -406,10 +412,14 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
 
 
     }
     }
 
 
-    changeCurrentFrame(frame: number){
+    changeCurrentFrame(frame: number) {
         this.setState({ currentFrame: frame });
         this.setState({ currentFrame: frame });
     }
     }
 
 
+    graphCanvasScroll() {
+        // Set scroll info
+    }
+
     render() {
     render() {
         return (
         return (
             <div id="animation-curve-editor">
             <div id="animation-curve-editor">
@@ -454,33 +464,20 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
 
 
                             </ul>
                             </ul>
                         </div>
                         </div>
-                        <div className="graph-chart">
+                        <div ref={this._graphCanvas} className="graph-chart" onScroll={() => this.graphCanvasScroll()}>
 
 
-                            <Playhead frame={this.state.currentFrame}/>
+                            <Playhead frame={this.state.currentFrame} />
 
 
                             {this.state.svgKeyframes && <SvgDraggableArea keyframeSvgPoints={this.state.svgKeyframes} updatePosition={(updatedSvgKeyFrame: IKeyframeSvgPoint, index: number) => this.renderPoints(updatedSvgKeyFrame, index)}>
                             {this.state.svgKeyframes && <SvgDraggableArea keyframeSvgPoints={this.state.svgKeyframes} updatePosition={(updatedSvgKeyFrame: IKeyframeSvgPoint, index: number) => this.renderPoints(updatedSvgKeyFrame, index)}>
 
 
                                 {/* Frame Labels  */}
                                 {/* Frame Labels  */}
-                                <text x="10" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>10</text>
-                                <text x="20" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>20</text>
-                                <text x="30" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>30</text>
-                                <text x="40" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>40</text>
-                                <text x="50" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>50</text>
-                                <text x="60" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>60</text>
-                                <text x="70" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>70</text>
-                                <text x="80" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>80</text>
-                                <text x="90" y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>90</text>
-
                                 { /* Vertical Grid  */}
                                 { /* Vertical Grid  */}
-                                <line x1="10" y1="0" x2="10" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="20" y1="0" x2="20" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="30" y1="0" x2="30" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="40" y1="0" x2="40" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="50" y1="0" x2="50" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="60" y1="0" x2="60" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="70" y1="0" x2="70" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="80" y1="0" x2="80" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="90" y1="0" x2="90" y2="100" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
+                                {this.state.frameAxisLength.map((f,i) => 
+                                <svg key={i}>
+                                    <text x={f.value} y="0" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>{f.value}</text>
+                                    <line x1={f.value} y1="0" x2={f.value} y2="100"></line>
+                                </svg>
+                                )}
 
 
                                 { /* Value Labels  */}
                                 { /* Value Labels  */}
                                 <text x="0" y="10" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>1.8</text>
                                 <text x="0" y="10" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>1.8</text>
@@ -494,15 +491,15 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
                                 <text x="0" y="90" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>0.2</text>
                                 <text x="0" y="90" dx="-1em" style={{ font: 'italic 0.2em sans-serif' }}>0.2</text>
 
 
                                 { /* Horizontal Grid  */}
                                 { /* Horizontal Grid  */}
-                                <line x1="0" y1="10" x2="100" y2="10" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="20" x2="100" y2="20" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="30" x2="100" y2="30" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="40" x2="100" y2="40" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="50" x2="100" y2="50" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="60" x2="100" y2="60" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="70" x2="100" y2="70" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="80" x2="100" y2="80" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
-                                <line x1="0" y1="90" x2="100" y2="90" style={{ stroke: 'black', strokeWidth: '0.2px' }}></line>
+                                <line x1="0" y1="10" x2="1000" y2="10"></line>
+                                <line x1="0" y1="20" x2="1000" y2="20"></line>
+                                <line x1="0" y1="30" x2="1000" y2="30"></line>
+                                <line x1="0" y1="40" x2="1000" y2="40"></line>
+                                <line x1="0" y1="50" x2="1000" y2="50"></line>
+                                <line x1="0" y1="60" x2="1000" y2="60"></line>
+                                <line x1="0" y1="70" x2="1000" y2="70"></line>
+                                <line x1="0" y1="80" x2="1000" y2="80"></line>
+                                <line x1="0" y1="90" x2="1000" y2="90"></line>
 
 
                                 { /* Single Curve -Modify this for multiple selection and view  */}
                                 { /* Single Curve -Modify this for multiple selection and view  */}
                                 <path id="curve" d={this.state.currentPathData} style={{ stroke: 'red', fill: 'none', strokeWidth: '0.5' }}></path>
                                 <path id="curve" d={this.state.currentPathData} style={{ stroke: 'red', fill: 'none', strokeWidth: '0.5' }}></path>
@@ -518,13 +515,10 @@ export class AnimationCurveEditorComponent extends React.Component<IAnimationCur
 
 
                             }
                             }
 
 
-                        Animation name: {this.state.selected.name}
-
                         </div>
                         </div>
-                       
                     </div>
                     </div>
                     <div className="row">
                     <div className="row">
-                            <Timeline currentFrame={this.state.currentFrame} onCurrentFrameChange={(frame: number) => this.changeCurrentFrame(frame)} keyframes={this.state.selected.getKeys()} selected={this.state.selected.getKeys()[0]}></Timeline>
+                        <Timeline currentFrame={this.state.currentFrame} onCurrentFrameChange={(frame: number) => this.changeCurrentFrame(frame)} keyframes={this.state.selected.getKeys()} selected={this.state.selected.getKeys()[0]}></Timeline>
                     </div>
                     </div>
                 </div>
                 </div>
 
 

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx

@@ -199,7 +199,7 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
                                 this._isCurveEditorOpen && <PopupComponent
                                 this._isCurveEditorOpen && <PopupComponent
                                     id="curve-editor"
                                     id="curve-editor"
                                     title="Curve Animation Editor"
                                     title="Curve Animation Editor"
-                                    size={{ width: 950, height: 890 }}
+                                    size={{ width: 950, height: 512 }}
                                     onOpen={(window: Window) => { window.console.log("Window opened!!") }}
                                     onOpen={(window: Window) => { window.console.log("Window opened!!") }}
                                     onClose={(window: Window) => this.onCloseAnimationCurveEditor(window)}>
                                     onClose={(window: Window) => this.onCloseAnimationCurveEditor(window)}>
 
 

+ 25 - 5
inspector/src/components/actionTabs/tabs/propertyGrids/animations/curveEditor.scss

@@ -34,6 +34,7 @@
             justify-content: flex-start;
             justify-content: flex-start;
             flex-direction: row;
             flex-direction: row;
             width: 100vw;
             width: 100vw;
+            height: 85vh;
 
 
             .timeline{
             .timeline{
                 width: 100vw;
                 width: 100vw;
@@ -128,13 +129,32 @@
 
 
         .graph-chart{
         .graph-chart{
             flex: 1 1 0%;
             flex: 1 1 0%;
-            margin: 25% auto;
+            overflow-x: scroll;
             padding-left: 32px;
             padding-left: 32px;
+            overflow-y: scroll;
+            scroll-behavior: smooth;
+            background-color: #444444;
+
             .linear{
             .linear{
-                width: 300px;
-                height: 300px;
+                height: 360px;
                 overflow: visible;
                 overflow: visible;
-                background-color: 'aliceblue';
+                border: 0px solid lightgrey;
+
+                svg {
+                    overflow: visible;
+                }
+
+                &:focus {
+                    outline-color: transparent;
+                }
+
+                line {
+                    stroke: #cecece;
+                    stroke-width: 0.2;
+                }
+                text {
+                    fill: #cecece;
+                }
             }
             }
 
 
             .playhead-wrapper {
             .playhead-wrapper {
@@ -165,7 +185,7 @@
 
 
             .playhead-line {
             .playhead-line {
                 width: 2px;
                 width: 2px;
-                height: calc(45vh - 100px);
+                height: calc(90vh - 100px);
                 background-color: rgb(255, 198, 14);
                 background-color: rgb(255, 198, 14);
                 position: absolute;
                 position: absolute;
                 margin-left: 12.5px;
                 margin-left: 12.5px;

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/playhead.tsx

@@ -12,7 +12,7 @@ export class Playhead extends React.Component<IPlayheadProps>{
     
     
     render() { 
     render() { 
        return (
        return (
-           <div className="playhead-wrapper" id="playhead" style={{left: `calc(${this.props.frame * 3.02}px - 13px)`}}>
+           <div className="playhead-wrapper" id="playhead" style={{left: `calc(${this.props.frame * 4}px - 13px)`}}>
             <div className="playhead">{this.props.frame}</div>
             <div className="playhead">{this.props.frame}</div>
             <div className="playhead-triangle"></div>
             <div className="playhead-triangle"></div>
             <div className="playhead-line"></div>
             <div className="playhead-line"></div>

+ 95 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/animations/svgDraggableArea.tsx

@@ -4,7 +4,7 @@ import { KeyframeSvgPoint, IKeyframeSvgPoint } from './keyframeSvgPoint';
 
 
 interface ISvgDraggableAreaProps {
 interface ISvgDraggableAreaProps {
     keyframeSvgPoints: IKeyframeSvgPoint[];
     keyframeSvgPoints: IKeyframeSvgPoint[];
-    updatePosition: (updatedKeyframe: IKeyframeSvgPoint, index: number) => void
+    updatePosition: (updatedKeyframe: IKeyframeSvgPoint, index: number) => void;
 }
 }
 
 
 export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
 export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
@@ -13,14 +13,23 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
     private _isCurrentPointControl: string;
     private _isCurrentPointControl: string;
     private _currentPointIndex: number;
     private _currentPointIndex: number;
     private _draggableArea: React.RefObject<SVGSVGElement>;
     private _draggableArea: React.RefObject<SVGSVGElement>;
+    private _panStart: Vector2;
+    private _panStop: Vector2;
 
 
     constructor(props: ISvgDraggableAreaProps) {
     constructor(props: ISvgDraggableAreaProps) {
         super(props);
         super(props);
         this._currentPointIndex = -1;
         this._currentPointIndex = -1;
         this._isCurrentPointControl = "";
         this._isCurrentPointControl = "";
         this._draggableArea = React.createRef();
         this._draggableArea = React.createRef();
+        this._panStart = new Vector2(0, 0);
+        this._panStop = new Vector2(0, 0);
     }
     }
 
 
+    componentDidMount() {
+        this._draggableArea.current?.addEventListener("keydown", this.keyDown.bind(this));
+        this._draggableArea.current?.addEventListener("keyup", this.keyUp.bind(this));
+    }  
+
     dragStart(e: React.TouchEvent<SVGSVGElement>): void;
     dragStart(e: React.TouchEvent<SVGSVGElement>): void;
     dragStart(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void;
     dragStart(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void;
     dragStart(e: any): void {
     dragStart(e: any): void {
@@ -33,6 +42,12 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
                 this._isCurrentPointControl = e.target.getAttribute("type");
                 this._isCurrentPointControl = e.target.getAttribute("type");
             }
             }
         }
         }
+
+        if (e.target.classList.contains("pannable")) {
+            if (e.buttons === 1 && e.ctrlKey) {
+                this._panStart.set(e.clientX, e.clientY);
+            }
+        }
     }
     }
 
 
     drag(e: React.TouchEvent<SVGSVGElement>): void;
     drag(e: React.TouchEvent<SVGSVGElement>): void;
@@ -69,6 +84,14 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
         this._active = false;
         this._active = false;
         this._currentPointIndex = -1;
         this._currentPointIndex = -1;
         this._isCurrentPointControl = "";
         this._isCurrentPointControl = "";
+
+        if (e.target.classList.contains("pannable")) {
+            if (this._panStart.x !== 0 && this._panStart.y !== 0) {
+                this._panStop.set(e.clientX, e.clientY);
+                this.panDirection();
+            }
+        }
+
     }
     }
 
 
     getMousePosition(e: React.TouchEvent<SVGSVGElement>): Vector2 | undefined;
     getMousePosition(e: React.TouchEvent<SVGSVGElement>): Vector2 | undefined;
@@ -90,10 +113,78 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
         }
         }
     }
     }
 
 
+    panDirection() {
+
+        // Movement Right to Left
+        if (this._panStart.x > this._panStop.x) {
+            console.log("right to left");
+            this.panTo("right", Math.abs(this._panStart.x - this._panStop.x));
+        }
+
+        // Movement Right to Left
+        if (this._panStart.x < this._panStop.x) {
+            this.panTo("left", Math.abs(this._panStart.x - this._panStop.x));
+            console.log("left to right");
+        }
+
+        // Movement Bottom to Up
+        if (this._panStart.y > this._panStop.y) {
+            console.log("down up");
+        }
+
+        // Movement Up to Bottom
+        if (this._panStart.y < this._panStop.y) {
+            console.log("up down");
+        }
+
+        this._panStart.set(0, 0);
+        this._panStop.set(0, 0);
+
+    }
+
+    panTo(direction: string, value: number) {
+
+        switch (direction) {
+            case "left":
+                (this._draggableArea.current?.parentElement as HTMLDivElement).scrollLeft -= (value * 1);
+                break;
+            case "right":
+                (this._draggableArea.current?.parentElement as HTMLDivElement).scrollLeft += (value * 1);
+                break;
+            case "top":
+                break;
+            case "down":
+                break;
+        }
+
+    }
+
+    keyDown(e: KeyboardEvent) {
+        e.preventDefault();
+        if (e.keyCode === 17) {
+            this._draggableArea.current?.style.setProperty("cursor", "grab");
+        }
+
+    }
+
+    keyUp(e: KeyboardEvent) {
+        e.preventDefault();
+        if (e.keyCode === 17) {
+            this._draggableArea.current?.style.setProperty("cursor", "initial");
+        }
+
+    }
+
+    focus(e: React.MouseEvent<SVGSVGElement>) {
+        e.preventDefault();
+        this._draggableArea.current?.focus();
+    }
+
+
     render() {
     render() {
         return (
         return (
             <>
             <>
-                <svg className="linear" style={{ border: '1px solid black' }} ref={this._draggableArea}
+                <svg className="linear pannable" ref={this._draggableArea}  tabIndex={0}
 
 
                     onMouseMove={(e) => this.drag(e)}
                     onMouseMove={(e) => this.drag(e)}
                     onTouchMove={(e) => this.drag(e)}
                     onTouchMove={(e) => this.drag(e)}
@@ -104,8 +195,9 @@ export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
                     onMouseUp={(e) => this.dragEnd(e)}
                     onMouseUp={(e) => this.dragEnd(e)}
                     onMouseLeave={(e) => this.dragEnd(e)}
                     onMouseLeave={(e) => this.dragEnd(e)}
                     // Add way to add new keyframe
                     // Add way to add new keyframe
+                    onClick={(e) => this.focus(e)}
 
 
-                    viewBox="0 0 100 100" preserveAspectRatio="none">
+                    viewBox="0 0 1000 100">
 
 
                     {this.props.children}
                     {this.props.children}
                     {this.props.keyframeSvgPoints.map((keyframe, i) =>
                     {this.props.keyframeSvgPoints.map((keyframe, i) =>