尝试在 d3 力图中的节点和边上渲染标签,但它们虽然在 dom 树下可用但不可见

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

为了在节点上渲染标签,我尝试了如下各种方法:

    var labels = node.append("text")
        .text(function (d) { return d.label; })
        .attr('x', 6)
        .attr('y', 3);

    node.append("title")
        .text(function (d) { return d.label; });

或者类似这样的:

 node.append("text")
        // .attr("text-anchor", "middle")
        // .attr("alignment-baseline", "middle")
        .text(d => d.label)
        .attr('x', 6)
        .attr('y', 3);

这是我的完整代码:

<svg id="chart">
</svg>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
    let drag = simulation => {

        function dragstarted(event) {
            if (!event.active) simulation.alphaTarget(0.3).restart()
            event.subject.fx = event.subject.x
            event.subject.fy = event.subject.y
        }

        function dragged(event) {
            event.subject.fx = event.x
            event.subject.fy = event.y
        }

        function dragended(event) {
            if (!event.active) simulation.alphaTarget(0)
            event.subject.fx = null;
            event.subject.fy = null;
        }

        return d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended)
    }


    let height = 600
    let width = 600

    let data = {
        "nodes": [{
            "id": "Myriel",
            "label": "Myriel name"
        },
        {
            "id": "Napoleon",
            "label": "Napoleon name"
        }
        ],
        "links": [{
            "source": "Myriel",
            "target": "Napoleon",
            "label": "hit me baby one more time"
        },
        {
            "source": "Napoleon",
            "target": "Myriel",
            "label": "meaw"
        }
        ]
    }

    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))

    const svg = d3.select("#chart")
        .attr("viewBox", [0, 0, width, height])

    // Define the arrowhead marker
    svg.append("defs").selectAll("marker")
        .data(["end"])      // Different link/path types can be defined here
        .enter().append("svg:marker")    // This section adds in the arrows
        .attr("id", String)
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 15)
        .attr("refY", -1.5)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("svg:path")
        .attr("d", "M0,-5L10,0L0,5");


    // Add the links with arrowheads
    const link = svg.append("g")
        .attr("stroke", "#999")
        .attr("stroke-opacity", 0.6)
        .selectAll("line")
        .data(links)
        .join("line")
        .attr("stroke-width", 1)
        .attr("marker-end", "url(#end)");  // Add the marker-end attribute to link

    link.append("text")
        .attr("text-anchor", "middle")
        .attr("alignment-baseline", "middle")
        .text(d => d.label);

    const node = svg.append("g")
        .attr("stroke", "#fff")
        .attr("stroke-width", 1.5)
        .selectAll("circle")
        .data(nodes)
        .join("circle")
        .attr("r", 5)
        .attr("fill", () => "#" + Math.floor(Math.random() * 16777215).toString(16))
        .call(drag(simulation))

    // node.append("text")
    //     // .attr("text-anchor", "middle")
    //     // .attr("alignment-baseline", "middle")
    //     .text(d => d.label)
    //     .attr('x', 6)
    //     .attr('y', 3);

    var labels = node.append("text")
        .text(function (d) { return d.label; })
        .attr('x', 6)
        .attr('y', 3);

    node.append("title")
        .text(function (d) { return d.label; });


    simulation.on("tick", () => {
        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)
    })

</script>

我想创建一个像这样的图表:

我该怎么做?

现在,它看起来像这样:

虽然在dom下可以使用,但是不可见。我已经尝试设置他们的位置很长一段时间了。

javascript d3.js
1个回答
0
投票

正如评论中提到的,将

text
元素作为
circle
的子元素是无效的 SVG。相反,将节点更改为
g
,然后将圆圈和文本放在其中。

这是对您的代码的快速更改:

<!DOCTYPE html>

<html>
  <head>
    <link rel="stylesheet" href="lib/style.css" />
    <script src="lib/script.js"></script>
  </head>

  <body>
    <svg id="chart"></svg>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script>
      let drag = (simulation) => {
        function dragstarted(event) {
          if (!event.active) simulation.alphaTarget(0.3).restart();
          event.subject.fx = event.subject.x;
          event.subject.fy = event.subject.y;
        }

        function dragged(event) {
          event.subject.fx = event.x;
          event.subject.fy = event.y;
        }

        function dragended(event) {
          if (!event.active) simulation.alphaTarget(0);
          event.subject.fx = null;
          event.subject.fy = null;
        }

        return d3
          .drag()
          .on('start', dragstarted)
          .on('drag', dragged)
          .on('end', dragended);
      };

      let height = 100;
      let width = 100;

      let data = {
        nodes: [
          {
            id: 'Myriel',
            label: 'Myriel name',
          },
          {
            id: 'Napoleon',
            label: 'Napoleon name',
          },
        ],
        links: [
          {
            source: 'Myriel',
            target: 'Napoleon',
            label: 'hit me baby one more time',
          },
          {
            source: 'Napoleon',
            target: 'Myriel',
            label: 'meaw',
          },
        ],
      };

      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));

      const svg = d3.select('#chart').attr('viewBox', [0, 0, width, height]);

      // Define the arrowhead marker
      svg
        .append('defs')
        .selectAll('marker')
        .data(['end']) // Different link/path types can be defined here
        .enter()
        .append('svg:marker') // This section adds in the arrows
        .attr('id', String)
        .attr('viewBox', '0 -5 10 10')
        .attr('refX', 15)
        .attr('refY', -1.5)
        .attr('markerWidth', 6)
        .attr('markerHeight', 6)
        .attr('orient', 'auto')
        .append('svg:path')
        .attr('d', 'M0,-5L10,0L0,5');

      // Add the links with arrowheads
      const link = svg
        .append('g')
        .attr('stroke', '#999')
        .attr('stroke-opacity', 0.6)
        .selectAll('line')
        .data(links)
        .join('line')
        .attr('stroke-width', 1)
        .attr('marker-end', 'url(#end)'); // Add the marker-end attribute to link

      link
        .append('text')
        .attr('text-anchor', 'middle')
        .attr('alignment-baseline', 'middle')
        .text((d) => d.label);

      const node = svg
        .append('g')
        .attr('stroke', '#fff')
        .attr('stroke-width', 1.5)
        .selectAll('g')
        .data(nodes)
        .join('g');

      node
        .append('circle')
        .attr('r', 5)
        .attr(
          'fill',
          () => '#' + Math.floor(Math.random() * 16777215).toString(16)
        )
        .call(drag(simulation));

      // node.append("text")
      //     // .attr("text-anchor", "middle")
      //     // .attr("alignment-baseline", "middle")
      //     .text(d => d.label)
      //     .attr('x', 6)
      //     .attr('y', 3);

      var labels = node
        .append('text')
        .text(function (d) {
          return d.label;
        })
        .attr('x', 6)
        .attr('y', 3)
        .attr('stroke', 'black')
        .style('font-family', 'sans-serif')
        .style('font-size', '10px');

      node.append('title').text(function (d) {
        return d.label;
      });

      simulation.on('tick', () => {
        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
          .select('circle')
          .attr('cx', (d) => d.x)
          .attr('cy', (d) => d.y);
        node
          .select('text')
          .attr('x', (d) => d.x)
          .attr('y', (d) => d.y);
      });
    </script>
  </body>
</html>

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