Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.js: get tick format from time scale

I'm building a timeline visualisation with d3 where the domain can vary from a couple of days to several decades. I'm using a d3 time scale and axis like this:

var timeScale = d3.time.scale()
    .domain([firstEvent, lastEvent])
    .range([leftPadding, w - rightPadding]);
var timeAxis = d3.svg.axis()
    .scale(timeScale)
    .orient("bottom");
timeAxis.ticks(5);

Since the domain is so variable, it is convenient to use ticks(x) which will automatically choose the tick format. My problem is that in some cases, the year is not shown, which is crucial. My idea was to check the tick format after the axis is created, and if it doesn't contain a year, show it manually next to the axis. However, I haven't been able to get the scale's tick format; using timeScale.tickFormat() just returns a function. How can I solve this problem?

like image 760
smcs Avatar asked Sep 26 '22 22:09

smcs


2 Answers

How about a simple regex test?

var hasYear = false;
var re = /^\d{4}$/;
// get the ticks text    
d3.selectAll('.x>.tick>text').each(function(d){
  // does the text look like a year?
  var txt = this.textContent;
  if (re.test(txt)){
    hasYear = true;
  }
});
console.log(hasYear);

Used this sample code and played around with various ranges:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

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

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

</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>

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

var x = d3.time.scale()
    .domain([new Date(2013, 12, 2), new Date(2013, 12, 6)])
    .range([0, width]);

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

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 + ")");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
    
xAxis.ticks().some(function(d){
  return /^\d{4}$/.exec("3434")
})

var hasYear = false;
var re = /^\d{4}$/;
d3.selectAll('.x>.tick>text').each(function(d){
  var txt = this.textContent;
  if (re.test(txt)){
    hasYear = true;
  }
});
console.log(hasYear);


</script>
like image 142
Mark Avatar answered Oct 11 '22 03:10

Mark


D3's time axis formatting checks whether any of the dates displayed on the ticks is on midnight, first of January to display only the year. You can check whether a full year will be displayed by getting the ticks and then checking this condition:

function isYear(t) {
  return +t == +(new Date(t.getFullYear(), 0, 1, 0, 0, 0, 0));
}
var ticks = timeScale.ticks();
var willDisplayYear = ticks.some(isYear);

Complete demo for both cases here.

like image 23
Lars Kotthoff Avatar answered Oct 11 '22 05:10

Lars Kotthoff