简体   繁体   中英

How to update & transition ordinalScale axis in d3 v4

I thought I'd learn a little about ES6 classes while doing some d3 work, and so I made an ordinal bar chart class ( fiddle here ). It displays multiple series of data (eg:

[
    [{"label":"apple", "value" :25},
    {"label":"orange", "value": 16},
    {"label":"pear", "value":19}],

    [{"label":"banana", "value" :12},
    {"label":"grape", "value": 6},
    {"label":"peach", "value":5}]
];

I'm trying to get the update part working (where you provide new data and the bars/axis transition nicely). Unfortunately much of the example code is for v3, which doesn't seem to work with v4 like I'm using. The specific method is:

updateData(data){
    //get an array of the ordinal labels out of the data
    let labels = function(data){
        let result = [];
        for(let i=0; i<data.length; i++){
            for (let j=0; j<data[i].length; j++){
                result.push(data[i][j].label);
            }
        }
        return result;
    }(data);

    //loop through the (potentially multiple) series in the data array
    for(let i=0; i<data.length; i++){
        let series = data[i],
            bars = this.svg.selectAll(".series" + i)
        bars
            .data(series)
          .enter().append("rect")
            .attr("class", ("series" + i))
            .classed("bar", true)
          .merge(bars) 
            .attr("x", 0)
            .attr("height", this.y.bandwidth())
            .attr("y", (d) => { return this.y(d.label); })
            .transition().duration(500) //grow bars horizontally on load
            .attr("width", (d) => { return this.x(d.value); });
        bars.exit().remove();
    }

    //update domain with new labels
    this.y.domain(labels);
    //change the y axis
    this.svg.select(".yaxis")
        .transition().duration(500)
        .call(this.yAxis)
}

I'm trying to base the update pattern on Mike Bostock's code .

I'm getting an internal d3 error from the .call(this.yAxis) , the transition doesn't animate, and the yaxis doesn't update. Additionally, the bars don't transition either. What's going wrong?

Several problems:

  • Update a scaleOrdinal/scaleBand axis BEFORE updating data join, otherwise the bars won't be able to find their y scale attribute (y(d.yourOrdinalLabel) . The axis code hence needs to go before the bars code.
  • bars (or whatever element you join to the data) should be declared as the result of that join operation, so that it can be chained with .attr() for the visual attributes. let bars = svg.selectAll(".yourClass").data(yourData);
  • It's more sensible to have a simple update method in the class if you're only going to be toggling exclusion of existing data series, not adding new data. See updated fiddle.

Working jsfiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM