Guest User

Untitled

a guest
Apr 20th, 2018
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.25 KB | None | 0 0
  1. (function() {
  2.  
  3.  
  4. d3.bullet = function() {
  5. var orient = "left", // TODO top & bottom
  6. reverse = false,
  7. duration = 0,
  8. ranges = bulletRanges,
  9. markers = bulletMarkers,
  10. measures = bulletMeasures,
  11. width = 380,
  12. height = 30,
  13. tickFormat = null;
  14.  
  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.  
  23. // Compute the new x-scale.
  24. var x1 = d3.scale.linear()
  25. .domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
  26. .range(reverse ? [width, 0] : [0, width]);
  27.  
  28. // Retrieve the old x-scale, if this is an update.
  29. var x0 = this.__chart__ || d3.scale.linear()
  30. .domain([0, Infinity])
  31. .range(x1.range());
  32.  
  33. // Stash the new scale.
  34. this.__chart__ = x1;
  35.  
  36. // Derive width-scales from the x-scales.
  37. var w0 = bulletWidth(x0),
  38. w1 = bulletWidth(x1);
  39.  
  40. // Update the range rects.
  41. var range = g.selectAll("rect.range")
  42. .data(rangez);
  43.  
  44. range.enter().append("rect")
  45. .attr("class", function(d, i) { return "range s" + i; })
  46. .attr("width", w0)
  47. .attr("height", height)
  48. .attr("x", reverse ? x0 : 0)
  49. .transition()
  50. .duration(duration)
  51. .attr("width", w1)
  52. .attr("x", reverse ? x1 : 0);
  53.  
  54. range.transition()
  55. .duration(duration)
  56. .attr("x", reverse ? x1 : 0)
  57. .attr("width", w1)
  58. .attr("height", height);
  59.  
  60. // Update the measure rects.
  61. var measure = g.selectAll("rect.measure")
  62. .data(measurez);
  63.  
  64. measure.enter().append("rect")
  65. .attr("class", function(d, i) { return "measure s" + i; })
  66. .attr("width", w0)
  67. .attr("height", height / 3)
  68. .attr("x", reverse ? x0 : 0)
  69. .attr("y", height / 3)
  70. .transition()
  71. .duration(duration)
  72. .attr("width", w1)
  73. .attr("x", reverse ? x1 : 0);
  74.  
  75. measure.transition()
  76. .duration(duration)
  77. .attr("width", w1)
  78. .attr("height", height / 3)
  79. .attr("x", reverse ? x1 : 0)
  80. .attr("y", height / 3);
  81.  
  82. // Update the marker lines.
  83. var marker = g.selectAll("line.marker")
  84. .data(markerz);
  85.  
  86. marker.enter().append("line")
  87. .attr("class", "marker")
  88. .attr("x1", x0)
  89. .attr("x2", x0)
  90. .attr("y1", height / 6)
  91. .attr("y2", height * 5 / 6)
  92. .transition()
  93. .duration(duration)
  94. .attr("x1", x1)
  95. .attr("x2", x1);
  96.  
  97. marker.transition()
  98. .duration(duration)
  99. .attr("x1", x1)
  100. .attr("x2", x1)
  101. .attr("y1", height / 6)
  102. .attr("y2", height * 5 / 6);
  103.  
  104. // Compute the tick format.
  105. var format = tickFormat || x1.tickFormat(8);
  106.  
  107. // Update the tick groups.
  108. var tick = g.selectAll("g.tick")
  109. .data(x1.ticks(8), function(d) {
  110. return this.textContent || format(d);
  111. });
  112.  
  113. // Initialize the ticks with the old scale, x0.
  114. var tickEnter = tick.enter().append("g")
  115. .attr("class", "tick")
  116. .attr("transform", bulletTranslate(x0))
  117. .style("opacity", 1e-6);
  118.  
  119. tickEnter.append("line")
  120. .attr("y1", height)
  121. .attr("y2", height * 7 / 6);
  122.  
  123. tickEnter.append("text")
  124. .attr("text-anchor", "middle")
  125. .attr("dy", "1em")
  126. .attr("y", height * 7 / 6)
  127. .text(format);
  128.  
  129. // Transition the entering ticks to the new scale, x1.
  130. tickEnter.transition()
  131. .duration(duration)
  132. .attr("transform", bulletTranslate(x1))
  133. .style("opacity", 1);
  134.  
  135. // Transition the updating ticks to the new scale, x1.
  136. var tickUpdate = tick.transition()
  137. .duration(duration)
  138. .attr("transform", bulletTranslate(x1))
  139. .style("opacity", 1);
  140.  
  141. tickUpdate.select("line")
  142. .attr("y1", height)
  143. .attr("y2", height * 7 / 6);
  144.  
  145. tickUpdate.select("text")
  146. .attr("y", height * 7 / 6);
  147.  
  148. // Transition the exiting ticks to the new scale, x1.
  149. tick.exit().transition()
  150. .duration(duration)
  151. .attr("transform", bulletTranslate(x1))
  152. .style("opacity", 1e-6)
  153. .remove();
  154. });
  155. d3.timer.flush();
  156. }
  157.  
  158. // left, right, top, bottom
  159. bullet.orient = function(x) {
  160. if (!arguments.length) return orient;
  161. orient = x;
  162. reverse = orient == "right" || orient == "bottom";
  163. return bullet;
  164. };
  165.  
  166. // ranges (bad, satisfactory, good)
  167. bullet.ranges = function(x) {
  168. if (!arguments.length) return ranges;
  169. ranges = x;
  170. return bullet;
  171. };
  172.  
  173. // markers (previous, goal)
  174. bullet.markers = function(x) {
  175. if (!arguments.length) return markers;
  176. markers = x;
  177. return bullet;
  178. };
  179.  
  180. // measures (actual, forecast)
  181. bullet.measures = function(x) {
  182. if (!arguments.length) return measures;
  183. measures = x;
  184. return bullet;
  185. };
  186.  
  187. bullet.width = function(x) {
  188. if (!arguments.length) return width;
  189. width = x;
  190. return bullet;
  191. };
  192.  
  193. bullet.height = function(x) {
  194. if (!arguments.length) return height;
  195. height = x;
  196. return bullet;
  197. };
  198.  
  199. bullet.tickFormat = function(x) {
  200. if (!arguments.length) return tickFormat;
  201. tickFormat = x;
  202. return bullet;
  203. };
  204.  
  205. bullet.duration = function(x) {
  206. if (!arguments.length) return duration;
  207. duration = x;
  208. return bullet;
  209. };
  210.  
  211. return bullet;
  212. };
  213.  
  214. function bulletRanges(d) {
  215. return d.ranges;
  216. }
  217.  
  218. function bulletMarkers(d) {
  219. return d.markers;
  220. }
  221.  
  222. function bulletMeasures(d) {
  223. return d.measures;
  224. }
  225.  
  226. function bulletTranslate(x) {
  227. return function(d) {
  228. return "translate(" + x(d) + ",0)";
  229. };
  230. }
  231.  
  232. function bulletWidth(x) {
  233. var x0 = x(0);
  234. return function(d) {
  235. return Math.abs(x(d) - x0);
  236. };
  237. }
  238.  
  239. })();
  240. <!DOCTYPE html>
  241. <meta charset="utf-8">
  242. <style>
  243.  
  244. body {
  245. font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  246. margin: auto;
  247. padding-top: 40px;
  248. position: relative;
  249. width: 960px;
  250. }
  251.  
  252. button {
  253. position: absolute;
  254. left: 10px;
  255. top: 10px;
  256. }
  257.  
  258. .bullet { font: 10px sans-serif; }
  259. .bullet .marker { stroke: #000; stroke-width: 2px; }
  260. .bullet .tick line { stroke: #666; stroke-width: .5px; }
  261. .bullet .range.s0 { fill: #eee; }
  262. .bullet .range.s1 { fill: #ddd; }
  263. .bullet .range.s2 { fill: #ccc; }
  264. .bullet .measure.s0 { fill: lightsteelblue; }
  265. .bullet .measure.s1 { fill: steelblue; }
  266. .bullet .title { font-size: 14px; font-weight: bold; }
  267. .bullet .subtitle { fill: #999; }
  268.  
  269. </style>
  270. <button>Update</button>
  271. <script src="//d3js.org/d3.v3.min.js"></script>
  272. <script src="bullet.js"></script>
  273. <script>
  274.  
  275. var margin = {top: 5, right: 40, bottom: 20, left: 120},
  276. width = 960 - margin.left - margin.right,
  277. height = 50 - margin.top - margin.bottom;
  278.  
  279. var chart = d3.bullet()
  280. .width(width)
  281. .height(height);
  282.  
  283. d3.json("bullets.json", function(error, data) {
  284. if (error) throw error;
  285.  
  286. var svg = d3.select("body").selectAll("svg")
  287. .data(data)
  288. .enter().append("svg")
  289. .attr("class", "bullet")
  290. .attr("width", width + margin.left + margin.right)
  291. .attr("height", height + margin.top + margin.bottom)
  292. .append("g")
  293. .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  294. .call(chart);
  295.  
  296. var title = svg.append("g")
  297. .style("text-anchor", "end")
  298. .attr("transform", "translate(-6," + height / 2 + ")");
  299.  
  300. title.append("text")
  301. .attr("class", "title")
  302. .text(function(d) { return d.title; });
  303.  
  304. title.append("text")
  305. .attr("class", "subtitle")
  306. .attr("dy", "1em")
  307. .text(function(d) { return d.subtitle; });
  308.  
  309. d3.selectAll("button").on("click", function() {
  310. svg.datum(randomize).call(chart.duration(1000)); // TODO automatic transition
  311. });
  312. });
  313.  
  314. function randomize(d) {
  315. if (!d.randomizer) d.randomizer = randomizer(d);
  316. d.ranges = d.ranges.map(d.randomizer);
  317. d.markers = d.markers.map(d.randomizer);
  318. d.measures = d.measures.map(d.randomizer);
  319. return d;
  320. }
  321.  
  322. function randomizer(d) {
  323. var k = d3.max(d.ranges) * .2;
  324. return function(d) {
  325. return Math.max(0, d + k * (Math.random() - .5));
  326. };
  327. }
  328.  
  329. </script>
Add Comment
Please, Sign In to add comment