我如何添加缩放到d3可折叠树示例? [英] How can I add zooming to the d3 collapsible tree example?

查看:1352
本文介绍了我如何添加缩放到d3可折叠树示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向d3折叠树中添加缩放功能示例 a>,但不能让它工作。我知道有关于此此处的问题,即使它似乎相当彻底我的更改不工作。我唯一得到的是一个白页。可能与事实,我是相当新的javascript / d3。这是我的代码。

 <!DOCTYPE html> 
< meta charset =utf-8>
< style>

svg {
pointer-events:all;
}

.node {
cursor:pointer;
}

.node circle {
fill:#fff;
stroke:steelblue;
stroke-width:1.5px;
}

tree {
pointer-events:all;
}

.node text {
font:12px sans-serif;
}

.link {
fill:none;
stroke:#ccc;
stroke-width:1.5px;
}



< / style>
< body>
< script src =d3.v3.min.js>< / script>
< script>

var margin = {top:20,right:120,bottom:20,left:120},
width = 1500 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;

var i = 0,
duration = 750,
root;

var tree = d3.layout.tree()
.size([height,width]);

var diagonal = d3.svg.diagonal()
.projection(function(d){return [d.y,d.x];});

var svg = d3.select(body)append(svg)
.attr(width,width + margin.right + margin.left)
.attr(height,height + margin.top + margin.bottom)
.append(g)
.attr(transform,translate(+ margin.left + ,+ margin.top +))

d3.json(flare.json,function(error,flare){
root = flare;
root。 x0 = height / 2;
root.y0 = 0;

函数collapse(d){
if(d.children){
d._children = d .children;
d._children.forEach(collapse);
d.children = null;
}
}

root.children.forEach collapse);
update(root);
});

d3.select(self.frameElement).style(height,800px);

函数更新(源){

//计算新的树布局。
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);

//规范化固定深度。
nodes.forEach(function(d){d.y = d.depth * 180;});

//更新节点...
var node = svg.selectAll(g.node)
.data(nodes,function(d){return d.id | |(d.id = ++ i);});

//在父级的上一个位置输入任何新节点。
var nodeEnter = node.enter()。append(g)
.attr(class,node)
.attr returntranslate(+ source.y0 +,+ source.x0 +);})
.on(click,click);

nodeEnter.append(circle)
.attr(r,1e-6)
.style(fill,function(d){return d。 _children?lightsteelblue:#fff;});

nodeEnter.append(text)
.attr(x,function(d){return d.children || d._children?-10:10;})
.attr(dy,.35em)
.attr(text-anchor,function(d){return d.children || d._children?end:start ;})
.text(function(d){return d.name;})
.style(fill-opacity,1e-6);

//将节点转换到新位置。
var nodeUpdate = node.transition()
.duration(duration)
.attr(transform,function(d){returntranslate(+ dy +,+ dx +);});

nodeUpdate.select(circle)
.attr(r,4.5)
.style(fill,function(d){return d._children? lightsteelblue:#fff;});

nodeUpdate.select(text)
.style(fill-opacity,1);

//将退出节点的节点转换到父节点的新位置。
var nodeExit = node.exit()。transition()
.duration(duration)
.attr(transform,function(d){returntranslate +,+ source.x +);})
.remove();

nodeExit.select(circle)
.attr(r,1e-6);

nodeExit.select(text)
.style(fill-opacity,1e-6);

//更新链接...
var link = svg.selectAll(path.link)
.data(links,function(d){return d.target。 ID; });

//在父级的上一个位置输入任何新的链接。
link.enter()。insert(path,g)
.attr(class,link)
.attr(d {
var o = {x:source.x0,y:source.y0};
return diagonal({source:o,target:o});
}

//转换链接到他们的新位置。
link.transition()
.duration(duration)
.attr(d,diagonal);

//将退出节点的节点转换到父节点的新位置。
link.exit()transition()
.duration(duration)
.attr(d,function(d){
var o = {x:source。 x,y:source.y};
return diagonal({source:o,target:o});
})
.remove();

//存储转换的旧位置。
nodes.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});

d3.select(svg)
.call(d3.behavior.zoom()
.scaleExtent([0.5,5])
.on zoom,zoom));


}

