Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / static / fusion / raptor / d3 / js / models / lineWithFocusChart.js
1 nv.models.lineWithFocusChart = function() {
2   "use strict";
3   //============================================================
4   // Public Variables with Default Settings
5   //------------------------------------------------------------
6
7   var lines = nv.models.line()
8     , lines2 = nv.models.line()
9     , xAxis = nv.models.axis()
10     , yAxis = nv.models.axis()
11     , x2Axis = nv.models.axis()
12     , y2Axis = nv.models.axis()
13     , legend = nv.models.legend()
14     , brush = d3.svg.brush()
15     ;
16
17   var margin = {top: 30, right: 30, bottom: 30, left: 60}
18     , margin2 = {top: 0, right: 30, bottom: 20, left: 60}
19     , color = nv.utils.defaultColor()
20     , width = null
21     , height = null
22     , height2 = 100
23     , x
24     , y
25     , x2
26     , y2
27     , showLegend = true
28     , brushExtent = null
29     , tooltips = true
30     , tooltip = function(key, x, y, e, graph) {
31         return '<h3>' + key + '</h3>' +
32                '<p>' +  y + ' at ' + x + '</p>'
33       }
34     , noData = "No Data Available."
35     , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'brush')
36     , transitionDuration = 250
37     ;
38
39   lines
40     .clipEdge(true)
41     ;
42   lines2
43     .interactive(false)
44     ;
45   xAxis
46     .orient('bottom')
47     .tickPadding(5)
48     ;
49   yAxis
50     .orient('left')
51     ;
52   x2Axis
53     .orient('bottom')
54     .tickPadding(5)
55     ;
56   y2Axis
57     .orient('left')
58     ;
59   //============================================================
60
61
62   //============================================================
63   // Private Variables
64   //------------------------------------------------------------
65
66   var showTooltip = function(e, offsetElement) {
67     var left = e.pos[0] + ( offsetElement.offsetLeft || 0 ),
68         top = e.pos[1] + ( offsetElement.offsetTop || 0),
69         x = xAxis.tickFormat()(lines.x()(e.point, e.pointIndex)),
70         y = yAxis.tickFormat()(lines.y()(e.point, e.pointIndex)),
71         content = tooltip(e.series.key, x, y, e, chart);
72
73     nv.tooltip.show([left, top], content, null, null, offsetElement);
74   };
75
76   //============================================================
77
78
79   function chart(selection) {
80     selection.each(function(data) {
81       var container = d3.select(this),
82           that = this;
83
84       var availableWidth = (width  || parseInt(container.style('width')) || 960)
85                              - margin.left - margin.right,
86           availableHeight1 = (height || parseInt(container.style('height')) || 400)
87                              - margin.top - margin.bottom - height2,
88           availableHeight2 = height2 - margin2.top - margin2.bottom;
89
90       chart.update = function() { container.transition().duration(transitionDuration).call(chart) };
91       chart.container = this;
92
93
94       //------------------------------------------------------------
95       // Display No Data message if there's nothing to show.
96
97       if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
98         var noDataText = container.selectAll('.nv-noData').data([noData]);
99
100         noDataText.enter().append('text')
101           .attr('class', 'nvd3 nv-noData')
102           .attr('dy', '-.7em')
103           .style('text-anchor', 'middle');
104
105         noDataText
106           .attr('x', margin.left + availableWidth / 2)
107           .attr('y', margin.top + availableHeight1 / 2)
108           .text(function(d) { return d });
109
110         return chart;
111       } else {
112         container.selectAll('.nv-noData').remove();
113       }
114
115       //------------------------------------------------------------
116
117
118       //------------------------------------------------------------
119       // Setup Scales
120
121       x = lines.xScale();
122       y = lines.yScale();
123       x2 = lines2.xScale();
124       y2 = lines2.yScale();
125
126       //------------------------------------------------------------
127
128
129       //------------------------------------------------------------
130       // Setup containers and skeleton of chart
131
132       var wrap = container.selectAll('g.nv-wrap.nv-lineWithFocusChart').data([data]);
133       var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineWithFocusChart').append('g');
134       var g = wrap.select('g');
135
136       gEnter.append('g').attr('class', 'nv-legendWrap');
137
138       var focusEnter = gEnter.append('g').attr('class', 'nv-focus');
139       focusEnter.append('g').attr('class', 'nv-x nv-axis');
140       focusEnter.append('g').attr('class', 'nv-y nv-axis');
141       focusEnter.append('g').attr('class', 'nv-linesWrap');
142
143       var contextEnter = gEnter.append('g').attr('class', 'nv-context');
144       contextEnter.append('g').attr('class', 'nv-x nv-axis');
145       contextEnter.append('g').attr('class', 'nv-y nv-axis');
146       contextEnter.append('g').attr('class', 'nv-linesWrap');
147       contextEnter.append('g').attr('class', 'nv-brushBackground');
148       contextEnter.append('g').attr('class', 'nv-x nv-brush');
149
150       //------------------------------------------------------------
151
152
153       //------------------------------------------------------------
154       // Legend
155
156       if (showLegend) {
157         legend.width(availableWidth);
158
159         g.select('.nv-legendWrap')
160             .datum(data)
161             .call(legend);
162
163         if ( margin.top != legend.height()) {
164           margin.top = legend.height();
165           availableHeight1 = (height || parseInt(container.style('height')) || 400)
166                              - margin.top - margin.bottom - height2;
167         }
168
169         g.select('.nv-legendWrap')
170             .attr('transform', 'translate(0,' + (-margin.top) +')')
171       }
172
173       //------------------------------------------------------------
174
175
176       wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
177
178
179       //------------------------------------------------------------
180       // Main Chart Component(s)
181
182       lines
183         .width(availableWidth)
184         .height(availableHeight1)
185         .color(
186           data
187             .map(function(d,i) {
188               return d.color || color(d, i);
189             })
190             .filter(function(d,i) {
191               return !data[i].disabled;
192           })
193         );
194
195       lines2
196         .defined(lines.defined())
197         .width(availableWidth)
198         .height(availableHeight2)
199         .color(
200           data
201             .map(function(d,i) {
202               return d.color || color(d, i);
203             })
204             .filter(function(d,i) {
205               return !data[i].disabled;
206           })
207         );
208
209       g.select('.nv-context')
210           .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')')
211
212       var contextLinesWrap = g.select('.nv-context .nv-linesWrap')
213           .datum(data.filter(function(d) { return !d.disabled }))
214
215       d3.transition(contextLinesWrap).call(lines2);
216
217       //------------------------------------------------------------
218
219
220       /*
221       var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
222           .datum(data.filter(function(d) { return !d.disabled }))
223
224       d3.transition(focusLinesWrap).call(lines);
225      */
226
227
228       //------------------------------------------------------------
229       // Setup Main (Focus) Axes
230
231       xAxis
232         .scale(x)
233         .ticks( availableWidth / 100 )
234         .tickSize(-availableHeight1, 0);
235
236       yAxis
237         .scale(y)
238         .ticks( availableHeight1 / 36 )
239         .tickSize( -availableWidth, 0);
240
241       g.select('.nv-focus .nv-x.nv-axis')
242           .attr('transform', 'translate(0,' + availableHeight1 + ')');
243
244       //------------------------------------------------------------
245
246
247       //------------------------------------------------------------
248       // Setup Brush
249
250       brush
251         .x(x2)
252         .on('brush', function() {
253             //When brushing, turn off transitions because chart needs to change immediately.
254             var oldTransition = chart.transitionDuration();
255             chart.transitionDuration(0); 
256             onBrush();
257             chart.transitionDuration(oldTransition);
258         });
259
260       if (brushExtent) brush.extent(brushExtent);
261
262       var brushBG = g.select('.nv-brushBackground').selectAll('g')
263           .data([brushExtent || brush.extent()])
264
265       var brushBGenter = brushBG.enter()
266           .append('g');
267
268       brushBGenter.append('rect')
269           .attr('class', 'left')
270           .attr('x', 0)
271           .attr('y', 0)
272           .attr('height', availableHeight2);
273
274       brushBGenter.append('rect')
275           .attr('class', 'right')
276           .attr('x', 0)
277           .attr('y', 0)
278           .attr('height', availableHeight2);
279
280       var gBrush = g.select('.nv-x.nv-brush')
281           .call(brush);
282       gBrush.selectAll('rect')
283           //.attr('y', -5)
284           .attr('height', availableHeight2);
285       gBrush.selectAll('.resize').append('path').attr('d', resizePath);
286
287       onBrush();
288
289       //------------------------------------------------------------
290
291
292       //------------------------------------------------------------
293       // Setup Secondary (Context) Axes
294
295       x2Axis
296         .scale(x2)
297         .ticks( availableWidth / 100 )
298         .tickSize(-availableHeight2, 0);
299
300       g.select('.nv-context .nv-x.nv-axis')
301           .attr('transform', 'translate(0,' + y2.range()[0] + ')');
302       d3.transition(g.select('.nv-context .nv-x.nv-axis'))
303           .call(x2Axis);
304
305
306       y2Axis
307         .scale(y2)
308         .ticks( availableHeight2 / 36 )
309         .tickSize( -availableWidth, 0);
310
311       d3.transition(g.select('.nv-context .nv-y.nv-axis'))
312           .call(y2Axis);
313
314       g.select('.nv-context .nv-x.nv-axis')
315           .attr('transform', 'translate(0,' + y2.range()[0] + ')');
316
317       //------------------------------------------------------------
318
319
320       //============================================================
321       // Event Handling/Dispatching (in chart's scope)
322       //------------------------------------------------------------
323
324       legend.dispatch.on('stateChange', function(newState) { 
325         chart.update();
326       });
327
328       dispatch.on('tooltipShow', function(e) {
329         if (tooltips) showTooltip(e, that.parentNode);
330       });
331
332       //============================================================
333
334
335       //============================================================
336       // Functions
337       //------------------------------------------------------------
338
339       // Taken from crossfilter (http://square.github.com/crossfilter/)
340       function resizePath(d) {
341         var e = +(d == 'e'),
342             x = e ? 1 : -1,
343             y = availableHeight2 / 3;
344         return 'M' + (.5 * x) + ',' + y
345             + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6)
346             + 'V' + (2 * y - 6)
347             + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y)
348             + 'Z'
349             + 'M' + (2.5 * x) + ',' + (y + 8)
350             + 'V' + (2 * y - 8)
351             + 'M' + (4.5 * x) + ',' + (y + 8)
352             + 'V' + (2 * y - 8);
353       }
354
355
356       function updateBrushBG() {
357         if (!brush.empty()) brush.extent(brushExtent);
358         brushBG
359             .data([brush.empty() ? x2.domain() : brushExtent])
360             .each(function(d,i) {
361               var leftWidth = x2(d[0]) - x.range()[0],
362                   rightWidth = x.range()[1] - x2(d[1]);
363               d3.select(this).select('.left')
364                 .attr('width',  leftWidth < 0 ? 0 : leftWidth);
365
366               d3.select(this).select('.right')
367                 .attr('x', x2(d[1]))
368                 .attr('width', rightWidth < 0 ? 0 : rightWidth);
369             });
370       }
371
372
373       function onBrush() {
374         brushExtent = brush.empty() ? null : brush.extent();
375         var extent = brush.empty() ? x2.domain() : brush.extent();
376
377         //The brush extent cannot be less than one.  If it is, don't update the line chart.
378         if (Math.abs(extent[0] - extent[1]) <= 1) {
379           return;
380         }
381
382         dispatch.brush({extent: extent, brush: brush});
383
384
385         updateBrushBG();
386
387         // Update Main (Focus)
388         var focusLinesWrap = g.select('.nv-focus .nv-linesWrap')
389             .datum(
390               data
391                 .filter(function(d) { return !d.disabled })
392                 .map(function(d,i) {
393                   return {
394                     key: d.key,
395                     values: d.values.filter(function(d,i) {
396                       return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1];
397                     })
398                   }
399                 })
400             );
401         focusLinesWrap.transition().duration(transitionDuration).call(lines);
402
403
404         // Update Main (Focus) Axes
405         g.select('.nv-focus .nv-x.nv-axis').transition().duration(transitionDuration)
406             .call(xAxis);
407         g.select('.nv-focus .nv-y.nv-axis').transition().duration(transitionDuration)
408             .call(yAxis);
409       }
410
411       //============================================================
412
413
414     });
415
416     return chart;
417   }
418
419
420   //============================================================
421   // Event Handling/Dispatching (out of chart's scope)
422   //------------------------------------------------------------
423
424   lines.dispatch.on('elementMouseover.tooltip', function(e) {
425     e.pos = [e.pos[0] +  margin.left, e.pos[1] + margin.top];
426     dispatch.tooltipShow(e);
427   });
428
429   lines.dispatch.on('elementMouseout.tooltip', function(e) {
430     dispatch.tooltipHide(e);
431   });
432
433   dispatch.on('tooltipHide', function() {
434     if (tooltips) nv.tooltip.cleanup();
435   });
436
437   //============================================================
438
439
440   //============================================================
441   // Expose Public Variables
442   //------------------------------------------------------------
443
444   // expose chart's sub-components
445   chart.dispatch = dispatch;
446   chart.legend = legend;
447   chart.lines = lines;
448   chart.lines2 = lines2;
449   chart.xAxis = xAxis;
450   chart.yAxis = yAxis;
451   chart.x2Axis = x2Axis;
452   chart.y2Axis = y2Axis;
453
454   d3.rebind(chart, lines, 'defined', 'isArea', 'size', 'xDomain', 'yDomain', 'xRange', 'yRange', 'forceX', 'forceY', 'interactive', 'clipEdge', 'clipVoronoi', 'id');
455
456   chart.options = nv.utils.optionsFunc.bind(chart);
457   
458   chart.x = function(_) {
459     if (!arguments.length) return lines.x;
460     lines.x(_);
461     lines2.x(_);
462     return chart;
463   };
464
465   chart.y = function(_) {
466     if (!arguments.length) return lines.y;
467     lines.y(_);
468     lines2.y(_);
469     return chart;
470   };
471
472   chart.margin = function(_) {
473     if (!arguments.length) return margin;
474     margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
475     margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
476     margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
477     margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
478     return chart;
479   };
480
481   chart.margin2 = function(_) {
482     if (!arguments.length) return margin2;
483     margin2 = _;
484     return chart;
485   };
486
487   chart.width = function(_) {
488     if (!arguments.length) return width;
489     width = _;
490     return chart;
491   };
492
493   chart.height = function(_) {
494     if (!arguments.length) return height;
495     height = _;
496     return chart;
497   };
498
499   chart.height2 = function(_) {
500     if (!arguments.length) return height2;
501     height2 = _;
502     return chart;
503   };
504
505   chart.color = function(_) {
506     if (!arguments.length) return color;
507     color =nv.utils.getColor(_);
508     legend.color(color);
509     return chart;
510   };
511
512   chart.showLegend = function(_) {
513     if (!arguments.length) return showLegend;
514     showLegend = _;
515     return chart;
516   };
517
518   chart.tooltips = function(_) {
519     if (!arguments.length) return tooltips;
520     tooltips = _;
521     return chart;
522   };
523
524   chart.tooltipContent = function(_) {
525     if (!arguments.length) return tooltip;
526     tooltip = _;
527     return chart;
528   };
529
530   chart.interpolate = function(_) {
531     if (!arguments.length) return lines.interpolate();
532     lines.interpolate(_);
533     lines2.interpolate(_);
534     return chart;
535   };
536
537   chart.noData = function(_) {
538     if (!arguments.length) return noData;
539     noData = _;
540     return chart;
541   };
542
543   // Chart has multiple similar Axes, to prevent code duplication, probably need to link all axis functions manually like below
544   chart.xTickFormat = function(_) {
545     if (!arguments.length) return xAxis.tickFormat();
546     xAxis.tickFormat(_);
547     x2Axis.tickFormat(_);
548     return chart;
549   };
550
551   chart.yTickFormat = function(_) {
552     if (!arguments.length) return yAxis.tickFormat();
553     yAxis.tickFormat(_);
554     y2Axis.tickFormat(_);
555     return chart;
556   };
557   
558   chart.brushExtent = function(_) {
559     if (!arguments.length) return brushExtent;
560     brushExtent = _;
561     return chart;
562   };
563
564   chart.transitionDuration = function(_) {
565     if (!arguments.length) return transitionDuration;
566     transitionDuration = _;
567     return chart;
568   };
569
570   //============================================================
571
572
573   return chart;
574 }