使用 react+ts 和 d3 创建新的力图

Posted

技术标签:

【中文标题】使用 react+ts 和 d3 创建新的力图【英文标题】:creating new force graph with react+ts and d3 【发布时间】:2022-01-10 12:22:55 【问题描述】:

我正在尝试使用 React + TS 和 D3 创建一个简单的力图。

主要问题 用线连接我的节点

这是我的代码:

import React from "react";
import  forceSimulation, forceManyBody, forceLink, forceCenter  from 'd3-force'
import d3 , SimulationNodeDatum  from "d3";
import  Box  from "@mui/system";


type Node = 
  id: string;
  class: string;
  x?: string;
  y?: string;


type Link = 
  source: string;
  target: string;
  connectionType: string;


数据(在同一个文件中):

const  links, nodes  = 
  nodes: [
    id: "honda",
    class: "cars",
  , 
    id: "civic",
    class: "cars",
  ,
    id: "toyota",
    class: "cars",
  ,
    id: "corola",
    class: "cars",
  ],
  links: [
    source: 'civic',
    target: 'honda',
    connectionType: 'm2o'
  ,
    source: 'corola',
    target: 'toyota',
    connectionType: 'm2o'
  ]

...这是组件:

function Rd4Component (): JSX.Element 
  const simulation = forceSimulation(nodes as SimulationNodeDatum[]);
    simulation
      .force('charge', forceManyBody().strength(-100))
    .force('link',
      forceLink(links)
        .id((d) => (d as Node).id)
        .distance(75)
    )
      .force("center", forceCenter(300, 300));

  const svg = d3.select('#Target');

  const node = svg
      .selectAll("circle")
      .data(nodes)
      .enter()
      .append("circle")
      .attr("r", 15)
      .attr("stroke", "green")
      .attr("stroke-width", 0.5)
      .style("fill", "red");

  const link = svg
      .selectAll('path.link')
      .data(links)
      .enter()
      .append("path")
      .attr("stroke", "black")
      .style("fill", "none");


  function ticked() 
     link
       .attr("x1", function (d: any) 
         return d.source.x;
       )
       .attr("y1", function (d: any) 
         return d.source.y;
       )
       .attr("x2", function (d: any) 
         return d.target.x;
       )
       .attr("y2", function (d: any) 
         return d.target.y;
       );

    node
      .attr("cx", function (d: any) 
        return d.x;
      )
      .attr("cy", function (d: any) 
        return d.y;
      );

    // label
    //   .attr("x", function (d: any) 
    //     return d.x + 5;
    //   )
    //   .attr("y", function (d: any) 
    //     return d.y + 5;
    //   );
  

  simulation.nodes(nodes as SimulationNodeDatum[])
    .on("tick", ticked)


  return <Box sx=overflowY: "scroll">
    <svg height=600 width=600 id="Target" />
  </Box>


export default Rd4Component;

结果如下:

【问题讨论】:

【参考方案1】:

path 替换为line(或为&lt;path&gt; 指定d 属性而不是x1x2y1y1 用于&lt;line&gt;

const  links, nodes  = 
  nodes: [
    id: "honda",
    class: "cars",
  , 
    id: "civic",
    class: "cars",
  ,
    id: "toyota",
    class: "cars",
  ,
    id: "corola",
    class: "cars",
  ],
  links: [
    source: 'civic',
    target: 'honda',
    connectionType: 'm2o'
  ,
    source: 'corola',
    target: 'toyota',
    connectionType: 'm2o'
  ]


const simulation = d3.forceSimulation(nodes);
    simulation
      .force('charge', d3.forceManyBody().strength(-50))
    .force('link',
      d3.forceLink(links)
        .id((d) => d.id)
        .distance(50)
    )
      .force("center", d3.forceCenter(100, 100));

  const svg = d3.select('svg');

  const link = svg
      .selectAll('line.link')
      .data(links)
      .enter()
      .append("line")
      .attr("stroke", "black")
      .style("fill", "none");
  
  const node = svg
      .selectAll("circle")
      .data(nodes)
      .enter()
      .append("circle")
      .attr("r", 15)
      .attr("stroke", "green")
      .attr("stroke-width", 0.5)
      .style("fill", "red");



  function ticked() 
     link
       .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;
       );

    node
      .attr("cx", function (d) 
        return d.x;
      )
      .attr("cy", function (d) 
        return d.y;
      );

    // label
    //   .attr("x", function (d: any) 
    //     return d.x + 5;
    //   )
    //   .attr("y", function (d: any) 
    //     return d.y + 5;
    //   );
  

  simulation.nodes(nodes)
    .on("tick", ticked)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg  >
  
</svg>

【讨论】:

以上是关于使用 react+ts 和 d3 创建新的力图的主要内容,如果未能解决你的问题,请参考以下文章

如何使流星中的d3方向力图反应?

使用 D3.js 的层次力图

在 D3js 力图中添加和删除节点

D3中力图节点内的圆形包装?

d3js,当鼠标拖动空白区域时,力图持续跳跃

如何检查没有链接的节点的d3 js力图并删除它们?