根据d3.js中的另一个值修复节点位置

时间:2015-06-24 19:23:20

标签: javascript d3.js

我有一个强制定向布局。节点派生自json值,其具有名称,组作为节点,源,目标和值作为链接。 json可以带有价值'尺寸'作为节点的一部分,我想看看我是否可以使用这个值来确定节点的放置位置0这个想法是尺寸越大,画布上放置的越高。

我有两个问题。 a)如果json在需要的基础上携带额外的元素,我不知道d3.js是否会渲染; b)我不确定如何根据这个' size'来更改y属性。元件。

我试过的代码是:

     var width = 1400,
    height = 500

var color = d3.scale.category20();

var force = d3.layout.force()
    .charge(-100)
    .linkDistance(130)
    .size([width, height]);

var svg = d3.select("#chart").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
    .append("g");


function zoom() {
  svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

var endpoint = window.location.href+".json"


d3.json(endpoint, function(graph) {
  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  var link = svg.selectAll(".link")
      .data(graph.links)
      .enter().append("line")
      .attr("class", "link")
      .style("marker-end",  "url(#suit)");

  var node = svg.selectAll(".node")
      .data(graph.nodes)
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", function(d) { return d.group * 3; })
      .attr("cy", function(d) { return d.group; })
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag)
      .on('mouseover', connectedNodes)
      .on('mouseout', UnconnectedNodes)
      .on("click",  function(d) { getprofile2(d); });

      function getprofile2(d){      
        $.ajax({
          url: "/graph/show", 
          type: "GET", 
          dataType: 'html',
          data: {name: d.name},
          success: function(result) {
            $('.bchart-content').html(result);
            addGraph(result);
          }
        });
      }


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

  node.append("circle")
  .attr("r", function(d) { return d.group * 3; });

  force.on("tick", function() {
    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; });
  });


  //Toggle stores whether the highlighting is on
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
    linkedByIndex[i + "," + i] = 1;
};
graph.links.forEach(function (d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

//This function looks up whether a pair are neighbours
function neighboring(a, b) {
    return linkedByIndex[a.index + "," + b.index];
}



function connectedNodes() {
    if (toggle == 0) {
        //Reduce the opacity of all but the neighbouring nodes
        d = d3.select(this).node().__data__;
        node.style("opacity", function (o) {
            return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
        });
        link.style("opacity", function (o) {
            return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
        });
        //Reduce the op
        toggle = 1;
    } else {
        //Put them back to opacity=1
        node.style("opacity", 1);
        link.style("opacity", 1);
        toggle = 0;
    }
}


function UnconnectedNodes() {
node.style("opacity", 1);
        link.style("opacity", 1);
        toggle = 0;
}





graphRec=JSON.parse(JSON.stringify(graph));
function threshold(thresh) {
    graph.links.splice(0, graph.links.length);
        for (var i = 0; i < graphRec.links.length; i++) {
            if (graphRec.links[i].value > thresh) {graph.links.push(graphRec.links[i]);}
        }
    restart();
}
//Restart the visualisation after any node and link changes
function restart() {
    link = link.data(graph.links);
    link.exit().remove();
    link.enter().insert("line", ".node").attr("class", "link");
    node = node.data(graph.nodes);
    node.enter().insert("circle", ".cursor").attr("class", "node").attr("r", 5).call(force.drag);
    force.start();
}
});

但没有任何改变。

我的数据如下:

{  
   "nodes":[  
      {  
         "name":"Et",
         "group":5
         "size":14
      },
      {  
         "name":"Non Qui",
         "group":5,
         "size":19
      },
      {  
         "name":"Officiis",
         "group":1
         "size":13
      },
      {  
         "name":"Bilbo",
         "group":1
         "size":10
      }
   ],
 "links":[  
      {  
         "source":1,
         "target":2,
         "value":2
      },
      {  
         "source":1,
         "target":3,
         "value":1
      }
 ]
}

2 个答案:

答案 0 :(得分:2)

Here是一个如何调整引力函数以产生你所追求的效果的例子。我还添加了一些震动以帮助扩散...

&#13;
&#13;
var width = 960,
  height = 500,
  padding = 0, // separation between nodes
  maxRadius = 12;

var n = 1000, // total number of nodes
  m = 10; // number of distinct layers

var color = d3.scale.category10()
  .domain(d3.range(m));

var y = d3.scale.ordinal()
  .domain(d3.range(m))
  .rangePoints([height, 0], 1);

var nodes = d3.range(n).map(function() {
  var i = Math.floor(Math.random() * m),
    v = (i + 10) / m * -Math.log(Math.random());
  return {
    radius: Math.sqrt(v) * maxRadius,
    color: color(i),
    cy: y(i)
  };
});

var force = d3.layout.force()
  .nodes(nodes)
  .size([width, height])
  .gravity(0)
  .charge(0)
  .on("tick", tick)
  .start();

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

var circle = svg.selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .attr("r", function(d) {
    return d.radius;
  })
  .style("fill", function(d) {
    return d.color;
  })
  .call(force.drag);

function tick(e) {
  var a = e.alpha;
  circle
    .each(gravity(.2 * a))
    .each(collide(.5))
    .attr("cx", function(d) {
      return brownian(d.x, a);
    })
    .attr("cy", function(d) {
      return brownian(d.y, a);
    });
  force.alpha(a / 0.99 * 0.999)
}
var brownian = (function(w) {
  return function(x, a) {
    return x + (Math.random() - 0.5) * w * a
  }
})(10);
// Move nodes toward cluster focus.
function gravity(alpha) {
  return function(d) {
    d.y += (d.cy - d.y) * alpha;
    //    d.x += (d.cx - d.x) * alpha;
  };
}

// Resolve collisions between nodes.
function collide(alpha) {
  var quadtree = d3.geom.quadtree(nodes);
  return function(d) {
    var r = d.radius + maxRadius + padding,
      nx1 = d.x - r,
      nx2 = d.x + r,
      ny1 = d.y - r,
      ny2 = d.y + r;
    quadtree.visit(function(quad, x1, y1, x2, y2) {
      if (quad.point && (quad.point !== d)) {
        var x = d.x - quad.point.x,
          y = d.y - quad.point.y,
          l = Math.sqrt(x * x + y * y),
          r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x += x;
          quad.point.y += y;
        }
      }
      return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
    });
  };
}
&#13;
circle {
  stroke: #fff;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

根据您的数据,代码应如下所示:

 var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", function(d) { return d.group * 3; })
    .attr("cy", function(d) { return d.size; })
    .style("fill", function(d) { return color(d.group); })

实际的&#34; cy&#34;也可能取决于绘图区域的最大高度,因此您可能需要相应地缩放它。

希望这会有所帮助:)