Last active
February 11, 2016 19:59
-
-
Save erlenstar/2093c590e5decc6a0ee8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*************************/ | |
/* Rendering Timelines | |
/*************************/ | |
// render all the timelines, based on opportunities, into a target element (d3.selection) | |
function renderTimelines($target, collects, downlinks) { | |
var ops = collects.concat(downlinks); | |
var sorted_ops = R.sortBy(R.prop("start_time"), ops); | |
var timelineWidth = (R.last(ops).end_time - R.head(ops).start_time) / 1000; | |
// consolidated satellite and groundstation timelines | |
var $hscroll = $target.append("div").attr("class", "hscroll"); | |
renderTimeline( | |
$hscroll.append("div").classed("collects-timeline", true) | |
, sorted_ops | |
, "scid" | |
, "gsid" | |
, d3.scale.category10() | |
, 100 | |
, timelineWidth | |
); | |
renderTimelineAxis($hscroll, timelineWidth, sorted_ops); | |
// only render scheduled downlinks | |
renderTimeline( | |
$hscroll.append("div").classed("downlinks-timeline", true) | |
, downlinks.filter(function(d) { return d.scheduled; }) | |
, "gsid" | |
, "scid" | |
, d3.scale.category10() | |
, 100 | |
, timelineWidth | |
); | |
} | |
// render a timeline with elements positioned along y by an ordinal prop and colored by another prop | |
// generally sat/rgs | |
function renderTimeline($target, ops, yProp, colorProp, colorScale, trackHeight, width) { | |
trackHeight = trackHeight || 30; | |
width = width || 4000; | |
var firstOp = R.head(ops) | |
, lastOp = R.last(ops) | |
, scaleBuffer = (1000 * 120) // add two minutes of buffer at each edge | |
; | |
var yPropDomain = R.uniq(R.pluck(yProp, ops)) | |
, colorPropDomain = R.uniq(R.pluck(colorProp, ops)) | |
, height = yPropDomain.length * trackHeight | |
, yScale = d3.scale.ordinal().domain(yPropDomain.sort(d3.ascending)).rangePoints([0, height -trackHeight]) | |
, xScale = d3.scale.linear().domain([firstOp.start_time, lastOp.end_time]).range([0, width]) | |
, widthScale = d3.scale.linear().domain([0, lastOp.end_time - firstOp.start_time]).range([0, width]) | |
, rectColor = colorScale | |
; | |
var $svg = $target.append("svg") | |
.classed("timeline", true) | |
.attr("width", width) | |
.attr("height", height); | |
// draw each opportunity | |
$svg.selectAll("rect.op") | |
.data(ops) | |
.enter().append("rect") | |
.attr("class", function(d) { | |
return "op " + d.opp_type + " " + d.scheduled + " opp-" + d.id; | |
}) | |
.classed("scheduled", function(d) { return d.scheduled; }) | |
.on("mouseover", function(d) { | |
highlightOpp(d.id, true); | |
}) | |
.on("mouseout", function(d) { | |
highlightOpp(d.id, false); | |
}) | |
.on("click", function(d) { | |
scrollToRow(d.id); | |
}) | |
.attr("height", function(d) { return d.scheduled ? trackHeight : trackHeight / 2 - 1; }) | |
.attr("width", function(d) { return widthScale(d.end_time - d.start_time); }) | |
.attr("x", function(d) { return xScale(d.start_time); }) | |
.attr("y", function(d) { return yScale(d[yProp]); }) | |
.append("title").text(function(d) { return makeOppTitle(d); }); | |
// y-axis labels | |
$svg.selectAll("text.label") | |
.data(yPropDomain) | |
.enter().append("text") | |
.classed("label", true) | |
.text(function(d) { return d; }) | |
.attr("x", 6) | |
.attr("y", function(d) { return yScale(d) + 24; }); | |
// lane lines | |
$svg.selectAll("line.lane") | |
.data(yPropDomain) | |
.enter().append("line") | |
.classed("lane", true) | |
.attr("x1", 0) | |
.attr("x2", width) | |
.attr("y1", function(d) { return yScale(d); }) | |
.attr("y2", function(d) { return yScale(d); }); | |
} | |
function renderTimelineAxis($target, width, opps) { | |
var mainX = d3.time.scale().domain([R.head(opps).start_time, R.last(opps).end_time]).range([0, width]) | |
, height = 30 | |
; | |
var $svg = $target.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var mainAxis = $svg.append("g") | |
.attr("class", "axis") | |
.attr("height", height); | |
mainAxis.append("rect") | |
.attr("width", width) | |
.attr("height", height) | |
.attr("class", "background"); | |
// main bottom tiny | |
var mainXTinyAxis = d3.svg.axis() | |
.scale(mainX) | |
.orient('bottom') | |
.ticks(d3.time.minutes, 1) | |
.tickFormat(d3.time.format('')) | |
.tickSize(height, 0); | |
var $mainXTinyAxis = mainAxis.append('g') | |
.attr('class', 'axis minorTime') | |
.call(mainXTinyAxis); | |
// main bottom minor | |
var mainXMinorAxis = d3.svg.axis() | |
.scale(mainX) | |
.orient('bottom') | |
.ticks(d3.time.minutes, 10) | |
.tickFormat(d3.time.format('%H:%M')) | |
.tickSize(height / 4, 0); | |
var $mainXMinorAxis = mainAxis.append('g') | |
.attr('class', 'axis minorTime') | |
.call(mainXMinorAxis); | |
// main bottom major | |
var mainXAxis = d3.svg.axis() | |
.scale(mainX) | |
.orient('bottom') | |
.ticks(d3.time.hours, 1) | |
.tickFormat(d3.time.format('')) | |
.tickSize(height / 3, 0); | |
var $mainXAxis = mainAxis.append('g') | |
.attr('class', 'axis majorTime') | |
.call(mainXAxis); | |
// bottom line | |
mainAxis.append('line') | |
.attr("x1", 0) | |
.attr("x2", width) | |
.attr('y1', height) | |
.attr('y2', height) | |
.attr("stroke", "#fff") | |
.attr('clip-path', 'url(#clip)'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment