2 nv.models.multiBarHorizontalChart = function() {
4 //============================================================
5 // Public Variables with Default Settings
6 //------------------------------------------------------------
8 var multibar = nv.models.multiBarHorizontal()
9 , xAxis = nv.models.axis()
10 , yAxis = nv.models.axis()
11 , legend = nv.models.legend().height(30)
12 , controls = nv.models.legend().height(30)
15 var margin = {top: 30, right: 20, bottom: 50, left: 60}
18 , color = nv.utils.defaultColor()
23 , tooltip = function(key, x, y, e, graph) {
24 return '<h3>' + key + ' - ' + x + '</h3>' +
27 , x //can be accessed via chart.xScale()
28 , y //can be accessed via chart.yScale()
29 , state = { stacked: stacked }
31 , noData = 'No Data Available.'
32 , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState')
33 , controlWidth = function() { return showControls ? 180 : 0 }
34 , transitionDuration = 250
45 .tickFormat(function(d) { return d })
49 .tickFormat(d3.format(',.1f'))
52 controls.updateState(false);
53 //============================================================
56 //============================================================
58 //------------------------------------------------------------
60 var showTooltip = function(e, offsetElement) {
61 var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
62 top = e.pos[1] + ( offsetElement.offsetTop || 0),
63 x = xAxis.tickFormat()(multibar.x()(e.point, e.pointIndex)),
64 y = yAxis.tickFormat()(multibar.y()(e.point, e.pointIndex)),
65 content = tooltip(e.series.key, x, y, e, chart);
67 nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement);
70 //============================================================
73 function chart(selection) {
74 selection.each(function(data) {
75 var container = d3.select(this),
78 var availableWidth = (width || parseInt(container.style('width')) || 960)
79 - margin.left - margin.right,
80 availableHeight = (height || parseInt(container.style('height')) || 400)
81 - margin.top - margin.bottom;
83 chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
84 chart.container = this;
87 state.disabled = data.map(function(d) { return !!d.disabled });
93 if (state[key] instanceof Array)
94 defaultState[key] = state[key].slice(0);
96 defaultState[key] = state[key];
100 //------------------------------------------------------------
101 // Display No Data message if there's nothing to show.
103 if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
104 var noDataText = container.selectAll('.nv-noData').data([noData]);
106 noDataText.enter().append('text')
107 .attr('class', 'nvd3 nv-noData')
109 .style('text-anchor', 'middle');
112 .attr('x', margin.left + availableWidth / 2)
113 .attr('y', margin.top + availableHeight / 2)
114 .text(function(d) { return d });
118 container.selectAll('.nv-noData').remove();
121 //------------------------------------------------------------
124 //------------------------------------------------------------
127 x = multibar.xScale();
128 y = multibar.yScale();
130 //------------------------------------------------------------
133 //------------------------------------------------------------
134 // Setup containers and skeleton of chart
136 var wrap = container.selectAll('g.nv-wrap.nv-multiBarHorizontalChart').data([data]);
137 var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarHorizontalChart').append('g');
138 var g = wrap.select('g');
140 gEnter.append('g').attr('class', 'nv-x nv-axis');
141 gEnter.append('g').attr('class', 'nv-y nv-axis');
142 gEnter.append('g').attr('class', 'nv-barsWrap');
143 gEnter.append('g').attr('class', 'nv-legendWrap');
144 gEnter.append('g').attr('class', 'nv-controlsWrap');
146 //------------------------------------------------------------
149 //------------------------------------------------------------
153 legend.width(availableWidth - controlWidth());
155 if (multibar.barColor())
156 data.forEach(function(series,i) {
157 series.color = d3.rgb('#ccc').darker(i * 1.5).toString();
160 g.select('.nv-legendWrap')
164 if ( margin.top != legend.height()) {
165 margin.top = legend.height();
166 availableHeight = (height || parseInt(container.style('height')) || 400)
167 - margin.top - margin.bottom;
170 g.select('.nv-legendWrap')
171 .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')');
174 //------------------------------------------------------------
177 //------------------------------------------------------------
182 { key: 'Grouped', disabled: multibar.stacked() },
183 { key: 'Stacked', disabled: !multibar.stacked() }
186 controls.width(controlWidth()).color(['#444', '#444', '#444']);
187 g.select('.nv-controlsWrap')
189 .attr('transform', 'translate(0,' + (-margin.top) +')')
193 //------------------------------------------------------------
196 wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
199 //------------------------------------------------------------
200 // Main Chart Component(s)
203 .disabled(data.map(function(series) { return series.disabled }))
204 .width(availableWidth)
205 .height(availableHeight)
206 .color(data.map(function(d,i) {
207 return d.color || color(d, i);
208 }).filter(function(d,i) { return !data[i].disabled }))
211 var barsWrap = g.select('.nv-barsWrap')
212 .datum(data.filter(function(d) { return !d.disabled }))
214 barsWrap.transition().call(multibar);
216 //------------------------------------------------------------
219 //------------------------------------------------------------
224 .ticks( availableHeight / 24 )
225 .tickSize(-availableWidth, 0);
227 g.select('.nv-x.nv-axis').transition()
230 var xTicks = g.select('.nv-x.nv-axis').selectAll('g');
233 .selectAll('line, text')
239 .ticks( availableWidth / 100 )
240 .tickSize( -availableHeight, 0);
242 g.select('.nv-y.nv-axis')
243 .attr('transform', 'translate(0,' + availableHeight + ')');
244 g.select('.nv-y.nv-axis').transition()
247 //------------------------------------------------------------
251 //============================================================
252 // Event Handling/Dispatching (in chart's scope)
253 //------------------------------------------------------------
255 legend.dispatch.on('stateChange', function(newState) {
257 dispatch.stateChange(state);
261 controls.dispatch.on('legendClick', function(d,i) {
262 if (!d.disabled) return;
263 controlsData = controlsData.map(function(s) {
271 multibar.stacked(false);
274 multibar.stacked(true);
278 state.stacked = multibar.stacked();
279 dispatch.stateChange(state);
284 dispatch.on('tooltipShow', function(e) {
285 if (tooltips) showTooltip(e, that.parentNode);
288 // Update chart from a state object passed to event handler
289 dispatch.on('changeState', function(e) {
291 if (typeof e.disabled !== 'undefined') {
292 data.forEach(function(series,i) {
293 series.disabled = e.disabled[i];
296 state.disabled = e.disabled;
299 if (typeof e.stacked !== 'undefined') {
300 multibar.stacked(e.stacked);
301 state.stacked = e.stacked;
304 selection.call(chart);
306 //============================================================
315 //============================================================
316 // Event Handling/Dispatching (out of chart's scope)
317 //------------------------------------------------------------
319 multibar.dispatch.on('elementMouseover.tooltip', function(e) {
320 e.pos = [e.pos[0] + margin.left, e.pos[1] + margin.top];
321 dispatch.tooltipShow(e);
324 multibar.dispatch.on('elementMouseout.tooltip', function(e) {
325 dispatch.tooltipHide(e);
327 dispatch.on('tooltipHide', function() {
328 if (tooltips) nv.tooltip.cleanup();
331 //============================================================
334 //============================================================
335 // Expose Public Variables
336 //------------------------------------------------------------
338 // expose chart's sub-components
339 chart.dispatch = dispatch;
340 chart.multibar = multibar;
341 chart.legend = legend;
345 d3.rebind(chart, multibar, 'x', 'y', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'clipEdge', 'id', 'delay', 'showValues', 'valueFormat', 'stacked', 'barColor');
347 chart.options = nv.utils.optionsFunc.bind(chart);
349 chart.margin = function(_) {
350 if (!arguments.length) return margin;
351 margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
352 margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
353 margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
354 margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
358 chart.width = function(_) {
359 if (!arguments.length) return width;
364 chart.height = function(_) {
365 if (!arguments.length) return height;
370 chart.color = function(_) {
371 if (!arguments.length) return color;
372 color = nv.utils.getColor(_);
377 chart.showControls = function(_) {
378 if (!arguments.length) return showControls;
383 chart.showLegend = function(_) {
384 if (!arguments.length) return showLegend;
389 chart.tooltip = function(_) {
390 if (!arguments.length) return tooltip;
395 chart.tooltips = function(_) {
396 if (!arguments.length) return tooltips;
401 chart.tooltipContent = function(_) {
402 if (!arguments.length) return tooltip;
407 chart.state = function(_) {
408 if (!arguments.length) return state;
413 chart.defaultState = function(_) {
414 if (!arguments.length) return defaultState;
419 chart.noData = function(_) {
420 if (!arguments.length) return noData;
425 chart.transitionDuration = function(_) {
426 if (!arguments.length) return transitionDuration;
427 transitionDuration = _;
430 //============================================================