VizStackedBar.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. "use strict";
  2. /**
  3.  * Licensed Materials - Property of IBM
  4.  * IBM Cognos Products: Cognos Analytics
  5.  * Copyright IBM Corp. 2015, 2016
  6.  * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7.  */
  8. define(['underscore', 'q', 'jquery', 'rave2', 'bi/admin/nls/StringResource', 'bi/admin/common/visualizations/VizControl'], function (_, Q, $, rave, StringResource, VizControl) {
  9. 'use strict'; //NOSONAR: meant to be strict
  10. var StackedContext = function StackedContext(xScale, yScale) {
  11. return {
  12. x: function x(d) {
  13. return xScale(d.x);
  14. },
  15. y: function y(d) {
  16. return yScale(d.y0 + d.y);
  17. },
  18. width: xScale.rangeBand(),
  19. height: function height(d) {
  20. return yScale(d.y0) - yScale(d.y0 + d.y);
  21. }
  22. };
  23. };
  24. var GroupedContext = function GroupedContext(xScale, yScale, numLayers, svgHeight) {
  25. return {
  26. x: function x(d, i, j) {
  27. return xScale(d.x) + xScale.rangeBand() / numLayers * j;
  28. },
  29. y: function y(d) {
  30. return yScale(d.y);
  31. },
  32. width: xScale.rangeBand() / numLayers,
  33. height: function height(d) {
  34. return svgHeight - yScale(d.y);
  35. }
  36. };
  37. };
  38. var VizStackedBar = VizControl.extend({
  39. chartMode: 'stacked',
  40. yticks: 5,
  41. init: function init(options) {
  42. this.margin.left = 45;
  43. this.margin.top = 10;
  44. this.margin.bottom = 60;
  45. VizStackedBar.inherited('init', this, arguments);
  46. },
  47. _prepareData: function _prepareData(data) {
  48. this._rawData = data;
  49. var attr2 = this._attr2Name;
  50. var da = this._groupData(data, this._attr2Name);
  51. this._attr2Values = da.map(function (item) {
  52. return item[0][attr2];
  53. });
  54. return da;
  55. },
  56. _draw: function _draw(data) {
  57. var n = data.length,
  58. m = data[0].layer.length,
  59. stack = rave.layout.stack().values(function (d) {
  60. return d.layer;
  61. }),
  62. layers = stack(data, function () {}),
  63. yGroupMax = rave.max(layers, function (l) {
  64. return rave.max(l.layer, function (d) {
  65. return d.y;
  66. });
  67. }),
  68. yStackMax = rave.max(layers, function (l) {
  69. return rave.max(l.layer, function (d) {
  70. return d.y0 + d.y;
  71. });
  72. }),
  73. yMax = this.chartMode === 'stacked' ? yStackMax : yGroupMax,
  74. bottom = this.margin.top + this.svgHeight;
  75. var x = rave.scale.ordinal().domain(rave.range(m)).rangeRoundBands([0, this.svgWidth], 0.1);
  76. var y = rave.scale.linear().domain([0, yMax * 1.2]).range([this.svgHeight, 0]);
  77. var xAxis = rave.svg.axis().scale(x).tickSize(5).orient('bottom');
  78. var maxDataValue = 0;
  79. data.forEach(function (dataItem) {
  80. maxDataValue = Math.max(dataItem.total, maxDataValue);
  81. });
  82. var yAxis = rave.svg.axis().scale(y).tickSize(5).tickPadding(6).ticks(Math.min(maxDataValue, this.yticks)).orient('left');
  83. this.svg.append('g').attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
  84. var getColor = function getColor(d) {
  85. return this._colorScale(d.name);
  86. };
  87. var layer = this.svg.selectAll('.layer').data(layers).enter().append('g').attr('class', 'layer').style('fill', getColor.bind(this)).attr('transform', function () {
  88. return 'translate(' + this.margin.left + ', ' + this.margin.top + ')';
  89. }.bind(this));
  90. var context = this.chartMode === 'stacked' ? new StackedContext(x, y, n, this.svgHeight) : new GroupedContext(x, y, n, this.svgHeight);
  91. var rects = layer.selectAll('rect').data(function (d) {
  92. return d.layer;
  93. }).enter().append('rect').attr('x', context.x).attr('y', this.svgHeight).attr('width', context.width).attr('height', 0);
  94. rects.on('mouseover', function () {
  95. var rect = rave.select(this);
  96. var color = rect.style('fill') || '#ddd';
  97. var rgb = rave.rgb(color).darker();
  98. rect.style('fill', rgb.toString());
  99. }).on('mouseout', function () {
  100. rave.select(this).style('fill', null);
  101. });
  102. rects.transition().delay(function (d, i) {
  103. return i * 20;
  104. }).attr('y', context.y).attr('height', context.height);
  105. this.svg.append('g').attr('class', 'bi-chart-axis x-axis').attr('transform', 'translate(' + this.margin.left + ', ' + bottom + ')').call(xAxis);
  106. var ya = this.svg.append('g').attr('class', 'bi-chart-axis y-axis-stackedbar').attr('transform', 'translate(' + this.margin.left + ', ' + this.margin.top + ')').call(yAxis);
  107. var rules = this.svg.selectAll('g.bi-chart-rule').data(y.ticks(this.yticks)).enter().append('g').attr('class', 'bi-chart-rule').attr('transform', function (d) {
  108. return 'translate(' + this.margin.left + ', ' + (this.margin.top + y(d)) + ')';
  109. }.bind(this));
  110. rules.append('line').attr('x2', this.svgWidth).style('stroke-opacity', function (d) {
  111. return d ? .7 : 0;
  112. });
  113. var legends = _.map(layers, function (l) {
  114. return l.name;
  115. });
  116. var lx = rave.scale.ordinal().domain(legends).rangeRoundBands([this.margin.left, this.width], 0.1);
  117. var legend = this.svg.selectAll('.bi-chart-legend').data(layers).enter().append('g').attr('class', 'bi-chart-legend').attr('transform', function (d) {
  118. return 'translate(' + lx(d.name) + ', ' + (bottom + 30) + ')';
  119. }.bind(this));
  120. legend.append('rect').attr('x', 0).attr('width', 18).attr('height', 18).style('fill', getColor.bind(this));
  121. legend.append('text').attr('x', 24).attr('y', 9).attr('dy', '.35em').text(function (d) {
  122. return StringResource.get(d.legendName) + (d.total ? ' ( ' + d.total + ' )' : ' ( 0 )');
  123. });
  124. var transRules = function (yMax) {
  125. y.domain([0, yMax * 1.2]);
  126. ya.transition().duration(300).ease('circle').call(yAxis);
  127. var rules = this.svg.selectAll('g.bi-chart-rule').data(y.ticks(this.yticks));
  128. rules.exit().remove();
  129. rules.enter().append('g').attr('class', 'bi-chart-rule').attr('transform', function (d) {
  130. return 'translate(' + this.margin.left + ', ' + (this.margin.top + y(d)) + ')';
  131. }.bind(this));
  132. rules.enter().append('line').attr('x2', this.svgWidth).style('stroke-opacity', function (d) {
  133. return d ? .7 : 0;
  134. });
  135. rules.transition().duration(300).ease('circle').attr('transform', function (d) {
  136. return 'translate(' + this.margin.left + ', ' + (this.margin.top + y(d)) + ')';
  137. }.bind(this));
  138. }.bind(this);
  139. var transitionGrouped = function transitionGrouped() {
  140. transRules(yGroupMax);
  141. var context = new GroupedContext(x, y, n, this.svgHeight);
  142. rects.transition().duration(300).delay(function (d, i) {
  143. return i * 20;
  144. }).attr('x', context.x).attr('width', context.width).transition().attr('y', context.y).attr('height', context.height);
  145. };
  146. var transitionStacked = function transitionStacked() {
  147. transRules(yStackMax);
  148. var context = new StackedContext(x, y, n, this.svgHeight);
  149. rects.transition().duration(300).delay(function (d, i) {
  150. return i * 20;
  151. }).attr('y', context.y).attr('height', context.height).transition().attr('x', context.x).attr('width', context.width);
  152. };
  153. this._transitionGrouped = transitionGrouped;
  154. this._transitionStacked = transitionStacked;
  155. },
  156. changeMode: function changeMode(mode) {
  157. if (this.chartMode !== mode) {
  158. this.chartMode = mode;
  159. if (mode === 'stacked') {
  160. this._transitionStacked();
  161. } else {
  162. this._transitionGrouped();
  163. }
  164. }
  165. }
  166. });
  167. return VizStackedBar;
  168. });