Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3.js time scale tick marks - Years and months only - Custom time format

I'm trying to make a zoomable chart with time scale on the x axis.

The default behaviour with an xScale like so:

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

and an xAxis like so:

var xAxis = d3.svg.axis()
  .scale(x);

is almost what I'm after.

But I'd like to have a custom Time Format that shows years, and instead of showing the name of the month, shows just a tick line, without the text (and maybe add a class to these ticks), while still retaining the default behaviour of the axis on zoom.

Any help would be much appreciated.

See JSfiddle here

Edit: I imagine that Lars' answer here would be a good approach, so long as it could be applied to a zoomable chart. Any fresh thoughts?

like image 268
ksav Avatar asked Dec 11 '15 19:12

ksav


People also ask

What is D3 scaleTime?

The d3. scaleTime() function is used to create and return a new time scale which have the particular domain and range. In this function the clamping is disabled by default.

What is tickSize in D3?

tickSize() function in D3. js is used to set the inner and outer tick size to the specified value and returns the axis. If size is not specified, returns the current inner tick size, which defaults to 6.

How does D3 ticks work?

The ticks function can take any number but it will modify that number to make sure the axis is a multiple of 2, 5, or 10. For example, if the domain is 0-100 and you want 4 ticks (0, 33.33, 66.66, 100) it will round up to 6 to give you "pretty" numbers (0, 20, 40, 60, 80, 100).

What is domain and range in D3?

D3 creates a function myScale which accepts input between 0 and 10 (the domain) and maps it to output between 0 and 600 (the range).


2 Answers

This may work. To shows years, and instead of showing the name of the month, shows just a tick line, without the text:

var timeAxis = d3.svg.axis()
        .scale(timeScale)
        .orient('bottom')
        .ticks(d3.time.years, 1)//should display 1 year intervals
        .tickFormat(d3.time.format('%Y'))//%Y-for year boundaries, such as 2011
        .tickSubdivide(12);//subdivide 12 months in a year

Resources:

  1. d3.js major minor tick style (http://bl.ocks.org/vjpgo/4689130)
  2. scale.ticks and scale.tickFormat() (https://github.com/mbostock/d3/wiki/Time-Intervals#year)

Sample code that shows a tick for every two hours, and formats it to only show hour and AM/PM:

var timeAxis = d3.svg.axis()
        .scale(timeScale)
        .orient('bottom')
        .ticks(d3.time.hours, 2)
        .tickFormat(d3.time.format('%I%p'));
like image 171
Justin Wilson Avatar answered Sep 25 '22 21:09

Justin Wilson


I ended up writing a small function to check the zoom level and set the axis' amount of ticks accordingly.

function calcTickAmount() {
  if (d3.event.scale > 15) {
    return 3
  } else {
    return 10;
  }
}

Then this function would be called within the update function

function draw() {
  xAxis.ticks(calcTickAmount());
  axes.call(xAxis);
}

// Config SVG
var width = 500,
  height = 300,
  minDate = '1860',
  maxDate = '1958';

// Draw SVG element
var svgSelect = d3.select('div.tl').append('svg');

// Translate SVG G to accomodate margin
var translateGroupSelect = svgSelect
  .attr('width', width)
  .attr('height', height)
  .append('g');

// Define d3 xScale
var x = d3.time.scale()
  .domain([new Date(minDate), new Date(maxDate)])
  .range([0, width]);

// Define main d3 xAxis
var xAxis = d3.svg.axis()
  .scale(x)
  .ticks(10);

// Draw axes
var axes = translateGroupSelect.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + 0 + ")")
  .call(xAxis);

// Define zoom
var zoom = d3.behavior.zoom()
  .x(x)
  .scaleExtent([1, 32])
  .center([width / 2, height / 2])
  .size([width, height])
  .on("zoom", draw);


// Apply zoom behavior to SVG element
svgSelect.call(zoom);


// Repetitive drawing stuff on every zoom event
function draw() {
  xAxis.ticks(calcTickAmount());
  axes.call(xAxis);
}

function calcTickAmount() {
  if (d3.event.scale > 15) {
    return 3
  } else {
    return 10;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div class="tl">
</div>

Updated Fiddle

like image 42
ksav Avatar answered Sep 23 '22 21:09

ksav