//点击切换子项。
function click(d){
if(d.children){
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);


function zoom(){
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -h * scale,
bbound = h * scale,
lbound =(-w + m [1])* scale,
rbound =(w-m [3]
//限制翻译为阈值
translation = [
Math.max(Math.min(translation [0],rbound),lbound),
Math.max min(translation [1],bbound),tbound)
];
d3.select(。drawarea)
.attr(transform,translate(+ translation +)+
scale(+ scale +)) ;
}




}

< / script>

为什么缩放实现不工作?

解决方案

我使用您的代码,发现几个潜在问题:



根据你运行的位置/方式,加载flare.json文件可能会导致CORS错误(例如,如果你尝试链接到bostock的github上的一个)。你可以直接将json对象嵌入到'flare'变量中,然后将你在d3.json()方法中的代码移动到脚本的底部,并将根变量赋给flare。

  var flare = ...粘贴flare.json的内容here ...; 

您的JavaScript方法定义在一个顺序中,您可以在定义之前引用方法缩放和点击方法之前的更新方法):

  collapse(d){...} 
zoom {...}
click(){...}
update(){...}

您的缩放方法引用'h','w'和'm',它们不会在任何位置定义。我假设它们应该是宽度,高度和边距:

  var zoom = function(){
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -height * scale,
bbound = height * scale,
lbound = + margin.right)* scale,
rbound =(width-margin.left)* scale;

最后,要解决缩放问题,您应该修复缩放方法:

  var zoom = function(){
var scale = d3.event.scale,
translation = d3.event。 translate,
tbound = -height * scale,
bbound = height * scale,
lbound =(-width + margin.right)* scale,
rbound = .left)* scale;
//限制翻译为阈值
translation = [
Math.max(Math.min(translation [0],rbound),lbound),
Math.max min(translation [1],bbound),tbound)
];
svg.attr(transform,translate(+ translation +)+scale(+ scale +));请注意,我将select(。drawArea)替换为select(。drawArea) svg。因为你想转换最高的g元素(这是在svg变量)。



只是FYI - 我真的不能真正得到这个工作在plnkr或jsFiddle,因为有奇怪的d3错误,由于方法变量/函数范围在plnkr和jsFiddle中处理(参见这里)。这可能是别人可以解决的问题。但是这里的代码是完整的(减去嵌入的flare.json变量)。我在我自己的Tomcat容器中运行这个代码,并且可以双击树,它放大。你可能想要进行缩放和平移,以便树不绘制在可见性窗口的边界之外(现在如果你双击它会放大,但是,这个树的左侧是浏览器窗口的边)。

 <!DOCTYPE html> 
< meta charset =utf-8>
< style>

svg {pointer-events:all; }
.node {cursor:pointer; }
.node circle {
fill:#fff;
stroke:steelblue;
stroke-width:1.5px;
}
tree {pointer-events:all; }
.node text {font:12px sans-serif; }
.link {
fill:none;
stroke:#ccc;
stroke-width:1.5px;
}

< / style>
< body>
< script src =http://d3js.org/d3.v3.min.js>< / script>
< script>

var margin = {top:20,right:120,bottom:20,left:120},
width = 1500 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;

var i = 0,
duration = 750,
root;

var tree = d3.layout.tree()
.size([height,width]);

var diagonal = d3.svg.diagonal()
.projection(function(d){return [d.y,d.x];});

var svg = d3.select(body)append(svg)
.attr(width,width + margin.right + margin.left)
.attr(height,height + margin.top + margin.bottom)
.append(g)
.attr(transform,translate(+ margin.left + ,+ margin.top +))

d3.select(self.frameElement).style(height,800px);

var collapse = function(d){
if(d.children){
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}

var zoom = function(){
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -height * scale,
bbound = height * scale,
lbound =(-width + margin.right)* scale,
rbound =(width - margin.left )* scale;
//限制翻译为阈值
translation = [
Math.max(Math.min(translation [0],rbound),lbound),
Math.max min(translation [1],bbound),tbound)
];
svg.attr(transform,translate(+ translation +)+scale(+ scale +));
}

