Select & delete edges

This commit is contained in:
futpib 2018-11-11 16:08:51 +03:00
parent 1c5f7e017e
commit a507e1a6c3
6 changed files with 92 additions and 34 deletions

View File

@ -16,6 +16,10 @@ module.exports = createActionCreators({
MOVE_SOURCE_OUTPUT: (sourceOutputIndex, destSourceIndex) => ({ sourceOutputIndex, destSourceIndex }), MOVE_SOURCE_OUTPUT: (sourceOutputIndex, destSourceIndex) => ({ sourceOutputIndex, destSourceIndex }),
KILL_CLIENT_BY_INDEX: clientIndex => ({ clientIndex }), KILL_CLIENT_BY_INDEX: clientIndex => ({ clientIndex }),
KILL_SINK_INPUT_BY_INDEX: sinkInputIndex => ({ sinkInputIndex }),
KILL_SOURCE_OUTPUT_BY_INDEX: sourceOutputIndex => ({ sourceOutputIndex }),
UNLOAD_MODULE_BY_INDEX: moduleIndex => ({ moduleIndex }), UNLOAD_MODULE_BY_INDEX: moduleIndex => ({ moduleIndex }),
}, },
}); });

View File

@ -101,7 +101,7 @@ class Edge extends EdgeBase {
}); });
return r.g({ return r.g({
className: 'edge-container', className: 'edge-container ' + (this.props.className || ''),
'data-source': data.source, 'data-source': data.source,
'data-target': data.target, 'data-target': data.target,
}, [ }, [

View File

@ -148,6 +148,19 @@ const Module = Client;
const gridDotSize = 2; const gridDotSize = 2;
const gridSpacing = 36; const gridSpacing = 36;
const Marker = ({ id, d }) => r('marker', {
id,
viewBox: '0 -8 16 16',
refX: '16',
markerWidth: '16',
markerHeight: '16',
orient: 'auto',
}, r.path({
className: 'arrow',
d,
}));
const renderDefs = () => r(React.Fragment, [ const renderDefs = () => r(React.Fragment, [
r.pattern({ r.pattern({
id: 'background-pattern', id: 'background-pattern',
@ -162,29 +175,26 @@ const renderDefs = () => r(React.Fragment, [
r: gridDotSize, r: gridDotSize,
})), })),
r('marker', { r(Marker, {
id: 'my-source-arrow', id: 'my-source-arrow',
viewBox: '0 -8 16 16',
refX: '16',
markerWidth: '16',
markerHeight: '16',
orient: 'auto',
}, r.path({
className: 'arrow',
d: 'M 16,-8 L 0,0 L 16,8', d: 'M 16,-8 L 0,0 L 16,8',
})), }),
r('marker', { r(Marker, {
id: 'my-sink-arrow', id: 'my-sink-arrow',
viewBox: '0 -8 16 16',
refX: '16',
markerWidth: '16',
markerHeight: '16',
orient: 'auto',
}, r.path({
className: 'arrow',
d: 'M 0,-8 L 16,0 L 0,8', d: 'M 0,-8 L 16,0 L 0,8',
})), }),
// WORKAROUND: `context-fill` did not work
r(Marker, {
id: 'my-source-arrow-selected',
d: 'M 16,-8 L 0,0 L 16,8',
}),
r(Marker, {
id: 'my-sink-arrow-selected',
d: 'M 0,-8 L 16,0 L 0,8',
}),
]); ]);
const renderNode = (nodeRef, data, key, selected, hovered) => r({ const renderNode = (nodeRef, data, key, selected, hovered) => r({
@ -262,13 +272,12 @@ const renderNodeText = state => dgo => r('foreignObject', {
state, state,
}))); })));
const afterRenderEdge = (id, element, edge, edgeContainer) => { const renderEdge = props => r(Edge, {
if (edge.type) { classSet: {
edgeContainer.classList.add(edge.type); [props.data.type]: true,
} },
}; ...props,
});
const renderEdge = edgeProps => r(Edge, edgeProps);
const renderEdgeText = state => ({ data, transform }) => r('foreignObject', { const renderEdgeText = state => ({ data, transform }) => r('foreignObject', {
transform, transform,
@ -361,7 +370,8 @@ class Graph extends React.Component {
} }
} }
onSelectEdge() { onSelectEdge(selected) {
this.setState({ selected });
} }
onCreateEdge() { onCreateEdge() {
@ -375,7 +385,12 @@ class Graph extends React.Component {
} }
} }
onDeleteEdge() { onDeleteEdge(selected) {
if (selected.type === 'sinkInput') {
this.props.killSinkInputByIndex(selected.index);
} else if (selected.type === 'sourceOutput') {
this.props.killSourceOutputByIndex(selected.index);
}
} }
render() { render() {
@ -488,7 +503,7 @@ class Graph extends React.Component {
showGraphControls: false, showGraphControls: false,
edgeArrowSize: 128, edgeArrowSize: 64,
backgroundFillId: '#background-pattern', backgroundFillId: '#background-pattern',
@ -499,8 +514,6 @@ class Graph extends React.Component {
renderEdge, renderEdge,
renderEdgeText: renderEdgeText(this.props), renderEdgeText: renderEdgeText(this.props),
afterRenderEdge,
})); }));
} }
} }

View File

