Skip to content

Instantly share code, notes, and snippets.

@jhb
Last active October 5, 2017 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhb/df33bbba4cec6e6eec30df0e4a8a3cb4 to your computer and use it in GitHub Desktop.
Save jhb/df33bbba4cec6e6eec30df0e4a8a3cb4 to your computer and use it in GitHub Desktop.
d3 time scale slightly off

d3 time axis slightly off

The problem on this diagram is tha the x axis is slightly off. Instead of starting on Tuesday 02 (Di 02) the whole axis is slightly "skewed" to the left, e.g. about 13px. On the very right of the axis you find the same extra 13 px of data for Fr 06, which shouldn't be there:

Why is this?

<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
body,html, #ct {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
#content {
width: 100%;
height: 100%;
padding: 20px;
}
#ct tr {
vertical-align: top;
}
#legend {
width: 20em;
min-width: 20em;
padding: 20px;
}
#chart {
width: 100%;
height: 100%;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar { fill: steelblue;
stroke: steelblue;
}
.bar2 { fill: #98bdcb;
stroke: #98bdcb;
}
.count, .usercount {
margin-right: 5px;
}
.count {
background: steelblue;
}
.usercount{
background: #98bdcb;
}
</style>
<script src="http://d3js.org/d3.v3.min.js"> </script>
<script src="tickformat.de.js"> </script>
</head>
<body>
<table id="ct">
<tr>
<td id="legend">
<b>Pro Tag</b><br>
<span class="count">&#160;&#160;&#160;&#160;</span> Anzahl Zugriffe<br>
<span class="usercount">&#160;&#160;&#160;&#160;</span>Unterschiedliche Nutzer<br>
<br><br>
<b>Insgesamt</b><br>
Zugriffe insgesamt: <span id="totalcount"></span> <br>
Davon in den letzten 90 Tagen: <span id="recentcount"></span><br>
</td>
<td id="content">
<svg id="chart"></svg>
</td>
</tr>
</table>
<script type="text/javascript">
function daydiff(sooner, later) {
return Math.round((later-sooner)/(1000*60*60*24));
}
var margin = {top: 5, right: 20, bottom: 20, left: 20};
d3.json("pagecount-total.json",function(error,rawdata) {
// prepare Data
var data = [];
var v;
var now = new Date();
var totalcount = 0;
var recentcount = 0;
var count = 0;
for(var key in rawdata) {
var isostring = key.substring(0, 4) + '-' + key.substring(4, 6) + '-' + key.substring(6, 8);
v = rawdata[key];
count = v['count'];
d = new Date(isostring);
totalcount += count;
if (daydiff(d,now)<90) recentcount+=count;
data.push({date: d, count: v['count'], usercount: v['usercount']});
}
console.table(data);
console.log('counts',totalcount,recentcount);
d3.select('#totalcount').text(totalcount);
d3.select('#recentcount').text(recentcount);
// set up chart object
var chart = d3.select("#chart");
var width = parseInt(chart.style('width')) - margin.left - margin.right;
var height = parseInt(chart.style('height')) - margin.top - margin.bottom;
// scales and ranges
var x = d3.time.scale().range([0,width]);
var y = d3.scale.linear().range([height,0]);
//var y2 = d3.scale.linear().range([height,0]);
// later on we set the bar width to be the size of one day. Hence the domain needs to be
// a day longer.
var dateextend = d3.extent(data, function(d) { return d.date });
var newstart = new Date();
newstart.setTime( dateextend[0].getTime() - (0 * 86400000) );
var newend = new Date();
newend.setTime( dateextend[1].getTime() + (1 * 86400000) );
console.log('newstart',newstart);
// the domains
x.domain([newstart,newend]);
//x.domain(dateextend);
y.domain([0, d3.max(data, function(d) {return d.count})]);
var numdays = daydiff(dateextend[0],dateextend[1])+1;
console.log('numdays',numdays);
xAxis = d3.svg.axis().scale(x)
.orient("bottom")
//.ticks(Math.max(width/70, 1))
.ticks(5)
.tickFormat(tickFormatDE);
yAxis = d3.svg.axis().scale(y)
.orient("left")
.ticks((Math.max(height/50, 1)))
// set up basic group for bars and axis
var g = chart.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
g.selectAll('.bar')
.data(data)
.enter()
.append('rect')
.attr('class','bar');
g.selectAll('.bar2')
.data(data)
.enter()
.append('rect')
.attr('class','bar2');
g.append("g").attr("class", "axis xaxis");
g.append("g").attr("class", "axis yaxis");
// Draw whenever a resize event occours
d3.select(window).on('resize', draw);
// And do a first draw
draw();
function draw() {
var width = parseInt(chart.style('width')) - margin.left - margin.right;
var height = parseInt(chart.style('height')) - margin.top - margin.bottom;
var barwidth = width/numdays;
if (barwidth == Infinity) barwidth=width;
console.log('width',width,'barwidth',barwidth);
// Update the range of the scale with new width/height
x.range([0, width]);
y.range([height, 0]);
g.selectAll('.bar')
.attr('x',function(d) {return x(d.date)-0*barwidth})
.attr('width',barwidth )
.attr('y',function(d){return y(d.count)})
.attr('height',function(d){return height-y(d.count)});
g.selectAll('.bar2')
.attr('x',function(d) {return x(d.date)-0.0*barwidth})
.attr('width',barwidth )
.attr('y',function(d){return y(d.usercount)})
.attr('height',function(d){return height-y(d.usercount)});
// Update the axis and text with the new scale
chart.select('.xaxis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.select('.yaxis')
.attr("transform", "translate("+(-0*barwidth)+",0)")
.call(yAxis);
}
});
</script>
</html>
{"20171002": {"count": 45, "usercount": 1}, "20171004": {"count": 11, "usercount": 1}, "20171005": {"count": 2, "usercount": 1}}
var localeFormatter = d3.locale({
"decimal": ",",
"thousands": ".",
"grouping": [3],
"currency": ["€", ""],
"dateTime": "%a %b %e %X %Y",
"date": "%d.%m.%Y",
"time": "%H:%M:%S",
"periods": ["AM", "PM"],
"days": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
"shortDays": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
"months": ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
"shortMonths": ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"]
})
var tickFormatDE = localeFormatter.timeFormat.multi([
["%H:%M", function(d) { return d.getMinutes(); }],
["%H:%M", function(d) { return d.getHours(); }],
["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
["%d. %b", function(d) { return d.getDate() != 1; }],
["%B", function(d) { return d.getMonth(); }],
["%Y", function() { return true; }]
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment