How do you find the last data point in d3 and draw a circle and a line on it?

Viewed 141

enter image description here

I have a basic line chart in d3 which displays properly. I need to find the last entry point of the data and draw a circle on it and a dotted line like the picture above.

Here is my current d3 code:

const xScale = scaleTime()
      .range([0, width])
      .domain(
        extent(data, (d: { week: any }) => {
          return d.week;
        })
      );

    const yScale = scaleLinear()
      .range([height, 0])
      .domain([
        min(data, (d: { index: number }) => {
          return d.index;
        }) - 20,
        max(data, (d: { index: number }) => {
          return d.index;
        }) + 20
      ]);

    const xAxis = axisBottom(xScale)
       .ticks(data.length);
    
    const svg = select(svgRef.current);

    svg
      .select(".x-axis")
      .style("transform", `translateY(${height}px)`)
      .call(xAxis);

    const yAxis = axisLeft(yScale);
    svg
      .select(".y-axis")
      .call(yAxis);

    const myLine = line()
      .x((d: { week: any }) => xScale(d.week))
      .y((d: { index: any }) => yScale(d.index))
      .curve(curveCardinal);

    svg
      .selectAll(".line")
      .data([data])
      .join("path")
      .attr("class", "data-circle")
      .attr("d", myLine)
      .attr("fill", "none")
      .attr("stroke", "purple")
      .attr("stroke-width", "5px");

      // draw circle here -- TODO
      svg
      .selectAll(".data-circle")
      .data([data])
      .append("circle")
      .attr("r", 7.5);

I tried to select the proper element around it which could return the final entry in the array, but i keep on getting errors, im not sure if its just a simple change.

The circle does not have to be on mouse hover but drawn by default. and would auto adjust if different data is loaded.

1 Answers

Calculate the point cooridnates on each update, select the point if it's already created or create a new one:

const lastData = data[data.length-1];
const y = yScale(lastData.index));
const x = xScale(lastData.week));

let lastPoint = svg.select('.last-point');
let lastLine = svg.select('.last-line');
if (!lastPoint.node()) {
  lastPoint = svg.append('circle')
    .classed('last-point', true)
    .style('fill', 'purple')
    .attr('r', 7.5);
  lastLine = svg.append('line')
    .classed('last-line', true)
    .attr('stroke-dasharray', '5,5')
    .style('stroke', 'gray');
}

lastPoint
  .attr('cx', x)
  .attr('cy', y);

lastLine
  .attr('x1', x)
  .attr('x2', x)
  .attr('y1', y)
  .attr('y2', height);
Related