score:5

Accepted answer

I had the same issue a few days ago. The way I did it is as follows:

We have two .join, the parent one is for the stack and the child is for the rectangles.

In the enter of the parent join, we call the updateRects in order to draw the rectangles for the first time, this updateRects function will do the child .join, this second join function will draw the rectangles.

For the update we do the same, but instead of doing it in the enter function of the join, we do it in the update.

Also, my SVG is structured in a different way, I have a stacks groups, then I have the stack group, and a bars group, in this bars group I add the rectangles. In the fiddle below, you can see that I added the parent group with the class stack.

The two functions are below:

updateStack:

  function updateStack(data) {
    // update the y scale
    y.domain([0, d3.max(data.map((d) => d.sum))]);
    g.select(".y").transition().duration(1000).call(yAxis);

    const stackData = stack(data);

    stackData.forEach((stackedBar) => {
      stackedBar.forEach((stack) => {
        stack.id = `${stackedBar.key}-${stack.data.year}`;
      });
    });

    let bars = g
      .selectAll("g.stacks")
      .selectAll(".stack")
      .data(stackData, (d) => {
        return d.key;
      });

    bars.join(
      (enter) => {
        const barsEnter = enter.append("g").attr("class", "stack");

        barsEnter
          .append("g")
          .attr("class", "bars")
          .attr("fill", (d) => {
            return color(d.key);
          });

        updateRects(barsEnter.select(".bars"));

        return enter;
      },
      (update) => {
        const barsUpdate = update.select(".bars");
        updateRects(barsUpdate);
      },
      (exit) => {
        return exit.remove();
      }
    );
  }

updateRects:

  function updateRects(childRects) {
    childRects
      .selectAll("rect")
      .data(
        (d) => d,
        (d) => d.id
      )
      .join(
        (enter) =>
          enter
            .append("rect")
            .attr("id", (d) => d.id)
            .attr("class", "bar")
            .attr("x", (d) => x(d.data.year))
            .attr("y", y(0))
            .attr("width", x.bandwidth())
            .call((enter) =>
              enter
                .transition()
                .duration(1000)
                .attr("y", (d) => y(d[1]))
                .attr("height", (d) => y(d[0]) - y(d[1]))
            ),
        (update) =>
          update.call((update) =>
            update
              .transition()
              .duration(1000)
              .attr("y", (d) => y(d[1]))
              .attr("height", (d) => y(d[0]) - y(d[1]))
          ),
        (exit) =>
          exit.call((exit) =>
            exit
              .transition()
              .duration(1000)
              .attr("y", height)
              .attr("height", height)
          )
      );
  }

Here is an update jsfiddle https://jsfiddle.net/5oqwLxdj/1/

I hope it helps.

score:0

It is getting called, but you can't see it. Try changing .attr(d => console.log('update stack')) to .attr(console.log('update stack')).


Related Query

More Query from same tag