简体   繁体   中英

D3 horizontal bar chart will not transition to new dataset

I'm working on a d3.js horizontal bar graph ( http://bl.ocks.org/juan-cb/ab9a30d0e2ace0d2dc8c ) which updates/transitions based on user selections. Currently, I have added labels to the graph but it is not updating anymore. Not sure where the issue is. The bars should start from the left side but have moved to the right for some reason as well. To add labels to the bars, I added "g" elements to hold both the rect and the text. Any help will be appreciated.

JsFiddle - https://jsfiddle.net/fewpwqhd/1/

JS

datasetTotal = [{
    label: "Category 1",
    value: 19
}, {
    label: "Category 2",
    value: 5
}, {
    label: "Category 3",
    value: 13
}, {
    label: "Category 4",
    value: 17
}, {
    label: "Category 5",
    value: 21
}, {
    label: "Category 6",
    value: 25
}];

datasetOption1 = [{
    label: "Category 1",
    value: 22
}, {
    label: "Category 2",
    value: 33
}, {
    label: "Category 3",
    value: 4
}, {
    label: "Category 4",
    value: 15
}, {
    label: "Category 5",
    value: 36
}, {
    label: "Category 6",
    value: 0
}];

datasetOption2 = [{
    label: "Category 1",
    value: 10
}, {
    label: "Category 2",
    value: 20
}, {
    label: "Category 3",
    value: 30
}, {
    label: "Category 4",
    value: 5
}, {
    label: "Category 5",
    value: 12
}, {
    label: "Category 6",
    value: 23
}];

d3.selectAll("input").on("change", selectDataset);

function selectDataset() {
    var value = this.value;
    if (value == "total") {
        change(datasetTotal);
    } else if (value == "option1") {
        change(datasetOption1);
    } else if (value == "option2") {
        change(datasetOption2);
    }
}

var margin = {
        top: (parseInt(d3.select('body').style('height'), 10) / 20),
        right: (parseInt(d3.select('body').style('width'), 10) / 20),
        bottom: (parseInt(d3.select('body').style('height'), 10) / 20),
        left: (parseInt(d3.select('body').style('width'), 10) / 5)
    },
    width = parseInt(d3.select('body').style('width'), 10) - margin.left - margin.right,
    height = parseInt(d3.select('body').style('height'), 10) - margin.top - margin.bottom;

var div = d3.select("body").append("div").attr("class", "toolTip");

var formatPercent = d3.format("");

var y = d3.scale.ordinal()
    .rangeRoundBands([height, 0], .2, 0.5);

var x = d3.scale.linear()
    .range([0, width]);

var xAxis = d3.svg.axis()
    .scale(x)
    .tickSize(-height)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
//.tickFormat(formatPercent);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

d3.select("input[value=\"total\"]").property("checked", true);
change(datasetTotal);

function change(dataset) {

    y.domain(dataset.map(function(d) {
        return d.label;
    }));
    x.domain([0, d3.max(dataset, function(d) {
        return d.value;
    })]);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.select(".y.axis").remove();
    svg.select(".x.axis").remove();

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(0)")
        .attr("x", 50)
        .attr("dx", ".1em")
        .style("text-anchor", "end")
        .text("Option %");


    var bar = svg.selectAll(".bar")
        .data(dataset, function(d) {
            return d.label;
        })
        // new data:
        .enter().append("g");

    bar.append("rect")
        .attr("class", "bar")
        .attr("x", function(d) {
            return x(d.value);
        })
        .attr("y", function(d) {
            return y(d.label);
        })
        .attr("width", function(d) {
            return width - x(d.value);
        })
        .attr("height", y.rangeBand());

    bar.append("text")
        .attr("x", function(d) {
            return x(d.value) - 3;
        })
        .attr("text-anchor", "end")
        .attr("y", function(d) {
            return y(d.label) + y.rangeBand() / 2;
        })
        .attr("dy", ".35em")
        .text(function(d) {
            return d.value;
        });


    var bars = d3.select("svg").selectAll("g.rects").data(dataset);

    // removed data:
    bars.exit().remove();

    // updated data:
    bars.transition()
        .duration(750)
        .attr("x", function(d) {
            return 0;
        })
        .attr("y", function(d) {
            return y(d.label);
        })
        .attr("width", function(d) {
            return x(d.value);
        })
        .attr("height", y.rangeBand());

};

Here is my suggestion: since you're appending both rectangles and texts elements to the <g> (groups), your enter-update-exit pattern should apply to the groups, not to the rectangles and texts:

var bar = svg.selectAll(".bar")
    .data(dataset, function(d) {
        return d.label;
    });

var barExit = bar.exit().remove();

var barEnter = bar.enter()
    .append("g")
    .attr("class", "bar");

In fact, as your datasets always have 6 categories, you don't even need all this (the code could be substantially shorter).

Here is your updated fiddle: https://jsfiddle.net/2523onr3/

PS I took the liberty to make the bars growing from left to right , not from right to left. If that's incorrect, just change the x and width attributes.

I'd be interested in the pros and cons versus this approach?

https://jsfiddle.net/sjp700/2523onr3/2/

bar = svg.selectAll(".bar")
              .data(dataset)

        bar_g = bar.enter()
              .append("g")
              .attr("class", "bar")
             .transition()
              .attr("transform", function (d) { return "translate(" + x(0) + "," + y(d.label) + ")"; });

        svg.selectAll(".bar")
             .append("rect")
             .attr("class", "rectband");

        svg.selectAll(".bar")
            .append("text")
            .attr("class", "textband");

        bar.selectAll(".textband")
          .attr("transform", function (d) { return "translate(" + x(d.value) + "," + 0 + ")"; })
          .attr("y", 30)
          .attr("dy", ".35em")
          .style("fill", "black")
          .text(function (d) { return d.value; });

        bar.selectAll(".rectband")
          .attr("width", function (d) { return x(d.value); })
          .attr("height", y.rangeBand());       

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