Javascript d3.js树状图:将新旧属性绑定到svg元素

Javascript d3.js树状图:将新旧属性绑定到svg元素,javascript,d3.js,properties,dendrogram,Javascript,D3.js,Properties,Dendrogram,我对d3的理解目前相当有限,我正在处理d3.js的树状图示例。它可以在几个地方找到: 例如,在美国 当我实现它时,一切都很顺利,直到你尝试更新一个属性,比如节点的圆直径。如果我这样做(使用像AngularJS这样的交互式框架来观察参数的变化):节点的大小会发生变化。所以还没问题。但是,如果单击其中一个节点,则大小将重置为初始化大小,而不是新的大小 单击节点时,请执行单击功能: var nodeEnter = node.enter().append("g")

我对d3的理解目前相当有限,我正在处理d3.js的树状图示例。它可以在几个地方找到: 例如,在美国

当我实现它时,一切都很顺利,直到你尝试更新一个属性,比如节点的圆直径。如果我这样做(使用像AngularJS这样的交互式框架来观察参数的变化):节点的大小会发生变化。所以还没问题。但是,如果单击其中一个节点,则大小将重置为初始化大小,而不是新的大小

单击节点时,请执行单击功能:

 var nodeEnter = node.enter().append("g")
                        .attr("class", "dendrogramnode2")
                        .on("click", 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 update(source) {

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

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

  // 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 "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
      .on("click", click);

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

  nodeEnter.append("text")
      .attr("x", 10)
      .attr("dy", ".35em")
      .attr("text-anchor", "start")
      //.attr("transform", function(d) { return d.x < 180 ? "translate(0)" : "rotate(180)translate(-" + (d.name.length * 8.5)  + ")"; })
      .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 "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })

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

  nodeUpdate.select("text")
      .style("fill-opacity", 1)
      .attr("transform", function(d) { return d.x < 180 ? "translate(0)" : "rotate(180)translate(-" + (d.name.length + 50)  + ")"; });

  // TODO: appropriate transform
  var nodeExit = node.exit().transition()
      .duration(duration)
      //.attr("transform", function(d) { return "diagonal(" + 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;
  });
}
函数更新(源代码){
//计算新的树布局。
变量节点=树节点(根),
链接=树。链接(节点);
//为固定深度进行规格化。
forEach(函数(d){d.y=d.depth*80;});
//更新节点…
var node=svg.selectAll(“g.node”)
.data(节点,函数(d){返回d.id | |(d.id=++i)});
//在父节点的上一个位置输入任何新节点。
var nodeEnter=node.enter().append(“g”)
.attr(“类”、“节点”)
//.attr(“转换”,函数(d){return”旋转(“+(d.x-90)+”)平移(“+d.y+”);})
。开启(“点击”,点击);
nodeEnter.append(“圆”)
.attr(“r”,1e-6)
.style(“fill”,函数(d){return d._children?“lightsteelblue”:“fff”});
nodeEnter.append(“文本”)
.attr(“x”,10)
.attr(“dy”,“.35em”)
.attr(“文本锚定”、“开始”)
//.attr(“transform”,函数(d){returnd.x<180?“translate(0)”:“rotate(180)translate”(“+(d.name.length*8.5)+”);)
.text(函数(d){返回d.name;})
.样式(“填充不透明度”,1e-6);
//将节点转换到其新位置。
var nodeUpdate=node.transition()
.持续时间(持续时间)
.attr(“转换”,函数(d){return”旋转(“+(d.x-90)+”)平移(“+d.y+”);})
节点更新。选择(“圆圈”)
.attr(“r”,4.5)
.style(“fill”,函数(d){return d._children?“lightsteelblue”:“fff”});
nodeUpdate.select(“文本”)
.style(“填充不透明度”,1)
.attr(“transform”,函数(d){returnd.x<180?“translate(0)”:“rotate(180)translate”(“+(d.name.length+50)+”);”);
//TODO:适当的转换
var nodeExit=node.exit().transition()
.持续时间(持续时间)
//.attr(“转换”,函数(d){return”对角线(“+source.y+”,“+source.x+”);})
.remove();
nodeExit.select(“圆”)
.attr(“r”,1e-6);
nodeExit.select(“文本”)
.样式(“填充不透明度”,1e-6);
//更新链接…
var link=svg.selectAll(“path.link”)
.data(链接,函数(d){返回d.target.id;});
//在父对象的上一个位置输入任何新链接。
link.enter()插入(“路径”,“g”)
.attr(“类”、“链接”)
.attr(“d”,函数(d){
var o={x:source.x0,y:source.y0};
返回对角线({source:o,target:o});
});
//过渡链接到他们的新位置。
link.transition()
.持续时间(持续时间)
.attr(“d”,对角线);
//将退出节点转换到父节点的新位置。
link.exit().transition()
.持续时间(持续时间)
.attr(“d”,函数(d){
var o={x:source.x,y:source.y};
返回对角线({source:o,target:o});
})
.remove();
//将旧位置隐藏起来,以便过渡。
nodes.forEach(函数(d){
d、 x0=d.x;
d、 y0=d.y;
});
}
因此,此更新函数称为:

  • 初始化时-->无问题(例如:圆r=5)

  • 当参数更新-->无问题时,参数将更新。(示例:圆r=10)

  • 单击节点-->时,有问题的-->图形采用初始参数。(示例:圆r=5)

  • 所有这些可能都与作用域和javascript如何处理数据绑定有很大关系,但我不知道如何正确地做到这一点。我要么需要能够访问新的属性,而不是旧的属性

    有什么办法可以做到这一点吗

  • 调整代码,以便采用新参数而不是旧参数

  • 将参数作为对象绑定到svg组(可能效率不高?),因此 可以使用d3选择器从任何范围手动获取它吗


  • 我已经为DOM元素设置了一个属性,这些属性在每个数据中没有差异

                function dograph(p){
                    //paramater object is passed and it's name is "p"
                    d3.select(elementid).selectAll("svg")[0][0]["p"] = p
                    //at some point update function gets called as part of an event and p is no longer available. 
    
                    //someSvgElement
                            .on("mouseover"){update())}
    
                    function update(source) {
                        var p = d3.select(elementid).selectAll("svg")[0][0]["p"];
                        //stuff happens
                    }
                }
    

    可能不是完美的解决方案,但它对我很有效。

    将数据的半径部分绑定到圆上更像是D3。这也可以修复这个错误。非常好的评论拉尔斯。但是,在这种情况下,调整一个参数并不需要针对每个数据点进行更改,而是更像一个整体属性:a)在DOM中占用更多空间,B)在更改它时,您需要遍历数据,以便针对每个数据点对其进行更改。所以我认为有一种更有效的方法来处理“开销”属性?我不认为a是重要的,因为它只是一个单一的数字。我也不认为B会是一个问题,因为您可以简单地设置并使用该属性,而不是在您当前的代码中使用数字。如果您在angularjs中的数据上放置$watch,a将变得非常重要。至于B,是的,我就是这么做的,谢谢你的回答:)。