2

I have been able to draw a directed graph using dagre. However, now I would like to delete a node/edge on clicking it. I can use g.delEdge and g.delNode for deleting but how do I get to know that someone has clicked on the node? Please see my javascript dagre code below and advise me what I need to add to it.(I am reading the required nodes and edges from a json file, parsing the data and plotting them)

function MyFunc()
{
var buffer = JSON.parse(data);
var nodesarray = new Array();
for(var i=0;i<Object.keys(buffer[0].nodes).length;i++)
{
 nodesarray.push(buffer[0].nodes[i].name);
}

// Create the input graph
var g = new dagreD3.Digraph();

for(i=0;i<nodesarray.length;i++)
{
 //To give styles to nodes
 //g.addNode(0,  { label: 'Female', labelStyle: 'font-weight: bold;', style: 'stroke: #f66; stroke-width: 10px;', nodeclass: 'type-TOP' });
 g.addNode(nodesarray[i],{label:nodesarray[i]});
}

for(var i=0;i<Object.keys(buffer[0].edges).length;i++)
{ 
 var source = buffer[0].edges[i].source; 
 var destination = buffer[0].edges[i].destination;
 var weight = buffer[0].edges[i].weight;
 var strokewidth = weight*10;
 var mystyle='stroke:#f66; stroke-width:';
 mystyle = mystyle + strokewidth + 'px';

 //To give styles to edges 
 //g.addEdge(null, 5, 7, { style: 'stroke: #f66; stroke-width: 3px;',label: "Label for the edge" });
 g.addEdge(i,source,destination,{style:  mystyle,label:weight});
}

/* Deleting a node/edge example */
//g.delNode(nodesarray[0]);
//g.delNode(nodesarray[1]);
//g.delEdge(0);

// Create the renderer
var renderer = new dagreD3.Renderer();
var l = dagreD3.layout()
              .nodeSep(100)
              .rankSep(200)
              .edgeSep(80)
              .rankDir("LR");
renderer.layout(l);

// Override drawNodes to add nodeclass as a class to each node in the output
// graph.
var oldDrawNodes = renderer.drawNodes();
renderer.drawNodes(function(graph, root) {
  var svgNodes = oldDrawNodes(graph, root);
  svgNodes.each(function(u) { d3.select(this).classed(graph.node(u).nodeclass, true); });
  return svgNodes;
});

// Disable pan and zoom
renderer.zoom(false);
//renderer.edgeInterpolate('linear');

// Set up an SVG group so that we can translate the final graph.
var svg = d3.select('svg'),
    svgGroup = svg.append('g');

// Run the renderer. This is what draws the final graph.
var layout = renderer.run(g, d3.select('svg g'));

// Center the graph
var xCenterOffset = (svg.attr('width') - layout.graph().width) / 2;
svgGroup.attr('transform', 'translate(' + xCenterOffset + ', 80)');
svg.attr('height', layout.graph().height + 200);
}
gaitat
  • 12,449
  • 4
  • 52
  • 76
IAMTubby
  • 1,627
  • 4
  • 28
  • 40

2 Answers2

3

I see that you've overridden functionality to add class selector, you can add click event handler similarly, see the following example.

    // Override drawNodes to set up the click.
    var oldDrawNodes = renderer.drawNodes();
    renderer.drawNodes(function(g, svg) {
      var svgNodes = oldDrawNodes(g, svg);

      // on click event handler
      svgNodes.on('click', function(d) { console.log('Clicked on node - ' + d); });

      return svgNodes;
    });

for adding click event handler for edges, try something like below given code

    var oldDrawEdges = renderer.drawEdgePaths();
    renderer.drawEdgePaths(function(g, svg) {
        var edges = oldDrawEdges(g, svg);
        edges.on('click', function (edgeId) { alert('Clicked on - ' + edgeId);});
        return edges;
    });
iamrakesh
  • 219
  • 4
  • 16
  • Woohoo! It works. But I have a couple of questions. 1. Is .on a function in dagre or is it from svg? Where is the documentation for it? If it's from svg, can I use all svg functions in dagre? 2. I tried doing the same to make edges clickable by replacing renderer.drawNodes with renderer.drawEdge. But it doesn't work. How do I make the edge clickable? – IAMTubby Oct 01 '14 at 08:59
  • I think 'on' function is from SVG. I actually went through the D3 sources and tried it. You can try finding for 'defaultDrawNodes' in D3 sources, and see how node are being drawn. For edges you might have to try overriding 'drawEdgePaths', I my self didn't try it, but it should work. Try finding 'defaultDrawEdgePaths' in D3 sources, to see how edges are being drawn. – iamrakesh Oct 01 '14 at 09:44
  • I tried click event handlers for edges and it works, see my updated post. – iamrakesh Oct 01 '14 at 09:48
  • I've to correct myself, 'on' function is not an SVG function but from D3, you can find the API reference on D3 Wiki - https://github.com/mbostock/d3/wiki/Selections#on – iamrakesh Oct 01 '14 at 10:04
  • Works,thanks... But I'm a bit confused here, drawEdgePaths is a function from dagre but .on is from d3? Hmm...Would it be possible to explain the above code snippet in a line or two? I think I'm not able to understand how dagre,d3 and svg are co-existing. 2.Also, is it possible to edit the style of an already drawn node, on an event? ie,I have already drawn a node using g.addNode(nodesarray[i],{label:nodesarray[i]}); ,say I want to change the color of a node on click,do I have to delete the node and then redraw it as g.addNode(0, { nodeclass: 'some-class-in-css' }); OR can it just be edited? – IAMTubby Oct 02 '14 at 03:39
  • Really appreciate all the help, it is really helping understand things. – IAMTubby Oct 02 '14 at 03:40
1

This worked for me for handling node clicks:

svg.selectAll("g.node").on("click", function(id) {
  console.log("Clicked " + id);
});
Graham Wheeler
  • 2,734
  • 1
  • 19
  • 23