当兄弟元素的转换结束时附加另一个元素

时间:2016-04-06 11:20:17

标签: d3.js

我有一个条形图,我使用过渡来设置矩形元素的高度,如下所示:

//Create a layer for each category of data that exists, as per dataPointLegend values
//e.g. DOM will render <g class="successful"><g>
layers = svg.selectAll('g.layer')
    .data(stacked, function(d) {
        return d.dataPointLegend;
    })
    .enter()
    .append('g')
    .attr('class', function(d) {
        return d.dataPointLegend;
    })
    //transform below is used to shift the entire layer up by one pixel to allow
    //x-axis to appear clearly, otherwise bars inside layer appear over the top.
    .attr('transform', 'translate(0,-1)');

//Create a layer for each datapoint object
//DOM will render <g class="successful"><g></g><g>
barLayers = layers.selectAll('g.layer')
    .data(function(d) {
        return d.dataPointValues;
    })
    .enter()
    .append('g');

//Create rect elements inside each of our data point layers
//DOM will render <g class="successful"><g><rect></rect></g></g>
barLayers
    .append('rect')
    .attr('x', function(d) {
        return x(d.pointKey);
    })
    .attr('width', x.rangeBand())
    .attr('y', height - margin.bottom - margin.top)
    .attr('height', 0)
    .transition()
    .delay(function(d, i) {
        return i * transitionDelayMs;
    })
    .duration(transitionDurationMs)
    .attr('y', function(d) {
        return y(d.y0 + d.pointValue);
    })
    .attr('height', function(d) {
        return height - margin.bottom - margin.top - y(d.pointValue)
    });

然后我有一个用于附加文本元素的进一步选择

//Render any point labels if present
//DOM will render <g><g><rect></rect><text></text></g></g>
if (width > miniChartWidth) {
    barLayers
        .append('text')
        .text(function(d) {
            return d.pointLabel
        })
        .attr('x', function(d) {
            return x(d.pointKey) + x.rangeBand() / 2;
        })
        .attr('y', function(d) {
            var textHeight = d3.select(this).node().getBoundingClientRect().height;
            //Position the text so it appears below the top edge of the corresponding data bar
            return y(d.y0 + d.pointValue) + textHeight;
        })
        .attr('class', 'data-value')
        .attr('fill-opacity', 0)
        .transition()
        .delay(function(d, i) {
            return i * transitionDelayMs + transitionDurationMs;
        })
        .duration(transitionDurationMs)
        .attr('fill-opacity', 1);
}

在所有rects完成高度增长之后,这很好地淡化了文本元素。我想知道的是,当每个柱完成其过渡时,是否可以将文本元素附加到相应的图层?

我已经看到了这个问题的答案 - Show text only after transition is complete d3.js

这看起来与我所追求的一致,我尝试在我的矩形渲染周期中添加.each('end',...),如此

.each('end', function(d){
    barLayers
        .append('text')
        .text(function() {
            return d.pointLabel
        })
        .attr('x', function() {
            return x(d.pointKey) + x.rangeBand() / 2;
        })
        .attr('y', function() {
            var textHeight = d3.select(this).node().getBoundingClientRect().height;
            //Position the text so it appears below the top edge of the corresponding data bar
            return y(d.y0 + d.pointValue) + textHeight;
        })
        .attr('class', 'data-value')
        .attr('fill-opacity', 0)
        .transition()
        .delay(function(d, i) {
            return i * transitionDelayMs + transitionDurationMs;
        })
        .duration(transitionDurationMs)
        .attr('fill-opacity', 1);

});

但是,对于我的每个text,我的每个数据点只保留一个g,我最终会得到很多rect元素。

我觉得我很亲密,但需要你聪明人的帮助:)

由于

1 个答案:

答案 0 :(得分:1)

whateverTheSelectionIs    
.each('end', function(d){
        barLayers
            .append('text')

.each分别针对您选择中的每个元素运行,并在每个元素内部向每个barLayer(barLayers)添加文本元素。所以你将得到一个(barLayers.size()* selection.size())数量的文本元素整体添加。您需要在右侧栏中添加一个文本元素/ g。

以下是可能有效的软糖。这很棘手,因为你要添加的文本是调用.each函数的选择中的reces的兄弟...,d3.select(this.parentNode)应该将你移动到rect的父级,这将是正确的barLayer。

whateverTheSelectionIs    
.each('end', function(d,i){
        d3.select(this.parentNode)
            .append('text')