Skip to content

Instantly share code, notes, and snippets.

@vatho
Last active February 23, 2018 15:13
Show Gist options
  • Save vatho/07b2a6a90428aa4d50f3f97ab843bfd2 to your computer and use it in GitHub Desktop.
Save vatho/07b2a6a90428aa4d50f3f97ab843bfd2 to your computer and use it in GitHub Desktop.
fresh block
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://rawgithub.com/emeeks/d3.layout.timeline/master/d3.timeline.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-format.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-time.v1.min.js"></script>
<script src="https://d3js.org/d3-time-format.v2.min.js"></script>
<script src="https://d3js.org/d3-scale.v2.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-brush.v1.min.js"></script>
<script src="https://d3js.org/d3-transition.v1.min.js"></script>
<script src="https://d3js.org/d3-drag.v1.min.js"></script>
<script src="https://d3js.org/d3-zoom.v1.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
<style>
</style>
</head>
<body>
<div id="legenda" />
<svg width="900" height="560" />
<script>
var data = [
{id: 1, start: '2018-02-01T13:00Z', end:'2018-02-05T13:00Z', category: '1', course: 'a'},
{id: 2, start: '2018-02-02T13:00Z', end:'2018-02-07T13:00Z', category: '1', course: 'b'},
{id: 3, start: '2018-02-01T13:00Z', end:'2018-02-05T13:00Z', category: '2', course: 'c'},
{id: 4, start: '2018-01-15T13:00Z', end:'2018-02-08T13:00Z', category: '7', course: 'd'},
{id: 5, start: '2018-01-05T13:00Z', end:'2018-02-27T13:00Z', category: '3', course: 'b'},
{id: 6, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '7', course: 'c'},
{id: 7, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '4', course: 'b'},
{id: 8, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '7', course: 'a'},
{id: 9, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '4', course: 'c'},
{id: 10, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '4', course: 'd'},
{id: 10, start: '2018-01-09T13:00Z', end:'2018-01-31T13:00Z', category: '4', course: 'd'},
];
data.forEach(function(d) {
d.start = new Date(d.start);
d.end = new Date(d.end);
});
var fieldForSwimlanes = 'course';
var fieldForCategories = 'category';
var swimlaneValues = d3.map(data, function(d){
return d[fieldForSwimlanes];}).keys();
var categories = d3.map(data, function(d){
return d[fieldForCategories];}).keys();
var svg = d3.select("svg"),
legenda = d3.select("#legenda"),
margin = {top: 20, right: 0, bottom: 150, left: 40},
margin2 = {top: 410, right: 0, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
legenda.selectAll(".legenda-item")
.data(categories).enter()
.append("div")
.attr("class", "legenda-item")
.append("p").text(d => d);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("end", brushed);
colorScale = d3.scaleOrdinal(d3.schemeSpectral[categories.length])
.domain(categories);
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]);
var dataExtent = d3.extent(
[d3.min(data, d=>d.start), d3.max(data, d=>d.end)]);
x.domain(dataExtent);
x2.domain(x.domain());
var xAxis = d3.axisBottom(x);
var timeline = d3.timeline()
.size([width,height])
.extent(dataExtent)
.padding(5)
.maxBandHeight(20);
var mainChart = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var overviewChart = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
mainChart.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
overviewChart.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (height2) + ")")
.call(d3.axisBottom(x2));
function drawMainChart() {
timeline.extent([x.domain()[0], x.domain()[1]]);
mainChart.selectAll(".swimlane").remove();
var swimlane = mainChart.selectAll('.swimlane')
.data(swimlaneValues)
.enter()
.append("g")
.attr("class", "swimlane")
.attr("transform", function(d, i) {
return "translate(0," + (margin.top + (i * 90)) + ")"; });
swimlane.append("rect")
.attr("x", -margin.left)
.attr("y", 0)
.attr("width", margin.left + width + margin.right)
.attr("height", height/swimlaneValues.length)
.style("fill", function (d, i) {
if(i%2==0) {
return "rgba(255,255,255,0)";
} else {
return "rgba(0,0,0,.07)";
}
});
swimlane.append("text")
.text(function(d) { return d;})
.attr("y", function(d, i) {console.log(i);return margin.top + (i * 90)})
.attr("x", -margin.left/2);
var events = swimlane.selectAll(".event")
.data(function(laneValue) {
return timeline(data.filter(function(event) {
return event.start <= x.domain()[1]
&& event.end >= x.domain()[0]
&& event[fieldForSwimlanes] === laneValue
}));
})
.enter().append("rect")
.attr("class", "event")
.attr("rx", 2)
.attr("x", function (d) { return d.start})
.attr("y", function (d) {return d.y})
.attr("height", function (d) {return d.dy})
.attr("width", function (d) {return d.end - d.start})
.style("fill", function (d) {
return colorScale(d[fieldForCategories])})
.style("stroke", "black")
.style("stroke-width", 1);
}
function drawOverviewChart() {
var mainToOverviewScale = height2/height;
var swimlane = overviewChart.selectAll('.swimlane')
.data(swimlaneValues)
.enter().append("g")
.attr("class", "swimlane")
.attr("transform", function(d, i) {
return "translate(0," + (mainToOverviewScale*(i * 90)) + ")"; });
swimlane.append("text")
.text(function(d) { return d;})
.attr("y", function(d, i) {margin.top + (i * 90)})
.attr("x", -margin2.left/2); ;
var events = swimlane.selectAll("rect")
.data(function(laneValue) {
return timeline(data.filter(function(event) {
return event[fieldForSwimlanes] === laneValue;
}));
})
.enter().append("rect")
.attr("class", "event")
.attr("rx", 2)
.attr("x", function (d) {return d.start})
.attr("y", function (d) {return d.y*mainToOverviewScale})
.attr("height", function (d) {return d.dy*mainToOverviewScale})
.attr("width", function (d) {return d.end - d.start})
.style("fill", function (d) {
return colorScale(d[fieldForCategories])})
.style("stroke", "black")
.style("stroke-width", 1);
overviewChart.append("g")
.attr("class", "brush")
.call(brush);
}
drawMainChart();
drawOverviewChart();
function brushed() {
var s = d3.event.selection || x2.range();
// s[0] -= margin.left;
x.domain(s.map(x2.invert, x2));
mainChart.select(".axis").call(xAxis);
drawMainChart();
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment