Built with blockbuilder.org
forked from GitNoise's block: Timeline with 2 streams and events
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width:100%; height: 100% }
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
transform: rotate(45 0 0)
}
.events line, .events circle {
stroke: darkslategray;
}
.events circle {
fill: white;
}
.general line, .fn line {
stroke: black;
stroke-opacity: 0.4;
}
.general rect, .fn rect {
fill-opacity: 0.8;
}
.events line {
stroke-dasharray: 3mm;
stroke-opacity: 0.5;
}
.txtBkgrnd rect {
fill: white;
fill-opacity: 0.8;
stroke: black;
stroke-width: 1px;
stroke-opacity: 0.4;
}
body {
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 0.8em;
}
</style>
</head>
<body>
<script>
// Feel free to change or delete any of the code you see!
var svg = d3.select("body").append("svg");
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
var adjustX = function(i) {
return ((fnGeneralTextDist - 25) + (i%3 * 25)) / Math.tan(Math.PI/4);
};
var fnEvents = [
{
id: 2000,
start: new Date('2008-01-01'),
end: new Date('2008-05-20'),
text: 'Red 1'
},
{
id: 2001,
start: new Date('2008-03-01'),
end: new Date('2008-10-31'),
text: 'Red 2'
}
];
var generalEvents = [
{
id: 1000,
start: new Date('2009-01-01'),
end: new Date('2009-12-31'),
text: 'Blue 1'
}
];
// configuration
var config = {
left: 50,
right: 200,
top: 50,
bottom: 50,
width: 680,
height: 500,
rangeRight: 680
};
var offset = 30;
var axisYPos = config.height/2;
var eventOffset = -200;
var generalFnOffset = 0;
var fnGeneralTextDist = 40;
// Scales
var xScale = d3.time.scale()
.domain([new Date('2007-01-01'), new Date('2011-12-31')])
//.range([config.left, config.width - config.right]);
.range([config.left, config.rangeRight]);
var yScale = d3.scale.linear()
.domain([0, 4])
.range([config.top, axisYPos - 20]);
// Axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
// Rendering
var svg = d3.select("svg");
// fn
var fn = svg.append("g").classed("fn", true);
fn.append("g").classed("time", true).selectAll("rect.range")
.data(fnEvents).enter()
.append("rect")
.classed("range", true)
.attr({
x: function(d) { return xScale(d.start); },
y: axisYPos - 20,
height: 20,
width: function(d) { return xScale(d.end) - xScale(d.start); },
fill: "#b44646"
});
fn.append("g").classed("fnText", true).selectAll("text")
.data(fnEvents).enter()
.append("text").attr({
x: function(d,i) { return xScale(d.start) + adjustX(i); },
y: function(d,i) {
console.log(axisYPos, fnGeneralTextDist, i)
return axisYPos - 20 - (fnGeneralTextDist-25) - i%3 * 25;
}
})
.text(function(d) { return d.text; })
.each(function(d) {
d.bbox = this.getBBox();
});
var fnLines = fn.append("g").classed("fnLines", true).selectAll("g")
.data(fnEvents).enter()
.append("g");
fnLines.append("line").classed("fnLine", true)
.attr({
x1: function(d) { return xScale(d.start); },
x2: function(d) { return xScale(d.start); },
y1: axisYPos,
y2: axisYPos - 20
});
fnLines.append("line").attr({
x1: function(d) { return xScale(d.start)},
x2: function(d,i) { return xScale(d.start) + adjustX(i) - 2; },
y1: axisYPos - 20,
y2: function(d,i) { return axisYPos - 20 - (fnGeneralTextDist-25) - i%3 * 25; }
});
// text background
fn.append("g").classed("txtBkgrnd", true).selectAll("rect")
.data(fnEvents).enter()
.append("rect")
.attr({
x: function(d) { return d.bbox.x - 2; },
y: function(d) { return d.bbox.y-2; },
width: function(d) { return d.bbox.width + 4; },
height: function(d) { return d.bbox.height + 4; }
});
d3.selectAll(".fn .fnText").moveToFront();
d3.select(".fn").attr("transform", "translate(0," + (generalFnOffset + 5) + ")");
// General stream
var general = svg.append("g").classed("general", true);
general.selectAll('.range')
.data(generalEvents).enter()
.append("rect").classed("range", true).attr({
x: function(d) { return xScale(d.start); },
y: axisYPos,
height: 20,
width: function(d) { return xScale(d.end) - xScale(d.start); },
fill: "#4682B4"
});
general.append("g").classed("generalText", true).selectAll("text")
.data(generalEvents).enter()
.append("text").attr({
x: function(d) { return xScale(d.start) + offset; },
y: axisYPos + (fnGeneralTextDist * 1.5)
})
.text(function(d) { return d.text; })
.each(function(d) {
d.bbox = this.getBBox();
});
var generalLines = general.append("g").classed("generalLine", true).selectAll("g")
.data(generalEvents).enter()
.append("g");
generalLines
.append("line")
.attr({
x1: function(d) { return xScale(d.start); },
x2: function(d) { return xScale(d.start); },
y1: axisYPos,
y2: axisYPos + 20
});
generalLines
.append("line").attr({
x1: function(d) { return xScale(d.start)},
x2: function(d) { return xScale(d.start) + offset - 2; },
y1: axisYPos + 20,
y2: axisYPos + (fnGeneralTextDist * 1.5) + 2
});
// text background
general.append("g").classed("txtBkgrnd", true).selectAll("rect")
.data(generalEvents).enter()
.append("rect")
.attr({
x: function(d) { return d.bbox.x - 2; },
y: function(d) { return d.bbox.y-2; },
width: function(d) { return d.bbox.width + 4; },
height: function(d) { return d.bbox.height + 4; }
});
d3.selectAll(".general .generalText").moveToFront();
d3.select(".general").attr("transform", "translate(0," + (generalFnOffset - 5) + ")");
// axis
var axis = svg.append("g").classed("axis", true).call(xAxis)
axis.attr({
'transform': 'translate(0,' + axisYPos + ')'
})
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-45)" );
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js