D3 - 2 Quadrant Bar Chart

D3 fiddle exploring how to create a bar chart with the following requirements: * x axis should use an ordinal scale and be labelled along the bottom * y axis should use a linear scale and rendered along left side of the chart * series bars should have a linear gradient * colors used in the gradient should be defined in a separate css file * the width and height of the chart should be based on the dimension of the window * the dimensions of the chart should refresh on window resize * the y axis should use a custom scale based on the values proximity to a fixed value (aka tolerance) * the chart should have two quadrant for plotting positive and negative y values

by brady houseknecht

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.js"></script>

CSS

body {
  font-family: "Courier New";
  font-size: small;
  text-align: center;
  background-color: black;
}

.axis path,
.axis line {
  fill: none;
  stroke: white;
  shape-rendering: crispEdges;
}

.axis text {
  font: 10px sans-serif;
  stroke: white;
}

.axis .h-grid-line {
  stroke: white;
  shape-rendering: crispEdges;
  stroke-opacity: 1;
  stroke-width: 2;
}

.axis .v-grid-line {
  stroke: turquoise;
  shape-rendering: crispEdges;
  stroke-opacity: .2;
}

stop.yellow {
  stop-color: #E9F90B;
}

stop.red {
  stop-color: #F91B0B;
}

stop.lightblue {
  stop-color: #0BC1F9;
}

stop.blue {
  stop-color: #0B0BF9;
}

JavaScript

(function(app, $, undefined) {
  "use strict";

  let metadata = {
    fiddleHeader: 'D3 - 2 Quadrant Bar Chart',
    urls: {
      github: 'https://github.com/bradyhouse/house/tree/master/fiddles/d3/fiddle-0025-TwoQuadrantBarChart'
    },
    consoleTag: 'H O U S E ~ f i d d l e s'
  };

  function barChart() {
    let _chart = {},
      _duration = 1000,
      _margins = {
        top: 30,
        left: 40,
        right: 0,
        bottom: 30
      },
      _width = window.innerWidth - _margins.left - _margins.right,
      _height = window.innerHeight - _margins.top - _margins.bottom,
      _xAxis, _yAxis,
      _forceY = [0],
      _data = [],
      _svg,
      _bodyG,
      _snapshot = false,
      getX = function(d) {
        return d.x
      },
      getY = function(d) {
        return d.y
      },
      x = d3.scale.ordinal(),
      y = d3.scale.linear(),
      x0, y0;


    function constrain(number, min, max) {
      let x = parseFloat(number);
      if (min === null) {
        min = number;
      }
      if (max === null) {
        max = number;
      }
      return (x < min) ? min : ((x > max) ? max : x);
    }

    function defineAxesAndScales() {

      /*_xScale = d3.scale.ordinal()
          .domain(_data.map(function (d) {
              return d.label;
          }))
          .rangeRoundBands([0, quadrantWidth(), 0.05]);*/
      x.domain(_data.map(function(d) {
          return d.label;
        }))
        .rangeBands([0, quadrantWidth()], .1);
      _xAxis = d3.svg.axis().scale(x).orient("bottom");
      y.domain(d3.extent(_data.map(function(d) {
        return d.y
      }).concat(_forceY)));

      y.range([quadrantHeight() - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]);
      /*_yScale = d3.scale.linear()
          .domain([
              d3.min(_data, function (d) {
                  let scale = Math.floor(d.y / 3),
                      ret = (scale < 0) ? constrain(scale, -20, -0.05) : 0;
                  return ret;
        ...