D3节点半径取决于链接数:weight属性 [英] D3 Node radius depends on number of links : weight property

查看:200
本文介绍了D3节点半径取决于链接数:weight属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用D3创建一个力向图. 到目前为止,节点的半径取决于JSON (d.size)

I am trying to create a force directed graph with D3. As for now, the radius of the node depends on a key-value pair in JSON ( d.size )

我知道 d3.weight 属性,该属性可用于计算链接数并与圆的 radius属性相关联,但是我可以通过某种方式无法正常工作.

I'm aware of the d3.weight property which can be used to count the number of links and associate with radius attribute of the circle, but I somehow could not get it to work.

请帮助我.

找到以下代码:

d3.json('graph.json', (error, graph) => {
  const width = 1200;
  const height = 900;

  const simulation = d3.forceSimulation()
    .nodes(graph.nodes)
    .force('link', d3.forceLink().id(d => d.id))
    .force('charge', d3.forceManyBody().strength([-605]))
    .force('center', d3.forceCenter(width / 2, height / 2))
    .on('tick', ticked);

  simulation.force('link')
    .links(graph.links)
    .distance([140]);

  const R = 30;

  const svg = d3.select('body').append('svg')
    .attr('width', width)
    .attr('height', height);

  // add defs-marker
  // add defs-markers
  svg.append('svg:defs').selectAll('marker')
    .data([{ id: 'end-arrow', opacity: 1 }, { id: 'end-arrow-fade', opacity: 0.1 }])
    .enter().append('marker')
      .attr('id', d => d.id)
      .attr('viewBox', '0 0 10 10')
      .attr('refX', 2 * R)
      .attr('refY', 5)
      .attr('markerWidth', 4)
      .attr('markerHeight', 4)
      .attr('orient', 'auto')
      .append('svg:path')
        .attr('d', 'M0,0 L0,10 L10,5 z')
        .style('opacity', d => d.opacity);

  let link = svg.selectAll('line')
    .data(graph.links)
    .enter().append('line');

  link  
    .attr('class', 'link')
    .attr('marker-end', 'url(#end-arrow)')
    .on('mouseout', fade(1));

  let node = svg.selectAll('.node')
    .data(graph.nodes)
    .enter().append('g')
    .attr('class', 'node');

  node.append('circle')
    .attr('r', function (d) {
                return (d.size * 12);
            })
    .on('mouseover', fade(0.1))
    .on('mouseout', fade(1))
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended));

  node.append('text')
    .attr('x', 0)
    .attr('dy', '.35em')
    .text(d => d.name);

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

  const linkedByIndex = {};
  graph.links.forEach(d => {
    linkedByIndex[`${d.source.index},${d.target.index}`] = 1;
  });

  function isConnected(a, b) {
    return linkedByIndex[`${a.index},${b.index}`] || linkedByIndex[`${b.index},${a.index}`] || a.index === b.index;
  }

  function fade(opacity) {
    return d => {
      node.style('stroke-opacity', function (o) {
        const thisOpacity = isConnected(d, o) ? 1 : opacity;
        this.setAttribute('fill-opacity', thisOpacity);
        return thisOpacity;
      });

      link.style('stroke-opacity', o => (o.source === d || o.target === d ? 1 : opacity));
      link.attr('marker-end', o => (opacity === 1 || o.source === d || o.target === d ? 'url(#end-arrow)' : 'url(#end-arrow-fade)'));
    };
  }
})

JSON结构如下:

{
    "nodes": [
        {
            "name": "A",
            "id": 0,
            "size": 1
        },
        {
            "name": "D",
            "id": 1,
            "size": 2
        },
        {
            "name": "K",
            "id": 2,
            "size": 3
        }
    ],
    "links": [
        {
            "source": 0,     //id of the soure application
            "target": 1      //id of the destination application
        },
        {
            "source": 0,
            "target": 2
        },
        {
            "source": 3,
            "target": 4
        }
    ]
}

推荐答案

d3.v4不支持weight属性.因此,我认为您必须自己计算节点权重.尝试这种方式.

d3.v4 does not support weight property. So I think you will have to calculate the node weight by yourselves. try this way.

node.append("circle")
   .attr("r", function(d) {      
     d.weight = link.filter(function(l) {
       return l.source.index == d.index || l.target.index == d.index
     }).size();      
     var minRadius = 10;
     return minRadius + (d.weight * 2);
   });

在d3.v3中,我们具有重量属性,可以按如下所示使用.

In d3.v3, we have weight property and can be used as shown below.

node.append("circle")
  .attr("r", function(d) {
    var minRadius = 10;
    return minRadius + (d.weight * 2);
  });

小提琴示例- https://jsfiddle.net/gilsha/9d6edrte/

这篇关于D3节点半径取决于链接数:weight属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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