SOURCE

console 命令行工具 X clear

                    
>
console
    const width = 600,height=400;

    const deviceNum = 2000;
    const nodes = new Array(deviceNum).fill("").map((d,i)=>{
        return {
            id:i+1,
            name:`device${i+1}`,
        }
    });
    //hub0和hub123456 连接
    const links = [{source:1,target:2},{source:1,target:3},{source:1,target:6},{source:1,target:11},
    {source:1,target:4},{source:7,target:8},
    {source:8,target:5},{source:7,target:5},
    {source:9,target:10}
    ]
    const connectedNodeIds = new Set();
    links.forEach(link => {
    connectedNodeIds.add(link.source.id || link.source);
    connectedNodeIds.add(link.target.id || link.target);
    });
    const linkNodes =[],standaloneNodes = [];
    nodes.forEach(node => {
    if(connectedNodeIds.has(node.id)){
        linkNodes.push(node);
    }else{
    //   node.isIsolated = !;
        standaloneNodes.push(node)
    }
    });
     const zoom = d3.zoom().scaleExtent([0.1,10]).on('zoom',zoomHandler);
    const g = d3.select(svg)
        .attr("width", width)
        .attr("height", height)
        .attr("viewBox", [0, 0, width, height]) 
        .attr("style", "max-width: 100%; height: auto; font: 12px sans-serif;")
         .call(zoom);
    let container_wrap = g.append('g');
    function zoomHandler(){
        let {x,y,k} = d3.event.transform;
        container_wrap.attr("transform","translate("+x+","+ y+ ")scale("+ k +")")
    }
   

  




    function linkArc(d) {
    const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y);
    //   return `
    //     M${d.source.x},${d.source.y}
    //     A${r},${r} 0 0,1 ${d.target.x},${d.target.y}
    //   `;
    return `
        M${d.source.x},${d.source.y}
        L${d.target.x},${d.target.y}
    `;
    }
    function attractTo(x, y) {
    return () => {
        for (const node of nodes) {
        if (node.isIsolated) {
            node.vx += (x - node.x) * 0.001;
            node.vy += (y - node.y) *  0.001;
        }
        }
    };
    }

    const simulation = d3.forceSimulation(linkNodes)
        .force("link", d3.forceLink(links).id(d => d.id).distance(80))
        .force("center", d3.forceCenter(width/2, height/2)) 
        .force("charge", d3.forceManyBody().strength(-400))
        .force("x", d3.forceX())
        .force("y", d3.forceY());
        

    simulation.stop();
    for (let i = 0; i < 300; ++i) simulation.tick();

    const link = container_wrap.append("g")
        .attr("fill", "none")
        .attr("stroke-width", 1.5)
        .selectAll("path")
        .data(links)
        .join("path")
        .attr("stroke", "#09c")
        .attr("d", linkArc);

    const node = container_wrap.append("g")
        .attr("fill", "currentColor")
        .attr("stroke-linecap", "round")
        .attr("stroke-linejoin", "round")
        .selectAll("g")
        .data(linkNodes)
        .join("g")
        .attr("transform", d => `translate(${d.x},${d.y})`);

        node.append("circle")
        .attr("stroke", "white")
        .attr("stroke-width", 1.5)
        .attr("r", 4);

    node.append("text")
        .attr("x", 8)
        .attr("y", "0.31em")
        .text(d => d.id)
        .clone(true).lower()
        .attr("fill", "none")
        .attr("stroke", "white")
        .attr("stroke-width", 3);

    const col = 4,nodeH = 30,nodeW= 30;
    const standaloneNode = container_wrap.append("g")
        .attr("fill", "currentColor")
        .attr("stroke-linecap", "round")
        .attr("stroke-linejoin", "round")
        .attr("transform","translate(10,10)")
        .selectAll("g")
        .data(standaloneNodes)
        .join("g")
        .attr("transform", (d,i) => `translate(${(i%col)*30},${height - ((Math.ceil(standaloneNodes.length/col) - Math.floor(i/col))*30)})`);

        standaloneNode.append("circle")
        .attr("stroke", "white")
        .attr("stroke-width", 1.5)
        .attr("r", 4);

        standaloneNode.append("text")
        .attr("x", 8)
        .attr("y", "0.31em")
        .text(d => d.id)
        .clone(true).lower()
        .attr("fill", "none")
        .attr("stroke", "white")
        .attr("stroke-width", 3);

    

  


<svg id="svg" ></svg>
svg{
    background-color: rgba(0,0,0,0.2);
}

本项目引用的自定义外部资源