D3 date pan/zoom

by danShumway

HTML

<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>

CSS

body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
}


.y.axis path {
  display: none;
}

text {
    opacity: 1;
}

JavaScript

var margin = {top: 20, right: 0, bottom: 20, left: 0},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var timeScale = {minor:'days', major:'months', super:'years'};
var domain = [new Date(2012, 7, 1), new Date(2013, 2, 1)];

var x = d3.time.scale()
    .domain(domain)
    .range([0, width]);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var gx = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (height-15) + ")");

function renderAxis(group, duration, ticks) {
    duration = duration || 0;
    ticks = ticks || {
        'major': ['month', undefined, "MMMM"],
        'minor': ['day', 5, undefined],
        'super': ['year', undefined, "MMMM YYYY"]
    }
    
    var _super = _.map(d3.time[ticks.super[0]].range(domain[0], domain[1], ticks.super[1]), function(n) {
        //d3 doesn't allow two ticks to occupy the exact same space,
        //so we need to get slightly creative with adding labels.  The easy solution (especially since .super ticks
        //are invisible, is to add a fraction of our existing scale.
        return { 'value': n, 'type': 'super', 'toString': function() { return n.valueOf()+1; } };
    });
    var _major = _.map(d3.time[ticks.major[0]].range(domain[0], domain[1], ticks.major[1]), function(n) {
        return { 'value': n, 'type': 'major', 'toString': function() { return n.valueOf(); } };
    });
    var _minor = _.map(d3.time[ticks.minor[0]].range(domain[0], domain[1], ticks.minor[1]), function(n) {
        return { 'value': n, 'type': 'minor', 'toString': function() { return n.valueOf(); } };
    });
    var _total = _super.concat(_major).concat(_minor);
    var xAxis = d3.svg.axis()
        .scale(x)
        .tickValues(_total)
        .tickSize(5,...