Javascript 用D3修改关系图

Javascript 用D3修改关系图,javascript,d3.js,underscore.js,Javascript,D3.js,Underscore.js,我遇到了下面的示例 它是基于 我注意到的问题是,它匹配第一个匹配节点并停止。这些关系基于每个条目的第一个匹配节点,而不是所有匹配节点 我已经修改了代码,但我似乎不明白为什么图形不能正确渲染 代码中执行此操作的部分位于第64行到第128行之间,位于下面。完整来源可从以下网址获得: 该脚本使用了underline.js,我认为更正应该是使用u.filter,而不是u.find。关于修改此代码以包含所有关系(而不是匹配第一个关系并停止)有何建议 可以找到输出的实例 那么,您希望在所有相关实体之间建立链

我遇到了下面的示例

它是基于

我注意到的问题是,它匹配第一个匹配节点并停止。这些关系基于每个条目的第一个匹配节点,而不是所有匹配节点

我已经修改了代码,但我似乎不明白为什么图形不能正确渲染

代码中执行此操作的部分位于第64行到第128行之间,位于下面。完整来源可从以下网址获得:

该脚本使用了underline.js,我认为更正应该是使用u.filter,而不是u.find。关于修改此代码以包含所有关系(而不是匹配第一个关系并停止)有何建议

可以找到输出的实例


那么,您希望在所有相关实体之间建立链接,而不仅仅是每个实体的第一个链接?我不太确定我是否理解这会有什么不同。那会是什么样子?拉尔斯,相当直截了当的o-o(电流)和o=o(我的问题)。如果每个实体都有更多具有共同点的节点,则显示它们是有意义的。想象一下,如果一个关系数据库只是以这种方式匹配联接,那就是为什么我们可以而且应该指定。连接很重要,我正在寻找这种可视化。从外观上看,u.filter将构建一个对象,然后需要做一些事情来循环并构造所有匹配项。查找在第一个匹配处停止。好的,那么您希望(可能)两个节点之间有多个连接?您应该能够简单地用
\u filter
替换
\u find
,以获得所有匹配项。我正在寻求有关执行此操作的逻辑的帮助。。。我知道uu过滤器将获取所有匹配项。任何建议都将不胜感激。基本上,您需要将循环后的
if(t)
替换为
\u find
,并使用循环遍历所有找到的元素。
var width = document.width,
    height = document.height,
    nodeRadius = 20,
    subNodeRadius = nodeRadius / 2,
    k = Math.sqrt(12 / (width * height));

var color = d3.scale.category20();

var force = d3.layout.force()
    .linkDistance(function(d) {
      if (d.type && d.type === 'property') {
        return 10;
      }
      else {
        return 100;
      }
    })
    .charge(-10 / k)
    .gravity(100 * k)
    .size([width, height])

var svg = d3.select("body").append("svg:svg")
    .attr("width", width)
    .attr("height", height)
    .attr("pointer-events", "all")
    .append('svg:g')
      .call(d3.behavior.zoom().on("zoom", redraw))
    .append('svg:g');

svg.append('svg:rect')
    .attr('width', width)
    .attr('height', height)
    .attr('fill', 'white');

