|
|
@@ -20,6 +20,8 @@ const edges = [
|
|
|
[2, 3]
|
|
|
];
|
|
|
|
|
|
+const zoomConstant = 0.01;
|
|
|
+
|
|
|
type NodeType = {
|
|
|
id: number,
|
|
|
x: number,
|
|
|
@@ -44,7 +46,8 @@ type StateType = {
|
|
|
deltaX: number | null,
|
|
|
deltaY: number | null,
|
|
|
dragBg: boolean,
|
|
|
- preventDrag: boolean
|
|
|
+ preventDrag: boolean,
|
|
|
+ scale: number
|
|
|
};
|
|
|
|
|
|
export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
@@ -59,7 +62,8 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
deltaX: null as (number | null),
|
|
|
deltaY: null as (number | null),
|
|
|
dragBg: false,
|
|
|
- preventDrag: false
|
|
|
+ preventDrag: false,
|
|
|
+ scale: 1
|
|
|
}
|
|
|
|
|
|
myRef: any = React.createRef();
|
|
|
@@ -71,6 +75,15 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
originX: Math.round(width / 2),
|
|
|
originY: Math.round(height / 2)
|
|
|
});
|
|
|
+
|
|
|
+ // Suppress trackpad gestures
|
|
|
+ this.myRef.addEventListener("touchmove", (e: any) => e.preventDefault());
|
|
|
+ this.myRef.addEventListener("mousewheel", (e: any) => e.preventDefault());
|
|
|
+ }
|
|
|
+
|
|
|
+ componentWillUnmount() {
|
|
|
+ this.myRef.removeEventListener("touchmove", (e: any) => e.preventDefault());
|
|
|
+ this.myRef.removeEventListener("mousewheel", (e: any) => e.preventDefault());
|
|
|
}
|
|
|
|
|
|
// Push to activeIds if not already present
|
|
|
@@ -107,6 +120,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
|
|
|
onMouseMove = (e: any) => {
|
|
|
let { originX, originY, dragBg, preventDrag } = this.state;
|
|
|
+ this.setState({ scale: 1 });
|
|
|
|
|
|
// Update origin-centered cursor coordinates
|
|
|
let bounds = this.myRef.getBoundingClientRect();
|
|
|
@@ -120,9 +134,16 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Set zoom scale
|
|
|
+ handleOnWheel = (e: any) => {
|
|
|
+ var scale = 1;
|
|
|
+ scale -= e.deltaY * zoomConstant;
|
|
|
+ this.setState({ scale });
|
|
|
+ };
|
|
|
+
|
|
|
// Pass origin to node for offset
|
|
|
renderNodes = () => {
|
|
|
- let { activeIds, originX, originY, cursorX, cursorY } = this.state;
|
|
|
+ let { activeIds, originX, originY, cursorX, cursorY, scale } = this.state;
|
|
|
|
|
|
return this.state.nodes.map((node: NodeType, i: number) => {
|
|
|
|
|
|
@@ -137,6 +158,12 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
node.x += this.state.deltaX;
|
|
|
node.y -= this.state.deltaY;
|
|
|
}
|
|
|
+
|
|
|
+ // Apply cursor-centered zoom
|
|
|
+ if (this.state.scale !== 1) {
|
|
|
+ node.x = cursorX + scale * (node.x - cursorX);
|
|
|
+ node.y = cursorY + scale * (node.y - cursorY);
|
|
|
+ }
|
|
|
|
|
|
return (
|
|
|
<Node
|
|
|
@@ -174,9 +201,10 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
|
|
|
onMouseMove={this.onMouseMove}
|
|
|
onMouseDown={() => this.setState({ dragBg: true })}
|
|
|
onMouseUp={() => this.setState({ dragBg: false })}
|
|
|
+ onWheel={this.handleOnWheel}
|
|
|
>
|
|
|
- {this.renderEdges()}
|
|
|
{this.renderNodes()}
|
|
|
+ {this.renderEdges()}
|
|
|
</StyledGraphDisplay>
|
|
|
);
|
|
|
}
|
|
|
@@ -187,5 +215,6 @@ const StyledGraphDisplay = styled.div`
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
overflow: hidden;
|
|
|
+ cursor: move;
|
|
|
background: #202227;
|
|
|
`;
|