我有一个json数据集,我使用this example库以与d3.js
类似的方式动态可视化。
但是,我希望将在图表中的位置改变到较低位置的柱子位于较高位置的“后面”。为此,我想基于数据设置z-index(具有低值的条具有较低的z-index,因此将位于具有较大值的条带之后)。不幸的是,SVG使用文档顺序作为z索引,这就是为什么每次图表更改时我都需要对文档内的条形图(示例中的chartRow
变量)进行重新排序。
有没有办法实现这个目标?
重新排序DOM中的元素
要使用d3重新排序DOM中的元素,您可以使用selection.sort和selection.order:
// Sort & then order:
selection.sort(function(a,b) {
return a.property - b.property;
})
.order();
Selection.sort根据绑定数据对选择进行排序,a
和b
各自表示绑定到单个元素的基准。生成的行为与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和答案与您拥有的示例有很多相似之处:在转换条形和条形顺序的长度时使用排序和排序。