力向图节点固定在中心 [英] Force directed graphs nodes stick to the center

查看:126
本文介绍了力向图节点固定在中心的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在回答了这个问题后在D3图表的Circle内插入文本

我的节点位于中心位置.我不确定哪个属性在指导我的节点及其x和y坐标.我最近更改了代码,在圆圈中添加了g图层,以便可以将文字和形状一起添加.

My nodes are sticking to the center. I am not sure which property is directing my nodes and their x and y coordinates. I recently chnaged my code to add a g layer to the circles so that i can append text along with shape.

数据

https://api.myjson.com/bins/hwtj0

更新代码

    async function d3function() {
        d3.selectAll("svg > *").remove();

        const svg = d3.select("svg");
        file = document.getElementById("selectFile").value;
        console.log("File: " + file)
        var width = 900
        var height = 900 
        svg.style("width", width + 'px').style("height", height + 'px');

        data = (await fetch(file)).json()
        d3.json(file).then(function(data) {

            const links = data.links.map(d => Object.create(d));
            const nodes = data.nodes.map(d => Object.create(d));
            console.log(links.length);
            console.log(nodes.length);
            const simulation = forceSimulation(nodes, links).on("tick", ticked);

            var categorical = [
              { "name" : "schemeAccent", "n": 8},
              { "name" : "schemeDark2", "n": 8},
            ]
            // var colorScale = d3.scaleOrdinal(d3[categorical[6].name])

            var color = d3.scaleOrdinal(d3[categorical[1].name]);


            var drag = simulation => {

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

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

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

            const link = svg.append("g")
                  .attr("stroke", "#999")
                  .attr("stroke-opacity", 0.6)
                .selectAll("line")
                .data(links)
                .enter().append("line")
                  .attr("stroke-width", d => Math.sqrt(d.value));

            // link.append("title").text(d => d.value);

            // var circles = svg.append("g")
            //       .attr("stroke", "#fff")
            //       .attr("stroke-width", 1.5)
            //     .selectAll(".circle")
            //     .data(nodes)

            // const node = circles.enter().append("circle")
            //       .attr("r", 5)
            //       .attr("fill", d => color(d.group))
            //       .call(drag(simulation));

            const node = svg.append("g")
                  .attr("stroke", "#fff")
                  .attr("stroke-width", 1.5)
                  .selectAll("circles")
                  .data(nodes)
                  .enter()
                .append("g")
                .classed('circles', true)
                .attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');

                node.append("circle")
                .classed('circle', true)
                .attr("r", 5)
                .attr("fill", d => color(d.group))
                .call(drag(simulation));

                node
                  .append("text")
                  .classed('circleText', true)
                  .attr('dy', '0.35em')
                  .attr('dx', 5)
                  .text(d => "Node: " + d.id);

            node.append("title").text(d => "Node: " + d.id);

            function ticked() {
                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);
            }

        });

    }



    function forceSimulation(nodes, links) {
      return d3.forceSimulation(nodes)
          .force("link", d3.forceLink(links).id(d => d.id))
          .force("charge", d3.forceManyBody())
          .force("center", d3.forceCenter());
    }

输出更新

预期输出

更新的HTML

<g stroke="#fff" stroke-width="1.5">
   <g class="circle" cx="-35.89111508769784" cy="131.13965804447696">
      <circle class="circle" r="5" fill="#1b9e77"></circle>
      <text class="circleText" dy="0.35em" dx="5">Node: 0</text>
      <title>Node: 0</title>
   </g>
   <g class="circle" cx="70.97799024729613" cy="-195.71408429254427">
      <circle class="circle" r="5" fill="#d95f02"></circle>
      <text class="circleText" dy="0.35em" dx="5">Node: 3</text>
      <title>Node: 3</title>
   </g>
   [....]
  </g>

推荐答案

您必须稍微修改代码,因为它当前假设您正在使用circle元素,您可以在其中使用cxcy,但是您现在使用的是g元素,该元素使用标准的xy坐标.

You have to adapt your code slightly as it currently assumes that you're working with circle elements, where you specify the centres using cx and cy, but you are now using g elements, which use standard x and y coordinates.

首先,从g元素中删除转换(这是我的演示代码的剩余部分):

