From a507e1a6c3a6279a1f47b8009376583630f78f6b Mon Sep 17 00:00:00 2001 From: futpib Date: Sun, 11 Nov 2018 16:08:51 +0300 Subject: [PATCH] Select & delete edges --- actions/pulse.js | 4 ++ components/graph/base.js | 2 +- components/graph/index.js | 73 ++++++++++++++++------------ components/graph/satellites-graph.js | 20 +++++++- index.css | 16 +++++- store/pulse-middleware.js | 11 +++++ 6 files changed, 92 insertions(+), 34 deletions(-) diff --git a/actions/pulse.js b/actions/pulse.js index bb16dbf..fe17b34 100644 --- a/actions/pulse.js +++ b/actions/pulse.js @@ -16,6 +16,10 @@ module.exports = createActionCreators({ MOVE_SOURCE_OUTPUT: (sourceOutputIndex, destSourceIndex) => ({ sourceOutputIndex, destSourceIndex }), 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 }), }, }); diff --git a/components/graph/base.js b/components/graph/base.js index 8b8c624..7745fa7 100644 --- a/components/graph/base.js +++ b/components/graph/base.js @@ -101,7 +101,7 @@ class Edge extends EdgeBase { }); return r.g({ - className: 'edge-container', + className: 'edge-container ' + (this.props.className || ''), 'data-source': data.source, 'data-target': data.target, }, [ diff --git a/components/graph/index.js b/components/graph/index.js index 0f635e9..47ec0f9 100644 --- a/components/graph/index.js +++ b/components/graph/index.js @@ -148,6 +148,19 @@ const Module = Client; const gridDotSize = 2; 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, [ r.pattern({ id: 'background-pattern', @@ -162,29 +175,26 @@ const renderDefs = () => r(React.Fragment, [ r: gridDotSize, })), - r('marker', { + r(Marker, { 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', - })), + }), - r('marker', { + r(Marker, { 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', - })), + }), + + // 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({ @@ -262,13 +272,12 @@ const renderNodeText = state => dgo => r('foreignObject', { state, }))); -const afterRenderEdge = (id, element, edge, edgeContainer) => { - if (edge.type) { - edgeContainer.classList.add(edge.type); - } -}; - -const renderEdge = edgeProps => r(Edge, edgeProps); +const renderEdge = props => r(Edge, { + classSet: { + [props.data.type]: true, + }, + ...props, +}); const renderEdgeText = state => ({ data, transform }) => r('foreignObject', { transform, @@ -361,7 +370,8 @@ class Graph extends React.Component { } } - onSelectEdge() { + onSelectEdge(selected) { + this.setState({ selected }); } 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() { @@ -488,7 +503,7 @@ class Graph extends React.Component { showGraphControls: false, - edgeArrowSize: 128, + edgeArrowSize: 64, backgroundFillId: '#background-pattern', @@ -499,8 +514,6 @@ class Graph extends React.Component { renderEdge, renderEdgeText: renderEdgeText(this.props), - - afterRenderEdge, })); } } diff --git a/components/graph/satellites-graph.js b/components/graph/satellites-graph.js index d845f78..9c6fbf4 100644 --- a/components/graph/satellites-graph.js +++ b/components/graph/satellites-graph.js @@ -43,6 +43,8 @@ class GraphView extends React.Component { onSwapEdge: this.onSwapEdge.bind(this), onNodeMove: this.onNodeMove.bind(this), + onSelectEdge: this.onSelectEdge.bind(this), + renderNode: this.renderNode.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) { if (dgo.type !== 'satellite') { return this.props.renderNode(nodeRef, dgo, key, selected, hovered); @@ -127,6 +134,8 @@ class GraphView extends React.Component { return satelliteNodes.concat(node); }, this.props.nodes)); + let { selected } = this.props; + const edges = flatten(values(mapObjIndexed((edges, target) => mapIndexed((edge, i) => { const satelliteEdge = { id: edge.id, @@ -136,6 +145,11 @@ class GraphView extends React.Component { index: edge.index, type: edge.type, }; + + if (edge === selected) { + selected = satelliteEdge; + } + satelliteEdgeToOriginalEdge.set(satelliteEdge, edge); return satelliteEdge; }, edges), edgesByTargetNodeKey))); @@ -143,6 +157,8 @@ class GraphView extends React.Component { return r(GraphViewBase, { ...this.props, + selected, + ref: this.graph, nodes, @@ -151,10 +167,12 @@ class GraphView extends React.Component { onSwapEdge: this.onSwapEdge, onNodeMove: this.onNodeMove, + onSelectEdge: this.onSelectEdge, + renderNode: this.renderNode, renderNodeText: this.renderNodeText, - afterRenderEdge: this.afterRenderEdge, + afterRenderEdge: this.props.afterRenderEdge && this.afterRenderEdge, }); } } diff --git a/index.css b/index.css index 6fb44f0..44de010 100644 --- a/index.css +++ b/index.css @@ -63,15 +63,27 @@ button:active { 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 { - /* marker-end: none; */ - /* marker-start: url(#start-arrow); */ marker-end: url(#my-source-arrow); } +.view-wrapper .sourceOutput .edge.selected { + marker-end: url(#my-source-arrow-selected); +} .view-wrapper .sinkInput .edge { marker-end: url(#my-sink-arrow); } +.view-wrapper .sinkInput .edge.selected { + marker-end: url(#my-sink-arrow-selected); +} #edge-custom-container .edge { marker-end: none; diff --git a/store/pulse-middleware.js b/store/pulse-middleware.js index 15b5fd9..cc0a586 100644 --- a/store/pulse-middleware.js +++ b/store/pulse-middleware.js @@ -109,10 +109,21 @@ module.exports = store => { pa.moveSourceOutput(sourceOutputIndex, destSourceIndex, rethrow); return state; }, + [pulseActions.killClientByIndex]: (state, { payload: { clientIndex } }) => { pa.killClientByIndex(clientIndex, rethrow); 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 } }) => { pa.unloadModuleByIndex(moduleIndex, rethrow); return state;