commitactivitygraph.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * GitPHP commit activity graph
  3. *
  4. * Display commit activity history graph
  5. *
  6. * @author Christopher Han <xiphux@gmail.com>
  7. * @copyright Copyright (c) 2012 Christopher Han
  8. * @package GitPHP
  9. * @subpackage Javascript
  10. */
  11. define(["modules/geturl", "modules/getproject", "d3"],
  12. function(url, project) {
  13. var labelrect = null;
  14. var label = null;
  15. var label2 = null;
  16. var width = 960;
  17. var height = 500;
  18. var x = null;
  19. var y = null;
  20. var histogram = null;
  21. var svg = null;
  22. var barGroup = null;
  23. var histogramdata = null;
  24. var subhistogramdata = null;
  25. var xaxis = null;
  26. var yaxis = null;
  27. var start = null;
  28. var end = null;
  29. var instructions = null;
  30. var redraw = function(mode) {
  31. if (end == histogramdata.length) {
  32. subhistogramdata = histogramdata.slice(start);
  33. } else {
  34. subhistogramdata = histogramdata.slice(start, end);
  35. }
  36. x.domain([subhistogramdata[0].x, subhistogramdata[subhistogramdata.length-1].x]);
  37. svg.transition().duration(500).select(".xaxis").call(xaxis);
  38. var bardata = barGroup.selectAll("rect")
  39. .data(subhistogramdata, function(d) { return d.x.getTime() });
  40. bardata.enter().append("rect")
  41. .attr("class", "bar")
  42. .attr("fill", "steelblue")
  43. .attr("width", 20)
  44. .style("opacity", 0)
  45. .attr("x", function(d) {
  46. if (mode == 1) {
  47. return x(d.x) - 60.5;
  48. } else if (mode == 2) {
  49. return x(d.x) + 59.5;
  50. } else {
  51. return x(d.x) - .5;
  52. }
  53. })
  54. .attr("height", 0)
  55. .on("mouseover", function(d) {
  56. var labeltext = d3.time.format("%B %Y")(d.x)
  57. var label2text = d.y + " commits";
  58. label.transition().duration(500)
  59. .style("opacity", 1)
  60. .text(labeltext);
  61. label2.transition().duration(500)
  62. .style("opacity", 1)
  63. .text(label2text);
  64. labelrect.transition().duration(500)
  65. .style("opacity", 1);
  66. })
  67. .on("mouseout", function(d) {
  68. label.transition().duration(500)
  69. .style("opacity", 0);
  70. label2.transition().duration(500)
  71. .style("opacity", 0);
  72. labelrect.transition().duration(500)
  73. .style("opacity", 0);
  74. });
  75. bardata.transition().duration(500)
  76. .attr("x", function(d, i) { return x(d.x) - .5; })
  77. .attr("height", function(d) { return height - y(d.y); })
  78. .style("opacity", 1);
  79. bardata.exit()
  80. .transition().duration(500)
  81. .attr("height", 0)
  82. .attr("x", function(d, i) {
  83. return x(d.x) - .5;
  84. })
  85. .style("opacity", 0)
  86. .remove();
  87. };
  88. var init = function(graphContainer) {
  89. x = d3.time.scale()
  90. .range([10, width-10]);
  91. y = d3.scale.linear()
  92. .range([height, 0]);
  93. instructions = d3.select(graphContainer).append("div")
  94. .style("text-align", "center")
  95. .style("padding-top", "10px")
  96. .style("width", width + "px")
  97. .style("height", "20px")
  98. .style("opacity", 0);
  99. svg = d3.select(graphContainer).append("svg")
  100. .attr("width", width + 60)
  101. .attr("height", height + 60);
  102. barGroup = svg.append("g")
  103. .attr("transform", "translate(20," + (height+20) + ")scale(1,-1)");
  104. var labelgroup = svg.append("g");
  105. labelrect = labelgroup.append("rect")
  106. .attr("width", 150)
  107. .attr("height", 70)
  108. .attr("x", (width/2)-75)
  109. .attr("y", (height/4)-30)
  110. .attr("stroke", "#EDECE6")
  111. .attr("stroke-width", 1)
  112. .attr("fill", "white")
  113. .style("opacity", 0);
  114. label = labelgroup.append("text")
  115. .attr("font-size", "16")
  116. .attr("text-anchor", "middle")
  117. .attr("dx", width/2)
  118. .attr("dy", (height/4))
  119. .text("Loading commits...");
  120. label2 = labelgroup.append("text")
  121. .attr("font-size", "16")
  122. .attr("text-anchor", "middle")
  123. .attr("dx", width/2)
  124. .attr("dy", (height/4)+20)
  125. .style("opacity", 0);
  126. d3.json(url + "?p=" + project + "&a=graphdata&g=commitactivity", function(data) {
  127. data.forEach(function(d) {
  128. d.CommitEpoch = new Date(d.CommitEpoch * 1000);
  129. });
  130. var extent = d3.extent(data, function(d) { return d.CommitEpoch; });
  131. extent[1].setMonth(extent[1].getMonth()+2);
  132. var range = d3.time.months(extent[0], extent[1]);
  133. histogram = d3.layout.histogram()
  134. .value(function(d) {
  135. return d.CommitEpoch;
  136. })
  137. .range(extent)
  138. .bins(d3.time.months(extent[0], extent[1]));
  139. histogramdata = histogram(data);
  140. start = histogramdata.length - 15;
  141. end = histogramdata.length;
  142. y.domain([0, d3.max(histogramdata, function(d) { return d.y; })]);
  143. label.transition().duration(500)
  144. .style("opacity", 0);
  145. xaxis = d3.svg.axis()
  146. .scale(x)
  147. .ticks(d3.time.months, 1)
  148. .orient("bottom");
  149. svg.append("g")
  150. .attr("class", "xaxis")
  151. .attr("transform", "translate(30," + (height+20) + ")");
  152. yaxis = d3.svg.axis()
  153. .scale(y)
  154. .ticks(10)
  155. .orient("right");
  156. svg.append("g")
  157. .attr("class", "yaxis")
  158. .attr("transform", "translate(" + (width+30) + ",20)")
  159. .call(yaxis);
  160. instructions.transition().duration(500)
  161. .text("<- Use the arrow keys to navigate ->")
  162. .style("opacity", 1);
  163. redraw();
  164. d3.select(window).on("keydown", function() {
  165. if (d3.event.keyCode == 37) {
  166. if (start > 0) {
  167. end--;
  168. start--;
  169. redraw(1);
  170. }
  171. } else if (d3.event.keyCode == 39) {
  172. if (end < histogramdata.length) {
  173. end++;
  174. start++;
  175. redraw(2);
  176. }
  177. }
  178. });
  179. });
  180. };
  181. return {
  182. init: init
  183. };
  184. }
  185. );