|
| 1 | +// Find the element where the commit timeline should be drawn |
| 2 | +var commits = d3.select("#commits"); |
| 3 | + |
| 4 | +var orgName = commits.attr("orgName") || "JavaPosseRoundup"; |
| 5 | +var startDate = commits.attr("startDate") || ""; |
| 6 | +var leftRightPadding = commits.attr("left-right-padding") || 20; |
| 7 | +var topBottomPadding = commits.attr("top-bottom-padding") || 150; |
| 8 | +var width = commits.attr("width") || $(document).width() - leftRightPadding; |
| 9 | +var height = commits.attr("height") || $(window).height() - topBottomPadding; |
| 10 | +var leftMargin = commits.attr("left-margin") || 180; |
| 11 | +var rightMargin = commits.attr("right-margin") || 0; |
| 12 | +var topMargin = commits.attr("top-margin") || 20; |
| 13 | +var bottomMargin = commits.attr("bottom-margin") || 60; |
| 14 | + |
| 15 | +var w = width - leftMargin - rightMargin, |
| 16 | + h = height - topMargin - bottomMargin; |
| 17 | + |
| 18 | +// Scales. Note the inverted domain for the y-scale: bigger is up! |
| 19 | +var x = d3.time.scale().rangeRound([0, w]), |
| 20 | + y = d3.scale.ordinal().rangePoints([0, h], .5), |
| 21 | + colors = d3.scale.category20(); |
| 22 | + |
| 23 | +// Axes. |
| 24 | +var xAxis = d3.svg.axis().scale(x).tickSubdivide(true); |
| 25 | +var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left"); |
| 26 | + |
| 27 | +// Add an SVG element with the desired dimensions and margin. |
| 28 | +var svg = commits.append("svg") |
| 29 | + .attr("width", width) |
| 30 | + .attr("height", height) |
| 31 | + .append("g") |
| 32 | + .attr("transform", "translate(" + leftMargin + "," + topMargin + ")"); |
| 33 | + |
| 34 | +// Add the clip path. |
| 35 | +svg.append("clipPath") |
| 36 | + .attr("id", "clip") |
| 37 | + .append("rect") |
| 38 | + .attr("width", w) |
| 39 | + .attr("height", h); |
| 40 | + |
| 41 | +// Need something in the background absorb the mouse events! |
| 42 | +svg.append("rect") |
| 43 | + .attr("width", w) |
| 44 | + .attr("height", h) |
| 45 | + .style("fill-opacity", ".0"); |
| 46 | + |
| 47 | +function drawChart(allCommits, timelines) { |
| 48 | + |
| 49 | + var tickHeight = height / (timelines.length * 4 + 1); |
| 50 | + |
| 51 | + var earliestCommitDate = d3.min(timelines, function(d) { return d.earliest; }); |
| 52 | + |
| 53 | + var start = d3.time.format("%Y-%m-%d").parse(startDate) || earliestCommitDate; |
| 54 | + |
| 55 | + x.domain([d3.time.day.floor(start), d3.time.day.ceil(new Date())]); |
| 56 | + |
| 57 | + y.domain(timelines.map(function(t) { return t.repo; })); |
| 58 | + |
| 59 | + // Add the x-axis. |
| 60 | + svg.append("g") |
| 61 | + .attr("class", "x axis") |
| 62 | + .attr("transform", "translate(0," + (h + topMargin + tickHeight) + ")") |
| 63 | + .call(xAxis); |
| 64 | + |
| 65 | + // Add the y-axis. |
| 66 | + svg.append("g") |
| 67 | + .attr("class", "y axis") |
| 68 | + .call(yAxis); |
| 69 | + |
| 70 | + svg.selectAll(".commit") |
| 71 | + .data(allCommits) |
| 72 | + .enter().append("line") |
| 73 | + .attr("class", "commit") |
| 74 | + .attr("clip-path", "url(#clip)") |
| 75 | + .attr("x1", function(d) { return x(d.commitDate); }) |
| 76 | + .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; }) |
| 77 | + .attr("x2", function(d) { return x(d.commitDate); }) |
| 78 | + .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; }) |
| 79 | + .style("stroke", function(d) { return colors(d.committerEmail); }) |
| 80 | + .on("mouseover", showCommitInfo); |
| 81 | + |
| 82 | + svg.selectAll(".timeline") |
| 83 | + .data(timelines) |
| 84 | + .enter().append("line") |
| 85 | + .attr("class", "timeline") |
| 86 | + .attr("clip-path", "url(#clip)") |
| 87 | + .attr("x1", function(d) { return x(d.earliest); }) |
| 88 | + .attr("y1", function(d) { return Math.floor(y(d.repo)); }) |
| 89 | + .attr("x2", function(d) { return x(d.latest); }) |
| 90 | + .attr("y2", function(d) { return Math.floor(y(d.repo)); }); |
| 91 | + |
| 92 | + svg.call(d3.behavior.zoom().x(x).on("zoom", zoom)); |
| 93 | + |
| 94 | + function zoom() { |
| 95 | + svg.select(".x.axis").call(xAxis); |
| 96 | + svg.selectAll(".commit") |
| 97 | + .data(allCommits) |
| 98 | + .attr("x1", function(d) { return x(d.commitDate); }) |
| 99 | + .attr("x2", function(d) { return x(d.commitDate); }); |
| 100 | + svg.selectAll(".timeline") |
| 101 | + .data(timelines) |
| 102 | + .attr("x1", function(d) { return x(d.earliest); }) |
| 103 | + .attr("x2", function(d) { return x(d.latest); }); |
| 104 | + svg.selectAll(".committer, .message") |
| 105 | + .attr("x", function(d) { return x(d.commitDate); }); |
| 106 | + } |
| 107 | + |
| 108 | + function showCommitInfo(d, i) { |
| 109 | + |
| 110 | + var committer = svg.selectAll(".committer") |
| 111 | + .data([d], function(d) { return d.sha; }); |
| 112 | + |
| 113 | + committer.enter().append("text") |
| 114 | + .attr("class", "committer") |
| 115 | + .attr("x", x(d.commitDate)) |
| 116 | + .attr("y", y(d.repo)) |
| 117 | + .attr("dx", -2) |
| 118 | + .attr("dy", 2 * tickHeight + 5) |
| 119 | + .attr("text-anchor", "end") |
| 120 | + .style("fill", colors(d.committerEmail)) |
| 121 | + .text(d.committerName); |
| 122 | + |
| 123 | + committer.exit().remove(); |
| 124 | + |
| 125 | + var message = svg.selectAll(".message") |
| 126 | + .data([d], function(d) { return d.sha; }); |
| 127 | + |
| 128 | + message.enter().append("text") |
| 129 | + .attr("class", "message") |
| 130 | + .attr("x", x(d.commitDate)) |
| 131 | + .attr("y", y(d.repo)) |
| 132 | + .attr("dx", 2) |
| 133 | + .attr("dy", 2 * tickHeight + 5) |
| 134 | + .text(d.message); |
| 135 | + |
| 136 | + message.exit().remove(); |
| 137 | + } |
| 138 | + |
| 139 | +} |
0 commit comments