简体   繁体   中英

d3.js force directed graph sphere

I have adapted Christopher Manning's force-directed graph on a sphere . I would like to have the graph settle down and then rotate the sphere without changing the relationships among the points in the graph. Instead, when I drag, it seems to drag the graph, and not rotate the sphere. Dragging the graph activates the force start. If I turn off force.start() nothing changes.

var svg = d3.select("#cluster").append("svg")
    .attr("width", width)
    .attr("height", height)
    .call(d3.behavior.drag()
      .origin(function() { var r = projection.rotate(); return {x: 2 * r[0], y: -2 * r[1]}; })
      .on("drag", function() { force.start(); var r = [d3.event.x / 2, -d3.event.y / 2, projection.rotate()[2]]; t0 = Date.now(); origin = r; projection.rotate(r); }))

From http://bl.ocks.org/mbostock/3795040 , I found that I could rotate the graticule, but then all of my links and nodes disappear.

var path = d3.geo.path()
    .projection(projection);

var λ = d3.scale.linear()
    .domain([0, width])
    .range([-180, 180]);

var φ = d3.scale.linear()
    .domain([0, height])
    .range([90, -90]);

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

svg.on("mousemove", function() {
  var p = d3.mouse(this);
  projection.rotate([λ(p[0]), φ(p[1])]);
  svg.selectAll("path").attr("d", path);
});

Links and nodes get added like this:

  var link = svg.selectAll("path.link")
      .data(graph.links)
      .enter().append("path").attr("class", "link")
      .attr ("stroke-width", function(d){return d.value/3});

  var node = svg.selectAll("path.node")
      .data(graph.nodes)
      .enter()
      .append("g")
      .attr("class", "gnode")
      .attr("text-anchor", "middle")

      .append("path").attr("class", "node")
      .style("fill", function(d) { return d.color; })
      .style("stroke", function(d) { return d3.rgb(fill(d.group)).darker(); })

What I would like to accomplish: when the graph settles into position, I would like to use the drag gesture to rotate the sphere with the nodes and links on it.

How do I make this happen?

This could be done by adjusting the handler registered for the drag event on the svg which is defined in your first snippet. This requires two edits:

  1. Get rid of force.start() because you don't want to restart the force on drag.
  2. Trigger the rendering of nodes and links after the projection has been updated, which can easily be done by calling tick() . If the force had not been deactivated by step 1., this would be called repeatedly because the function is registered as the handler for the force layout's tick event. Now, that you have deactivated the force, you will have to call it explicitely.

The reformatted code will look like:

.on("drag", function() { 
  //force.start();     // 1. Don't restart the force.
  var r = [d3.event.x / 2, -d3.event.y / 2, projection.rotate()[2]];
  t0 = Date.now();
  origin = r;
  projection.rotate(r);
  tick();              // 2. Trigger the rendering after adjusting the projection.
}))

Have a look at this working example .

This may rotate along one axis

var rotateScale = d3.scale.linear().domain([0, width]).range([-180,180]);//width of  SVG

d3.select("svg").on("mousedown",startRotating).on("mouseup",stopRotating);

function startRotating() {
   d3.select("svg").on("mousemove",function() {
      var p = d3.mouse(this);
      projection.rotate([rotateScale(p[0]),0]);
   });
}
function stopRotating() {
   d3.select("svg").on("mousemove",null);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM