tripalFeature.adminChart.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. Drupal.behaviors.tripalFeature_adminSummaryChart = {
  2. attach: function (context, settings) {
  3. // First add the container after the view header.
  4. var container = d3.select('#tripal-feature-admin-summary');
  5. if (container.empty) {
  6. container = d3.select('.view-header').append('div')
  7. .attr('id', 'tripal-feature-admin-summary')
  8. .classed('tripal-admin-summary',true);
  9. container.append('div')
  10. .attr('id', 'tripal-feature-admin-summary-chart')
  11. .classed('tripal-admin-chart',true);
  12. container.append('div')
  13. .attr('id', 'tripal-feature-admin-summary-figure-desc')
  14. .classed('tripal-admin-figure-desc',true);
  15. }
  16. // Set-up the dimensions for our chart canvas.
  17. // Note: these are adjusted below so think of these are your minimum size.
  18. var margin = {top: 20, right: 50, bottom: 20, left: 100},
  19. fullWidth = document.getElementById('tripal-feature-admin-summary').offsetWidth,
  20. width = fullWidth - margin.left - margin.right,
  21. height = 300 - margin.top - margin.bottom;
  22. var color = d3.scale.ordinal()
  23. .range(["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"]);
  24. var formatNum = d3.format("0,000");
  25. // The data was parsed and saved into tripalFeature.admin.summary
  26. // in the preprocess function for this template.
  27. if (Drupal.settings.tripalFeature.admin.summary) {
  28. // Determine the max number of characters in both the type name
  29. // and the total number of features per bar for use in width/magin adjustments.
  30. var maxTypeLength = 0;
  31. var maxTotalLength = 0;
  32. var numBars = Drupal.settings.tripalFeature.admin.summary.length;
  33. for(var i=0; i < numBars; i++){
  34. var element = Drupal.settings.tripalFeature.admin.summary[i];
  35. if(element.name.length > maxTypeLength){
  36. maxTypeLength = element.name.length;
  37. }
  38. if(element.total_features.length > maxTotalLength){
  39. maxTotalLength = element.total_features.length;
  40. }
  41. }
  42. // Ensure a minimum in case something goes wrong...
  43. if (maxTotalLength < 4) { maxTotalLength = 4; }
  44. if (maxTypeLength < 10) { maxTypeLength = 10; }
  45. // Adjust our bottom margin based on the length of type names in the data.
  46. // Assume 4px/character based on the slope of the label.
  47. xAxisHeight = maxTypeLength * 3;
  48. margin.bottom = xAxisHeight + 25;
  49. // Adjust the width of the chart based on the number or bars (types)
  50. // and the length of the bar totals which need to fit on the top of the bar.
  51. // Assume 9px/character since it's not rotated.
  52. if ((width + margin.left + margin.right) < (numBars * (maxTotalLength * 9))) {
  53. width = numBars * (maxTotalLength * 9);
  54. }
  55. // Also if we need to put the legend along the top we need to
  56. // increase the top margin.
  57. if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {
  58. // Draw a top legend in the margin.
  59. var columnWidth = d3.max(Drupal.settings.tripalFeature.admin.organisms, function(d,i) {return d.length;}) * 10;
  60. var maxNumColumns = Math.round(width / columnWidth);
  61. var numRows = Math.ceil(Drupal.settings.tripalFeature.admin.organisms.length / maxNumColumns);
  62. var idealNumColumns = Math.round(Drupal.settings.tripalFeature.admin.organisms.length / numRows);
  63. var legendMargin = {
  64. left: (width - (idealNumColumns * columnWidth))/2,
  65. right: (width - (idealNumColumns * columnWidth))/2,
  66. bottom: 25
  67. };
  68. margin.top = margin.top + (numRows * 20) + legendMargin.bottom;
  69. }
  70. // Set-up the scales of the chart.
  71. var x0 = d3.scale.ordinal()
  72. .rangeRoundBands([0, width], .1);
  73. var x1 = d3.scale.ordinal();
  74. var y = d3.scale.linear()
  75. .range([height, 0]);
  76. // Now set-up the axis functions.
  77. var xAxis = d3.svg.axis()
  78. .scale(x0)
  79. .orient('bottom');
  80. var yAxis = d3.svg.axis()
  81. .scale(y)
  82. .orient('left')
  83. .ticks(10, '');
  84. // Create our chart canvas.
  85. var svg = d3.select('#tripal-feature-admin-summary-chart').append('svg')
  86. .attr('width', width + margin.left + margin.right)
  87. .attr('height', height + margin.top + margin.bottom)
  88. .append('g')
  89. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  90. // map the data to the x & y axis' of our chart.
  91. data = Drupal.settings.tripalFeature.admin.summary;
  92. x0.domain(data.map(function(d) { return d.name; }));
  93. x1.domain(Drupal.settings.tripalFeature.admin.organisms).rangeRoundBands([0, x0.rangeBand()]);
  94. y.domain([0, Drupal.settings.tripalFeature.admin.maxBarHeight]);
  95. // Create the x-axis.
  96. var xaxis = svg.append('g')
  97. .attr('class', 'x axis')
  98. .attr('transform', 'translate(0,' + height + ')')
  99. .call(xAxis);
  100. xaxis.selectAll("text")
  101. .style("text-anchor", "end")
  102. .attr("dx", "-.8em")
  103. .attr("dy", ".15em")
  104. .attr("transform", function(d) { return "rotate(-25)"; });
  105. // Label the x-axis.
  106. xaxis.append('g')
  107. .attr('class', 'axis-label')
  108. .attr('transform', 'translate(' + width/2 + ',' + xAxisHeight + ')')
  109. .append('text')
  110. .attr('font-size', '16px')
  111. .attr('dy', '.71em')
  112. .style('text-anchor', 'middle')
  113. .text('Types of Features');
  114. // Create the y-axis.
  115. var yaxis = svg.append('g')
  116. .attr('class', 'y axis')
  117. .call(yAxis);
  118. // Label the y-axis.
  119. yaxis.append('g')
  120. .attr('class', 'axis-label')
  121. .attr('transform', 'translate(-70,' + height/2 + ')')
  122. .append('text')
  123. .attr('transform', 'rotate(-90)')
  124. .attr('font-size', '16px')
  125. .attr('dy', '.71em')
  126. .style('text-anchor', 'middle')
  127. .text('Total Number of Features');
  128. // Add a g element to contain each set of bars (1 per type).
  129. var type = svg.selectAll(".type")
  130. .data(data)
  131. .enter().append("g")
  132. .attr("class", "g")
  133. .attr("transform", function(d) { return "translate(" + x0(d.name) + ",0)"; });
  134. // Now add the bars :)
  135. // Keep in mind some processing was done in the preprocess function to
  136. // generate the bars array based on the organisms array
  137. // and pre-calculated the y0 & y1 used here.
  138. type.selectAll("rect")
  139. .data(function(d) { return d.bars; })
  140. .enter().append("rect")
  141. .attr("width", x0.rangeBand())
  142. .attr("y", function(d) { return y(d.y1); })
  143. .attr("height", function(d) { return y(d.y0) - y(d.y1); })
  144. .style("fill", function(d) { return color(d.name); })
  145. .append("svg:title")
  146. .text(function(d) { return formatNum(d.y1 - d.y0); });
  147. // Add the total to the top of the bar.
  148. svg.selectAll("g.bar-totals")
  149. .data(data)
  150. .enter().append('g')
  151. .classed('bar-totals', true)
  152. .append("text")
  153. .attr("class", "bar-label")
  154. .attr("text-anchor", "middle")
  155. .attr('font-size', '10px')
  156. .attr("x", function(d) { return x0(d.name) + x0.rangeBand()/2; })
  157. .attr("y", function(d) { return y(d.total_features) -5; })
  158. .text(function(d) { return formatNum(d.total_features); });
  159. // Legend
  160. //---------
  161. // NOTE: we would prefer to have the legend overlapping the chart on the
  162. // right side but this could be a problem if you have a similar count
  163. // for all features (legend overlaps bars) or a large number of types
  164. // (legend gets pushed out of the viewable screen area). In these cases
  165. // switch to a bottom legend.
  166. if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {
  167. // Draw a bottom legend in the margin.
  168. var legend = svg.append('g')
  169. .classed('legend', true)
  170. .attr('transform', 'translate(' + (legendMargin.left - 20) + ',-' + margin.top + ')');
  171. var legendItem = legend.selectAll('g')
  172. .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())
  173. .enter().append("g")
  174. .attr("class", "legend-item")
  175. .attr("transform", function(d,i) {
  176. xOff = (i % idealNumColumns) * columnWidth;
  177. yOff = Math.floor(i / idealNumColumns) * 25;
  178. return "translate(" + xOff + "," + yOff + ")"
  179. });
  180. legendItem.append("rect")
  181. //.attr("x", width - 18)
  182. .attr("width", 18)
  183. .attr("height", 18)
  184. .style("fill", color);
  185. legendItem.append("text")
  186. .attr("x", 24)
  187. .attr("y", 9)
  188. .attr("dy", ".35em")
  189. .style("text-anchor", "start")
  190. .attr('font-style','italic')
  191. .text(function(d) { return d; });
  192. }
  193. else {
  194. // Draw a right inset legend.
  195. var legend = svg.append('g')
  196. .classed('legend', true)
  197. .attr('transform', 'translate(0,-' + margin.top + ')');
  198. var legendItem = legend.selectAll('g')
  199. .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())
  200. .enter().append("g")
  201. .attr("class", "legend")
  202. .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
  203. legendItem.append("rect")
  204. .attr("x", width - 18)
  205. .attr("width", 18)
  206. .attr("height", 18)
  207. .style("fill", color);
  208. legendItem.append("text")
  209. .attr("x", width - 24)
  210. .attr("y", 9)
  211. .attr("dy", ".35em")
  212. .style("text-anchor", "end")
  213. .attr('font-style','italic')
  214. .text(function(d) { return d; });
  215. }
  216. // Add a small blurb mentioning this is from an mview and you should update ;).
  217. d3.selectAll('#tripal-feature-admin-summary-figure-desc')
  218. .html(Drupal.settings.tripalFeature.admin.figureDesc);
  219. }
  220. }
  221. };