@ -43,6 +43,8 @@ class GraphView extends React.Component {
onSwapEdge: this.onSwapEdge.bind(this), onSwapEdge: this.onSwapEdge.bind(this),
onNodeMove: this.onNodeMove.bind(this), onNodeMove: this.onNodeMove.bind(this),
onSelectEdge: this.onSelectEdge.bind(this),
renderNode: this.renderNode.bind(this), renderNode: this.renderNode.bind(this),
renderNodeText: this.renderNodeText.bind(this), renderNodeText: this.renderNodeText.bind(this),
@ -96,6 +98,11 @@ class GraphView extends React.Component {
} }
} }
onSelectEdge(edge) {
const originalEdge = satelliteEdgeToOriginalEdge.get(edge);
this.props.onSelectEdge(originalEdge);
}
renderNode(nodeRef, dgo, key, selected, hovered) { renderNode(nodeRef, dgo, key, selected, hovered) {
if (dgo.type !== 'satellite') { if (dgo.type !== 'satellite') {
return this.props.renderNode(nodeRef, dgo, key, selected, hovered); return this.props.renderNode(nodeRef, dgo, key, selected, hovered);
@ -127,6 +134,8 @@ class GraphView extends React.Component {
return satelliteNodes.concat(node); return satelliteNodes.concat(node);
}, this.props.nodes)); }, this.props.nodes));
let { selected } = this.props;
const edges = flatten(values(mapObjIndexed((edges, target) => mapIndexed((edge, i) => { const edges = flatten(values(mapObjIndexed((edges, target) => mapIndexed((edge, i) => {
const satelliteEdge = { const satelliteEdge = {
id: edge.id, id: edge.id,
@ -136,6 +145,11 @@ class GraphView extends React.Component {
index: edge.index, index: edge.index,
type: edge.type, type: edge.type,
}; };
if (edge === selected) {
selected = satelliteEdge;
}
satelliteEdgeToOriginalEdge.set(satelliteEdge, edge); satelliteEdgeToOriginalEdge.set(satelliteEdge, edge);
return satelliteEdge; return satelliteEdge;
}, edges), edgesByTargetNodeKey))); }, edges), edgesByTargetNodeKey)));
@ -143,6 +157,8 @@ class GraphView extends React.Component {
return r(GraphViewBase, { return r(GraphViewBase, {
...this.props, ...this.props,
selected,
ref: this.graph, ref: this.graph,
nodes, nodes,
@ -151,10 +167,12 @@ class GraphView extends React.Component {
onSwapEdge: this.onSwapEdge, onSwapEdge: this.onSwapEdge,
onNodeMove: this.onNodeMove, onNodeMove: this.onNodeMove,
onSelectEdge: this.onSelectEdge,
renderNode: this.renderNode, renderNode: this.renderNode,
renderNodeText: this.renderNodeText, renderNodeText: this.renderNodeText,
afterRenderEdge: this.afterRenderEdge, afterRenderEdge: this.props.afterRenderEdge && this.afterRenderEdge,
}); });
} }
} }

View File

@ -63,15 +63,27 @@ button:active {
color: var(--themeSelectedFgColor); color: var(--themeSelectedFgColor);
} }
.view-wrapper .graph .edge.selected {
stroke: var(--themeSelectedBgColor);
}
#my-source-arrow-selected > .arrow, #my-sink-arrow-selected > .arrow {
fill: var(--themeSelectedBgColor);
}
.view-wrapper .sourceOutput .edge { .view-wrapper .sourceOutput .edge {
/* marker-end: none; */
/* marker-start: url(#start-arrow); */
marker-end: url(#my-source-arrow); marker-end: url(#my-source-arrow);
} }
.view-wrapper .sourceOutput .edge.selected {
marker-end: url(#my-source-arrow-selected);
}
.view-wrapper .sinkInput .edge { .view-wrapper .sinkInput .edge {
marker-end: url(#my-sink-arrow); marker-end: url(#my-sink-arrow);
} }
.view-wrapper .sinkInput .edge.selected {
marker-end: url(#my-sink-arrow-selected);
}
#edge-custom-container .edge { #edge-custom-container .edge {
marker-end: none; marker-end: none;

View File

@ -109,10 +109,21 @@ module.exports = store => {
pa.moveSourceOutput(sourceOutputIndex, destSourceIndex, rethrow); pa.moveSourceOutput(sourceOutputIndex, destSourceIndex, rethrow);
return state; return state;
}, },
[pulseActions.killClientByIndex]: (state, { payload: { clientIndex } }) => { [pulseActions.killClientByIndex]: (state, { payload: { clientIndex } }) => {
pa.killClientByIndex(clientIndex, rethrow); pa.killClientByIndex(clientIndex, rethrow);
return state; return state;
}, },
[pulseActions.killSinkInputByIndex]: (state, { payload: { sinkInputIndex } }) => {
pa.killSinkInputByIndex(sinkInputIndex, rethrow);
return state;
},
[pulseActions.killSourceOutputByIndex]: (state, { payload: { sourceOutputIndex } }) => {
pa.killSourceOutputByIndex(sourceOutputIndex, rethrow);
return state;
},
[pulseActions.unloadModuleByIndex]: (state, { payload: { moduleIndex } }) => { [pulseActions.unloadModuleByIndex]: (state, { payload: { moduleIndex } }) => {
pa.unloadModuleByIndex(moduleIndex, rethrow); pa.unloadModuleByIndex(moduleIndex, rethrow);
return state; return state;