function redraw() {
  console.log("here", d3.event.translate, d3.event.scale);
  svg.attr("transform",
      "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}

d3.json("categories.json", function(error, graph) {
  // Break out property nodes
  var people = _.where(graph.nodes, {type: 'person'}),
      nodes = people;

  _.each(people, function(p) {
    _.each(p, function(prop, _k) {
      if (_k !== 'name' && _k !== 'Name' && _k !== 'id' && _k !== 'type') {
        nodes.push({
          target: p.id,
          type: 'property',
          name: _k,
          value: prop
        });
      }
    });
  });

  force.nodes(nodes);

  // Dynamically build links based on shared attributes
  var links = [];
  var _nodes = nodes.slice();  // copy
  _.each(nodes, function(n, i) {
    if (n.type === "person") {
      _nodes.shift();
      var t = i,
          matchKey,
          matchValue;
          //console.log(n);
      for (var key in n) {
        //console.log(n[key]+"THAT");
        if (key === 'type' || key === 'target') {
          continue;
        }
        var val = n[key];
        //console.log(val + "THIS");
        //should likely use _.filter()  as opposed to _.find... 
        t = _.filter(_nodes, function(_n) {

          //console.log(val);
          return _n[key] === val;
        });

        if (t) {
          //matchKey = key;
          //matchValue = val;
          //break;
        }
      }

      console.log(t);

        _.each(t, function(tv,tk) {//ITERATES OVER OBJECT COLLECTION

            for(var tk2 in tv){ //ITERATES OVER EACH KEY VAL PAIR IN OBJECT.
                if(tk2 ==='type' || tk2 ==='Likes Food'){
                    continue;
                }
                var val2 = tv[tk2];

                at = _.find(t, function(_at){
                    return _at[tk2] === val2;
                });
                //console.log(at+"THIS IS AT");
                if(at){

                    //console.log(tk2+":"+tv[tk2]);
                    var matchkey2 = tk2; 
                    var matchval2 = val2;
                    console.log(matchkey2+":"+matchval2);
                    var uniqat = _.clone(at);
                    delete uniqat[matchkey2];
                    //delete uniqat.name;
                    //delete uniqat['Name'];

                      links.push(_.extend({
          source: tk,
          target: (at && at.id) || tk,
          matchKey: matchkey2,
          matchValue: matchval2
        }, {props: uniqat}));

                }
            }


        });






    }
    else {
      links.push(_.extend(n, {
        source: i
      }));
    }

  });

  force.links(links);
  force.start();

  var link = svg.selectAll(".link")
      .data(links)
    .enter().append("g")
      .attr('class', function(d) {
        if (d.props) {
          return 'person link';
        }
        else return 'property link';
      });

  var line = link.append('line')
      .style("stroke-width", 1);

  var matchCirlce = svg.selectAll('.link.person')
      .append('circle')
        .attr('r', subNodeRadius)
        .style('fill', '#000');

  var text = svg.selectAll('.link.person')
      .append("text")
        .attr('dy', '.35em')
        .attr('text-anchor', 'middle')
        .text(function(d) {
          if (d.matchValue === true || d.matchValue === false) {
            return d.matchKey;
          }
          else {
            return d.matchKey+ ": " + d.matchValue;
          }
        });

  var node = svg.selectAll(".node")
      .data(nodes)
    .enter()
      .append('g')
      .attr("class", function(d) {
        if (d.type && d.type === 'person') {
          return 'node person'
        }
        else {
          return 'node property';
        }
      })
      .call(force.drag);

  var circle = node.append("circle")
      .attr("r", function(d) {
        if (d.type && d.type === 'person') {
          return nodeRadius;
        }
        else {
          return subNodeRadius;
        }
      })
      .style('fill', function(d) {
        if (d.type && d.type === 'person') {
          return color(d.id);
        }
        else {
          return '#eee'
        }
      });

  node.append("text")
      .attr('dy', '.35em')
      .attr('text-anchor', 'middle')
      .text(function(d) {
        if (d.type && d.type === 'person') {
          return d.name;
        }
        else {
          if (d.value === true || d.value === false) {
            return d.name;
          }
          else return d.value;
        }
      });

  force.on("tick", function() {

    node.attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });

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

    text.attr("transform", translateBetween);
    matchCirlce.attr("transform", translateBetween);

  });

});

function translateBetween(d) {
  var x1 = d.source.x;
  var y1 = d.source.y;
  var x2 = d.target.x;
  var y2 = d.target.y;
  return "translate(" + (x1 + x2) / 2 + "," + (y1 + y2) / 2 + ")";
}