Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / static / fusion / d3 / js / models / backup / bulletChart.js
1
2 // Chart design based on the recommendations of Stephen Few. Implementation
3 // based on the work of Clint Ivy, Jamie Love, and Jason Davies.
4 // http://projects.instantcognition.com/protovis/bulletchart/
5 nv.models.bulletChart = function() {
6
7   //============================================================
8   // Public Variables with Default Settings
9   //------------------------------------------------------------
10
11   var bullet = nv.models.bullet()
12     ;
13
14   var orient = 'left' // TODO top & bottom
15     , reverse = false
16     , margin = {top: 5, right: 40, bottom: 20, left: 120}
17     , ranges = function(d) { return d.ranges }
18     , markers = function(d) { return d.markers }
19     , measures = function(d) { return d.measures }
20     , width = null
21     , height = 55
22     , tickFormat = null
23     , tooltips = true
24     , tooltip = function(key, x, y, e, graph) {
25         return '<h3>' + e.label + '</h3>' +
26                '<p>' +  e.value + '</p>'
27       }
28     , noData = "No Data Available."
29     , dispatch = d3.dispatch('tooltipShow', 'tooltipHide')
30     ;
31
32   //============================================================
33
34
35   //============================================================
36   // Private Variables
37   //------------------------------------------------------------
38
39   var showTooltip = function(e, parentElement) {
40     var offsetElement = parentElement.parentNode.parentNode,
41         left = e.pos[0] + offsetElement.offsetLeft + margin.left,
42         top = e.pos[1] + offsetElement.offsetTop + margin.top;
43
44     var content = '<h3>' + e.label + '</h3>' +
45             '<p>' + e.value + '</p>';
46
47     nv.tooltip.show([left, top], content, e.value < 0 ? 'e' : 'w', null, offsetElement.parentNode);
48   };
49
50   //============================================================
51
52
53   function chart(selection) {
54     selection.each(function(d, i) {
55       var container = d3.select(this);
56
57       var availableWidth = (width  || parseInt(container.style('width')) || 960)
58                              - margin.left - margin.right,
59           availableHeight = height - margin.top - margin.bottom,
60           that = this;
61
62
63       chart.update = function() { chart(selection) };
64       chart.container = this;
65
66       //------------------------------------------------------------
67       // Display No Data message if there's nothing to show.
68
69       /*
70       // Disabled until I figure out a better way to check for no data with the bullet chart
71       if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
72         var noDataText = container.selectAll('.nv-noData').data([noData]);
73
74         noDataText.enter().append('text')
75           .attr('class', 'nvd3 nv-noData')
76           .attr('dy', '-.7em')
77           .style('text-anchor', 'middle');
78
79         noDataText
80           .attr('x', margin.left + availableWidth / 2)
81           .attr('y', margin.top + availableHeight / 2)
82           .text(function(d) { return d });
83
84         return chart;
85       } else {
86         container.selectAll('.nv-noData').remove();
87       }
88       */
89
90       //------------------------------------------------------------
91
92
93
94       var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
95           markerz = markers.call(this, d, i).slice().sort(d3.descending),
96           measurez = measures.call(this, d, i).slice().sort(d3.descending);
97
98
99       //------------------------------------------------------------
100       // Setup containers and skeleton of chart
101
102       var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]);
103       var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart');
104       var gEnter = wrapEnter.append('g');
105       var g = wrap.select('g');
106
107       gEnter.append('g').attr('class', 'nv-bulletWrap');
108       gEnter.append('g').attr('class', 'nv-titles');
109
110       wrap.attr('transform', 'translate(' + margin.left + ',' + ( margin.top + i*height )+ ')');
111
112       //------------------------------------------------------------
113
114
115       // Compute the new x-scale.
116       var MaxX = Math.max(rangez[0] ? rangez[0]:0 , markerz[0] ? markerz[0] : 0 , measurez[0] ? measurez[0] : 0)
117       var x1 = d3.scale.linear()
118           .domain([0, MaxX]).nice()  // TODO: need to allow forceX and forceY, and xDomain, yDomain
119           .range(reverse ? [availableWidth, 0] : [0, availableWidth]);
120
121       // Retrieve the old x-scale, if this is an update.
122       var x0 = this.__chart__ || d3.scale.linear()
123           .domain([0, Infinity])
124           .range(x1.range());
125
126       // Stash the new scale.
127       this.__chart__ = x1;
128
129       /*
130       // Derive width-scales from the x-scales.
131       var w0 = bulletWidth(x0),
132           w1 = bulletWidth(x1);
133
134       function bulletWidth(x) {
135         var x0 = x(0);
136         return function(d) {
137           return Math.abs(x(d) - x(0));
138         };
139       }
140
141       function bulletTranslate(x) {
142         return function(d) {
143           return 'translate(' + x(d) + ',0)';
144         };
145       }
146       */
147
148       var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0)
149           w1 = function(d) { return Math.abs(x1(d) - x1(0)) };
150
151
152       var title = gEnter.select('.nv-titles').append("g")
153           .attr("text-anchor", "end")
154           .attr("transform", "translate(-6," + (height - margin.top - margin.bottom) / 2 + ")");
155       title.append("text")
156           .attr("class", "nv-title")
157           .text(function(d) { return d.title; });
158
159       title.append("text")
160           .attr("class", "nv-subtitle")
161           .attr("dy", "1em")
162           .text(function(d) { return d.subtitle; });
163
164
165
166       bullet
167         .width(availableWidth)
168         .height(availableHeight)
169
170       var bulletWrap = g.select('.nv-bulletWrap');
171
172       d3.transition(bulletWrap).call(bullet);
173
174
175
176       // Compute the tick format.
177       var format = tickFormat || x1.tickFormat(8);
178
179       // Update the tick groups.
180       var tick = g.selectAll('g.nv-tick')
181           .data(x1.ticks(8), function(d) {
182             return this.textContent || format(d);
183           });
184
185       // Initialize the ticks with the old scale, x0.
186       var tickEnter = tick.enter().append('g')
187           .attr('class', 'nv-tick')
188           .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' })
189           .style('opacity', 1e-6);
190
191       tickEnter.append('line')
192           .attr('y1', availableHeight)
193           .attr('y2', availableHeight * 7 / 6);
194
195       tickEnter.append('text')
196           .attr('text-anchor', 'middle')
197           .attr('dy', '1em')
198           .attr('y', availableHeight * 7 / 6)
199           .text(format);
200
201       // Transition the entering ticks to the new scale, x1.
202       d3.transition(tickEnter)
203           .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
204           .style('opacity', 1);
205
206       // Transition the updating ticks to the new scale, x1.
207       var tickUpdate = d3.transition(tick)
208           .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
209           .style('opacity', 1);
210
211       tickUpdate.select('line')
212           .attr('y1', availableHeight)
213           .attr('y2', availableHeight * 7 / 6);
214
215       tickUpdate.select('text')
216           .attr('y', availableHeight * 7 / 6);
217
218       // Transition the exiting ticks to the new scale, x1.
219       d3.transition(tick.exit())
220           .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' })
221           .style('opacity', 1e-6)
222           .remove();
223
224
225       //============================================================
226       // Event Handling/Dispatching (in chart's scope)
227       //------------------------------------------------------------
228
229       dispatch.on('tooltipShow', function(e) {
230         if (tooltips) showTooltip(e, that.parentNode);
231       });
232
233       //============================================================
234
235     });
236
237     d3.timer.flush();
238
239     return chart;
240   }
241
242
243   //============================================================
244   // Event Handling/Dispatching (out of chart's scope)
245   //------------------------------------------------------------
246
247   bullet.dispatch.on('elementMouseover.tooltip', function(e) {
248     dispatch.tooltipShow(e);
249   });
250
251   bullet.dispatch.on('elementMouseout.tooltip', function(e) {
252     dispatch.tooltipHide(e);
253   });
254
255   dispatch.on('tooltipHide', function() {
256     if (tooltips) nv.tooltip.cleanup();
257   });
258
259   //============================================================
260
261
262   //============================================================
263   // Expose Public Variables
264   //------------------------------------------------------------
265
266   chart.dispatch = dispatch;
267   chart.bullet = bullet;
268
269   // left, right, top, bottom
270   chart.orient = function(x) {
271     if (!arguments.length) return orient;
272     orient = x;
273     reverse = orient == 'right' || orient == 'bottom';
274     return chart;
275   };
276
277   // ranges (bad, satisfactory, good)
278   chart.ranges = function(x) {
279     if (!arguments.length) return ranges;
280     ranges = x;
281     return chart;
282   };
283
284   // markers (previous, goal)
285   chart.markers = function(x) {
286     if (!arguments.length) return markers;
287     markers = x;
288     return chart;
289   };
290
291   // measures (actual, forecast)
292   chart.measures = function(x) {
293     if (!arguments.length) return measures;
294     measures = x;
295     return chart;
296   };
297
298   chart.width = function(x) {
299     if (!arguments.length) return width;
300     width = x;
301     return chart;
302   };
303
304   chart.height = function(x) {
305     if (!arguments.length) return height;
306     height = x;
307     return chart;
308   };
309
310   chart.margin = function(_) {
311     if (!arguments.length) return margin;
312     margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
313     margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
314     margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
315     margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
316     return chart;
317   };
318
319   chart.tickFormat = function(x) {
320     if (!arguments.length) return tickFormat;
321     tickFormat = x;
322     return chart;
323   };
324
325   chart.tooltips = function(_) {
326     if (!arguments.length) return tooltips;
327     tooltips = _;
328     return chart;
329   };
330
331   chart.tooltipContent = function(_) {
332     if (!arguments.length) return tooltip;
333     tooltip = _;
334     return chart;
335   };
336
337   chart.noData = function(_) {
338     if (!arguments.length) return noData;
339     noData = _;
340     return chart;
341   };
342
343   //============================================================
344
345
346   return chart;
347 };
348
349