Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / static / fusion / raptor / d3 / js / models / historicalBar.js
1 //TODO: consider deprecating and using multibar with single series for this
2 nv.models.historicalBar = function() {
3   "use strict";
4   //============================================================
5   // Public Variables with Default Settings
6   //------------------------------------------------------------
7
8   var margin = {top: 0, right: 0, bottom: 0, left: 0}
9     , width = 960
10     , height = 500
11     , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
12     , x = d3.scale.linear()
13     , y = d3.scale.linear()
14     , getX = function(d) { return d.x }
15     , getY = function(d) { return d.y }
16     , forceX = []
17     , forceY = [0]
18     , padData = false
19     , clipEdge = true
20     , color = nv.utils.defaultColor()
21     , xDomain
22     , yDomain
23     , xRange
24     , yRange
25     , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
26     , interactive = true
27     ;
28
29   //============================================================
30
31
32   function chart(selection) {
33     selection.each(function(data) {
34       var availableWidth = width - margin.left - margin.right,
35           availableHeight = height - margin.top - margin.bottom,
36           container = d3.select(this);
37
38
39       //------------------------------------------------------------
40       // Setup Scales
41
42       x   .domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ))
43
44       if (padData)
45         x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5)  / data[0].values.length ]);
46       else
47         x.range(xRange || [0, availableWidth]);
48
49       y   .domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) ))
50           .range(yRange || [availableHeight, 0]);
51
52       // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
53
54       if (x.domain()[0] === x.domain()[1])
55         x.domain()[0] ?
56             x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
57           : x.domain([-1,1]);
58
59       if (y.domain()[0] === y.domain()[1])
60         y.domain()[0] ?
61             y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
62           : y.domain([-1,1]);
63
64       //------------------------------------------------------------
65
66
67       //------------------------------------------------------------
68       // Setup containers and skeleton of chart
69
70       var wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]);
71       var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id);
72       var defsEnter = wrapEnter.append('defs');
73       var gEnter = wrapEnter.append('g');
74       var g = wrap.select('g');
75
76       gEnter.append('g').attr('class', 'nv-bars');
77
78       wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
79
80       //------------------------------------------------------------
81
82
83       container
84           .on('click', function(d,i) {
85             dispatch.chartClick({
86                 data: d,
87                 index: i,
88                 pos: d3.event,
89                 id: id
90             });
91           });
92
93
94       defsEnter.append('clipPath')
95           .attr('id', 'nv-chart-clip-path-' + id)
96         .append('rect');
97
98       wrap.select('#nv-chart-clip-path-' + id + ' rect')
99           .attr('width', availableWidth)
100           .attr('height', availableHeight);
101
102       g   .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
103
104
105
106       var bars = wrap.select('.nv-bars').selectAll('.nv-bar')
107           .data(function(d) { return d }, function(d,i) {return getX(d,i)});
108
109       bars.exit().remove();
110
111
112       var barsEnter = bars.enter().append('rect')
113           //.attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
114           .attr('x', 0 )
115           .attr('y', function(d,i) {  return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) })
116           .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) })
117           .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) 
118           .on('mouseover', function(d,i) {
119             if (!interactive) return;
120             d3.select(this).classed('hover', true);
121             dispatch.elementMouseover({
122                 point: d,
123                 series: data[0],
124                 pos: [x(getX(d,i)), y(getY(d,i))],  // TODO: Figure out why the value appears to be shifted
125                 pointIndex: i,
126                 seriesIndex: 0,
127                 e: d3.event
128             });
129
130           })
131           .on('mouseout', function(d,i) {
132                 if (!interactive) return;
133                 d3.select(this).classed('hover', false);
134                 dispatch.elementMouseout({
135                     point: d,
136                     series: data[0],
137                     pointIndex: i,
138                     seriesIndex: 0,
139                     e: d3.event
140                 });
141           })
142           .on('click', function(d,i) {
143                 if (!interactive) return;
144                 dispatch.elementClick({
145                     //label: d[label],
146                     value: getY(d,i),
147                     data: d,
148                     index: i,
149                     pos: [x(getX(d,i)), y(getY(d,i))],
150                     e: d3.event,
151                     id: id
152                 });
153               d3.event.stopPropagation();
154           })
155           .on('dblclick', function(d,i) {
156               if (!interactive) return;
157               dispatch.elementDblClick({
158                   //label: d[label],
159                   value: getY(d,i),
160                   data: d,
161                   index: i,
162                   pos: [x(getX(d,i)), y(getY(d,i))],
163                   e: d3.event,
164                   id: id
165               });
166               d3.event.stopPropagation();
167           });
168
169       bars
170           .attr('fill', function(d,i) { return color(d, i); })
171           .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i })
172           .transition()
173           .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) 
174            //TODO: better width calculations that don't assume always uniform data spacing;w
175           .attr('width', (availableWidth / data[0].values.length) * .9 );
176
177
178       bars.transition()
179           .attr('y', function(d,i) {
180             var rval = getY(d,i) < 0 ?
181                     y(0) :
182                     y(0) - y(getY(d,i)) < 1 ?
183                       y(0) - 1 :
184                       y(getY(d,i));
185             return nv.utils.NaNtoZero(rval);
186           })
187           .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) });
188
189     });
190
191     return chart;
192   }
193
194   //Create methods to allow outside functions to highlight a specific bar.
195   chart.highlightPoint = function(pointIndex, isHoverOver) {
196       d3.select(".nv-historicalBar-" + id)
197         .select(".nv-bars .nv-bar-0-" + pointIndex)
198               .classed("hover", isHoverOver)
199                ;
200   };
201
202   chart.clearHighlights = function() {
203       d3.select(".nv-historicalBar-" + id)
204         .select(".nv-bars .nv-bar.hover")
205               .classed("hover", false)
206                ;
207   };
208   //============================================================
209   // Expose Public Variables
210   //------------------------------------------------------------
211
212   chart.dispatch = dispatch;
213
214   chart.options = nv.utils.optionsFunc.bind(chart);
215   
216   chart.x = function(_) {
217     if (!arguments.length) return getX;
218     getX = _;
219     return chart;
220   };
221
222   chart.y = function(_) {
223     if (!arguments.length) return getY;
224     getY = _;
225     return chart;
226   };
227
228   chart.margin = function(_) {
229     if (!arguments.length) return margin;
230     margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
231     margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
232     margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
233     margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
234     return chart;
235   };
236
237   chart.width = function(_) {
238     if (!arguments.length) return width;
239     width = _;
240     return chart;
241   };
242
243   chart.height = function(_) {
244     if (!arguments.length) return height;
245     height = _;
246     return chart;
247   };
248
249   chart.xScale = function(_) {
250     if (!arguments.length) return x;
251     x = _;
252     return chart;
253   };
254
255   chart.yScale = function(_) {
256     if (!arguments.length) return y;
257     y = _;
258     return chart;
259   };
260
261   chart.xDomain = function(_) {
262     if (!arguments.length) return xDomain;
263     xDomain = _;
264     return chart;
265   };
266
267   chart.yDomain = function(_) {
268     if (!arguments.length) return yDomain;
269     yDomain = _;
270     return chart;
271   };
272
273   chart.xRange = function(_) {
274     if (!arguments.length) return xRange;
275     xRange = _;
276     return chart;
277   };
278
279   chart.yRange = function(_) {
280     if (!arguments.length) return yRange;
281     yRange = _;
282     return chart;
283   };
284
285   chart.forceX = function(_) {
286     if (!arguments.length) return forceX;
287     forceX = _;
288     return chart;
289   };
290
291   chart.forceY = function(_) {
292     if (!arguments.length) return forceY;
293     forceY = _;
294     return chart;
295   };
296
297   chart.padData = function(_) {
298     if (!arguments.length) return padData;
299     padData = _;
300     return chart;
301   };
302
303   chart.clipEdge = function(_) {
304     if (!arguments.length) return clipEdge;
305     clipEdge = _;
306     return chart;
307   };
308
309   chart.color = function(_) {
310     if (!arguments.length) return color;
311     color = nv.utils.getColor(_);
312     return chart;
313   };
314
315   chart.id = function(_) {
316     if (!arguments.length) return id;
317     id = _;
318     return chart;
319   };
320
321   chart.interactive = function(_) {
322     if(!arguments.length) return interactive;
323     interactive = false;
324     return chart;
325   };
326
327   //============================================================
328
329
330   return chart;
331 }