var graph = {
'nodes':[
{'id':'Material_Definition','group':0},
{'id':'Lot1','group':1},
{'id':'Lot2','group':1},
{'id':'Lot3','group':1},
{'id':'Lot4','group':1},
{'id':'Lot5','group':1},
{'id':'Lot6','group':1},
{'id':'Lot7','group':1},
{'id':'Lot8','group':1},
{'id':'Lot9','group':1},
{'id':'Lot10','group':1},
{'id':'Lot11','group':1},
{'id':'Lot12','group':1},
{'id':'Lot13','group':1},
{'id':'Lot14','group':1},
{'id':'Lot15','group':1},
{'id':'Lot16','group':1},
{'id':'Lot17','group':1},
{'id':'Lot18','group':1},
{'id':'Lot19','group':1},
{'id':'Lot20','group':1},
{'id':'SubLot1_Lot1','group':2},
{'id':'SubLot2_Lot1','group':2},
{'id':'SubLot3_Lot1','group':2},
{'id':'SubLot4_Lot1','group':2},
{'id':'SubLot5_Lot1','group':2},
{'id':'SubLot6_Lot1','group':2},
{'id':'SubLot1_Lot2','group':2},
{'id':'SubLot2_Lot2','group':2},
{'id':'SubLot3_Lot2','group':2},
{'id':'SubLot4_Lot2','group':2},
{'id':'SubLot5_Lot2','group':2},
{'id':'SubLot6_Lot2','group':2}],
'links':[
/* Material Definition linked to Lots */
{'source':'Material_Definition','target':'Lot1','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot2','value':8,'type':'A'},
{'source':'Material_Definition','target':'Lot3','value':10,'type':'A'},
{'source':'Material_Definition','target':'Lot3','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot4','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot5','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot6','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot7','value':2,'type':'A'},
{'source':'Material_Definition','target':'Lot8','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot9','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot10','value':8,'type':'A'},
{'source':'Material_Definition','target':'Lot11','value':10,'type':'A'},
{'source':'Material_Definition','target':'Lot12','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot13','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot14','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot15','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot16','value':2,'type':'A'},
{'source':'Material_Definition','target':'Lot17','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot18','value':1,'type':'A'},
{'source':'Material_Definition','target':'Lot19','value':2,'type':'A'},
{'source':'Material_Definition','target':'Lot20','value':1,'type':'A'},
/* Lot1 is linked to Sublots */
{'source':'Lot1','target':'SubLot1_Lot1','value':2,'type':'A'},
{'source':'Lot1','target':'SubLot2_Lot1','value':1,'type':'A'},
{'source':'Lot1','target':'SubLot3_Lot1','value':2,'type':'A'},
{'source':'Lot1','target':'SubLot4_Lot1','value':1,'type':'A'},
{'source':'Lot1','target':'SubLot5_Lot1','value':2,'type':'A'},
{'source':'Lot1','target':'SubLot6_Lot1','value':1,'type':'A'},
/* Lot2 is linked to Sublots */
{'source':'Lot2','target':'SubLot1_Lot2','value':2,'type':'A'},
{'source':'Lot2','target':'SubLot2_Lot2','value':1,'type':'A'},
{'source':'Lot2','target':'SubLot3_Lot2','value':2,'type':'A'},
{'source':'Lot2','target':'SubLot4_Lot2','value':1,'type':'A'},
{'source':'Lot2','target':'SubLot5_Lot2','value':2,'type':'A'},
{'source':'Lot2','target':'SubLot6_Lot2','value':1,'type':'A'},
/* Interconnected Lots */
{'source':'Lot10','target':'Lot18','value':2,'type':'A'},
{'source':'Lot10','target':'Lot19','value':1,'type':'A'},
{'source':'Lot10','target':'Lot20','value':2,'type':'A'},
{'source':'Lot7','target':'Lot8','value':1,'type':'A'},
{'source':'Lot7','target':'Lot9','value':2,'type':'A'},
{'source':'Lot7','target':'Lot10','value':1,'type':'A'},
{'source':'Lot12','target':'Lot4','value':2,'type':'A'},
{'source':'Lot12','target':'Lot3','value':1,'type':'A'},
{'source':'Lot12','target':'Lot2','value':2,'type':'A'},
{'source':'Lot16','target':'Lot1','value':1,'type':'A'},
{'source':'Lot16','target':'Lot9','value':2,'type':'A'},
{'source':'Lot16','target':'Lot12','value':1,'type':'A'}
]};
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory10);
var zoom_handler = d3.zoom().on("zoom", zoom_actions);
// zoom_handler(svg);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().distance(300).id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2));
var g = svg.append("g")
.attr("class", "everything");
svg.call(zoom_handler)
.call(zoom_handler.transform, d3.zoomIdentity.translate(200, 150).scale(0.2));
var linkElements = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.style("stroke-width",5.5)
.style("stroke",'black');
var nodeElements = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 40)
.attr('class', 'nodecircles')
.attr("fill", function(d) { return color(d.id); })
.attr("stroke", "#fff")
.attr('stroke-width', 21)
.attr("id", function(d) { return d.id })
.on('mouseover', selectNode)
.on('mouseout', releaseNode)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function releaseNode(d) {
nodeElements.transition().duration(500)
.attr("fill", function(d) { return color(d.id)
})
.attr('r', 40);
}
var textElements = g.append("g") // use g.append instead of svg.append to enable zoom
.attr("class", "texts")
.selectAll("text")
.data(graph.nodes)
.enter().append("text")
.text(function(node) {
return node.id
})
.attr("font-size", 55)
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("style", "font-weight:bold; text-stroke: 1px #fff;")
.attr("dx", 0)
.attr("dy", 20)
function ticked() {
linkElements
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
nodeElements
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.each(d => { d3.select('#t_' + d.id).attr('x', d.x + 10).attr('y', d.y + 3); });
textElements
.attr('x', function(d) {
return d.x
})
.attr('y', function(d) {
return d.y
});
}
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function zoom_actions() {
g.attr("transform", d3.event.transform)
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function selectNode(selectedNode) {
var neighbors = getNeighbors(selectedNode)
nodeElements.transition()
.duration(500)
.attr('fill', function(node) {
return getNodeColor(node, neighbors)
})
.attr('r', function(node) {
return getNodeRadius(node,neighbors);
})
}
function getNeighbors(node) {
return graph.links.reduce(function(neighbors, link) {
if (link.target.id === node.id) {
neighbors.push(link.source.id)
} else if (link.source.id === node.id) {
neighbors.push(link.target.id)
}
return neighbors
}, [node.id])
}
function getNodeColor(node, neighbors) {
// If is neighbor
if ( neighbors.indexOf(node.id) > -1) {
return 'rgba(251, 130, 30, 1)'
}
else {
return color(node.id);
}
}
function getNodeRadius(node, neighbors) {
// If is neighbor
if ( neighbors.indexOf(node.id) > -1) {
return '60'
}
else {
return '40'
}
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #000;
stroke-width: 1.5px;
}
text {
font-size: 10px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="shortcut icon" href="//#" />
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
</html>
<svg width="798" height="400"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>