Domanda

I am trying to implement a version of the SVG Semantic Zoom and Pan example for D3.js, found here. I am trying to do this with a Dendrogram / tree (example here), as recommended by Mike Bostock (here). The goal is like this jsFiddle that one of the other threads mentioned, except without the weird node / path unlinking behavior. My personal attempt is located here.

I was getting an error in Firebug with Mike's code, about "cannot translate(NaN,NaN)", so I changed the code in the zoom function to what is shown below. However, the behavior is weird. Now 1) my paths don't zoom / move, and 2) I can only pan the nodes from Lower Right--Upper Left (if I try panning from Lower Left--Upper Right, the nodes still move along the LR-UL direction).

var vis = d3.select("#tree").append("svg:svg")
              .attr("viewBox", "0 0 600 600")
              .attr("width", w + m[1] + m[3])
              .attr("height", h + m[0] + m[2])
              .append("svg:g")
              .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
              .call(d3.behavior.zoom().x(x).y(y).scaleExtent([1,8]).on("zoom",zoom));

// zoom in / out
function zoom() {
    var nodes = vis.selectAll("g.node");
    nodes.attr("transform", transform);
}

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

I tried following the other solutions given in the Google Groups thread mentioned above and the jsFiddle, but I don't make much progress. Including the path links from the jsFiddle in my code and a translate() function lets me scale the paths--except 1) they flip vertically (somewhere x and y transposition isn't working right); 2) the paths don't zoom at the same rate as the nodes (perhaps related to #1), so they become "unlinked"; and 3) when I pan, the paths now pan in all directions, but the nodes don't move. When I click on a node to expand the tree, the paths re-adjust and fix themselves, so the update code seems to work better (but I don't know how to identify / copy the working parts of that). See my code here.

function zoom(d) {
    var nodes = vis.selectAll("g.node");
    nodes.attr("transform", transform);

    // Update the links...
    var link = vis.selectAll("path.link");
    link.attr("d", translate);
}

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

function translate(d) {
    var sourceX = x(d.target.parent.y);
    var sourceY = y(d.target.parent.x);
    var targetX = x(d.target.y);
    var targetY = (sourceX + targetX)/2;
    var linkTargetY = y(d.target.x0);
    var result = "M"+sourceX+","+sourceY+" C"+targetX+","+sourceY+" "+targetY+","+y(d.target.x0)+" "+targetX+","+linkTargetY+"";
    //console.log(result);

   return result;

My questions are:

  • Are there any working examples of zoom / pan on a Dendrogram / tree that I can look at?
  • With the code I have above, can anyone identify where / how the paths are getting flipped? I have tried various permutations within the translate() function of drawing the SVG Cubic Bezier curve, but nothing seems to work right. Again, my jsFiddle is here.
  • Any troubleshooting tips or ideas why panning only partially works?

Thank you everyone for your help!

È stato utile?

Soluzione

You had a pretty good implementation that was derailed by one major typo:

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

Should have been

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

To have your paths not flip you should have probably not reversed the y-axis:

y = d3.scale.linear().domain([0, h]).range([h, 0])

changed to

y = d3.scale.linear().domain([0, h]).range([0, h])

Fixes are here: http://jsfiddle.net/6kEpp/2/. But for future reference, you should probably have your x-axis operate on x-values, and y-axis operate on y-values, or you're just going to really confuse yourself.

Final remarks to polish your implementation:

  1. There is a little bit of jumpiness in the bezier drawing going from the default rendering (or right after opening/closing a node) to the zoom implementation. You just need to make those the same bezier function, and it will feel a lot better when you play with it.
  2. You need to update the zoom vector after the graph redraws itself, based on the relative movement of existing nodes. Otherwise, there will be a sudden jump when you try to zoom again after opening/closing a node.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top