Assign different colours to vertical lines in a line chart based on property value

I would like to create a line chart with two vertical lines that mark the start (in red) and end (in green) of a streak of high values (10). The colours of these lines should be appointed based on the start_end property in the output variable, like so:

enter image description here

Any ideas on how to achieve this? This is my code so far (i’m using d3 v6)

{
  const svg = d3.select(DOM.svg(width, height))
  
  svg.append('g').call(xAxis)
  svg.append('g').call(yAxis)
 
  svg.append("line")
        .datum(output)
        .attr("d", line)
        .attr("fill", "none")
        .style("stroke", "steelblue")
        .style("stroke-width", 4)
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("x1", xScale(output.timestamp))
        .attr("y1", 0)
        .attr("x2", xScale(output.timestamp))
        .attr("y2", 10)
        
  svg.append('path')
      .datum(segment)
      .attr('d', line)
      .style('fill', 'none')
      .style('stroke', 'black')  
  
  return svg.node()
}

output = [
  {timestamp: "2020-09-25T04:00:54.857Z", jam_factor: 10, start_end: "start"}
  {timestamp: "2020-09-29T18:02:23.282Z", jam_factor: 8.39212, start_end: "end"}
]

Answer

I generated some data and show below how to add start and stop lines in a generic way.

const data = [0, 3, 5, 7, 5, 4, 6, 7, 10, 10, 10, 10, 7, 5, 7, 6, 8, 9, 9, 10, 10, 10, 10, 10, 10, 9, 5, 6, 4, 6, 8, 10, 10, 9].map((v, i) => {
  const now = new Date();
  now.setDate(i);
  return {
    timestamp: now,
    value: v,
  };
});

// Find all places where we first hit or stop hitting 10
let active = false;
data.forEach((d, i) => {
  if (d.value === 10) {
    if (!active) {
      d.start = true;
      active = true;
    }
  } else {
    // The previous was the last active one
    if (active) {
      data[i - 1].end = true;
      active = false;
    }
  }
});

const width = 600,
  height = 300;
const x = d3.scaleTime()
  .domain(d3.extent(data, d => d.timestamp))
  .range([0, width]);
const y = d3.scaleLinear()
  .domain([0, 10])
  .range([height - 10, 10]);
const line = d3.line()
  .x(d => x(d.timestamp))
  .y(d => y(d.value))

const svg = d3.select('svg')
  .attr('width', width)
  .attr('height', height)

svg.append("path")
  .datum(data)
  .attr("d", line)
  .style("stroke", "steelblue")
  .style("stroke-width", 2)
  .style("fill", "none");

svg.selectAll("line")
  .data(data.filter(d => d.start || d.end))
  .enter()
  .append("line")
  .attr("x1", d => x(d.timestamp))
  .attr("x2", d => x(d.timestamp))
  .attr("y1", y.range()[0])
  .attr("y2", y.range()[1])
  .attr("stroke", d => d.start ? "green" : "red")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg></svg>