Skip to content

Instantly share code, notes, and snippets.

@erlenstar
Last active February 11, 2016 19:59
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 erlenstar/2093c590e5decc6a0ee8 to your computer and use it in GitHub Desktop.
Save erlenstar/2093c590e5decc6a0ee8 to your computer and use it in GitHub Desktop.
/*************************/
/* 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