| |
| nv.models.bar = function() { |
| var margin = {top: 20, right: 10, bottom: 80, left: 60}, |
| width = 960, |
| height = 500, |
| animate = 500, |
| label ='label', |
| rotatedLabel = true, |
| showLabels = true, |
| id = Math.floor(Math.random() * 10000), //Create semi-unique ID in case user doesn't select one |
| color = d3.scale.category20(), |
| field ='y', |
| title = ''; |
| |
| var x = d3.scale.ordinal(), |
| y = d3.scale.linear(), |
| xAxis = d3.svg.axis().scale(x).orient('bottom'), |
| yAxis = d3.svg.axis().scale(y).orient('left'), |
| dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'tooltipShow', 'tooltipHide'); |
| |
| |
| function chart(selection) { |
| selection.each(function(data) { |
| x .domain(data.map(function(d,i) { return d[label]; })) |
| .rangeRoundBands([0, width - margin.left - margin.right], .1); |
| |
| |
| var min = d3.min(data, function(d) { return d[field] }); |
| var max = d3.max(data, function(d) { return d[field] }); |
| var x0 = Math.max(-min, max); |
| var x1 = -x0; |
| |
| // If we have no negative values, then lets stack this with just positive bars |
| if (min >= 0) x1 = 0; |
| |
| y .domain([x1, x0]) |
| .range([height - margin.top - margin.bottom, 0]) |
| .nice(); |
| |
| xAxis.ticks( width / 100 ); |
| yAxis.ticks( height / 36 ).tickSize(-(width - margin.right - margin.left), 0); |
| |
| var parent = d3.select(this) |
| .on("click", function(d,i) { |
| dispatch.chartClick({ |
| data: d, |
| index: i, |
| pos: d3.event, |
| id: id |
| }); |
| }); |
| |
| |
| var wrap = parent.selectAll('g.wrap').data([data]); |
| var gEnter = wrap.enter(); |
| gEnter.append("text") |
| .attr("class", "title") |
| .attr("dy", ".91em") |
| .attr("text-anchor", "start") |
| .text(title); |
| gEnter = gEnter.append('g').attr('class', 'nvd3 wrap').attr('id','wrap-'+id).append('g'); |
| |
| |
| |
| gEnter.append('g').attr('class', 'x axis'); |
| gEnter.append('g').attr('class', 'y axis'); |
| gEnter.append('g').attr('class', 'bars'); |
| |
| |
| wrap.attr('width', width) |
| .attr('height', height); |
| |
| var g = wrap.select('g') |
| .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); |
| |
| |
| var bars = wrap.select('.bars').selectAll('.bar') |
| .data(function(d) { return d; }); |
| |
| bars.exit().remove(); |
| |
| |
| var barsEnter = bars.enter().append('svg:rect') |
| .attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"}) |
| .attr("fill", function(d, i) { return color(i); }) |
| .attr('x', 0 ) |
| .on('mouseover', function(d,i){ |
| d3.select(this).classed('hover', true); |
| dispatch.tooltipShow({ |
| label: d[label], |
| value: d[field], |
| data: d, |
| index: i, |
| // TODO: Calculate the center to the bar |
| pos: [d3.event.pageX, d3.event.pageY], |
| id: id |
| }); |
| |
| }) |
| .on('mouseout', function(d,i){ |
| d3.select(this).classed('hover', false); |
| dispatch.tooltipHide({ |
| label: d[label], |
| value: d[field], |
| data: d, |
| index: i, |
| id: id |
| }); |
| }) |
| .on('click', function(d,i) { |
| dispatch.elementClick({ |
| label: d[label], |
| value: d[field], |
| data: d, |
| index: i, |
| pos: d3.event, |
| id: id |
| }); |
| d3.event.stopPropagation(); |
| }) |
| .on('dblclick', function(d,i) { |
| dispatch.elementDblClick({ |
| label: d[label], |
| value: d[field], |
| data: d, |
| index: i, |
| pos: d3.event, |
| id: id |
| }); |
| d3.event.stopPropagation(); |
| }); |
| |
| |
| bars |
| .attr('class', function(d) { return d[field] < 0 ? "bar negative" : "bar positive"}) |
| .attr('transform', function(d,i) { return 'translate(' + x(d[label]) + ',0)'; }) |
| .attr('width', x.rangeBand ) |
| .order() |
| .transition() |
| .duration(animate) |
| .attr('y', function(d) { return y(Math.max(0, d[field])); }) |
| .attr('height', function(d) { return Math.abs(y(d[field]) - y(0)); }); |
| |
| |
| g.select('.x.axis') |
| .attr('transform', 'translate(0,' + y.range()[0] + ')') |
| .call(xAxis); |
| |
| |
| if (rotatedLabel) { |
| g.select('.x.axis').selectAll('text').attr('text-anchor','start').attr("transform", function(d) { |
| return "rotate(35)translate(" + this.getBBox().height/2 + "," + '0' + ")"; |
| }); |
| } |
| if (!showLabels) { |
| g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,0)'); |
| g.select('.x.axis').selectAll('line').attr('style', 'opacity: 0'); |
| } |
| /*else { |
| g.select('.x.axis').selectAll('text').attr('fill', 'rgba(0,0,0,1)'); |
| g.select('.x.axis').selectAll('line').attr('style', 'opacity: 1'); |
| }*/ |
| |
| |
| |
| g.select('.y.axis') |
| .call(yAxis); |
| }); |
| |
| return chart; |
| } |
| |
| chart.margin = function(_) { |
| if (!arguments.length) return margin; |
| margin = _; |
| return chart; |
| }; |
| |
| chart.width = function(_) { |
| if (!arguments.length) return width; |
| if (margin.left + margin.right + 20 > _) |
| width = margin.left + margin.right + 20; // Min width |
| else |
| width = _; |
| return chart; |
| }; |
| |
| chart.height = function(_) { |
| if (!arguments.length) return height; |
| if (margin.top + margin.bottom + 20 > _) |
| height = margin.top + margin.bottom + 20; // Min height |
| else |
| height = _; |
| return chart; |
| }; |
| |
| chart.animate = function(_) { |
| if (!arguments.length) return animate; |
| animate = _; |
| return chart; |
| }; |
| |
| chart.labelField = function(_) { |
| if (!arguments.length) return (label); |
| label = _; |
| return chart; |
| }; |
| |
| chart.dataField = function(_) { |
| if (!arguments.length) return (field); |
| field = _; |
| return chart; |
| }; |
| |
| chart.id = function(_) { |
| if (!arguments.length) return id; |
| id = _; |
| return chart; |
| }; |
| |
| chart.rotatedLabel = function(_) { |
| if (!arguments.length) return rotatedLabel; |
| rotatedLabel = _; |
| return chart; |
| }; |
| |
| chart.showLabels = function(_) { |
| if (!arguments.length) return (showLabels); |
| showLabels = _; |
| return chart; |
| }; |
| |
| chart.title = function(_) { |
| if (!arguments.length) return (title); |
| title = _; |
| return chart; |
| }; |
| |
| chart.xaxis = {}; |
| // Expose the x-axis' tickFormat method. |
| d3.rebind(chart.xaxis, xAxis, 'tickFormat'); |
| |
| chart.yaxis = {}; |
| // Expose the y-axis' tickFormat method. |
| d3.rebind(chart.yaxis, yAxis, 'tickFormat'); |
| |
| chart.dispatch = dispatch; |
| |
| return chart; |
| } |