//点击切换子项。
var click = function(d){
if(d.children){
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
};

var update = function(source){
//计算新的树布局。
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);

//规范化固定深度。
nodes.forEach(function(d){d.y = d.depth * 180;});

//更新节点...
var node = svg.selectAll(g.node)
.data(nodes,function(d){return d.id | |(d.id = ++ i);});

//在父级的上一个位置输入任何新节点。
var nodeEnter = node.enter()。append(g)
.attr(class,node)
.attr returntranslate(+ source.y0 +,+ source.x0 +);})
.on(click,click);

nodeEnter.append(circle)
.attr(r,1e-6)
.style(fill,function(d){return d。 _children?lightsteelblue:#fff;});

nodeEnter.append(text)
.attr(x,function(d){return d.children || d._children?-10:10;})
.attr(dy,.35em)
.attr(text-anchor,function(d){return d.children || d._children?end:start ;})
.text(function(d){return d.name;})
.style(fill-opacity,1e-6);

//将节点转换到新位置。
var nodeUpdate = node.transition()
.duration(duration)
.attr(transform,function(d){returntranslate(+ dy +,+ dx +);});

nodeUpdate.select(circle)
.attr(r,4.5)
.style(fill,function(d){return d._children? lightsteelblue:#fff;});

nodeUpdate.select(text)
.style(fill-opacity,1);

//将退出节点的节点转换到父节点的新位置。
var nodeExit = node.exit()。transition()
.duration(duration)
.attr(transform,function(d){returntranslate +,+ source.x +);})
.remove();

nodeExit.select(circle)
.attr(r,1e-6);

nodeExit.select(text)
.style(fill-opacity,1e-6);

//更新链接...
var link = svg.selectAll(path.link)
.data(links,function(d){return d.target。 ID; });

//在父级的上一个位置输入任何新的链接。
link.enter()。insert(path,g)
.attr(class,link)
.attr(d {
var o = {x:source.x0,y:source.y0};
return diagonal({source:o,target:o});
}

//转换链接到他们的新位置。
link.transition()
.duration(duration)
.attr(d,diagonal);

//将退出节点的节点转移到父节点的新位置。
link.exit()transition()
.duration(duration)
.attr(d,function(d){
var o = {x:source。 x,y:source.y};
return diagonal({source:o,target:o});
})
.remove();

//存储转换的旧位置。
nodes.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});

d3.select(svg)
.call(d3.behavior.zoom()
.scaleExtent([0.5,5])
.on zoom,zoom));
};

d3.json(flare.json,function(json){
root = json;
root.x0 = height / 2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
});

< / script>


I am trying to add a zooming feature to the d3 collapsible tree example, but can't get it to work. I know there's been a question about this here and even though it seems rather thorough my changes don't work. The only thing I get is a white page. Probably has to do with the fact that I'm rather new with javascript/d3. Here is my code.

<!DOCTYPE html>
<meta charset="utf-8">
<style>

svg {
    pointer-events: all;
}

.node {
  cursor: pointer;
}

.node circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 1.5px;
}

tree {
pointer-events: all;
}

.node text {
  font: 12px sans-serif;
}

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 1.5px;
}



</style>
<body>
<script src="d3.v3.min.js"></script>
<script>

var margin = {top: 20, right: 120, bottom: 20, left: 120},
    width = 1500 - margin.right - margin.left,
    height = 800 - margin.top - margin.bottom;

var i = 0,
    duration = 750,
    root;

var tree = d3.layout.tree()
    .size([height, width]);

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

d3.json("flare.json", function(error, flare) {
  root = flare;
  root.x0 = height / 2;
  root.y0 = 0;

  function collapse(d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }

  root.children.forEach(collapse);
  update(root);
});

d3.select(self.frameElement).style("height", "800px");

