Y axis line is flickering using D3

209 views Asked by At

I'm trying to create a running line chart where it animates changes and the X and Y axis and the line itself.

I've started with the basic animation explanation at: https://observablehq.com/@d3/learn-d3-animation?collection=@d3/learn-d3

And created my own (see code and link below)

My problem is that as soon as I add the await chartBug.update the Y axis starts flickering. See animated gif below:

I think I need the await, to wait for the animation to complete before I start the next animation, and control the smooth speed of the animation.

While I'm here I would like also to ask how can I force the axis to draw the start and end ticks.

Thanks for the help

Here's a link to the page on www.observablehq.com

Here's the Animated gif of the problem - the source code is below: Animated gif showing my problem

chartBug = {
  const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

  const zx = x.copy(); // x, but with a new domain.
  const zy = y.copy(); // x, but with a new domain.

  const line = d3
    .line()
    .x(d => zx(d.date))
    .y(d => y(d.close));

  const path = svg
    .append("path")
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 1.5)
    .attr("stroke-miterlimit", 1)
    .attr("d", line(data));

  const gx = svg.append("g").call(xAxis, zx);

  const gy = svg.append("g").call(yAxis, y);

  return Object.assign(svg.node(), {
    update(step) {
      const partialData = [];
      for (let i = 0; i < step; i++) {
        partialData.push(data[i]);
      }
      const t = svg.transition().duration(50);
      zx.domain(d3.extent(partialData, d => d.date));
      gx.transition(t).call(xAxis, zx);

      zy.domain([0, d3.max(partialData, d => d.close)]);
      gy.transition(t).call(yAxis, zy);

      path.transition(t).attr("d", line(data));
      return t.end();
    }
  });
}
{
  replay2;
  for (let i = 0, n = data.length; i < n; ++i) {
    await chartBug.update(i);
    yield i;
  }
}
1

There are 1 answers

0
calmar On BEST ANSWER

the issue seems to be on your yAxis function, every new update and rescale yAxis is recreated and the domain is redraw and removed, if you don't mind keep it you can remove call(g => g.select(".domain").remove() from it. You need to await to update after the transition is done. I think this also answer your other question

yAxis = (g, scale = y) => g
    .attr("transform", `translate(${margin.left},0)`)
    .call(d3.axisLeft(scale).ticks(height / 40))