Sorvah
Sorvah

Reputation: 333

Make D3 Stacked Bar Chart fill parent SVG container

I have a D3 stacked bar chart component and I am trying to make it fill the available space in the parent SVG. This will allow me to resize the chart with HTML rather than having to manually input sizes.

Currently my sizes are hard coded and I have no idea how to change this to a more responsive format.

Here is the relevant component code slice:

let data = this.get('data')
    let div = select('body')
      .append("div")
      .attr("class", "stack-tooltip")
    let series = stack()
      .keys(["count1", "count2", "count3"])
      .offset(stackOffsetDiverging)
      (data);

    let svg = select(this.$('svg')[0]),
      margin = {
        top: 20,
        right: 30,
        bottom: 30,
        left: 60
      },
      width = +svg.attr("width"),
      height = +svg.attr("height");

    let x = scaleBand()
      .domain(data.map(function(d) {
        return d.label;
      }))
      .rangeRound([margin.left, width - margin.right])
      .padding(0.1);

    let y = scaleLinear()
      .domain([min(series, stackMin), max(series, stackMax)])
      .rangeRound([height - margin.bottom, margin.top]);

    let z = scaleOrdinal().range(['#DAEAF1', '#99CFE0', '#72BCD4']);

    svg.append("g")
      .selectAll("g")
      .data(series)
      .enter().append("g")
      .attr("fill", function(d) {
        return z(d.key);
      })
      .selectAll("rect")
      .data(function(d) {
        return d;
      })
      .enter().append("rect")
      .attr("width", x.bandwidth)
      .attr("x", function(d) {
        return x(d.data.label);
      })
      .attr("y", function(d) {
        return y(d[1]);
      })
      .attr("height", function(d) {
        return y(d[0]) - y(d[1]);
      })
      .attr('opacity', d => {
        let selected = this.get('selectedLabel');
        return (selected && d.data.label !== selected) ? '0.5' : '1.0';
      })

  function stackMin(h) {
      return min(h, function(d) {
        return d[0];
      });
    }

    function stackMax(h) {
      return max(h, function(d) {
        return d[1];
      });
    }

I did try to change the rangeRound values to a percentage on both the 'X' and 'Y' functions but I was unable to render the bars of the chart when trying to change the values in the X and Y attributes to template literals.

The SVG in the component template is created with a simple <svg width='800' height="300"></svg>

Any help is greatly appreciated

Upvotes: 1

Views: 555

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101800

If you want it to scale to its parent container, you'll need to give the SVG a viewBox, instead of a width and height.

The viewBox tells the browser which area of the SVG coordinate space, the contents occupy. That way it knows how to scale the contents.

Upvotes: 1

Related Questions