根据json中的坐标定位节点

Locating the nodes according to the coordinates in the json

我试图让定向网络的节点在页面启动时看起来位于 json 文档中反映的坐标处。但是,实际代码重新计算了节点位置,这不符合我的应用程序的要求。有帮助吗?

主要代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
    .node {}

    .link { 
        stroke: #999; 
        stroke-opacity: .6; 
        stroke-width: 1px; 
        }
    line {
        stroke: rgb(212, 212, 212);
        stroke-width: 1px;
        shape-rendering: crispEdges; 
        }
    svg { 
        box-sizing: border-box;
        border: 1px solid rgb(212, 212, 212);
        }
    </style>
    </head>
    <body>
    <svg width="960" height="600"></svg>

    <script src="https://d3js.org/d3.v4.min.js" type="text/javascript"></script>
    <script src="https://d3js.org/d3-selection-multi.v1.js"></script>

    <script type="text/javascript">

    var width = 960,
    height = 500,
    resolution = 150,
    r = 15;

    var colors = d3.scaleOrdinal(d3.schemeCategory10);

    var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    node,
    link;

    svg.selectAll('.vertical')
    .data(d3.range(1, width / resolution))
    .enter().append('line')
    .attr('class', 'vertical')
    .attr('x1', function(d) { return d * resolution; })
    .attr('y1', 0)
    .attr('x2', function(d) { return d * resolution; })
    .attr('y2', height);

    svg.selectAll('.horizontal')
    .data(d3.range(1, height / resolution))
    .enter().append('line')
    .attr('class', 'horizontal')
    .attr('x1', 0)
    .attr('y1', function(d) { return d * resolution; })
     .attr('x2', width)
    .attr('y2', function(d) { return d * resolution; });

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

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

    d3.json("graph.json", function (error, graph) {
    if (error) throw error;
    update(graph.links, graph.nodes);
    })

    function update(links, nodes) {
    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;});

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

    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': 15,
            'fill': '#000'
        });

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

    node = svg.selectAll(".node")
        .data(nodes)
        .enter()
        .append("g")
        .attr("class", "node")
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; })
        .call(d3.drag()
                .on("start", dragstarted)
                .on("drag", dragged)
                //.on("end", dragended)
        );

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

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

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

    simulation
        .nodes(nodes)
        .on("tick", ticked);

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

    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("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;
    });
    }

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

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

    gridX = round(Math.max(r, Math.min(width - r, d.fx)), resolution);
    gridY = round(Math.max(r, Math.min(height - r, d.fy)), resolution);

    d3.select(this).attr('cx', d.fx = gridX).attr('cy', d.fy = gridY);


    }

    function round(p, n) {
    return p % n < n / 2 ? p - (p % n) : p + n - (p % n);
    }

    </script>

    </body>
    </html>

Here I attach the data of the json document that hosts the directed graph data:

    {
     "nodes": [
    {
      "name": "1",
      "label": "1",
      "social": "I",
      "id": 1,
      "x": 150, 
      "y": 450
    },
    {
      "name": "2",
      "label": "2",
      "social": "G",
      "id": 1,
      "x": 300, 
      "y": 150
    },
    {
      "name": "3",
      "label": "3",
      "social": "T",
      "id": 1,
      "x": 450, 
      "y": 300
    }
    ],
    "links": [
    {
      "source": 1,
      "target": 2,
      "type": "N:1"
    },
    {
      "source": 2,
      "target": 3,
      "type": "1:N"
    }
    ]
    }

此代码无效:

node = svg.selectAll(".node")
  .data(nodes)
  .enter()
  .append("g")
  .attr("class", "node")
  .attr('cx', function(d) { return d.x; })
  .attr('cy', function(d) { return d.y; })
  ...

替换为:

node = svg.selectAll(".node")
  .data(nodes)
  .enter()
  .append('g')
  .classed('node', true)
  .attr('transform', d => `translate(${d.x},${d.y})`)
  ...

元素没有 cxcy 属性,它使用变换反而。此外,d3 classed 例程比 attr('class').

更有用

UPD:新创建的链接缺少初始坐标:

link = svg.selectAll(".link")
  .data(links)
  .enter()
  .append("line")
  .classed("link", true)
  .attr('marker-end','url(#arrowhead)')
  .attr("x1", d => d.source.x)
  .attr("x2", d => d.target.x)
  .attr("y1", d => d.source.y)
  .attr("y1", d => d.target.y)