2018-09-01 13:32:04 +00:00
|
|
|
import * as React from 'react';
|
|
|
|
import { connect } from 'react-redux';
|
2018-09-03 18:15:28 +00:00
|
|
|
import { Sigma, SigmaEnableWebGL, Filter, ForceAtlas2 } from 'react-sigma';
|
2018-09-01 13:32:04 +00:00
|
|
|
|
2018-09-01 17:24:05 +00:00
|
|
|
import { selectAndLoadInstance } from '../redux/actions';
|
2018-09-01 13:32:04 +00:00
|
|
|
|
|
|
|
const STYLE = {
|
|
|
|
bottom: "0",
|
|
|
|
left: "0",
|
|
|
|
position: "absolute",
|
|
|
|
right: "0",
|
|
|
|
top: "50px",
|
|
|
|
}
|
|
|
|
const SETTINGS = {
|
|
|
|
defaultEdgeColor: "#5C7080",
|
2018-09-01 17:54:13 +00:00
|
|
|
defaultLabelColor: "#F5F8FA",
|
2018-09-01 13:32:04 +00:00
|
|
|
defaultNodeColor: "#CED9E0",
|
|
|
|
drawEdges: true,
|
|
|
|
drawLabels: true,
|
|
|
|
edgeColor: "default",
|
2018-09-01 17:54:13 +00:00
|
|
|
labelColor: "default",
|
2018-09-03 18:15:28 +00:00
|
|
|
labelThreshold: 10,
|
|
|
|
maxEdgeSize: 1,
|
|
|
|
minEdgeSize: 0.3,
|
2018-09-01 13:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class GraphImpl extends React.Component {
|
|
|
|
|
|
|
|
render() {
|
2018-09-05 15:55:43 +00:00
|
|
|
let graph = this.props.graph;
|
|
|
|
if (!graph) {
|
|
|
|
// TODO: error state
|
2018-09-01 13:32:04 +00:00
|
|
|
return null;
|
|
|
|
}
|
2018-09-05 15:55:43 +00:00
|
|
|
// Check that all nodes have size & coordinates; otherwise the graph will look messed up
|
|
|
|
const lengthBeforeFilter = graph.nodes.length;
|
|
|
|
graph = {...graph, nodes: graph.nodes.filter(n => n.size && n.x && n.y)};
|
|
|
|
if (graph.nodes.length !== lengthBeforeFilter) {
|
|
|
|
// tslint:disable-next-line:no-console
|
|
|
|
console.error("Some nodes were missing details: " + this.props.graph.nodes.filter(n => !n.size || !n.x || !n.y).map(n => n.label));
|
|
|
|
}
|
2018-09-01 13:32:04 +00:00
|
|
|
return (
|
|
|
|
<Sigma
|
2018-09-05 15:55:43 +00:00
|
|
|
graph={graph}
|
2018-09-01 13:32:04 +00:00
|
|
|
renderer="webgl"
|
|
|
|
settings={SETTINGS}
|
|
|
|
style={STYLE}
|
2018-09-01 17:24:05 +00:00
|
|
|
onClickNode={(e) => this.props.selectAndLoadInstance(e.data.node.label)}
|
2018-12-06 16:46:44 +00:00
|
|
|
onClickStage={this.onClickStage}
|
2018-09-01 13:32:04 +00:00
|
|
|
>
|
|
|
|
<Filter neighborsOf={this.props.currentInstanceName} />
|
2018-09-03 18:15:28 +00:00
|
|
|
<ForceAtlas2 iterationsPerRender={1} timeout={6000}/>
|
2018-09-01 13:32:04 +00:00
|
|
|
</Sigma>
|
|
|
|
)
|
|
|
|
}
|
2018-12-06 16:46:44 +00:00
|
|
|
|
|
|
|
onClickStage = (e) => {
|
|
|
|
// Deselect the instance (unless this was a drag event)
|
|
|
|
if (!e.data.captor.isDragging) {
|
|
|
|
this.props.selectAndLoadInstance(null);
|
|
|
|
}
|
|
|
|
}
|
2018-09-01 13:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const mapStateToProps = (state) => ({
|
2018-09-01 17:24:05 +00:00
|
|
|
currentInstanceName: state.currentInstance.currentInstanceName,
|
2018-09-01 13:32:04 +00:00
|
|
|
graph: state.data.graph,
|
|
|
|
})
|
|
|
|
const mapDispatchToProps = (dispatch) => ({
|
2018-09-01 17:24:05 +00:00
|
|
|
selectAndLoadInstance: (instanceName) => dispatch(selectAndLoadInstance(instanceName)),
|
2018-09-01 13:32:04 +00:00
|
|
|
})
|
|
|
|
export const Graph = connect(mapStateToProps, mapDispatchToProps)(GraphImpl)
|