chart = {
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));
const simulation = d3
.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide(d => d.degree + 45));
const svg = d3
.create("svg")
.attr("height", height)
.attr("width", width)
var groups = [
{group:"Finance", color:1},
{group:"Information Technology", color:2},
{group:"Business Administration", color:3},
{group:"Manufacturing", color:4}
];
const link = svg
.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.8)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => Math.sqrt(d.value));
const node = svg
.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("circle") // select all circle objects
.data(nodes) // use the nodes entries in the data to draw the circles
.join("circle") // adjust the nodes when something moves
.attr("r", d => d.degree + 2) // draw each node as a circle with the radius of its degree value plus 2px
.attr("fill", color) // use the color function defined below to assign a color to each modularity class
.on("mouseover", tooltip_in) // when the mouse hovers a node, call the tooltip_in function to create the tooltip
.on("mouseout", tooltip_out) // when the mouse stops hovering a node, call the tooltip_out function to get rid of the tooltip
.on("click", tooltip_full)
.call(drag(simulation)); // use the drag function defined below to allow us to click and drag nodes. This can be commented out if you don't want to use the drag function below
const textElems = svg // add text labels to the nodes on the svg
.append('g')
.selectAll('text') // select all text elements
.data(nodes) // use the nodes information to get the text
.join('text') // adjust the labels when something moves
.text(d => d.id) // use the id attribute of the nodes to write the labels
.attr('font-size', 12) // give each label the css font-size attribute of 12 pixels
.call(drag(simulation)); // use the drag function defined below to move the labels when nodes are dragged. This can be commented out if you don't want to use the drag function below
// this is a standard simulation function that is the same across basically all force directed network visualizations in d3. It keeps the sources and targets of each interacting node pair linked even when the graph is moving around because of collisions or dragging. I honestly just copy/paste the same simulation function across all my network graphs instead of rewriting it every time.
// every time the graph changes due to dragging or movement generated by the layout, update the links, nodes, and text
simulation.on("tick", () => {
link // adjust the position of every link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node.attr("cx", d => d.x).attr("cy", d => d.y); // adjust the position of the nodes
textElems // adjust the text labels
.attr("x", d => d.x + 10) // draw the label 10px to the left of the center of the node
.attr("y", d => d.y) // but draw it at the same height as the center of the node
.attr("visibility", function(d) {
// add the css visibility attribute to all text labels
if (d.degree >= 10) {
// if the degree value of the node is greater than or equal to 10
return "visible"; // make its label visible using a css attribute
} else {
// if the degree of the node is smaller than 10
return "hidden"; // make its label hidden using a css attribute
}
});
});
// Define your color scale
const legcolor = d3.scaleOrdinal()
.domain(["Finance", "Information Technology", "Business Administration", "Manufacturing"])
.range(d3.schemeCategory10);
// Append a group element to the SVG to hold the legend items, positioned as desired
const legend = svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(20, 800)"); // Replace 'x, y' with the desired starting position of the legend
// Set up spacing and size for the legend items
const legendItemWidth = 200; // Width of each legend item, adjust as needed
const legendSpacing = 30; // Space between each legend item
// Create legend items
legcolor.domain().forEach((d, i) => {
const legendItem = legend.append("g")
.attr("class", "legend-item")
.attr("transform", `translate(${i * (legendItemWidth + legendSpacing)}, 0)`);
// Append rectangle for color
legendItem.append("rect")
.attr("width", 18) // Width of the color box
.attr("height", 18) // Height of the color box
.attr("fill", legcolor(d));
// Append text label
legendItem.append("text")
.attr("x", 24) // Position text right of the color box
.attr("y", 14) // Align text vertically
.text(d);
});
return svg.node(); // draw all the crap above
}