如何在动态变化的d3 vis中根据数据值重新排列svg元素的DOM顺序?

问题描述 投票:1回答:1

我有一个json数据集,我使用this example库以与d3.js类似的方式动态可视化。

但是,我希望将在图表中的位置改变到较低位置的柱子位于较高位置的“后面”。为此,我想基于数据设置z-index(具有低值的条具有较低的z-index,因此将位于具有较大值的条带之后)。不幸的是,SVG使用文档顺序作为z索引,这就是为什么每次图表更改时我都需要对文档内的条形图(示例中的chartRow变量)进行重新排序。

有没有办法实现这个目标?

javascript d3.js dom svg
1个回答
1
投票

重新排序DOM中的元素

要使用d3重新排序DOM中的元素,您可以使用selection.sortselection.order

// Sort & then order:
selection.sort(function(a,b) {
  return a.property - b.property; 
})
.order();

Selection.sort根据绑定数据对选择进行排序,ab各自表示绑定到单个元素的基准。生成的行为与Array.sort基本相同,但不是使用数组,而是使用绑定数据对选择中的元素进行排序。提供给selection.sort(比较函数)的函数内容决定了排序顺序:

比较函数默认为升序,传递两个元素的数据a和b进行比较。它应返回负值,正值或零值。如果是否定的,那么a应该在b之前;如果是肯定的,那么a应该在b之后;否则,a和b被认为是相等的,并且顺序是任意的。 (docs

一旦我们有一个排序选择,我们就可以应用selection.order(),它会根据选择的顺序将每个元素重新插入到DOM中。请记住,首先绘制的元素可以被稍后绘制的元素覆盖 - 首先在选择中可能包含在所有内容之下。


因此,如果我们有这样的东西,那么根据数据数组的顺序依次绘制重叠条:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);


// Order the bars:
bars.sort(function(a,b) {
  return b.value - a.value;
}).order();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

比方说,我们可以拉起小条,以便通过排序和订单获得更高的可视性:

enter image description here

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1);

  
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

根据订单重新定位

如上所示,这不会重置每个条的x或y属性以反映z上的排序(如示例中所示)。在我上面的基本示例中,我们可以基于i重置x值(这可以通过重新缩放来完成,但足以成为单独的问题和答案):

var bars = [
  {value: 100},
  {value: 50},
  {value: 200},
  {value: 70},
  {value: 40},
  {value: 120}
];

var height = 200;
var width = 500;

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

var bars = svg.selectAll("rect")
  .data(bars)
  .enter()
  .append("rect")
  .attr("width", 45)
  .attr("height", function(d) { return d.value; })
  .attr("y", function(d) { return height-d.value; })
  .attr("x", function(d,i) { return i * 30 + 50; })
  .attr("fill", function(d,i){ return d3.schemeCategory10[i]; })
  .attr("stroke","black")
  .attr("stroke-width",1)
  
bars = bars.sort(function(a,b) {
  return a.value - b.value;
}).order();

bars.transition()
  .attr("x", function(d,i) { return i * 30 + 50; })
  .delay(500)
  .duration(2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

另请参阅:此question和答案与您拥有的示例有很多相似之处:在转换条形和条形顺序的长度时使用排序和排序。

© www.soinside.com 2019 - 2024. All rights reserved.