d3:图形中新添加的链接不尊重图形物理

时间:2020-06-30 13:58:51

标签: javascript reactjs d3.js

我正在使用D3库创建图形,并且有一些表格可以添加新的链接和节点。

添加节点可以正常工作,问题出在我链接它们时:几次拖动事件后,新链接就会停​​止并固定在没有意义的位置。图片中的“ TEST”链接应从“ Michale:Person”到屏幕底部的“ A:B”节点。

这是我正在使用的代码:

import React from 'react'
import * as d3 from 'd3'
import "d3-selection-multi"

function Graph(props) {
  const {nodes, links} = props

  const ticked = (link, node, edgepaths, edgelabels) => {
    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("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});

    edgepaths.attr('d', function (d) {
      return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
    });

    edgelabels.attr('transform', function (d) {
      if (d.target.x < d.source.x) {
        var bbox = this.getBBox();

        const rx = bbox.x + bbox.width / 2;
        const ry = bbox.y + bbox.height / 2;
        return 'rotate(180 ' + rx + ' ' + ry + ')';
      }
      else {
        return 'rotate(0)';
      }
    });
  }

  const d3Container = React.useRef(null);

  const drawGraph = () => {
    if (nodes && links && d3Container.current) {
      const colors = d3.scaleOrdinal(d3.schemeCategory10)

      const svg = d3.select(d3Container.current)

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

      const simulation = d3.forceSimulation()
        .force("link", d3.forceLink().id(function (d) {return d.id;}).distance(100).strength(1))
        .force("charge", d3.forceManyBody())
        .force("center", d3.forceCenter( +svg.attr("width") / 2, +svg.attr("height")/ 2));

      update(svg, colors, simulation)
    }
  }

  const update = (svg, colors, simulation) => {
    if (!svg) return    

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

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

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

    link.append("title")
      .text(function (d) {return d.type;});

    const edgepaths = (svg.selectAll(".edgepath")
      .data(links)
      .enter()
      .append('path')
      .attrs({
        'class': 'edgepath',
        'fill-opacity': 0,
        'stroke-opacity': 0,
        'id': function (d, i) {return 'edgepath' + i}
      })
      .style("pointer-events", "none"))

    const edgelabels = (svg.selectAll(".edgelabel")
      .data(links)
      .enter()
      .append('text')
      .style("pointer-events", "none")
      .attrs({
        'class': 'edgelabel',
        'id': function (d, i) {return 'edgelabel' + i},
        'font-size': 10,
        'fill': '#aaa'
      }))

    edgelabels.append('textPath')
      .attr('xlink:href', function (d, i) {return '#edgepath' + i})
      .style("text-anchor", "middle")
      .style("pointer-events", "none")
      .attr("startOffset", "50%")
      .text(function (d) {return d.type});

    console.log('nodes')
    console.log(nodes)
    const node = svg.selectAll(".node")
      .data(nodes)
      .enter()
      .append("g")
      .attr("class", "node")
      .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", () => { console.log('dragging ended')})
      )

    node.append("circle")
      .attr("r", 5)
      .style("fill", function (d, i) {return colors(i);})

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

    node.append("text")
      .attr("dy", -3)
      .text(function (d) {return d.name+":"+d.label;});

    simulation
      .nodes(nodes)
      .on("tick", () => ticked(link, node, edgepaths, edgelabels));

    simulation.force("link")
      .links(links);
  }

  React.useEffect(() => {
    drawGraph()
  }, [d3Container.current, nodes, links])

  return (
    <svg
      width="960"
      height="600"
      ref={d3Container}
    ></svg>
  );
}

export default Graph

我想念什么? enter image description here

0 个答案:

没有答案