A simple version of the GiHub commit calendar, just to try to simplify this exemple by using d3.time utilities. if you need this type of calendar, you should know about the cal-heatmap plugin.
forked from biovisualize's block: Simple GitHub Calendar
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
.cell {
stroke: silver;
}
.label {
font-size: 10px;
font-family: sans-serif;
fill: #666;
}
.tooltip {
border: silver 1px solid;
background-color: white;
position: absolute;
pointer-events: none;
border-radius: 8px 8px 0px 8px;
padding: 5px;
opacity: 0.8;
font-size: 10px;
font-family: sans-serif;
}
.hovered {
stroke: black;
}
.cell-hover {
pointer-events: none;
stroke-width: 2px;
stroke: black;
}
.cell.out-of-range {
display: none;
}
</style>
</head>
<body>
<div class="container"></div>
<div class="tooltip"></div>
<script>
var firstDayOfTheMonth = new Date('01/01/2015');
var lastDayOfTheMonth = new Date('12/31/2015');
var firstDayOfWeekBeforeFirstDayOfMonth = d3.time.week.offset(firstDayOfTheMonth, -1);
var data = d3.time.weeks(firstDayOfWeekBeforeFirstDayOfMonth, lastDayOfTheMonth)
.map(function(d){
var date = new Date(d);
return d3.time.days(date, d3.time.week.offset(date, 1)).map(function(dB){ return {date: dB, value: ~~(Math.random()*100)}; });
});
var firstIncompleteWeek = d3.time.days(firstDayOfWeekBeforeFirstDayOfMonth, new Date(data[0][0].date));
var lastIncompleteWeek = d3.time.days(lastDayOfTheMonth, new Date(data[data.length-1][data[0].length -1].date));
var dataValues = d3.merge(data).map(function(d){ return d.value; });
// nullify days out of range
data[0].forEach(function(d, i){
if(i < data[0].length - firstIncompleteWeek.length){
d.value = null;
}
});
data[data.length-1].forEach(function(d, i){
if(i > data[0].length - 1 - lastIncompleteWeek.length){
d.value = null;
}
});
var config = {
width: 1000,
height: 250,
margin: {top: 80, right: 10, bottom: 40, left: 30},
dateFormatX: d3.time.format('%d %b'),
dateFormatY: d3.time.format('%a'),
dateFormatTooltip: d3.time.format('%d %b, %Y'),
labelAxisPadding: 5,
colorScale: d3.scale.linear().domain(d3.extent(dataValues)).range(['white', 'skyblue'])
};
config.chartWidth = config.width - config.margin.left - config.margin.right;
config.chartHeight = config.height - config.margin.top - config.margin.bottom;
config.cellWidth = Math.floor(config.chartWidth / data.length);
config.cellHeight = ~~(config.chartHeight / data[0].length);
var tooltip = d3.select('.tooltip').style({display: 'none'});
var chartContainer = d3.select('.container')
.append('svg')
.attr({
width: config.width,
height: config.height
})
.append('g')
.attr({
transform: 'translate(' + [config.margin.left, config.margin.top] + ')'
});
var columns = chartContainer.selectAll('g.column')
.data(data);
columns.enter().append('g')
.attr({
'class': 'column'
});
columns.selectAll('rect.cell')
.data(function(d){ return d; })
.enter().append('rect')
.classed('cell', true)
.classed('out-of-range', function(d){ return d.value === null; })
.attr({
x: function(d, i, pI){ return config.cellWidth * pI; },
y: function(d, i, pI){ return config.cellHeight * i; },
width: config.cellWidth,
height: config.cellHeight,
fill: function(d){ return config.colorScale(d.value); }
})
.on('mousemove', function(d){
var currentCell = d3.select(this);
var currentCellX = currentCell.attr('x');
var currentCellY = currentCell.attr('y');
tooltip.html(config.dateFormatTooltip(d.date) + '<br>Value: ' + d.value)
.style({
display: 'block',
left: function(){
return d3.event.clientX - this.offsetWidth + 'px';
},
top: function(){
return d3.event.clientY - this.offsetHeight + 'px';
}
});
cellHover.attr({
x: currentCellX,
y: currentCellY,
fill: config.colorScale(d.value)
})
.style({display: 'block'})
})
.on('mouseout', function(){
tooltip.style({ display: 'none'});
cellHover.style({display: 'none'})
});
columns.exit().remove();
chartContainer.selectAll('text.label.x')
.data(d3.transpose(data)[0])
.enter().append('text')
.attr({
'class': 'label x',
x: function(d, i){ return config.cellWidth * i; },
dy: function(d, i){ return - config.labelAxisPadding; },
transform: function(d, i){
return 'rotate(-60, ' + (config.cellWidth * i + 5) + ', -10)';
}
})
.text(function(d){ return config.dateFormatX(new Date(d.date)); });
chartContainer.selectAll('text.label.y')
.data(data[0])
.enter().append('text')
.attr({
'class': 'label y',
y: function(d, i){ return config.cellHeight * i + config.cellHeight / 2; }
})
.text(function(d){ return config.dateFormatY(new Date(d.date)); })
.attr({
dx: function(d, i){ return -this.getBBox().width - config.labelAxisPadding; }
});
var cellHover = chartContainer.append('rect')
.style({ display: 'none'})
.attr({
'class': 'cell-hover',
width: config.cellWidth,
height: config.cellHeight
});
</script>
</body>
</html>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js