Line Chart Click Event

by falsy

HTML

<!doctype html>
<html lang="ko">
  <head>
    <title>D3 line chart example</title>
  </head>
  <body>
    <div id="svg-area">
      <div id="tooltip"></div>
    </div>
  </body>
</html>

CSS

#svg-area {
  position: relative;
}

#tooltip {
  position: absolute;
  opacity: 0;
  width: 40px;
  height: 20px;
  line-height: 20px;
  transition: all 0.3s;
  border-radius: 5px;
  text-align: center;
  color: #fff;
  font-size: 14px;
  font-weight: bold;
  background: #add7a8;
}

JavaScript

const tooltip = document.getElementById('tooltip');
const width = 500;
const height = 300;
const margin = {top: 40, right: 40, bottom: 40, left: 40};
const padding = 30;
const data = [
  {date: new Date('2018-01-01'), value: 10},
  {date: new Date('2018-01-02'), value: 20},
  {date: new Date('2018-01-03'), value: 30},
  {date: new Date('2018-01-04'), value: 25},
  {date: new Date('2018-01-05'), value: 35},
  {date: new Date('2018-01-06'), value: 45},
  {date: new Date('2018-01-07'), value: 60},
  {date: new Date('2018-01-08'), value: 50}
];

const maxValue = d3.max(data.map(d => d.value));
const maxIdx = data.length - 1;

const cursorData = data.map((d) => {
  return { date: d.date, value: maxValue };
});
 
const x = d3.scaleTime()
  .domain(d3.extent(data, d => d.date))
  .range([margin.left + 30, width - margin.right])
  .nice();
 
const cursorX = d3.scaleBand()
  .domain(cursorData.map(d => d.date))
  .range([margin.left + 30, width - margin.right])
  .padding(0);

const xWidth = cursorX.bandwidth();
 
const y = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.value)]).nice()
  .range([height - margin.bottom, margin.top]);
 
const xAxis = g => g
  .attr("transform", `translate(${xWidth/2}, ${height - margin.bottom})`)
  .call(d3.axisBottom(x).ticks(d3.timeDay).tickFormat(d=>d3.timeFormat("%a %d")(d)))
  .call(g => g.select('.domain').remove())
  .call(g => g.selectAll('line').remove());
 
const yAxis = g => g
  .attr("transform", `translate(${margin.left},0)`)
  .call(d3.axisLeft(y))
  .call(g => g.select(".domain").remove())
  .call(g => g.selectAll('line')
  .attr('x2', width)
  .style('stroke', '#ddd'))
 
const line = d3.line()
  .defined(d => !isNaN(d.value))
  .x(d => x(d.date))
  .y(d => y(d.value));
 
const svg = d3.select('#svg-area').append('svg').style('width', width).style('height', height);

const showTooltip = (i) => { 
  const targetData = data[i];
  const posX = Math.floor(x(targetData.date)) - Math.floor((tooltip.offsetWidth)/2);
  const posY...