Hotkeys for moving edges and nodes

This commit is contained in:
futpib 2018-11-17 22:53:20 +03:00
parent 3dff4b5d51
commit c4a38c598f
4 changed files with 168 additions and 8 deletions

View File

@ -55,6 +55,38 @@ class GraphView extends GraphViewBase {
derivedState.nodes = props.layoutEngine.adjustNodes(derivedState.nodes, derivedState.nodesMap); derivedState.nodes = props.layoutEngine.adjustNodes(derivedState.nodes, derivedState.nodesMap);
} }
if (props.moved && props.selected) {
const edgeKey = `${props.moved.source}_${props.moved.target}`;
const nodeKey = `key-${props.selected.id}`;
if (derivedState.edgesMap[edgeKey] && derivedState.nodesMap[nodeKey]) {
derivedState.previousMoved = props.moved;
derivedState.draggingEdge = true;
derivedState.draggedEdge = props.moved;
derivedState.edgeEndNode = props.selected;
derivedState.hoveredNode = true;
derivedState.hoveredNodeData = props.selected;
derivedState.selectedNodeObj = {
nodeId: null,
node: null,
};
}
} else if (!props.moved && state.previousMoved) {
derivedState.previousMoved = null;
derivedState.draggingEdge = false;
derivedState.draggedEdge = null;
derivedState.edgeEndNode = null;
derivedState.hoveredNode = false;
derivedState.hoveredNodeData = null;
}
return derivedState; return derivedState;
} }
@ -77,9 +109,39 @@ class GraphView extends GraphViewBase {
} }
} }
if (!prevProps.moved && this.props.moved) {
this.removeEdgeElement(this.props.moved.source, this.props.moved.target);
} else if (prevProps.moved && !this.props.moved) {
const container = document.querySelector('#edge-custom-container');
if (container) {
container.remove();
}
}
if (this.props.selected &&
this.props.moved &&
(
prevProps.selected !== this.props.selected ||
prevProps.moved !== this.props.moved
) &&
this.state.draggedEdge
) {
this.dragEdge();
}
super.componentDidUpdate(prevProps, prevState); super.componentDidUpdate(prevProps, prevState);
} }
getMouseCoordinates() {
if (this.props.selected && this.props.moved) {
return [
this.props.selected.x,
this.props.selected.y,
];
}
return super.getMouseCoordinates();
}
getNodeComponent(id, node) { getNodeComponent(id, node) {
const { nodeTypes, nodeSubtypes, nodeSize, renderNode, renderNodeText, nodeKey } = this.props; const { nodeTypes, nodeSubtypes, nodeSize, renderNode, renderNodeText, nodeKey } = this.props;
return r(Node, { return r(Node, {

View File

@ -526,6 +526,7 @@ class Graph extends React.Component {
this.state = { this.state = {
selected: null, selected: null,
moved: null,
}; };
this._requestedIcons = new Set(); this._requestedIcons = new Set();
@ -627,7 +628,8 @@ class Graph extends React.Component {
(nextProps.infos === this.props.infos) && (nextProps.infos === this.props.infos) &&
(nextProps.preferences === this.props.preferences) && (nextProps.preferences === this.props.preferences) &&
(nextProps.icons === this.props.icons) && (nextProps.icons === this.props.icons) &&
(nextState.selected === this.state.selected) (nextState.selected === this.state.selected) &&
(nextState.moved === this.state.moved)
); );
} }
@ -708,7 +710,7 @@ class Graph extends React.Component {
onSwapEdge(sourceNode, targetNode, edge) { onSwapEdge(sourceNode, targetNode, edge) {
if (edge.type === 'sinkInput') { if (edge.type === 'sinkInput') {
this.props.moveSinkInput(edge.index, targetNode.index); this.props.moveSinkInput(edge.index, targetNode.index);
} else { } else if (edge.type === 'sourceOutput') {
this.props.moveSourceOutput(edge.index, targetNode.index); this.props.moveSourceOutput(edge.index, targetNode.index);
} }
} }
@ -779,8 +781,19 @@ class Graph extends React.Component {
this.graphViewElement.focus(); this.graphViewElement.focus();
} }
deselect() { hotKeyEscape() {
this.setState({ selected: null }); const { moved } = this.state;
if (moved) {
this.setState({
moved: null,
});
return;
}
this.setState({
selected: null,
});
} }
hotKeyMute() { hotKeyMute() {
@ -870,11 +883,19 @@ class Graph extends React.Component {
} }
hotKeyFocusDown() { hotKeyFocusDown() {
if (this._hotKeyMovePosition('down')) {
return;
}
const selected = this._findNextObjectForSelection(this.state.selected, 'down'); const selected = this._findNextObjectForSelection(this.state.selected, 'down');
this.setState({ selected }); this.setState({ selected });
} }
hotKeyFocusUp() { hotKeyFocusUp() {
if (this._hotKeyMovePosition('up')) {
return;
}
const selected = this._findNextObjectForSelection(this.state.selected, 'up'); const selected = this._findNextObjectForSelection(this.state.selected, 'up');
this.setState({ selected }); this.setState({ selected });
} }
@ -932,13 +953,78 @@ class Graph extends React.Component {
} }
hotKeyFocusLeft() { hotKeyFocusLeft() {
if (this._hotKeyMovePosition('left')) {
return;
}
this._focusHorizontal('left'); this._focusHorizontal('left');
} }
hotKeyFocusRight() { hotKeyFocusRight() {
if (this._hotKeyMovePosition('right')) {
return;
}
this._focusHorizontal('right'); this._focusHorizontal('right');
} }
_hotKeyMovePosition(direction) {
const { selected, moved } = this.state;
if (!selected ||
selected !== moved ||
![ 'sink', 'source', 'client', 'module' ].includes(moved.type)
) {
return false;
}
const x = direction === 'right' ? 1 : direction === 'left' ? -1 : 0;
const y = direction === 'down' ? 1 : direction === 'up' ? -1 : 0;
moved.x += x * (size + (size / 12));
moved.y += y * (size + (size / 12));
this.forceUpdate();
return true;
}
hotKeyMove() {
let { selected, moved } = this.state;
if (!selected) {
return;
}
if (moved) {
this.onSwapEdge(null, selected, moved);
this.setState({
selected: moved,
moved: null,
});
return;
}
moved = selected;
if (moved.type === 'sinkInput') {
selected = find(
node => node.id !== moved.target && node.type === 'sink',
this.state.nodes,
);
} else if (moved.type === 'sourceOutput') {
selected = find(
node => node.id !== moved.target && node.type === 'source',
this.state.nodes,
);
}
this.setState({
selected,
moved,
});
}
render() { render() {
const { nodes, edges } = this.state; const { nodes, edges } = this.state;
@ -954,6 +1040,7 @@ class Graph extends React.Component {
edges, edges,
selected: this.state.selected, selected: this.state.selected,
moved: this.state.moved,
nodeTypes: {}, nodeTypes: {},
nodeSubtypes: {}, nodeSubtypes: {},

View File

@ -92,7 +92,7 @@ class GraphView extends React.Component {
static getDerivedStateFromProps(props) { static getDerivedStateFromProps(props) {
const originalEdgesByTargetNodeKey = groupBy(prop('target'), props.edges); const originalEdgesByTargetNodeKey = groupBy(prop('target'), props.edges);
let { selected } = props; let { selected, moved } = props;
const satelliteEdges = []; const satelliteEdges = [];
@ -106,6 +106,10 @@ class GraphView extends React.Component {
selected = satelliteEdge; selected = satelliteEdge;
} }
if (edge === moved) {
moved = satelliteEdge;
}
satelliteEdges.push(satelliteEdge); satelliteEdges.push(satelliteEdge);
return satelliteNode; return satelliteNode;
@ -115,7 +119,9 @@ class GraphView extends React.Component {
originalEdgesByTargetNodeKey, originalEdgesByTargetNodeKey,
satelliteNodesByTargetNodeKey, satelliteNodesByTargetNodeKey,
satelliteEdges, satelliteEdges,
selected, selected,
moved,
}; };
} }
@ -206,7 +212,9 @@ class GraphView extends React.Component {
const { const {
satelliteNodesByTargetNodeKey, satelliteNodesByTargetNodeKey,
satelliteEdges: edges, satelliteEdges: edges,
selected, selected,
moved,
} = this.state; } = this.state;
const nodes = flatten(map(node => { const nodes = flatten(map(node => {
@ -219,6 +227,7 @@ class GraphView extends React.Component {
...this.props, ...this.props,
selected, selected,
moved,
ref: this.graphViewRef, ref: this.graphViewRef,

View File

@ -24,11 +24,13 @@ const keyMap = {
hotKeyFocusLeft: [ 'h', 'left' ], hotKeyFocusLeft: [ 'h', 'left' ],
hotKeyFocusRight: [ 'l', 'right' ], hotKeyFocusRight: [ 'l', 'right' ],
hotKeyMove: 'm',
hotKeyVolumeDown: [ '/', '9' ], hotKeyVolumeDown: [ '/', '9' ],
hotKeyVolumeUp: [ '*', '0' ], hotKeyVolumeUp: [ '*', '0' ],
hotKeyMute: 'm', hotKeyMute: 'space',
hotKeyShiftMute: 'M', hotKeyShiftMute: 'shift+space',
}; };
class MyHotKeys extends React.Component { class MyHotKeys extends React.Component {
@ -72,7 +74,7 @@ class MyHotKeys extends React.Component {
hotKeyEscape() { hotKeyEscape() {
this.hotKeyFocusGraph(); this.hotKeyFocusGraph();
this.graphRef.current.getWrappedInstance().deselect(); this.graphRef.current.getWrappedInstance().hotKeyEscape();
} }
render() { render() {