Reputation: 361
Let's consider a horizontal bar chart as shown in the attached photo. I need to show the duration of each segment along with the x-axis
. I am able to show the tick values using d3.svg.axis().tickValues(vals)
.
But I need to show the duration in between two ticks. Can anyone help me to achieve this using d3?
Thanks in advance.
Upvotes: 1
Views: 88
Reputation: 102219
Here is my solution. I'm using D3 version 3 (because you wrote d3.svg.axis() in your question) and a linear scale, just to show you the principle. You can easily change it to a time scale.
Given this data:
var data = [0, 10, 40, 45, 85, 100];
We're gonna plot the differences between the ticks, i.e.: 10, 30, 5, 40 and 15.
The first step is setting the scale:
var scale = d3.scale.linear()
.domain(d3.extent(data))
.range([margin, w - margin]);
Then, in the axis generator, we set the ticks to match the data with:
.tickValues(data)
And we calculate the correct numbers with:
.tickFormat(function(d,i){
if(i>0){
return data[i] - data[i-1];
} else { return ""};
});
The last step is translating the text to the middle position:
var ticks = d3.selectAll(".tick text").each(function(d, i) {
d3.select(this).attr("transform", function() {
if (i > 0) {
return "translate(" + (-scale(data[i] - data[i - 1]) / 2 + margin/2) + ",0)";
}
})
})
Check the demo:
var w = 500,
h = 100;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var data = [0, 10, 40, 45, 85, 100];
var margin = 20;
var scale = d3.scale.linear()
.domain(d3.extent(data))
.range([margin, w - margin]);
var colors = d3.scale.category10();
var rects = svg.selectAll(".rects")
.data(data)
.enter()
.append("rect");
rects.attr("y", 10)
.attr("height", 35)
.attr("fill", (d,i)=> colors(i))
.attr("x", d=>scale(d))
.attr("width", (d,i)=> {
return scale(data[i+1] - data[i]) - margin
});
var axis = d3.svg.axis()
.scale(scale)
.orient("bottom")
.tickValues(data)
.tickFormat(function(d, i) {
if (i > 0) {
return data[i] - data[i - 1];
} else {
return ""
};
});
var gX = svg.append("g")
.attr("transform", "translate(0,50)")
.attr("class", "axis")
.call(axis);
var ticks = d3.selectAll(".tick text").each(function(d, i) {
d3.select(this).attr("transform", function() {
if (i > 0) {
return "translate(" + (-scale(data[i] - data[i - 1]) / 2 + margin / 2) + ",0)";
}
})
})
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1