【问题标题】:How to rearrange the DOM order of svg elements based on their data values in a dynamically changing d3 vis?如何根据动态变化的 d3 vis 中的数据值重新排列 svg 元素的 DOM 顺序?
【发布时间】:2019-08-31 13:16:45
【问题描述】:

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

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

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

【问题讨论】:

  • 在 svg 中,您可能想要使用 appendChild 而不是使用 z-index,就像您在这个 codepen 示例中看到的那样:SVG z-index a pen by Blake Bowen

标签: javascript d3.js dom svg


【解决方案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 中。请记住,首先绘制的元素可能会被稍后绘制的元素覆盖 - 选择中的第一个意味着可能位于所有内容的下方。


如果我们有这样的东西,重叠条是根据数据数组的顺序顺序绘制的:

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>

我们可以拉起小条,例如,通过排序和顺序提高可见性:

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 和答案与您的示例有很多相似之处:在转换条形长度和条形顺序时使用排序和排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2016-07-26
    • 2014-07-25
    • 2014-12-24
    • 2021-11-04
    相关资源
    最近更新 更多