Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bullet.js 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. (function() {
  2. // Chart design based on the recommendations of Stephen Few. Implementation
  3. // based on the work of Clint Ivy, Jamie Love, and Jason Davies.
  4. // http://projects.instantcognition.com/protovis/bulletchart/
  5. d3.bullet = function() {
  6. var orient = "left", // TODO top & bottom
  7. reverse = false,
  8. duration = 0,
  9. ranges = bulletRanges,
  10. markers = bulletMarkers,
  11. measures = bulletMeasures,
  12. width = 380,
  13. height = 30,
  14. tickFormat = null;
  15. // For each small multiple…
  16. function bullet(g) {
  17. g.each(function(d, i) {
  18. var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
  19. markerz = markers.call(this, d, i).slice().sort(d3.descending),
  20. measurez = measures.call(this, d, i).slice().sort(d3.descending),
  21. g = d3.select(this);
  22. // Compute the new x-scale.
  23. var x1 = d3.scale.linear()
  24. .domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
  25. .range(reverse ? [width, 0] : [0, width]);
  26. // Retrieve the old x-scale, if this is an update.
  27. var x0 = this.__chart__ || d3.scale.linear()
  28. .domain([0, Infinity])
  29. .range(x1.range());
  30. // Stash the new scale.
  31. this.__chart__ = x1;
  32. // Derive width-scales from the x-scales.
  33. var w0 = bulletWidth(x0),
  34. w1 = bulletWidth(x1);
  35. // Update the range rects.
  36. var range = g.selectAll("rect.range")
  37. .data(rangez);
  38. range.enter().append("rect")
  39. .attr("class", function(d, i) { return "range s" + i; })
  40. .attr("width", w0)
  41. .attr("height", height)
  42. .attr("x", reverse ? x0 : 0)
  43. .transition()
  44. .duration(duration)
  45. .attr("width", w1)
  46. .attr("x", reverse ? x1 : 0);
  47. range.transition()
  48. .duration(duration)
  49. .attr("x", reverse ? x1 : 0)
  50. .attr("width", w1)
  51. .attr("height", height);
  52. // Update the measure rects.
  53. var measure = g.selectAll("rect.measure")
  54. .data(measurez);
  55. measure.enter().append("rect")
  56. .attr("class", function(d, i) { return "measure s" + i; })
  57. .attr("width", w0)
  58. .attr("height", height / 3)
  59. .attr("x", reverse ? x0 : 0)
  60. .attr("y", height / 3)
  61. .transition()
  62. .duration(duration)
  63. .attr("width", w1)
  64. .attr("x", reverse ? x1 : 0);
  65. measure.transition()
  66. .duration(duration)
  67. .attr("width", w1)
  68. .attr("height", height / 3)
  69. .attr("x", reverse ? x1 : 0)
  70. .attr("y", height / 3);
  71. // Update the marker lines.
  72. var marker = g.selectAll("line.marker")
  73. .data(markerz);
  74. marker.enter().append("line")
  75. .attr("class", "marker")
  76. .attr("x1", x0)
  77. .attr("x2", x0)
  78. .attr("y1", height / 6)
  79. .attr("y2", height * 5 / 6)
  80. .transition()
  81. .duration(duration)
  82. .attr("x1", x1)
  83. .attr("x2", x1);
  84. marker.transition()
  85. .duration(duration)
  86. .attr("x1", x1)
  87. .attr("x2", x1)
  88. .attr("y1", height / 6)
  89. .attr("y2", height * 5 / 6);
  90. // Compute the tick format.
  91. var format = tickFormat || x1.tickFormat(8);
  92. // Update the tick groups.
  93. var tick = g.selectAll("g.tick")
  94. .data(x1.ticks(8), function(d) {
  95. return this.textContent || format(d);
  96. });
  97. // Initialize the ticks with the old scale, x0.
  98. var tickEnter = tick.enter().append("g")
  99. .attr("class", "tick")
  100. .attr("transform", bulletTranslate(x0))
  101. .style("opacity", 1e-6);
  102. tickEnter.append("line")
  103. .attr("y1", height)
  104. .attr("y2", height * 7 / 6);
  105. tickEnter.append("text")
  106. .attr("text-anchor", "middle")
  107. .attr("dy", "1em")
  108. .attr("y", height * 7 / 6)
  109. .text(format);
  110. // Transition the entering ticks to the new scale, x1.
  111. tickEnter.transition()
  112. .duration(duration)
  113. .attr("transform", bulletTranslate(x1))
  114. .style("opacity", 1);
  115. // Transition the updating ticks to the new scale, x1.
  116. var tickUpdate = tick.transition()
  117. .duration(duration)
  118. .attr("transform", bulletTranslate(x1))
  119. .style("opacity", 1);
  120. tickUpdate.select("line")
  121. .attr("y1", height)
  122. .attr("y2", height * 7 / 6);
  123. tickUpdate.select("text")
  124. .attr("y", height * 7 / 6);
  125. // Transition the exiting ticks to the new scale, x1.
  126. tick.exit().transition()
  127. .duration(duration)
  128. .attr("transform", bulletTranslate(x1))
  129. .style("opacity", 1e-6)
  130. .remove();
  131. });
  132. d3.timer.flush();
  133. }
  134. // left, right, top, bottom
  135. bullet.orient = function(x) {
  136. if (!arguments.length) return orient;
  137. orient = x;
  138. reverse = orient == "right" || orient == "bottom";
  139. return bullet;
  140. };
  141. // ranges (bad, satisfactory, good)
  142. bullet.ranges = function(x) {
  143. if (!arguments.length) return ranges;
  144. ranges = x;
  145. return bullet;
  146. };
  147. // markers (previous, goal)
  148. bullet.markers = function(x) {
  149. if (!arguments.length) return markers;
  150. markers = x;
  151. return bullet;
  152. };
  153. // measures (actual, forecast)
  154. bullet.measures = function(x) {
  155. if (!arguments.length) return measures;
  156. measures = x;
  157. return bullet;
  158. };
  159. bullet.width = function(x) {
  160. if (!arguments.length) return width;
  161. width = x;
  162. return bullet;
  163. };
  164. bullet.height = function(x) {
  165. if (!arguments.length) return height;
  166. height = x;
  167. return bullet;
  168. };
  169. bullet.tickFormat = function(x) {
  170. if (!arguments.length) return tickFormat;
  171. tickFormat = x;
  172. return bullet;
  173. };
  174. bullet.duration = function(x) {
  175. if (!arguments.length) return duration;
  176. duration = x;
  177. return bullet;
  178. };
  179. return bullet;
  180. };
  181. function bulletRanges(d) {
  182. return d.ranges;
  183. }
  184. function bulletMarkers(d) {
  185. return d.markers;
  186. }
  187. function bulletMeasures(d) {
  188. return d.measures;
  189. }
  190. function bulletTranslate(x) {
  191. return function(d) {
  192. return "translate(" + x(d) + ",0)";
  193. };
  194. }
  195. function bulletWidth(x) {
  196. var x0 = x(0);
  197. return function(d) {
  198. return Math.abs(x(d) - x0);
  199. };
  200. }
  201. })();