function update(source) {

  // Compute the new tree layout.
  var nodes = tree.nodes(root).reverse(),
      links = tree.links(nodes);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) { d.y = d.depth * 180; });

  // Update the nodes…
  var node = svg.selectAll("g.node")
      .data(nodes, function(d) { return d.id || (d.id = ++i); });

  // Enter any new nodes at the parent's previous position.
  var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
      .on("click", click);

  nodeEnter.append("circle")
      .attr("r", 1e-6)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeEnter.append("text")
      .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
      .attr("dy", ".35em")
      .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
      .text(function(d) { return d.name; })
      .style("fill-opacity", 1e-6);

  // Transition nodes to their new position.
  var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

  nodeUpdate.select("circle")
      .attr("r", 4.5)
      .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

  nodeUpdate.select("text")
      .style("fill-opacity", 1);

  // Transition exiting nodes to the parent's new position.
  var nodeExit = node.exit().transition()
      .duration(duration)
      .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
      .remove();

  nodeExit.select("circle")
      .attr("r", 1e-6);

  nodeExit.select("text")
      .style("fill-opacity", 1e-6);

  // Update the links…
  var link = svg.selectAll("path.link")
      .data(links, function(d) { return d.target.id; });

  // Enter any new links at the parent's previous position.
  link.enter().insert("path", "g")
      .attr("class", "link")
      .attr("d", function(d) {
        var o = {x: source.x0, y: source.y0};
        return diagonal({source: o, target: o});
      });

  // Transition links to their new position.
  link.transition()
      .duration(duration)
      .attr("d", diagonal);

  // Transition exiting nodes to the parent's new position.
  link.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {x: source.x, y: source.y};
        return diagonal({source: o, target: o});
      })
      .remove();

  // Stash the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });

    d3.select("svg")
    .call(d3.behavior.zoom()
          .scaleExtent([0.5, 5])
          .on("zoom", zoom));


}

// Toggle children on click.
function click(d) {
  if (d.children) {
    d._children = d.children;
    d.children = null;
  } else {
    d.children = d._children;
    d._children = null;
  }
  update(d);


function zoom() {
    var scale = d3.event.scale,
        translation = d3.event.translate,
        tbound = -h * scale,
        bbound = h * scale,
        lbound = (-w + m[1]) * scale,
        rbound = (w - m[3]) * scale;
    // limit translation to thresholds
    translation = [
        Math.max(Math.min(translation[0], rbound), lbound),
        Math.max(Math.min(translation[1], bbound), tbound)
    ];
    d3.select(".drawarea")
        .attr("transform", "translate(" + translation + ")" +
              " scale(" + scale + ")");
}




}

</script>

Why does the zoom implementation not work?

解决方案

I played with your code a bit and found several potential issues:

Depending on where/how you are running this, loading the flare.json file could cause a CORS error (eg. if you try to link to the one on bostock's github). You can embed the json object directly in a 'flare' variable and then just move the code you have in the d3.json() method to the bottom of the script and assign the root variable to flare.

var flare =  ...paste contents of flare.json here... ;

Your javascript methods are defined in an order where you reference methods before they are defined (you should move the zoom and click methods before the update method):

collapse(d){...}
zoom(){...}
click(){...}
update(){...}

Your zoom method references 'h', 'w', and 'm', which aren't defined anywhere. I assume they are supposed to be width, height, and margin:

var zoom = function() {
    var scale = d3.event.scale,
        translation = d3.event.translate,
        tbound = -height * scale,
        bbound = height * scale,
        lbound = (-width + margin.right) * scale,
        rbound = (width - margin.left) * scale;

Finally, to fix the zoom thing, you should fix the zoom method like so:

var zoom = function() {
    var scale = d3.event.scale,
        translation = d3.event.translate,
        tbound = -height * scale,
        bbound = height * scale,
        lbound = (-width + margin.right) * scale,
        rbound = (width - margin.left) * scale;
    // limit translation to thresholds
    translation = [
        Math.max(Math.min(translation[0], rbound), lbound),
        Math.max(Math.min(translation[1], bbound), tbound)
    ];
    svg.attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")");
}

Note that I replaced the "select(".drawArea")" with "svg." because you want to transform the top g element (which is what is in the "svg" variable).

Just FYI - I couldn't really get this working in plnkr or jsFiddle because there are weird d3 errors due to the way variables/function scope are handled in plnkr and jsFiddle (see here). That may be an issue someone else can work out. But here's the code in it's entirety (minus the embedded flare.json variable). I ran this code in my own Tomcat container and can double click on the tree and it zooms in. You may want to play around with zooming and panning so that the tree doesn't draw outside of the boundaries of the visibile window (right now if you double click it will zoom, but recenter, so the left side of the tree is off the side of the browser window).

<!DOCTYPE html>
<meta charset="utf-8">
<style>

svg {  pointer-events: all;  }
.node { cursor: pointer;  }
.node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 1.5px;
}
tree {  pointer-events: all;  }
.node text {  font: 12px sans-serif;  }
.link {
    fill: none;
    stroke: #ccc;
    stroke-width: 1.5px;
}

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var margin = {top: 20, right: 120, bottom: 20, left: 120},
    width = 1500 - margin.right - margin.left,
    height = 800 - margin.top - margin.bottom;

