Reputation: 11
Could someone please help me? I'm struggling with this for hours...
I want to make a bar chart using d3.js... The bars will represent an on/off state which will be fetched from a db and the db is filled from a raspberry..
I'm struggling with the x axis. I want it to represent 24 hours. So for instance if I flick a switch at 15:23:02 and then at 15:26:34 I get bars at the x axis at that time..
I found an example of a bar chart that does this but the x axis is in dates (day and date)..
The parts that are confusing for me are these:
.domain([new Date(data[0].date), d3.time.day.offset(new Date(data[data.length - 1].date), 1)])
.ticks(d3.time.days, 1)
.tickFormat(d3.time.format('%a %d'))
I know the tickFormat should be %H:%M:%S
Also the data in the example uses dates..
var data = [{"date":"2012-03-20","total":1},
... etc
When I change them to times
var data = [{"date":"14:23:43","total":1},
nothing works ofcourse..
Could someone just point me how to do it ?
Here is a jsfiddle where I'm trying to do this:
http://jsfiddle.net/hpjqt1dL/1/
Thanks in advance
Upvotes: 1
Views: 7755
Reputation: 1976
When you're dealing with just time values (with no date) one of the easiest ways of dealing with it, is to just assume that the date is equal to the current date and then have your times be offsets from 00:00
on that day.
Here's an updated fiddle that does that for you: http://jsfiddle.net/hpjqt1dL/4/
There are a number of changes:
Your data variable has been updated to reflect the change from date to time.
var data = [{
"time": "01:00:00",
"total": 1
}, {
"time": "01:05:30",
"total": 1
}, {
"time": "02:10:00",
"total": 1
}, {
"time": "03:15:30",
"total": 1
}, {
"time": "04:25:30",
"total": 1
}, {
"time": "07:55:15",
"total": 1
}, {
"time": "12:18:00",
"total": 1
}, {
"time": "17:00:00",
"total": 1
}];
Add a handler to set the date/time in each data element correctly:
var today = new Date();
today.setHours(0, 0, 0, 0);
todayMillis = today.getTime();
data.forEach(function(d) {
var parts = d.time.split(/:/);
var timePeriodMillis = (parseInt(parts[0], 10) * 60 * 60 * 1000) +
(parseInt(parts[1], 10) * 60 * 1000) +
(parseInt(parts[2], 10) * 1000);
d.time = new Date();
d.time.setTime(todayMillis + timePeriodMillis);
});
This will set the time
attribute of each data element to a value that is today
at midnight, plus the time specified in the data.
Fix up the x
scale:
var x = d3.time.scale()
.domain(extents)
.nice(d3.time.day, 1)
.rangeRound([0, width - margin.left - margin.right]);
This sets the domain to the extents specified in the data and uses nice
to round to a whole day.
Fix up the x
axis generator:
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom')
.ticks(d3.time.hours, 2)
.tickFormat(d3.time.format('%H:%M'))
.tickSize(0)
.tickPadding(8);
The ticks
and tickFormat
parameters are set to something that makes sense based on the data.
Fix up the code that creates the rects
to use the new data:
svg.selectAll('.chart')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', function (d) {
return x(d.time);
})
.attr('y', function (d) {
return height - margin.top - margin.bottom - (height - margin.top - margin.bottom - y(d.total))
})
.attr('width', 10)
.attr('height', function (d) {
return height - margin.top - margin.bottom - y(d.total)
});
The x
value that is returned is just the d.time
attribute passed to the x
scale, returning the corresponding x position in the SVG.
The data that I've chosen as an example will highlight a potential issue you may want to deal with. Due to the width of the bars that you're using, it's possible that you will end up with overlaps as the first two bars in the chart show. I'll leave it up to you to figure out how best to deal with this.
Upvotes: 3