D3强制布局:如何强制一组节点留在给定区域中 [英] D3 Force Layout : How to force a group of node to stay in a given area

查看:265
本文介绍了D3强制布局:如何强制一组节点留在给定区域中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在D3强制布局图中,我尝试根据某些节点的组来强制某些节点停留在给定区域中.

In a D3 force layout graph, i try to force certain nodes to stay in a given area, based on their group.

有一个固定的中心节点.我希望通过红线连接的节点保持在屏幕高度的前1/3,通过描边线连接的节点保持在屏幕高度的后1/3,而通过蓝线连接的节点保持在屏幕高度的后1/3.

There is a center node, which is fixed. I want nodes connected by red line to stay in first 1/3 of screen height, nodes connected by stroke line stay in the second 1/3 and nodes connected by blue lines stay in last 1/3.

但是我希望它平滑:​​在加载时,节点移动到给定的区域,并远离另一个区域.到中心节点的距离可能不固定.

But i want it smooth : at the loading, nodes moves to the given zone, and stay away from the other. The distance with the center node may not be fixed.

每个组中的节点数是可变的.

The number of nodes in each group is variable.

如何使用d3.js v4实现这一目标?

How can achieve that with d3.js v4 ?

感谢您的帮助:)

推荐答案

您必须使用forceX,其中:

沿着x轴朝给定位置x创建新的定位力.如果未指定x,则默认为0.

Creates a new positioning force along the x-axis towards the given position x. If x is not specified, it defaults to 0.

在此演示中(基于此Bostock的代码),nodes数组包含一个group:

In this demo (based on this Bostock's code), the nodes array contains a group:

nodes:[
    {"id": "A", "group": 1},
    {"id": "B", "group": 2},
    {"id": "C", "group": 2},
    //etc...
]

使用此group值,我们可以将节点定位在左侧或右侧.这只是一个示例,请根据您的代码进行更改:

Using this group value, we can position the nodes to the left or to the right. This is just an example, change it according to your code:

.force("x", d3.forceX(function(d){
    if(d.group === 2){
        return width/3
    } else if (d.group === 3){
        return 2*width/3
    } else {
        return width/2 
    }
}))

因此,如果节点属于组2(青色节点),则将其放置在宽度的1/3处;如果它属于组3(橙色节点),则将其放置在宽度的2/3处.

So, if the nodes belongs to group 2 (cyan nodes), we position it at 1/3 of the width, and if it belongs to group 3 (orange nodes) we position it at 2/3 of the width.

定位不是完美的,因为电荷的强度和链接的距离会影响其他参数.

The positioning is not perfect, because other parameters can influence it, as the charge's strength and the link's distance.

这是一个演示:

var graph = {
nodes:[
	{"id": "A", "group": 1},
	{"id": "B", "group": 2},
	{"id": "C", "group": 2},
	{"id": "D", "group": 2},
	{"id": "E", "group": 2},
	{"id": "F", "group": 3},
	{"id": "G", "group": 3},
	{"id": "H", "group": 3},
	{"id": "I", "group": 3}
],
links:[
{"source": "A", "target": "B", "value": 1},
{"source": "A", "target": "C", "value": 1},
{"source": "A", "target": "D", "value": 1},
{"source": "A", "target": "E", "value": 1},
{"source": "A", "target": "F", "value": 1},
{"source": "A", "target": "G", "value": 1},
{"source": "A", "target": "H", "value": 1},
{"source": "A", "target": "I", "value": 1},
]
};

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

var color = d3.scaleOrdinal(d3.schemeCategory20);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(100))
    .force("charge", d3.forceManyBody())
		.force("x", d3.forceX(function(d){
			if(d.group === 2){
				return width/3
			} else if (d.group === 3){
				return 2*width/3
			} else {
				return width/2 
			}
		}))
    .force("y", d3.forceY(height/2))
    .force("center", d3.forceCenter(width / 2, height / 2));

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke-width", function(d) { return Math.sqrt(d.value); });

  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
      .attr("r", 5)
      .attr("fill", function(d) { return color(d.group); })
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

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

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

  simulation.force("link")
      .links(graph.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("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return 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;
}

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}

<svg width="400" height="300"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>

这篇关于D3强制布局:如何强制一组节点留在给定区域中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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