D3 - Scaled V Bar

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)

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.begin {
  stop-color: #E9F90B;
}

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

JavaScript

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

  let metadata = {
    fiddleHeader: 'D3 - Gradient Bar Chart',
    urls: {
      github: 'https://github.com/bradyhouse/house/tree/master/fiddles/d3/fiddle-0024-BarChart'
    },
    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,
      _xScale, _yScale,
      _xAxis, _yAxis,
      _data = [],
      _svg,
      _bodyG,
      _snapshot = false;


    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]);
      _xAxis = d3.svg.axis().scale(_xScale).orient("bottom");
      _yScale = d3.scale.linear()
        .domain([0, d3.max(_data, function(d) {
          let scale = Math.floor(d.y / 3),
            ret = (scale >= 0) ? constrain(scale, 0.05, 20) : constrain(scale, -20, -0.05);
          return ret;
        })])
        .range([quadrantHeight(), 0]);
      _yAxis = d3.svg.axis()
        .scale(_yScale)
        .orient("left")
        .ticks(3)
        .tickSubdivide(0)
        .tickFormat(function(v) {
          return v + " X";
        });
    }

    function defineBodyClip(svg) {
      var padding = 5;

      svg.append("defs")
        .append("clipPath")
        .attr("id", "body-clip")
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", quadrantWidth() + 2 * padding)
        .attr("height",...