Search code examples
javascriptreactjsdagre-d3

Diagram is not rendering - Dagre-d3


I converted this Dagre-D3 demo to a React component.

The code I used is shown below:

import React from 'react';
import * as d3 from "d3";
import * as dagreD3 from 'dagre-d3';
import * as dagre from "dagre";

export default class KafkaFlow extends React.Component {
    constructor () {
        super();
    }

componentDidMount() {
    // Create the input graph
        let g = new dagreD3.graphlib.Graph().setGraph({});

        // Set an object for the graph label
        g.setGraph({});

        // Default to assigning a new object as a label for each new edge.
        g.setDefaultEdgeLabel(function () {
            return {};
        });

        // Add nodes to the graph. The first argument is the node id. The second is
        // metadata about the node. In this case we're going to add labels to each of
        // our nodes.
        g.setNode("kspacey", {label: "Kevin Spacey", width: 144, height: 100});
        g.setNode("swilliams", {label: "Saul Williams", width: 160, height: 100});
        g.setNode("bpitt", {label: "Brad Pitt", width: 108, height: 100});
        g.setNode("hford", {label: "Harrison Ford", width: 168, height: 100});
        g.setNode("lwilson", {label: "Luke Wilson", width: 144, height: 100});
        g.setNode("kbacon", {label: "Kevin Bacon", width: 121, height: 100});

        // Add edges to the graph.
        g.setEdge("kspacey", "swilliams");
        g.setEdge("swilliams", "kbacon");
        g.setEdge("bpitt", "kbacon");
        g.setEdge("hford", "lwilson");
        g.setEdge("lwilson", "kbacon");

        dagre.layout(g);

    // Create the renderer
    let render = new dagreD3.render();

    // Set up an SVG group so that we can translate the final graph.
     let svg=d3.select(ReactDOM.findDOMNode(this.refs.nodeTree));

    // Run the renderer. This is what draws the final graph.
    render(d3.select(ReactDOM.findDOMNode(this.refs.nodeTreeGroup)), g);

    svg.attr("height", g.graph().height + 40);
}

render() {
    return (
        <svg id="nodeTree" ref={(ref) => this.nodeTree=ref} width="960" height="600"><g ref={(r) =>this.nodeTreeGroup=r}/></svg>
    )
    };
}

When I execute this code snippet, the graph is not being generated. Also there is no error in the console either. I couldn't find out the reason. Any ideas what is wrong?


Solution

  • First of all, for this kind of specific question, it's usually easier for people to understand and help you if you create an environment for others to look by using codepen or jsfiddle.

    I think there are definitely errors on the console when I first try your code. Maybe you were using the newer version of chrome where it hides the console messages unless you click the expand button on the left. Here is the working code.

    class KafkaFlow extends React.Component {
      constructor() {
        super();
      }
    
      componentDidMount() {
        // Create the input graph
        let g = new dagreD3.graphlib.Graph().setGraph({});
        // Set an object for the graph label
        g.setGraph({});
    
        // Default to assigning a new object as a label for each new edge.
        g.setDefaultEdgeLabel(function () {
          return {};
        });
    
        // Add nodes to the graph. The first argument is the node id. The second is
        // metadata about the node. In this case we're going to add labels to each of
        // our nodes.
        g.setNode("kspacey", { label: "Kevin Spacey", width: 144, height: 100 });
        g.setNode("swilliams", { label: "Saul Williams", width: 160, height: 100 });
        g.setNode("bpitt", { label: "Brad Pitt", width: 108, height: 100 });
        g.setNode("hford", { label: "Harrison Ford", width: 168, height: 100 });
        g.setNode("lwilson", { label: "Luke Wilson", width: 144, height: 100 });
        g.setNode("kbacon", { label: "Kevin Bacon", width: 121, height: 100 });
    
        // Add edges to the graph.
        g.setEdge("kspacey", "swilliams");
        g.setEdge("swilliams", "kbacon");
        g.setEdge("bpitt", "kbacon");
        g.setEdge("hford", "lwilson");
        g.setEdge("lwilson", "kbacon");
    
        // don't know where is dagre coming from
        //dagre.layout(g);
    
        // Create the renderer
        let render = new dagreD3.render();
    
        // Set up an SVG group so that we can translate the final graph.
        let svg = d3.select(this.nodeTree);
    
        // Run the renderer. This is what draws the final graph.
        render(d3.select(this.nodeTreeGroup), g);
    
        svg.attr("height", g.graph().height + 40);
      }
    
      render() {
        return (
          <svg
            id="nodeTree"
            ref={(ref) => { this.nodeTree = ref; }}
            width="960"
            height="600"
          >
            <g ref={(r) => { this.nodeTreeGroup = r; }} />
          </svg>
        );
      }
    }
    

    Demo: https://codepen.io/anon/pen/vRWZmL?editors=0011

    The biggest problem is misusing ReactDOM.findDOMNode(this.refs.nodeTree). Since you were using a callback function to set property on the class. this.refs will not contain anything since we were not using the legacy api where string is used in the ref.

    See https://reactjs.org/docs/refs-and-the-dom.html for more detail about refs in react.