I have the following diagram created using D3 and dagre-d3.
var width = 960, height = 700;
// REMOVE OLD SVG
d3.select("#wkfsvg").remove();
// ADD NEW SVG
var graphArea = d3.select("body").append("svg")
.attr({ width: width, height: height, "pointer-events": "all" })
.attr("id","wkfsvg");
var g = new dagreD3.graphlib.Graph().setGraph({});
d3.select("svg").
insert("g", "g");
var nodesJson = [
{
"nodes": "Initiate",
"status": "startend",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Find the Next Approver",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Check for Manager",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Set Status & ACL for IT Project Manager",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Set Status & ACL for IT Sign Off Approvers",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "IT Project Manager Approves",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Finance Approver",
"nodes": "Finance Approver",
"status": "dormant",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send Email for Completion",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send to Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send Email to Requestor",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Set ACL on Form for Requestor",
"nodes": "Set ACL on Form for Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set Completion ACL on Form",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Set Completion ACL on PO",
"nodes": "Set Completion ACL on PO",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set Completion ACL on Attachments",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set ACL on Attachment",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of PM Rejection",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of FA Rejection",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of PM",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of FA",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "End",
"status": "startend",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
}
];
// Automatically label each of the nodes
nodesJson.forEach(function(node) {
if(node.status == "future") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes+' <tspan dx="0" dy="-10">\uf007</tspan>', class: "future" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "future" });
}
} else if(node.status == "completed") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes+' <tspan dx="0" dy="-10">\uf007</tspan>', class: "completed" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "completed" });
}
} else if(node.status == "dormant") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes, class: "dormant" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "dormant" });
}
} else if(node.status == "startend") {
g.setNode(node.nodes, { label: node.nodes, class: "startend" });
} else {
g.setNode(node.nodes, { label: node.nodes });
}
});
var edgesJson = [
{
"type": "approve",
"source": "Find the Next Approver",
"target": "Check for Manager"
},
{
"type": "approve",
"source": "Check for Manager",
"target": "Set Status & ACL for IT Sign Off Approvers"
},
{
"type": "approve",
"source": "Check for Manager",
"target": "Set Status & ACL for IT Project Manager"
},
{
"type": "approve",
"source": "Set Status & ACL for IT Project Manager",
"target": "IT Project Manager Approves"
},
{
"type": "approve",
"source": "Set Status & ACL for IT Sign Off Approvers",
"target": "Finance Approver"
},
{
"type": "approve",
"source": "Set ACL on Form for Requestor",
"target": "Send to Requestor"
},
{
"type": "approve",
"source": "Set Completion ACL on Form",
"target": "Set Completion ACL on PO"
},
{
"type": "approve",
"source": "IT Project Manager Approves",
"target": "Send Email to Requestor"
},
{
"type": "approve",
"source": "Set Completion ACL on PO",
"target": "Set Completion ACL on Attachments"
},
{
"type": "approve",
"source": "Set Completion ACL on Attachments",
"target": "Send Email for Completion"
},
{
"type": "approve",
"source": "Initiate",
"target": "Set ACL on Attachment"
},
{
"type": "approve",
"source": "Set ACL on Attachment",
"target": "Find the Next Approver"
},
{
"type": "approve",
"source": "Update Comments of PM Rejection",
"target": "Set ACL on Form for Requestor"
},
{
"type": "reject",
"source": "IT Project Manager Approves",
"target": "Update Comments of PM Rejection"
},
{
"type": "approve",
"source": "Update Comments of FA Rejection",
"target": "Set ACL on Form for Requestor"
},
{
"type": "approve",
"source": "Send Email to Requestor",
"target": "Update Comments of PM"
},
{
"type": "approve",
"source": "Update Comments of PM",
"target": "Set Status & ACL for IT Sign Off Approvers"
},
{
"type": "approve",
"source": "Finance Approver",
"target": "Update Comments of FA"
},
{
"type": "approve",
"source": "Update Comments of FA",
"target": "Set Completion ACL on Form"
},
{
"type": "reject",
"source": "Finance Approver",
"target": "Update Comments of FA Rejection"
},
{
"type": "approve",
"source": "Send to Requestor",
"target": "Update Comments of Requestor"
},
{
"type": "approve",
"source": "Update Comments of Requestor",
"target": "Check for Manager"
},
{
"type": "approve",
"source": "Send Email for Completion",
"target": "End"
}
];
edgesJson.forEach(function(edge) {
if(edge.type == "approve") {
g.setEdge(edge.source, edge.target, { label: "" });
}
// Make the edge of rejected paths red and dashed
if(edge.type == "reject") {
g.setEdge(edge.source, edge.target, {
label: "", class: "rejectEdgePath"
});
}
});
var svg = d3.select("svg"),
inner = svg.select("g");
// Set the rankdir
//g.graph().rankdir = "LR";
g.graph().nodesep = 60;
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
var selectedNode = inner.selectAll("g.node");
selectedNode.on('click', function (d) {
console.log('clicked '+d);
});
.node rect {
stroke: #333;
fill: #fff;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
.rejectEdgePath path {
stroke: red;
fill: red;
stroke-width: 1.5px;
stroke-dasharray: 5, 5;
}
g.dormant > rect {
fill: #CC66FF;
}
g.completed > rect {
fill: #66FF99;
}
g.future > rect {
fill: #99CCFF;
}
g.acquired > rect {
fill: #EBBFFF;
}
g.paused > rect {
fill: #FF0000;
}
g.startend > rect {
fill: #CC6666;
}
foreignobject {
fill: black;
font-family: FontAwesome;
font-size: 15px;
text-anchor: middle;
// cursor: move;
}
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://cpettitt.github.io/project/dagre-d3/latest/dagre-d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
On click of a node I need to find details of the node that was clicked. So I have written the following code -
var selectedNode = inner.selectAll("g.node");
selectedNode.on('click', function (d) {
console.log('clicked '+d);
});
However, this just gives me the Node name. I would like to print other attributes from nodesJson as well, like 'status', 'creation_date', 'performer_name' etc.
Can someone please advice how to go about this?
Thank you
I am no expert on d3.js, so there might be a (much) better way to do this. The easiest way that comes to my mind would be to look through the array of your nodes until you find the one that was clicked and then display information from that.
function getNodeInfo(name) {
for (var i=0;i<nodesJson.length;i++)
if (nodesJson[i].nodes==name) return nodesJson[i];
}
The most problem with that would be that if you have multiple nodes with the same name, it would only ever get details of the first one in the array. If that is not a problem, then you could just do it like this:
var width = 960, height = 700;
// REMOVE OLD SVG
d3.select("#wkfsvg").remove();
// ADD NEW SVG
var graphArea = d3.select("body").append("svg")
.attr({ width: width, height: height, "pointer-events": "all" })
.attr("id","wkfsvg");
var g = new dagreD3.graphlib.Graph().setGraph({});
d3.select("svg").
insert("g", "g");
var nodesJson = [
{
"nodes": "Initiate",
"status": "startend",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Find the Next Approver",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Check for Manager",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Set Status & ACL for IT Project Manager",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Automatic"
},
{
"nodes": "Set Status & ACL for IT Sign Off Approvers",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "IT Project Manager Approves",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Finance Approver",
"nodes": "Finance Approver",
"status": "dormant",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send Email for Completion",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send to Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Send Email to Requestor",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Set ACL on Form for Requestor",
"nodes": "Set ACL on Form for Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set Completion ACL on Form",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"id": "Set Completion ACL on PO",
"nodes": "Set Completion ACL on PO",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set Completion ACL on Attachments",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Set ACL on Attachment",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of PM Rejection",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of FA Rejection",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of PM",
"status": "completed",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of FA",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "Update Comments of Requestor",
"status": "future",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
},
{
"nodes": "End",
"status": "startend",
"creation_date": "",
"performer_name": "",
"execution_type": "Manual"
}
];
function getNodeInfo(name) {
for (var i=0;i<nodesJson.length;i++)
if (nodesJson[i].nodes==name) return nodesJson[i];
}
// Automatically label each of the nodes
nodesJson.forEach(function(node) {
if(node.status == "future") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes+' <tspan dx="0" dy="-10">\uf007</tspan>', class: "future" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "future" });
}
} else if(node.status == "completed") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes+' <tspan dx="0" dy="-10">\uf007</tspan>', class: "completed" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "completed" });
}
} else if(node.status == "dormant") {
if(node.execution_type == "Manual") {
g.setNode(node.nodes, { labelType: "html", label: node.nodes, class: "dormant" });
} else {
g.setNode(node.nodes, { label: node.nodes, class: "dormant" });
}
} else if(node.status == "startend") {
g.setNode(node.nodes, { label: node.nodes, class: "startend" });
} else {
g.setNode(node.nodes, { label: node.nodes });
}
});
var edgesJson = [
{
"type": "approve",
"source": "Find the Next Approver",
"target": "Check for Manager"
},
{
"type": "approve",
"source": "Check for Manager",
"target": "Set Status & ACL for IT Sign Off Approvers"
},
{
"type": "approve",
"source": "Check for Manager",
"target": "Set Status & ACL for IT Project Manager"
},
{
"type": "approve",
"source": "Set Status & ACL for IT Project Manager",
"target": "IT Project Manager Approves"
},
{
"type": "approve",
"source": "Set Status & ACL for IT Sign Off Approvers",
"target": "Finance Approver"
},
{
"type": "approve",
"source": "Set ACL on Form for Requestor",
"target": "Send to Requestor"
},
{
"type": "approve",
"source": "Set Completion ACL on Form",
"target": "Set Completion ACL on PO"
},
{
"type": "approve",
"source": "IT Project Manager Approves",
"target": "Send Email to Requestor"
},
{
"type": "approve",
"source": "Set Completion ACL on PO",
"target": "Set Completion ACL on Attachments"
},
{
"type": "approve",
"source": "Set Completion ACL on Attachments",
"target": "Send Email for Completion"
},
{
"type": "approve",
"source": "Initiate",
"target": "Set ACL on Attachment"
},
{
"type": "approve",
"source": "Set ACL on Attachment",
"target": "Find the Next Approver"
},
{
"type": "approve",
"source": "Update Comments of PM Rejection",
"target": "Set ACL on Form for Requestor"
},
{
"type": "reject",
"source": "IT Project Manager Approves",
"target": "Update Comments of PM Rejection"
},
{
"type": "approve",
"source": "Update Comments of FA Rejection",
"target": "Set ACL on Form for Requestor"
},
{
"type": "approve",
"source": "Send Email to Requestor",
"target": "Update Comments of PM"
},
{
"type": "approve",
"source": "Update Comments of PM",
"target": "Set Status & ACL for IT Sign Off Approvers"
},
{
"type": "approve",
"source": "Finance Approver",
"target": "Update Comments of FA"
},
{
"type": "approve",
"source": "Update Comments of FA",
"target": "Set Completion ACL on Form"
},
{
"type": "reject",
"source": "Finance Approver",
"target": "Update Comments of FA Rejection"
},
{
"type": "approve",
"source": "Send to Requestor",
"target": "Update Comments of Requestor"
},
{
"type": "approve",
"source": "Update Comments of Requestor",
"target": "Check for Manager"
},
{
"type": "approve",
"source": "Send Email for Completion",
"target": "End"
}
];
edgesJson.forEach(function(edge) {
if(edge.type == "approve") {
g.setEdge(edge.source, edge.target, { label: "" });
}
// Make the edge of rejected paths red and dashed
if(edge.type == "reject") {
g.setEdge(edge.source, edge.target, {
label: "", class: "rejectEdgePath"
});
}
});
var svg = d3.select("svg"),
inner = svg.select("g");
// Set the rankdir
//g.graph().rankdir = "LR";
g.graph().nodesep = 60;
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
var selectedNode = inner.selectAll("g.node");
selectedNode.on('click', function (d) {
var nodeInfo = getNodeInfo(d);
console.log('clicked '+nodeInfo.nodes+' (status: '+nodeInfo.status+')');
});
.node rect {
stroke: #333;
fill: #fff;
}
.edgePath path {
stroke: #333;
fill: #333;
stroke-width: 1.5px;
}
.rejectEdgePath path {
stroke: red;
fill: red;
stroke-width: 1.5px;
stroke-dasharray: 5, 5;
}
g.dormant > rect {
fill: #CC66FF;
}
g.completed > rect {
fill: #66FF99;
}
g.future > rect {
fill: #99CCFF;
}
g.acquired > rect {
fill: #EBBFFF;
}
g.paused > rect {
fill: #FF0000;
}
g.startend > rect {
fill: #CC6666;
}
foreignobject {
fill: black;
font-family: FontAwesome;
font-size: 15px;
text-anchor: middle;
// cursor: move;
}
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://cpettitt.github.io/project/dagre-d3/latest/dagre-d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>