Tuesday, 9 May 2023

How to add gap and text between path in d3.js?

I have created a line chart using d3.js, now I want to add the gap and text between the path.

live demo

What I have so far.

HTML

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>D3 Stacked Bar and Line Chart</title>
    <script src="https://d3js.org/d3.v5.min.js"></script>
  </head>
  <style>
    .dot {
  display: none;
}

.line-segment {
  fill: none;
  stroke: steelblue;
  stroke-width: 2;
}

.line-text {
  font-size: 12px;
  font-weight: bold;
}
  </style>
  <body>
    <div id="main-chart">
        <svg width="960" height="500"></svg>
    </div>
  </body>
</html>

JS

const data = [
  { year: "2015", value: 120 },
  { year: "2016", value: 200 },
  { year: "2017", value: 300 },
  { year: "2018", value: 400 },
  { year: "2019", value: 500 }
];

const margin = { top: 20, right: 20, bottom: 30, left: 50 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;

const svg = d3.select("body").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", `translate(${margin.left},${margin.top})`);

const xScale = d3.scaleBand()
  .range([0, width])
  .domain(data.map(d => d.year))
  .padding(0.2);

const yScale = d3.scaleLinear()
  .range([height, 0])
  .domain([0, d3.max(data, d => d.value)]);

const line = d3.line()
  .x(d => xScale(d.year) + xScale.bandwidth() / 2)
  .y(d => yScale(d.value))
  .defined(function(d) {return !isNaN(d)});

svg.append("g")
  .attr("transform", `translate(0, ${height})`)
  .call(d3.axisBottom(xScale));

svg.append("g")
  .call(d3.axisLeft(yScale));

  svg.selectAll(".line-segment")
  .data(data.slice(0, -1))
  .enter().append("path")
  .attr("class", "line-segment")
  .attr("d", d => {
    const x1 = xScale(d.year) + xScale.bandwidth() / 2;
    const x2 = xScale(data[data.indexOf(d) + 1].year) + xScale.bandwidth() / 2;
    const y1 = yScale(d.value);
    const y2 = yScale(data[data.indexOf(d) + 1].value);
    return `M${x1},${y1} L${x2},${y2}`;
  })
  .attr("stroke", "steelblue")
  .attr("stroke-width", 2);


svg.selectAll(".line-text")
  .data(data)
  .enter().append("text")
  .attr("class", "line-text")
  .text(d => d.value)
  .attr("x", d => xScale(d.year) + xScale.bandwidth() / 2)
  .attr("y", d => yScale(d.value) - 0)
  .attr("text-anchor", "middle")
  .attr("font-size", "12px");
 

The above solution gives me the following enter image description here

But the expected result should be something like this

enter image description here



from How to add gap and text between path in d3.js?

No comments:

Post a Comment