var i = 0,
    duration = 750,
    root;

var tree = d3.layout.tree()
    .size([height, width]);

var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

d3.select(self.frameElement).style("height", "800px");

var collapse = function(d) {
    if (d.children) {
        d._children = d.children;
        d._children.forEach(collapse);
        d.children = null;
    }
}

var zoom = function() {
    var scale = d3.event.scale,
        translation = d3.event.translate,
        tbound = -height * scale,
        bbound = height * scale,
        lbound = (-width + margin.right) * scale,
        rbound = (width - margin.left) * scale;
    // limit translation to thresholds
    translation = [
        Math.max(Math.min(translation[0], rbound), lbound),
        Math.max(Math.min(translation[1], bbound), tbound)
    ];
    svg.attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")");
}

// Toggle children on click.
var click = function(d) {
    if (d.children) {
        d._children = d.children;
        d.children = null;
    } else {
        d.children = d._children;
        d._children = null;
    }
    update(d);
};

var update = function(source) {
    // Compute the new tree layout.
    var nodes = tree.nodes(root).reverse(),
        links = tree.links(nodes);

    // Normalize for fixed-depth.
    nodes.forEach(function(d) { d.y = d.depth * 180; });

    // Update the nodes…
    var node = svg.selectAll("g.node")
        .data(nodes, function(d) { return d.id || (d.id = ++i); });

    // Enter any new nodes at the parent's previous position.
    var nodeEnter = node.enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
        .on("click", click);

    nodeEnter.append("circle")
        .attr("r", 1e-6)
        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

    nodeEnter.append("text")
        .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
        .attr("dy", ".35em")
        .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
        .text(function(d) { return d.name; })
        .style("fill-opacity", 1e-6);

    // Transition nodes to their new position.
    var nodeUpdate = node.transition()
        .duration(duration)
        .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

    nodeUpdate.select("circle")
        .attr("r", 4.5)
        .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });

    nodeUpdate.select("text")
        .style("fill-opacity", 1);

    // Transition exiting nodes to the parent's new position.
    var nodeExit = node.exit().transition()
        .duration(duration)
        .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
        .remove();

    nodeExit.select("circle")
        .attr("r", 1e-6);

    nodeExit.select("text")
        .style("fill-opacity", 1e-6);

    // Update the links…
    var link = svg.selectAll("path.link")
        .data(links, function(d) { return d.target.id; });

    // Enter any new links at the parent's previous position.
    link.enter().insert("path", "g")
        .attr("class", "link")
        .attr("d", function(d) {
            var o = {x: source.x0, y: source.y0};
            return diagonal({source: o, target: o});
         });

    // Transition links to their new position.
    link.transition()
        .duration(duration)
        .attr("d", diagonal);

    // Transition exiting nodes to the parent's new position.
    link.exit().transition()
        .duration(duration)
        .attr("d", function(d) {
            var o = {x: source.x, y: source.y};
            return diagonal({source: o, target: o});
         })
        .remove();

    // Stash the old positions for transition.
    nodes.forEach(function(d) {
        d.x0 = d.x;
        d.y0 = d.y;
    });

    d3.select("svg")
        .call(d3.behavior.zoom()
        .scaleExtent([0.5, 5])
        .on("zoom", zoom));
};

d3.json("flare.json", function(json){
    root = json;
    root.x0 = height / 2;
    root.y0 = 0;
    root.children.forEach(collapse);
    update(root);
});

</script>

这篇关于我如何添加缩放到d3可折叠树示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