JSFiddle - React, Tailwind, and code Playground
by Rajesh Danabal
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Network Graph with Clustering</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
</head>
<body>
<canvas id="networkCanvas"></canvas>
</body>
</html>
CSS
body { margin: 0; overflow: hidden; }
canvas { display: block; }
JavaScript
document.addEventListener("DOMContentLoaded", function () {
const canvas = document.getElementById("networkCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const numNodes = 100;
const numClusters = 5;
const clusterCenters = [];
const hullOffset = 20;
// Generate cluster centers
for (let i = 0; i < numClusters; i++) {
clusterCenters.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height
});
}
// Create nodes with clusters
const nodes = [];
for (let i = 0; i < numNodes; i++) {
const cluster = i % numClusters;
nodes.push({
id: i,
cluster,
x: clusterCenters[cluster].x + Math.random() * 50 - 25,
y: clusterCenters[cluster].y + Math.random() * 50 - 25
});
}
// Create links between same-cluster nodes
const links = [];
nodes.forEach((node, i) => {
for (let j = 0; j < 3; j++) {
const target = Math.floor(Math.random() * numNodes);
if (i !== target && nodes[target].cluster === node.cluster) {
links.push({ source: node, target: nodes[target] });
}
}
});
// D3 force simulation
const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(50))
.force("charge", d3.forceManyBody().strength(-10))
.force("collision", d3.forceCollide(15))
.force("x", d3.forceX(d => clusterCenters[d.cluster].x).strength(0.1))
.force("y", d3.forceY(d => clusterCenters[d.cluster].y).strength(0.1))
.on("tick", draw);
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Group nodes by cluster
const clusters = {};
nodes.forEach(node => {
if (!clusters[node.cluster]) {
...