Getting d3 axis tick marks to line up center with graph points
<p>For reference here is an image. Notice that the date on hover doesn't perfectly align with the date on the axis. If I try to change the margins I can shift the dates around but still with uneven spacing. I'm looking for a way to more manually control the spacing of the dates on the axis.
<a href="https://i.stack.imgur.com/X64mt.png" rel="nofollow"><img src="https://i.stack.imgur.com/X64mt.png" alt="enter image description here"></a></p>

<p>Here is the code in question:
<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>const dataGroup = [
        {
          key: props.lineChart.key,
          values: props.lineChart.values,
          startColor: '#E2FFE4',
          endColor: '#6FFCAF',
          area: false,
        }];
      const vis = d3.select(ReactDOM.findDOMNode(this));
      const bisectDate = d3.bisector(d =&gt; d.x).left;
      const WIDTH = 1000;
      const HEIGHT = 480;
      const MARGINS = {
        top: 20,
        right: 40,
        bottom: 20,
        left: 30,
      };
      const minYValue = 0;
      const maxYValue = d3.max(dataGroup.map(group =&gt;
        d3.max(group.values, row =&gt; row.y)
      ));

      const format = d3.time.format('%m/%d');
      const xScale = d3.time.scale()
        .range([MARGINS.left, WIDTH - MARGINS.right])
        .domain(d3.extent(dataGroup[0].values, d =&gt; d.x));

      const customScale = d3.time.scale()
        .range([8, WIDTH - MARGINS.right])
        .domain(d3.extent(dataGroup[0].values, d =&gt; d.x));

      const yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom])
        .domain([minYValue, maxYValue + 200]);

      const xAxis = d3.svg.axis()
              .scale(customScale)
              .ticks(d3.time.days, 1)
              .tickFormat(format);

      const yAxis = d3.svg.axis()
              .scale(yScale)
              .ticks(5)
              .tickFormat(d =&gt; (d === 0 ? 0 : numeral(d).format('0a')))
              .orient('left');

              vis.append("g")
                  .attr("class", "grid")
                  .attr("transform", "translate(" + MARGINS.left + ",0)")
                  .call(makeXAxis(yScale)
                      .tickSize(-(WIDTH - MARGINS.right - MARGINS.left), 0, 0)
                      .tickFormat("")
                  )

              var lineGen = d3.svg.line()
                      .x(function(d) {
                          return xScale(new Date(d.x));
                      })
                      .y(function(d) {
                          return yScale(d.y);
                      })
              console.log('Data Group', dataGroup);

              dataGroup.forEach(function(d, i) {
                   vis.append("linearGradient")
                      .attr("id", "line-gradient")
                      .attr("gradientUnits", "userSpaceOnUse")
                      .attr("x1", 0).attr("y1", "0")
                      .attr("x2", "100%").attr("y2", "0")
                      .selectAll("stop")
                      .data([
                          {offset: "0%", color: "yellow"},
                          {offset: "100%", color: "orange"}
                      ])
                      .enter().append("stop")
                      .attr("offset", function(d) { return d.offset; })
                      .attr("stop-color", function(d) { return d.color; });

                      vis.append('svg:path')
                      .attr('class', "line clickable")
                      .attr('d', lineGen(d.values))
                      .attr('stroke', 'blue')
                      .attr('stroke-width', 2)
                      .attr('fill', 'none');

              });


              vis.append("svg:g")
                      .attr("class", "x axis")
                      .attr("transform", "translate(5," + (HEIGHT - MARGINS.bottom + 20) + ")")
                      .call(xAxis);
              vis.append("svg:g")
                      .attr("class", "y axis")
                      .attr("transform", "translate(" + (MARGINS.left) + ",0)")
                      .call(yAxis);

              var focus = vis.append("g")
                          .attr("class", "focus")
                          .style("display", "none")
                          .style("opacity", "1");

              focus.append("circle")
                  .attr("r", 8)
                  .attr("fill", 'orange')
                  .attr("stroke", 'white')
                  .attr("stroke-width", '2px')

              var tooltip = vis.append("g")
                              .attr("class", "tooltip")
                              .style("display", "none");


              tooltip.append("rect")
                  .attr("width", 90)
                  .attr("height", 20)
                  .attr("rx", 2.5)
                  .attr("ry", 2.5)
                  .attr("fill", 'lightgray');

              var tooltipText = tooltip.append("text")
                  .attr("dy", 15)
                  .attr("dx", 15);

              tooltipText.text(null).append("tspan")
                  .attr('class', 'date');

              tooltipText.append("tspan").text(' ');

              tooltipText.append("tspan")
                  .attr('class', 'volume');

              vis.on("mouseover", function() { focus.style("display", null); verticalLine.style("display", null); tooltip.style("display", null);})
                  .on("mouseout", function() {
                    focus.style("display", "none");
                    verticalLine.style("display", "none");
                    tooltip.style("display", "none");
                    updateInfluencerSample({
                    });
                  })
                  .on("mousemove", mousemove);

              function mousemove() {
                  if(dataGroup.length === 1) {
                      index = 0;
                  }
                  else {
                      var isPositive = (yScale.invert(d3.mouse(this)[1]) &gt; 0),
                          index = isPositive ? 0 : 1;
                  }
                      var x0 = xScale.invert(d3.mouse(this)[0]),
                      i = bisectDate(dataGroup[index].values, x0, 1),
                      d0 = dataGroup[index].values[i - 1],
                      d1 = dataGroup[index].values[i];

                  if(d0 &amp;&amp; d1) {
                      var d = x0 - d0.x &gt; d1.x - x0 ? d1 : d0;
                      if(dataGroup.length === 1) d.y = Math.abs(d.y);
                      var criticalPointYPos = (d.y &gt; 0) ? -0.6 : 1.2;
                      focus.attr("transform", "translate(" + xScale(d.x) + "," + yScale(d.y) + ")");
                      tooltip.attr("transform", "translate(" + (xScale(d.x) - 45) + "," + (HEIGHT - MARGINS.bottom) + ")");
                      tooltip.select(".date").text(format(new Date(d.x))).attr('fill', '#929292');
                      tooltip.select(".volume").text(numeral(d.y).format('0a')).attr('fill', '#929292');
                      d3.select(".verticalLine").attr({
                                  x1: 0,
                                  x2: 0,
                                  y1: MARGINS.top,
                                  y2: HEIGHT - MARGINS.bottom,
                              })
                      .style("stroke-dasharray", ("3, 3"))
                      .attr("stroke-width", 3)
                      .attr("transform", function () {
                          return "translate(" + xScale(d.x) + ",0)";
                      });
                      updateInfluencerSample({
                          author: new Date().getMilliseconds(),
                          date: d.x,
                      });
                  }
              }

              var verticalLine = vis.append('line')
                                  .attr({
                                      x1: 0,
                                      x2: 0,
                                      y1: yScale(maxYValue),
                                      y2: HEIGHT - MARGINS.bottom,
                                  })
                                  .attr('stroke', 'gray')
                                  .attr('class', 'verticalLine')
                                  .style('display', 'none');

              vis.transition().style("opacity", 1);
  }</code></pre>
</div>
</div>
</p>