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?
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.
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.
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).
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).
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:
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'));
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With