Select & delete edges
This commit is contained in:
parent
1c5f7e017e
commit
a507e1a6c3
|
@ -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 }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,
|
||||||
}, [
|
}, [
|
||||||
|
|
|
@ -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,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
index.css
16
index.css
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user