1
votes

I have a demo here

Its a line bar chart using D3 in an Angular app.

I want the chart to be responsive so when the page is resized the chart width will increase and the height will be stay the same.

I'm doing this by capturing the window resize and then calling the function that draws the chart.

This works for the axis but I cant get the line and points to redraw.

I think it's to do with the way I'm trying to us the update pattern

How can I use the update pattern to redraw this line graph

const that = this;
const valueline = d3.line()
  .x(function (d, i) {
    return that.x(d.date) + 0.5 * that.x.bandwidth();
  })
  .y(function (d) {
    return that.y(d.value);
  });

this.x.domain(data.map((d: any) => d.date));

this.y.domain(d3.extent(data, function (d) {
  return d.value
}));

const thisLine = this.chart.append("path")
  .data([data])
  .attr("class", "line")
  .attr("d", valueline);

const totalLength = thisLine.node().getTotalLength();

thisLine.attr("stroke-dasharray", totalLength + " " + totalLength)
  .attr("stroke-dashoffset", totalLength);

thisLine.transition()
  .duration(1500)
  .attr("stroke-dashoffset", 0)

let circle = this.chart.selectAll("line-circle")
  .data(data);

circle = circle  
  .enter()
    .append("circle")
    .attr("class", "line-circle")
    .attr("r", 4)
    .attr("cx", function (d) {
      return that.x(d.date) + 0.5 * that.x.bandwidth();
    })
    .attr("cy", function (d) {
      return that.y(d.value);
    })  

circle  
  .attr("r", 4)
  .attr("cx", function (d) {
    return that.x(d.date) + 0.5 * that.x.bandwidth();
  })
  .attr("cy", function (d) {
    return that.y(d.value);
  })   

circle
  .exit()
  .remove() 
1

1 Answers

1
votes

You have problems in both circles' selection and the line selection.

The circles' selection:

  1. You're selecting "line-circle". Instead of that, you have to select by class: ".line-circle";
  2. You're reassigning the circle selection:

    circle = circle.enter()//etc...
    

    Don't do that, otherwise circle will point to the enter selection, not to the update selection anymore. Just do:

    circle.enter()//etc...
    

The path:

You're appending a new path every time you call the function. Don't do that. Instead, select the existing path and change its d attribute, or append a new path if there is none. Both behaviours can be achieved with this code:

let thisLine = this.chart.selectAll(".line")
    .data([data]);

thisLine = thisLine.enter()
    .append("path")
    .attr("class", "line")
    .merge(thisLine)
    .attr("d", valueline);

Here is your forked code: https://stackblitz.com/edit/basic-scatter-mt-vvdxqr?file=src/app/bar-chart.ts