概要 实例 介绍 源码

堆叠柱状图

源文件:index.html

  1. <!DOCTYPE html>
  2. <meta charset="utf-8">
  3. <style>
  4. form {
  5. font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  6. position: absolute;
  7. left: 10px;
  8. top: 10px;
  9. }
  10. label {
  11. display: block;
  12. }
  13. </style>
  14. <form>
  15. <label><input type="radio" name="mode" value="grouped"> Grouped</label>
  16. <label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
  17. </form>
  18. <svg width="960" height="500"></svg>
  19. <script src="https://d3js.org/d3.v4.min.js"></script>
  20. <script>
  21. var n = 4, // The number of series.
  22. m = 58; // The number of values per series.
  23. // The xz array has m elements, representing the x-values shared by all series.
  24. // The yz array has n elements, representing the y-values of each of the n series.
  25. // Each yz[i] is an array of m non-negative numbers representing a y-value for xz[i].
  26. // The y01z array has the same structure as yz, but with stacked [y₀, y₁] instead of y.
  27. var xz = d3.range(m),
  28. yz = d3.range(n).map(function() { return bumps(m); }),
  29. y01z = d3.stack().keys(d3.range(n))(d3.transpose(yz)),
  30. yMax = d3.max(yz, function(y) { return d3.max(y); }),
  31. y1Max = d3.max(y01z, function(y) { return d3.max(y, function(d) { return d[1]; }); });
  32. var svg = d3.select("svg"),
  33. margin = {top: 40, right: 10, bottom: 20, left: 10},
  34. width = +svg.attr("width") - margin.left - margin.right,
  35. height = +svg.attr("height") - margin.top - margin.bottom,
  36. g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  37. var x = d3.scaleBand()
  38. .domain(xz)
  39. .rangeRound([0, width])
  40. .padding(0.08);
  41. var y = d3.scaleLinear()
  42. .domain([0, y1Max])
  43. .range([height, 0]);
  44. var color = d3.scaleOrdinal()
  45. .domain(d3.range(n))
  46. .range(d3.schemeCategory20c);
  47. var series = g.selectAll(".series")
  48. .data(y01z)
  49. .enter().append("g")
  50. .attr("fill", function(d, i) { return color(i); });
  51. var rect = series.selectAll("rect")
  52. .data(function(d) { return d; })
  53. .enter().append("rect")
  54. .attr("x", function(d, i) { return x(i); })
  55. .attr("y", height)
  56. .attr("width", x.bandwidth())
  57. .attr("height", 0);
  58. rect.transition()
  59. .delay(function(d, i) { return i * 10; })
  60. .attr("y", function(d) { return y(d[1]); })
  61. .attr("height", function(d) { return y(d[0]) - y(d[1]); });
  62. g.append("g")
  63. .attr("class", "axis axis--x")
  64. .attr("transform", "translate(0," + height + ")")
  65. .call(d3.axisBottom(x)
  66. .tickSize(0)
  67. .tickPadding(6));
  68. d3.selectAll("input")
  69. .on("change", changed);
  70. var timeout = d3.timeout(function() {
  71. d3.select("input[value=\"grouped\"]")
  72. .property("checked", true)
  73. .dispatch("change");
  74. }, 2000);
  75. function changed() {
  76. timeout.stop();
  77. if (this.value === "grouped") transitionGrouped();
  78. else transitionStacked();
  79. }
  80. function transitionGrouped() {
  81. y.domain([0, yMax]);
  82. rect.transition()
  83. .duration(500)
  84. .delay(function(d, i) { return i * 10; })
  85. .attr("x", function(d, i) { return x(i) + x.bandwidth() / n * this.parentNode.__data__.key; })
  86. .attr("width", x.bandwidth() / n)
  87. .transition()
  88. .attr("y", function(d) { return y(d[1] - d[0]); })
  89. .attr("height", function(d) { return y(0) - y(d[1] - d[0]); });
  90. }
  91. function transitionStacked() {
  92. y.domain([0, y1Max]);
  93. rect.transition()
  94. .duration(500)
  95. .delay(function(d, i) { return i * 10; })
  96. .attr("y", function(d) { return y(d[1]); })
  97. .attr("height", function(d) { return y(d[0]) - y(d[1]); })
  98. .transition()
  99. .attr("x", function(d, i) { return x(i); })
  100. .attr("width", x.bandwidth());
  101. }
  102. // Returns an array of m psuedorandom, smoothly-varying non-negative numbers.
  103. // Inspired by Lee Byron’s test data generator.
  104. // http://leebyron.com/streamgraph/
  105. function bumps(m) {
  106. var values = [], i, j, w, x, y, z;
  107. // Initialize with uniform random values in [0.1, 0.2).
  108. for (i = 0; i < m; ++i) {
  109. values[i] = 0.1 + 0.1 * Math.random();
  110. }
  111. // Add five random bumps.
  112. for (j = 0; j < 5; ++j) {
  113. x = 1 / (0.1 + Math.random());
  114. y = 2 * Math.random() - 0.5;
  115. z = 10 / (0.1 + Math.random());
  116. for (i = 0; i < m; i++) {
  117. w = (i / m - y) * z;
  118. values[i] += x * Math.exp(-w * w);
  119. }
  120. }
  121. // Ensure all values are positive.
  122. for (i = 0; i < m; ++i) {
  123. values[i] = Math.max(0, values[i]);
  124. }
  125. return values;
  126. }
  127. </script>