javascripts/dashboard/SingleStackedBar.js

  1. import d3 from "~/javascripts/dashboard/d3_modules"
  2. /**
  3. * @class javascripts.dashboard.SingleStackedBar
  4. * @classdesc d3.js single stacked bar chart
  5. */
  6. export default class SingleStackedBar {
  7. constructor(selectedData, selectedContext, wrapper) {
  8. this.selectedData = selectedData
  9. this.selectedContext = selectedContext
  10. this.wrapper = d3.select(wrapper)
  11. this.dv = {
  12. xScale: null
  13. }
  14. this.dimensions = {
  15. width: parseInt(this.wrapper.style("width"), 10),
  16. height: 93,
  17. margin: {
  18. top: 0,
  19. right: 0,
  20. bottom: 0,
  21. left: 0,
  22. }
  23. }
  24. this.dimensions.boundedWidth = this.dimensions.width
  25. - this.dimensions.margin.left
  26. - this.dimensions.margin.right
  27. this.dimensions.boundedHeight = this.dimensions.height
  28. - this.dimensions.margin.top
  29. - this.dimensions.margin.bottom
  30. }
  31. /**
  32. * Called the first time the page is loaded to setup the visualisation
  33. *
  34. * @instance
  35. * @memberof javascripts.dashboard.SingleStackedBar
  36. **/
  37. createDataVis() {
  38. this.setScales()
  39. this.initialiseDataVis()
  40. this.drawDataVis()
  41. }
  42. /**
  43. * When the data set is updated this will cause the visualisation to animate
  44. *
  45. * @instance
  46. * @memberof javascripts.dashboard.SingleStackedBar
  47. **/
  48. updateDataVis(selectedData, selectedContext) {
  49. this.selectedData = selectedData
  50. this.selectedContext = selectedContext
  51. this.redrawDataVis()
  52. }
  53. /**
  54. * Setup the scales for the visualisation
  55. *
  56. * @instance
  57. * @memberof javascripts.dashboard.SingleStackedBar
  58. **/
  59. setScales() {
  60. this.dv.xScale = d3.scaleLinear()
  61. .domain([0, 100])
  62. .range([0, this.dimensions.boundedWidth])
  63. }
  64. /**
  65. * Setup the wrapper and the bounds for the visualisation
  66. *
  67. * @instance
  68. * @memberof javascripts.dashboard.SingleStackedBar
  69. **/
  70. initialiseDataVis() {
  71. const wrapper = this.wrapper
  72. .append("svg")
  73. .attr("width", this.dimensions.width)
  74. .attr("height", this.dimensions.height)
  75. this.dv.bounds = wrapper.append("g")
  76. .style(
  77. "transform",
  78. `translate(${this.dimensions.margin.left}px, ${this.dimensions.margin.top}px)`
  79. )
  80. }
  81. /**
  82. * Animate the rendering of the stack bar chart, the legend and the percentage values within the
  83. * legend
  84. *
  85. * @instance
  86. * @memberof javascripts.dashboard.SingleStackedBar
  87. **/
  88. drawDataVis() {
  89. // Initially set bars in position with no width
  90. this.dv.bounds.selectAll("rect")
  91. .data(this.selectedData)
  92. .enter().append("rect")
  93. .attr("class", d => `single-stacked-bar--${d.barClassModifier}`)
  94. .attr("x", d => this.dv.xScale(d.cumulative))
  95. .attr("y", 0)
  96. .attr("height", 53)
  97. .attr("width", 0)
  98. // Transition in the bar width 1 bar at a time with a delay set so the next bar waits for the
  99. // preceeding bar to finish animating
  100. this.dv.bounds.selectAll("rect")
  101. .data(this.selectedData)
  102. .transition()
  103. .ease(d3.easeLinear)
  104. .delay(d => (d.cumulative / 100) * 250)
  105. .duration(d => (d.percentage / 100) * 250)
  106. .attr("width", d => this.dv.xScale(d.percentage))
  107. this.dv.bounds.selectAll(".single-stacked-bar-legend")
  108. .data(this.selectedData)
  109. .enter().append("rect")
  110. .attr("class", d => `single-stacked-bar-legend single-stacked-bar-legend--${d.barClassModifier}`)
  111. .attr("x", (d, i) => i * 90)
  112. .attr("y", 63)
  113. .attr("height", 30)
  114. .attr("width", 60)
  115. this.dv.bounds.selectAll('.single-stacked-bar-percentage')
  116. .data(this.selectedData)
  117. .enter().append("text")
  118. .attr("class", "single-stacked-bar-percentage")
  119. .attr("x", (d, i) => (i * 90) + 30)
  120. .attr("y", 82)
  121. .text(d => `${d.percentage} %`)
  122. }
  123. /**
  124. * Animate the bars transitioning to the updated data set and change the percentage values in the
  125. * legend
  126. *
  127. * @instance
  128. * @memberof javascripts.dashboard.SingleStackedBar
  129. **/
  130. redrawDataVis() {
  131. this.dv.bounds.selectAll("rect")
  132. .data(this.selectedData)
  133. .transition()
  134. .duration(250)
  135. .ease(d3.easeCubicInOut)
  136. .attr("x", d => this.dv.xScale(d.cumulative))
  137. .attr("width", d => this.dv.xScale(d.percentage))
  138. this.dv.bounds.selectAll(".single-stacked-bar-percentage")
  139. .data(this.selectedData)
  140. .transition()
  141. .duration(250)
  142. .ease(d3.easeCubicInOut)
  143. .text(d => `${d.percentage} %`)
  144. }
  145. }