如何在d3中按照节点顺序从左到右创建水平海峡图

问题描述 投票:0回答:1

我想创建一个简单的 d3 水平海峡图。

它将包含节点、链接和每个链接的线。

如何在刻度中正确定义节点/边的坐标来实现它(无需手动设置坐标)。

我需要提前做一些计算吗?

我基本上希望第一个节点出现在链(图)的最左侧,最后一个节点(它是一条条纹线)出现在链(图)的最右侧。

如何确定图中节点的顺序以对齐它们。

更新

这是我到目前为止达到的小提琴:

这里我只是硬编码了我想要动态的 y 轴。

我的节点也没有顺序。

  const nodes = [
  { id: 'A' },
  { id: 'B' },
  { id: 'C' },
];

const edges = [
  { source: 'A', target: 'B' },
  { source: 'B', target: 'C' },
];

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

// Create arrowhead marker
svg.append('defs').append('marker')
    .attr('id', 'arrowhead')
    .attr('viewBox', '-0 -5 10 10')
    .attr('refX', 15)
    .attr('refY', 0)
    .attr('orient', 'auto')
    .attr('markerWidth', 10)
    .attr('markerHeight', 10)
    .attr('xoverflow', 'visible')
    .append('svg:path')
    .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
    .attr('fill', '#ccc')
    .style('stroke','none');

const simulation = d3.forceSimulation(nodes)
    .force("link", d3.forceLink(edges).id(d => d.id).distance(150))
    .force("charge", d3.forceManyBody().strength(-100))
    .force("y", d3.forceY(200))
    .force("x", d3.forceX(200));
    //.force("center", d3.forceCenter(400, 200));

const link = svg.selectAll(".link")
    .data(edges)
    .enter().append("line")
    .attr("class", "link")
    .attr('marker-end', 'url(#arrowhead)');

const node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", 20);

simulation.on("tick", () => {
    link.attr("x1", d => d.source.x)
        .attr("y1", d => 20)
        .attr("x2", d => d.target.x)
        .attr("y2", d => 20);

    node.attr("cx", d => d.x)
        .attr("cy", d => 20);
});

https://jsfiddle.net/g87s23L5/3/

理想情况下,我正在寻找一种使用 d3 内置力量的方法

d3.js
1个回答
0
投票

当您创建模拟时,我调整了力(“x”,...)以根据节点的索引来定位节点。这将确保节点按从左到右的顺序出现。

这是固定代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>D3 Horizontal Straight Graph</title>
  <script src="https://d3js.org/d3.v6.min.js"></script>
  <style>
    .node {
      fill: #3498db;
      stroke: #2980b9;
      stroke-width: 2px;
      cursor: pointer;
    }

    .link {
      fill: none;
      stroke: #ccc;
      stroke-width: 2px;
      cursor: pointer;
      marker-end: url(#arrowhead); /* Add arrowhead to links */

.line {
  stroke: black;
    stroke-width: 2px;
}
    }
  </style>
</head>
<body>
  <svg width="800" height="400"></svg>
  <script>
     const nodes = [
      { id: 'A' },
      { id: 'B' },
      { id: 'C' },
    ];

    const edges = [
      { source: 'A', target: 'B' },
      { source: 'B', target: 'C' },
    ];

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

    // Create arrowhead marker
    svg.append('defs').append('marker')
        .attr('id', 'arrowhead')
        .attr('viewBox', '-0 -5 10 10')
        .attr('refX', 15)
        .attr('refY', 0)
        .attr('orient', 'auto')
        .attr('markerWidth', 10)
        .attr('markerHeight', 10)
        .attr('xoverflow', 'visible')
        .append('svg:path')
        .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
        .attr('fill', '#ccc')
        .style('stroke','none');

    const simulation = d3.forceSimulation(nodes)
        .force("link", d3.forceLink(edges).id(d => d.id).distance(150))
        .force("charge", d3.forceManyBody().strength(-100))
        .force("y", d3.forceY(20))
        .force("x", d3.forceX((d, i) => i * 20)); // Position nodes based on index

    const link = svg.selectAll(".link")
        .data(edges)
        .enter().append("line")
        .attr("class", "link")
        .attr('marker-end', 'url(#arrowhead)');

    const node = svg.selectAll(".node")
        .data(nodes)
        .enter().append("circle")
        .attr("class", "node")
        .attr("r", 20);

    simulation.on("tick", () => {
        link.attr("x1", d => d.source.x)
            .attr("y1", d => 20)
            .attr("x2", d => d.target.x)
            .attr("y2", d => 20);

        node.attr("cx", d => d.x)
            .attr("cy", d => 200);
    });
  </script>
</body>
</html>

你可以在这里检查我的小提琴

© www.soinside.com 2019 - 2024. All rights reserved.