simple-bar-chart.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. import Ember from 'ember';
  19. export default Ember.Component.extend({
  20. data: [],
  21. xAxisTickFormatter: null,
  22. yAxisTickFormatter: null,
  23. xAxisText: '',
  24. yAxisText: '',
  25. enableTooltip: true,
  26. onBarChartClickCallback: Ember.K,
  27. hideTootlipOnBarChartClick: true,
  28. initChart() {
  29. this.height = 400;
  30. this.barWidth = 30;
  31. this.width = Math.max(500, 40 * this.data.length);
  32. },
  33. drawChart() {
  34. var margin = {top: 20, right: 20, bottom: 100, left: 100},
  35. axisLabelPadding = 10,
  36. width = this.width - margin.left - margin.right - axisLabelPadding,
  37. height = this.height - margin.top - margin.bottom - axisLabelPadding,
  38. xAxisText = this.xAxisText? this.xAxisText : '',
  39. yAxisText = this.yAxisText? this.yAxisText : '',
  40. data = this.data,
  41. self = this;
  42. var xScale = d3.scale.ordinal().rangeRoundBands([0, width], 0.1);
  43. var yScale = d3.scale.linear().range([height, 0]);
  44. var xAxis = d3.svg.axis()
  45. .scale(xScale)
  46. .orient("bottom")
  47. .tickFormat(function(tick) {
  48. if (self.isFunction(self.xAxisTickFormatter)) {
  49. return self.xAxisTickFormatter(tick);
  50. } else {
  51. return tick;
  52. }
  53. });
  54. var yAxis = d3.svg.axis()
  55. .scale(yScale)
  56. .orient("left")
  57. .tickFormat(function(tick) {
  58. if (self.isFunction(self.yAxisTickFormatter)) {
  59. return self.yAxisTickFormatter(tick);
  60. } else {
  61. return tick;
  62. }
  63. });
  64. var svg = d3.select(this.element)
  65. .append("svg")
  66. .attr("class", "simple-bar-chart")
  67. .attr("width", width + margin.left + margin.right + axisLabelPadding)
  68. .attr("height", height + margin.top + margin.bottom + axisLabelPadding)
  69. .append("g")
  70. .attr("transform", "translate("+(margin.left+axisLabelPadding)+","+(margin.top)+")");
  71. xScale.domain(data.map(function(d) { return d.label; }));
  72. yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
  73. var gx = svg.append("g")
  74. .attr("class", "x axis")
  75. .attr("transform", "translate(0," + height + ")")
  76. .call(xAxis);
  77. gx.selectAll("text")
  78. .style("text-anchor", "end")
  79. .attr("dx", "-.8em")
  80. .attr("dy", "-.3em")
  81. .attr("transform", "rotate(-60)");
  82. gx.append("text")
  83. .attr("transform", "translate("+(width/2)+","+(margin.bottom)+")")
  84. .style("text-anchor", "middle")
  85. .text(xAxisText);
  86. var gy = svg.append("g")
  87. .attr("class", "y axis")
  88. .call(yAxis);
  89. gy.append("text")
  90. .attr("transform", "translate("+(-margin.left)+","+(height/2)+")rotate(-90)")
  91. .style("text-anchor", "middle")
  92. .text(yAxisText);
  93. var barWidth = this.barWidth;
  94. var minBarWidth = Math.min(barWidth, xScale.rangeBand());
  95. var bars = svg.selectAll("bar")
  96. .data(data)
  97. .enter().append("rect")
  98. .attr("x", function(d) {
  99. var padding = 0;
  100. var rangeBand = xScale.rangeBand();
  101. if ((rangeBand - barWidth) > 0) {
  102. padding = (rangeBand - barWidth) / 2;
  103. }
  104. return xScale(d.label) + padding;
  105. })
  106. .attr("width", minBarWidth)
  107. .attr("y", function() {
  108. return yScale(0);
  109. })
  110. .attr("height", function() {
  111. return height - yScale(0);
  112. })
  113. .on('click', function(d) {
  114. if (self.enableTooltip && self.hideTootlipOnBarChartClick) {
  115. self.hideTootlip();
  116. }
  117. if (self.isFunction(self.onBarChartClickCallback)) {
  118. self.onBarChartClickCallback(d);
  119. }
  120. });
  121. bars.transition()
  122. .duration(1000)
  123. .delay(100)
  124. .attr("y", function(d) {
  125. return yScale(d.value);
  126. })
  127. .attr("height", function(d) {
  128. return height - yScale(d.value);
  129. });
  130. if (this.enableTooltip) {
  131. this.bindTooltip(bars);
  132. }
  133. },
  134. bindTooltip(bars) {
  135. var self = this;
  136. var tooltip = this.tooltip;
  137. if (tooltip) {
  138. bars.on("mouseenter", function(d) {
  139. tooltip.html(d.tooltip);
  140. self.showTooltip();
  141. }).on("mousemove", function() {
  142. tooltip.style("left", (d3.event.pageX + 5) + "px")
  143. .style("top", (d3.event.pageY - 25) + "px");
  144. }).on("mouseout", function() {
  145. self.hideTootlip();
  146. });
  147. }
  148. },
  149. initTooltip() {
  150. this.tooltip = d3.select("body")
  151. .append("div")
  152. .attr("class", "tooltip simple-barchart-tooltip")
  153. .style("opacity", 1);
  154. this.hideTootlip();
  155. },
  156. hideTootlip() {
  157. if (this.tooltip) {
  158. this.tooltip.style("display", "none");
  159. }
  160. },
  161. showTooltip() {
  162. if (this.tooltip) {
  163. this.tooltip.style("display", "block");
  164. }
  165. },
  166. isFunction(func) {
  167. return Ember.typeOf(func) === "function";
  168. },
  169. didInsertElement() {
  170. this.initChart();
  171. if (this.enableTooltip) {
  172. this.initTooltip();
  173. }
  174. this.drawChart();
  175. },
  176. willDestroyElement() {
  177. if (this.tooltip) {
  178. this.tooltip.remove();
  179. }
  180. }
  181. });