title: positioning xAxis and yAxis with d3.js
body: <p>What I have works but I am wondering if there is a better way.</p>
  
  <p>I have <a href="http://www.d3geometry.com/functions?uid=333333" rel="nofollow">this</a> page as my working example.  The source code is <a href="https://github.com/dagda1/d3-geometry/blob/master/app/js/components/function-plot.js" rel="nofollow">here</a> and this question deals specifically drawing x axis and y axis with positive and negative values.  </p>
  
  <p>I have a <code>drawAxes</code> method that looks like this:</p>
  
  <pre><code>  drawAxes(data) {
      const xAxis = d3.svg.axis()
              .scale(this.xScale);
  
      const yAxis = d3.svg.axis()
              .orient('left')
              .scale(this.yScale);
  
      const dimensions = this.getDimensions();
  
      this.xScale.domain(d3.extent(data, (d) =&gt; d.x));
  
      const minY = d3.min(data, (d) =&gt; d.y);
      const maxY = d3.max(data, (d) =&gt; d.y);
  
      const nonNegativeXAxis = minY &gt;= 0 &amp;&amp; maxY &gt;= 0;
      const positiveAndNegativeXAxis = minY &lt; 0 &amp;&amp; maxY &gt; 0;
  
      let yScaleDomain, xAxisPosition;
  
      if(nonNegativeXAxis) {
        yScaleDomain = [0, d3.max(data, (d) =&gt; d.y)];
      }  else {
        yScaleDomain = d3.extent(data, (d) =&gt; d.y);
      }
  
      this.yScale.domain(yScaleDomain);
  
      const findZeroTick = (data) =&gt; {
        return data === 0;
      };
  
      this.svg.append('g')
        .attr('class', 'axis y-axis')
        .style('visibility', 'hidden')
        .call(yAxis);
  
      if(nonNegativeXAxis) {
        yScaleDomain = [0, d3.max(data, (d) =&gt; d.y)];
        xAxisPosition = dimensions.height;
      } else if(positiveAndNegativeXAxis) {
        xAxisPosition = this.svg.selectAll(".tick").filter(findZeroTick).map((tick) =&gt; {
          return d3.transform(d3.select(tick[0]).attr('transform')).translate[1];
        });
      } else {
        yScaleDomain = d3.extent(data, (d) =&gt; d.y);
        xAxisPosition = 0;
      }
  
      this.svg.append('g')
        .attr('class', 'axis x-axis')
        .attr('transform', `translate(0, ${xAxisPosition})`)
        .call(xAxis);
  
      d3.select('.y-axis').remove();
  
      const minX = d3.min(data, (d) =&gt; d.x);
      const maxX = d3.max(data, (d) =&gt; d.y);
  
      const positiveXOnly = minX &gt; 0 &amp;&amp; maxX &gt; 0;
      const negativeXOnly = minX &lt; 0 &amp;&amp; maxX &lt; 0;
  
      let yAxisPosition;
  
      if(positiveXOnly) {
        yAxisPosition = 0;
      } else if(negativeXOnly) {
        yAxisPosition = dimensions.width;
      } else {
        yAxisPosition = this.svg.selectAll(".x-axis .tick").filter(findZeroTick).map((tick) =&gt; {
          return d3.transform(d3.select(tick[0]).attr('transform')).translate[0];
        });
      }
  
      this.svg.append('g')
        .attr('class', 'axis y-axis')
        .attr('transform', `translate(${yAxisPosition}, 0)`)
        .call(yAxis);
    }
  </code></pre>
  
  <p>WHat I found great difficulty in was positioning the y axis x axis at 0 on the opposite axis.</p>
  
  <p>How I did this was to first of all draw the y axis but keep it hidden:</p>
  
  <pre><code>this.svg.append('g')
    .attr('class', 'axis y-axis')
    .style('visibility', 'hidden')
    .call(yAxis);
  </code></pre>
  
  <p>I then found the position of 0 on the y axis by selecting all the ticks and finding the y coordinate of the 0 tick, I use this value to position the x axis:</p>
  
  <pre><code>const findZeroTick = (data) =&gt; {
    return data === 0;
  };
  
  xAxisPosition = this.svg.selectAll(".tick").filter(findZeroTick).map((tick) =&gt; {
    return d3.transform(d3.select(tick[0]).attr('transform')).translate[1];
  });
  
  this.svg.append('g')
    .attr('class', 'axis x-axis')
    .attr('transform', `translate(0, ${xAxisPosition})`)
    .call(xAxis);
  </code></pre>
  
  <p>To position the yAxis, I first of all remove the yAxis and then do a similar calculation by selecting all the ticks on the x-axis and then adding the yAxis again with and using the retrieved value to position the yAxis:</p>
  
  <pre><code>d3.select('.y-axis').remove();
  
  yAxisPosition = this.svg.selectAll(".x-axis .tick").filter(findZeroTick).map((tick) =&gt; {
    return d3.transform(d3.select(tick[0]).attr('transform')).translate[0];
  });
  
  this.svg.append('g')
    .attr('class', 'axis y-axis')
    .attr('transform', `translate(${yAxisPosition}, 0)`)
    .call(yAxis);
  </code></pre>
  
  <p>Is there a more efficient way of achieving the same result or failing that, can I move the axis without having to remove it and re-add it?</p>