【问题标题】:D3.js: Dynamically generate source and target based on identical json valuesD3.js:根据相同的 json 值动态生成源和目标
【发布时间】:2016-12-14 09:03:11
【问题描述】:

美好的一天,我是 d3/javascript 的新手,这可能是一个简单/重复的问题,但我无法让我的这部分代码工作..

我这里有这个 json 数组:

var myArray = [{"id": "red", "value":"1"},
 {"id": "orange", "value":"2"},
 {"id": "yellow", "value":"3"},
 {"id": "green", "value":"1"},
 {"id": "blue", "value":"1"},
 {"id": "violet", "value":"3"}];

我知道要在 D3 中的节点之间创建链接,我需要一个具有 [{"source": "___", "target": "___"} 结构的数组。

是否有人能够指导我根据它们的值链接上述数组项(即节点图会将具有相同值的所有节点链接在一起)?

我现在想到的一个解决方案是手动迭代并使用 for..if.. 循环创建链接,但是如果我有很多节点(>1000?),这将迭代很多次,并且会沿途创建重复项.

这是所需输出的图片:

【问题讨论】:

  • 它们如何链接在一起? value 是否被用来以某种方式链接它们?
  • Yes :) 例如,在图中,“Red”、“Green”、“Blue”节点是链接的,“Yellow”、“Violet”也是链接的!我会用图片编辑 :) 但它是硬编码的,虽然哈哈..
  • 啊,明白了,所以value 就像一个分组 ID
  • 是的 :) 也附上了一张图片!

标签: javascript d3.js nodes


【解决方案1】:

这是使用嵌套 for 循环的解决方案:

var links = [];

for (var i = 0; i < nodes.length; i++) {
    for (var j = i + 1; j < nodes.length; j++) {
        if (nodes[i].value === nodes[j].value) {
            links.push({
                source: nodes[i].id,
                target: nodes[j].id
            });
        }
    }
}

这是一个演示:

var nodes = [{
    "id": "red",
    "value": "1"
}, {
    "id": "orange",
    "value": "2"
}, {
    "id": "yellow",
    "value": "3"
}, {
    "id": "green",
    "value": "1"
}, {
    "id": "blue",
    "value": "1"
}, {
    "id": "violet",
    "value": "3"
}];

var links = [];

for (var i = 0; i < nodes.length; i++) {
    for (var j = i + 1; j < nodes.length; j++) {
        if (nodes[i].value === nodes[j].value) {
            links.push({
                source: nodes[i].id,
                target: nodes[j].id
            });
        }
    }
}

console.log(links);

这是一个力的演示,带有你的数组:

var nodes = [{
    "id": "red",
    "value": "1"
}, {
    "id": "orange",
    "value": "2"
}, {
    "id": "yellow",
    "value": "3"
}, {
    "id": "green",
    "value": "1"
}, {
    "id": "blue",
    "value": "1"
}, {
    "id": "violet",
    "value": "3"
}];

var links = [];

for (var i = 0; i < nodes.length; i++) {
    for (var j = i + 1; j < nodes.length; j++) {
        if (nodes[i].value === nodes[j].value) {
            links.push({
                source: nodes[i].id,
                target: nodes[j].id
            });
        }
    }
};

var width = 300, height = 300;

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

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

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(links)
    .enter().append("line")
      .attr("stroke-width", 1)
			.attr("stroke", "gray")
			.attr("fill", "none");

  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(nodes)
    .enter().append("circle")
      .attr("r", 10)
			.attr("stroke", "gray")
      .attr("fill", function(d) { return d.id; });

  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("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  }
&lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 嗨!感谢您的帮助!对不起,我低于 15 个代表,所以我的赞成票没有显示 :( 我担心的一个方面是,如果我要在一个大数组(有 1000 个 ++ 节点)上运行代码,程序将不得不经历多次迭代。我是否必须进行 d3.rollup 或内部排序以减少迭代次数?
  • 有不同的方法来做你想做的事,有不同的表现。最好的想法就是对其进行基准测试。现代浏览器是如此之快,以至于差异可以忽略不计(即使对于具有 1k 个节点的数组)。
  • 完成!感谢您的帮助,尤其是关于如何以 d3.force 方式使用它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
相关资源
最近更新 更多