Skip to content

Commit 9ba5fa9

Browse files
committed
feat: allow edge selection, show placeholder when element has no data
1 parent 99730df commit 9ba5fa9

File tree

6 files changed

+53
-42
lines changed

6 files changed

+53
-42
lines changed

src/charts/CytoViz/CytoViz.js

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import cytoscape from 'cytoscape';
1515
import BubbleSets from 'cytoscape-bubblesets';
1616
import dagre from 'cytoscape-dagre';
1717
import useStyles from './style';
18-
import { NodeData, TabPanel } from './components';
18+
import { ElementData, TabPanel } from './components';
1919

2020
cytoscape.use(BubbleSets);
2121
cytoscape.use(dagre);
@@ -24,20 +24,28 @@ const DEFAULT_LAYOUTS = ['dagre'];
2424

2525
export const CytoViz = (props) => {
2626
const classes = useStyles();
27-
const { cytoscapeStylesheet, defaultSettings, elements, extraLayouts, labels, loading, getNodeDetails, bubblesets } =
28-
props;
27+
const {
28+
cytoscapeStylesheet,
29+
defaultSettings,
30+
elements,
31+
extraLayouts,
32+
labels,
33+
loading,
34+
getElementDetails,
35+
bubblesets,
36+
} = props;
2937

30-
let getNodeDetailsCallback = getNodeDetails;
31-
if (!getNodeDetailsCallback) {
38+
let getElementDetailsCallback = getElementDetails;
39+
if (!getElementDetailsCallback) {
3240
// eslint-disable-next-line react/display-name
33-
getNodeDetailsCallback = (node) => <NodeData data={node.data()} labels={labels.nodeData} />;
34-
getNodeDetailsCallback.displayName = 'NodeData';
41+
getElementDetailsCallback = (element) => <ElementData data={element.data()} labels={labels.elementData} />;
42+
getElementDetailsCallback.displayName = 'ElementData';
3543
}
3644

3745
// Layout
3846
const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
3947
const [currentDrawerTab, setCurrentDrawerTab] = React.useState(0);
40-
const [currentNodeDetails, setCurrentNodeDetails] = React.useState(null);
48+
const [currentElementDetails, setCurrentElementDetails] = React.useState(null);
4149
const closeDrawer = () => {
4250
setIsDrawerOpen(false);
4351
};
@@ -78,30 +86,29 @@ export const CytoViz = (props) => {
7886

7987
const initCytoscape = (cytoscapeRef) => {
8088
cytoscapeRef.removeAllListeners();
81-
// Prevent multiple selection
82-
cytoscapeRef.on('select', 'node, edge', (e) => cytoscapeRef.elements().not(e.target).unselect());
83-
// Init node selection behavior
84-
cytoscapeRef.on('select', 'node', function (e) {
85-
const selectedNode = e.target;
86-
setCurrentNodeDetails(getNodeDetailsCallback(selectedNode));
89+
// Prevent multiple selection & init elements selection behavior
90+
cytoscapeRef.on('select', 'node, edge', function (e) {
91+
cytoscapeRef.elements().not(e.target).unselect();
92+
const selectedElement = e.target;
93+
setCurrentElementDetails(getElementDetailsCallback(selectedElement));
8794
});
88-
cytoscapeRef.on('unselect', 'node', function (e) {
89-
setCurrentNodeDetails(null);
95+
cytoscapeRef.on('unselect', 'node, edge', function (e) {
96+
setCurrentElementDetails(null);
9097
});
9198
// Add handling of double click events
92-
cytoscapeRef.on('dbltap', 'node', function (e) {
93-
const selectedNode = e.target;
99+
cytoscapeRef.on('dbltap', 'node, edge', function (e) {
100+
const selectedElement = e.target;
94101
setCurrentDrawerTab(0);
95102
setIsDrawerOpen(true);
96-
setCurrentNodeDetails(getNodeDetailsCallback(selectedNode));
103+
setCurrentElementDetails(getElementDetailsCallback(selectedElement));
97104
});
98105

99106
// Init bubblesets
100107
const bb = cytoscapeRef.bubbleSets();
101108
for (const groupName in bubblesets) {
102-
const groupNodes = cytoscapeRef.nodes(`.${groupName}`);
109+
const nodesGroup = cytoscapeRef.nodes(`.${groupName}`);
103110
const groupColor = bubblesets[groupName];
104-
bb.addPath(groupNodes, undefined, null, {
111+
bb.addPath(nodesGroup, undefined, null, {
105112
virtualEdges: true,
106113
style: {
107114
fill: groupColor,
@@ -173,7 +180,7 @@ export const CytoViz = (props) => {
173180
</div>
174181
<div className={classes.drawerContent}>
175182
<TabPanel value={currentDrawerTab} index={0}>
176-
{currentNodeDetails || labels.noSelectedNode}
183+
{currentElementDetails || labels.noSelectedElement}
177184
</TabPanel>
178185
<TabPanel value={currentDrawerTab} index={1}>
179186
<div className={classes.settingsContainer}>
@@ -272,9 +279,9 @@ CytoViz.propTypes = {
272279
*/
273280
extraLayouts: PropTypes.object,
274281
/**
275-
* Function to generate a string or component elements details from the data of the currently selected node.
282+
* Function to generate a string or React component from the data of the currently selected element (node or edge).
276283
*/
277-
getNodeDetails: PropTypes.func,
284+
getElementDetails: PropTypes.func,
278285
/**
279286
* Map of bubblesets to display in cytoscape graph. Keys of this object are the group names (each group can be
280287
represented by a compound node in cytoscape elements to get a better layout), and values are the color of the group.
@@ -286,15 +293,15 @@ CytoViz.propTypes = {
286293
{
287294
elementDetails: 'string',
288295
loading: 'string',
289-
noSelectedNode: 'string',
296+
noSelectedElement: 'string',
290297
settings: {
291298
compactMode: 'string',
292299
layout: 'string',
293300
title: 'string',
294301
spacingFactor: 'string',
295302
zoomLimits: 'string',
296303
}
297-
nodeData: {
304+
elementData: {
298305
dictKey: 'string',
299306
dictValue: 'string',
300307
}
@@ -312,15 +319,15 @@ CytoViz.propTypes = {
312319
const DEFAULT_LABELS = {
313320
elementDetails: 'Details',
314321
loading: 'Loading...',
315-
noSelectedNode: 'Select a node to view its data',
322+
noSelectedElement: 'Select a node or edge to show its data',
316323
settings: {
317324
compactMode: 'Compact layout',
318325
layout: 'Layout',
319326
title: 'Settings',
320327
spacingFactor: 'Spacing factor',
321328
zoomLimits: 'Min & max zoom',
322329
},
323-
nodeData: {
330+
elementData: {
324331
dictKey: 'Key',
325332
dictValue: 'Value',
326333
},

src/charts/CytoViz/components/NodeData/NodeData.js renamed to src/charts/CytoViz/components/ElementData/ElementData.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,36 @@ const _generateAttributeDetails = (classes, labels, attributeName, attributeValu
4747
}
4848
};
4949

50-
const NodeData = (props) => {
50+
const ElementData = (props) => {
5151
const classes = useStyles();
5252
const { data, labels } = props;
5353
if (!data) {
54-
return 'No data to display for this node.';
54+
return labels.noData;
5555
}
5656

57-
return (
58-
<div className={classes.nodeDetailsContainer}>
59-
{Object.keys(data).map((key) => _generateAttributeDetails(classes, labels, key, data[key]))}
60-
</div>
61-
);
57+
let filteredElementAttributes = Object.keys(data)
58+
.map((key) => _generateAttributeDetails(classes, labels, key, data[key]))
59+
.filter((el) => el !== null);
60+
if (filteredElementAttributes.length === 0) {
61+
filteredElementAttributes = labels.noData;
62+
}
63+
64+
return <div className={classes.elementDetailsContainer}>{filteredElementAttributes}</div>;
6265
};
6366

64-
NodeData.propTypes = {
67+
ElementData.propTypes = {
6568
data: PropTypes.object,
6669
labels: PropTypes.object,
6770
};
6871

69-
NodeData.defaultProps = {
72+
ElementData.defaultProps = {
7073
data: PropTypes.object,
7174
labels: {
75+
attributes: {},
7276
dictKey: 'Key',
7377
dictValue: 'Value',
74-
attributes: {},
78+
noData: 'No data to display for this element.',
7579
},
7680
};
7781

78-
export default NodeData;
82+
export default ElementData;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './ElementData';

src/charts/CytoViz/components/NodeData/style.js renamed to src/charts/CytoViz/components/ElementData/style.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { makeStyles } from '@material-ui/core';
55

66
const useStyles = makeStyles((theme) => ({
7-
nodeDetailsContainer: {
7+
elementDetailsContainer: {
88
display: 'flex',
99
flexDirection: 'column',
1010
},

src/charts/CytoViz/components/NodeData/index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { default as NodeData } from './NodeData';
1+
export { default as ElementData } from './ElementData';
22
export { default as TabPanel } from './TabPanel';

0 commit comments

Comments
 (0)