First, remove the transform from the g element (that's a leftover from my demo code):

const node = svg.append("g")
  .attr("stroke", "#fff")
  .attr("stroke-width", 1.5)
.selectAll(".circles")  // note - should be .circles!
  .data(nodes)
  .enter()
  .append("g")
  .classed('circles', true)

并在ticked()函数中,将node更新代码更改为可对g元素(不具有cxcy)使用的转换:

and in the ticked() function, change the node updating code into a transform that works on g elements (which don't have cx or cy):

node.attr('transform', d => 'translate(' + d.x + ',' + d.y + ')' )

演示:

var json = {"nodes":[{"id":"0","group":0},{"id":"1","group":1},{"id":"2","group":2},{"id":"3","group":3},{"id":"4","group":4},{"id":"5","group":5},{"id":"6","group":6},{"id":"7","group":7},{"id":"8","group":8},{"id":"9","group":9},{"id":"10","group":10},{"id":"11","group":11},{"id":"12","group":12},{"id":"13","group":13},{"id":"14","group":14},{"id":"15","group":15},{"id":"16","group":16},{"id":"17","group":17},{"id":"18","group":18},{"id":"19","group":19}],"links":[{"source":"0","target":"1","value":1},{"source":"0","target":"18","value":1},{"source":"0","target":"10","value":1},{"source":"0","target":"12","value":1},{"source":"0","target":"5","value":1},{"source":"0","target":"8","value":1},{"source":"1","target":"0","value":1},{"source":"1","target":"9","value":1},{"source":"1","target":"4","value":1},{"source":"2","target":"4","value":1},{"source":"2","target":"17","value":1},{"source":"2","target":"13","value":1},{"source":"2","target":"15","value":1},{"source":"3","target":"6","value":1},{"source":"4","target":"14","value":1},{"source":"4","target":"2","value":1},{"source":"4","target":"5","value":1},{"source":"4","target":"19","value":1},{"source":"4","target":"1","value":1},{"source":"5","target":"4","value":1},{"source":"5","target":"0","value":1},{"source":"6","target":"3","value":1},{"source":"7","target":"18","value":1},{"source":"7","target":"16","value":1},{"source":"8","target":"0","value":1},{"source":"9","target":"1","value":1},{"source":"10","target":"0","value":1},{"source":"10","target":"15","value":1},{"source":"12","target":"0","value":1},{"source":"13","target":"15","value":1},{"source":"13","target":"2","value":1},{"source":"14","target":"4","value":1},{"source":"15","target":"13","value":1},{"source":"15","target":"10","value":1},{"source":"15","target":"2","value":1},{"source":"16","target":"7","value":1},{"source":"17","target":"2","value":1},{"source":"18","target":"0","value":1},{"source":"18","target":"7","value":1},{"source":"19","target":"4","value":1},{"source":"19","target":"4","value":1}]};


d3.selectAll("svg > *").remove();

const svg = d3.select("svg");
var width = 900
var height = 900
svg.style("width", width + 'px').style("height", height + 'px');

const links = json.links.map(d => Object.create(d));
const nodes = json.nodes.map(d => Object.create(d));
const simulation = forceSimulation(nodes, links).on("tick", ticked);

var categorical = [
{
  "name": "schemeAccent",
  "n": 8
},
{
  "name": "schemeDark2",
  "n": 8
}, ]

var color = d3.scaleOrdinal(d3[categorical[1].name]);


var drag = simulation => {

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

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

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

const link = svg.append("g")
  .attr("stroke", "#999")
  .attr("stroke-opacity", 0.6)
  .selectAll("line")
  .data(links)
  .enter().append("line")
  .attr("stroke-width", d => Math.sqrt(d.value));

const node = svg.append("g")
  .attr("stroke", "#fff")
  .attr("stroke-width", 1.5)
  .selectAll(".circles")
  .data(nodes)
  .enter()
  .append("g")
  .classed('circles', true)
  .call(drag(simulation))
//    .attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');

const circle = node.append("circle")
  .classed('circle', true)
  .attr("r", 5)
  .attr("fill", d => color(d.group))

node
  .append("text")
  .classed('circleText', true)
  .attr('dy', '0.35em')
  .attr('dx', 5)
  .text(d => "Node: " + d.id);

node.append("title").text(d => "Node: " + d.id);

function ticked() {
  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('transform', d => 'translate(' + d.x + ',' + d.y + ')')
}

function forceSimulation(nodes, links) {
  return d3.forceSimulation(nodes)
    .force("link", d3.forceLink(links).id(d => d.id))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter());
}

.circleText { fill: black; stroke: none }

<script src="//d3js.org/d3.v5.js"></script>
<svg></svg>

这篇关于力向图节点固定在中心的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