title: D3JS V4 Zoomable line chart with circle points and tooltip
body: <p>My requirement is to draw a graph using the data in format as follows array of array. Which is converted to array of objects to used in graph.</p>
  <p>with 100 000 data.
  So following features needed:</p>
  <ol>
  <li>Zoomable - This feature is implemented in the code below.</li>
  <li>Tooltip on hover -
  Unable to set tooltip on hover. How can I do this?</li>
  <li>Circle once zoom section showing less than 100 records - Can find the extent but failing to set circle on the zoomed section.</li>
  <li>Line break on x-axis date time to accommodate more data - Is there any way to set html record in x axis with formatted data or using \n or word break etc?</li>
  </ol>
  <p>My code is as follows</p>
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  
  &lt;!-- Load d3.js --&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; /&gt;
  
  &lt;script src=&quot;https://d3js.org/d3.v4.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;generator.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;data-set.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js&quot;
      integrity=&quot;sha512-a+/SD0dbGeXTN4AA5F1dDZqsPvXKKyS1bvU2z5ElpKNJ4xQlOMUs/1+suA+j+kj5nAAya+VmT5HUKZmazluxVQ==&quot;
      crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
  &lt;!-- Create a div where the graph will take place --&gt;
  &lt;div id=&quot;my_dataviz&quot;&gt;
  &lt;/div&gt;
  
  
  &lt;script&gt;
  
      // set the dimensions and margins of the graph
      var margin = { top: 50, right: 50, bottom: 50, left: 50 };
  
      var height = window.innerHeight / 2;
      var width = window.innerWidth / 2;
      var tooltip = { width: 100, height: 100, x: 10, y: -30 };
  
      // append the svg object to the body of the page
      var svg = d3.select(&quot;#my_dataviz&quot;)
          .append(&quot;svg&quot;)
          .attr(&quot;width&quot;, width + margin.left + margin.right)
          .attr(&quot;height&quot;, height + margin.top + margin.bottom)
          .append(&quot;g&quot;)
          .attr(&quot;transform&quot;,
              &quot;translate(&quot; + margin.left + &quot;,&quot; + margin.top + &quot;)&quot;)
  
  
      svg.append(&quot;text&quot;)
          .attr(&quot;transform&quot;, &quot;rotate(-90)&quot;)
          .attr(&quot;y&quot;, -40)
          .attr(&quot;dy&quot;, &quot;.4em&quot;)
          .style(&quot;text-anchor&quot;, &quot;end&quot;)
          .text(&quot;CPU Utilization (In Percentage)&quot;);
  
      svg.append(&quot;text&quot;)
          .attr(&quot;y&quot;, (height + 40))
          .attr(&quot;x&quot;, (width / 2))
          .style(&quot;text-anchor&quot;, &quot;end&quot;)
          .text(&quot;Date Time&quot;);
  
  
      var data = data_set.map((d) =&gt; {
          return { &quot;date&quot;: d[0], &quot;data&quot;: d[1] }
      });
      console.log(data);
      setChart(data);
      // Now I can use this dataset:
      function setChart(data) {
  
          // Add X axis --&gt; it is a date format
          var x = d3.scaleTime()
              .domain(d3.extent(data, function (d) { return new Date(d.date); }))
              .range([0, width]);
          xAxis = svg.append(&quot;g&quot;)
              .attr(&quot;transform&quot;, &quot;translate(0,&quot; + height + &quot;)&quot;)
              .call(d3.axisBottom(x)
                  .ticks(width / 120)
                  .tickFormat(d3.timeFormat(&quot;%Y-%m-%d %H:%I&quot;)))
  
  
          // Add Y axis
          var y = d3.scaleLinear()
              .domain([0, d3.max(data, function (d) { return +d.data; })])
              .range([height, 0]);
          yAxis = svg.append(&quot;g&quot;)
              .call(d3.axisLeft(y));
  
  
          // Add a clipPath: everything out of this area won't be drawn.
          var clip = svg.append(&quot;defs&quot;).append(&quot;svg:clipPath&quot;)
              .attr(&quot;id&quot;, &quot;clip&quot;)
              .append(&quot;svg:rect&quot;)
              .attr(&quot;width&quot;, width)
              .attr(&quot;height&quot;, height)
              .attr(&quot;x&quot;, 0)
              .attr(&quot;y&quot;, 0);
  
          // Add brushing
          var brush = d3.brushX()                   // Add the brush feature using the d3.brush function
              .extent([[0, 0], [width, height]])  // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
              .on(&quot;end&quot;, updateChart)               // Each time the brush selection changes, trigger the 'updateChart' function
  
          // Create the line variable: where both the line and the brush take place
          var line = svg.append('g')
              .attr(&quot;clip-path&quot;, &quot;url(#clip)&quot;)
          var div = d3.select(&quot;body&quot;).append(&quot;div&quot;)
              .attr(&quot;class&quot;, &quot;tooltip&quot;)
              .style(&quot;opacity&quot;, 0);
          // Add the line
          var chart = line.append(&quot;path&quot;)
              .datum(data)
              .attr(&quot;class&quot;, &quot;line&quot;)  // I add the class line to be able to modify this line later on.
              .attr(&quot;fill&quot;, &quot;none&quot;)
  
              .attr(&quot;stroke&quot;, &quot;#90c1fe&quot;)
              .attr(&quot;stroke-width&quot;, 1)
              .attr(&quot;d&quot;, d3.line()
                  .x(function (d) { return x(new Date(d.date)) })
                  .y(function (d) { return y(d.data) })
              )
  
  
          svg.selectAll(&quot;myCircles&quot;).data(data)
              .enter()
              .append(&quot;circle&quot;)
              .attr(&quot;fill&quot;, &quot;#90c1fe&quot;)
              .attr(&quot;stroke&quot;, &quot;none&quot;)
              .attr(&quot;cx&quot;, function (d) { return x(d.date) })
              .attr(&quot;cy&quot;, function (d) { return y(d.data) })
              .attr(&quot;r&quot;, 1)
  
          console.log(data);
          // Add the brushing
          line.append(&quot;g&quot;)
              .attr(&quot;class&quot;, &quot;brush&quot;)
              .call(brush);
  
          // A function that set idleTimeOut to null
          var idleTimeout
          function idled() { idleTimeout = null; }
          // A function that update the chart for given boundaries
          function updateChart() {
              // What are the selected boundaries?
              extent = d3.event.selection
  
              if (extent &amp;&amp; extent[1] - extent[0] &lt; 100) {
  
              }
              // If no selection, back to initial coordinate. Otherwise, update X axis domain
              if (!extent) {
                  if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
                  x.domain([4, 8])
              } else {
                  x.domain([x.invert(extent[0]), x.invert(extent[1])])
                  line.select(&quot;.brush&quot;).call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
              }
  
              // Update axis and line position
              xAxis.transition().duration(2000).call(d3.axisBottom(x).ticks(width / 120).tickFormat(d3.timeFormat(&quot;%Y-%m-%d %H:%M:%S&quot;)))
  
              line.select('.line')
                  .transition()
                  .duration(2000)
                  .attr(&quot;d&quot;, d3.line()
                      .x(function (d) { return x(d.date) })
                      .y(function (d) { return y(d.data) })
                  )
  
  
  
          }
  
  
          // If user double click, reinitialize the chart
          svg.on(&quot;dblclick&quot;, function () {
              resetChart();
          });
  
  
          function resetChart() {
              x.domain(d3.extent(data, function (d) { return d.date; }))
              xAxis.transition().duration(2000)
                  .call(d3.axisBottom(x)
  
                      .ticks(width / 120)
                      // .tickFormat(d3.timeFormat(&quot;%Y-%m-%d %H:%I&quot;)));
                      .tickFormat(d3.timeFormat(&quot;%Y-%m-%d %H:%I&quot;)))
  
              line
                  .select('.line')
                  .transition().duration(2000)
                  .attr(&quot;d&quot;, d3.line()
                      .x(function (d) { return x(d.date) })
                      .y(function (d) { return y(d.data) })
                  )
  
          }
  
  
      };
  
  
  
  
  &lt;/script&gt;
  </code></pre>