Initial OpenECOMP Portal commit
[portal.git] / ecomp-portal-BE / war / static / fusion / d3 / js / models / axis.js
diff --git a/ecomp-portal-BE/war/static/fusion/d3/js/models/axis.js b/ecomp-portal-BE/war/static/fusion/d3/js/models/axis.js
new file mode 100644 (file)
index 0000000..9895c3f
--- /dev/null
@@ -0,0 +1,470 @@
+nv.models.axis = function() {
+  "use strict";
+  //============================================================
+  // Public Variables with Default Settings
+  //------------------------------------------------------------
+
+  var axis = d3.svg.axis()
+    ;
+
+  var margin = {top: 0, right: 0, bottom: 0, left: 0}
+    , width = 75 //only used for tickLabel currently
+    , height = 60 //only used for tickLabel currently
+    , scale = d3.scale.linear()
+    , axisLabelText = null
+    , showMaxMin = true //TODO: showMaxMin should be disabled on all ordinal scaled axes
+    , highlightZero = true
+    , rotateLabels = 0
+    , rotateYLabel = true
+    , staggerLabels = false
+    , isOrdinal = false
+    , ticks = null
+       , logScale = false
+    , axisLabelDistance = 12 //The larger this number is, the closer the axis label is to the axis.
+    ;
+
+  axis
+    .scale(scale)
+    .orient('bottom')
+    .tickFormat(function(d) { return d })
+    ;
+
+  //============================================================
+
+
+  //============================================================
+  // Private Variables
+  //------------------------------------------------------------
+
+  var scale0;
+
+  //============================================================
+
+
+  function chart(selection) {
+    selection.each(function(data) {
+      var container = d3.select(this);
+
+
+      //------------------------------------------------------------
+      // Setup containers and skeleton of chart
+
+      var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]);
+      var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis');
+      var gEnter = wrapEnter.append('g');
+      var g = wrap.select('g')
+
+      //------------------------------------------------------------
+
+
+      if (ticks !== null)
+        axis.ticks(ticks);
+      else if (axis.orient() == 'top' || axis.orient() == 'bottom')
+        axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100);
+
+
+      //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
+
+
+      g.transition().call(axis);
+
+      scale0 = scale0 || axis.scale();
+
+      var fmt = axis.tickFormat();
+      if (fmt == null) {
+        fmt = scale0.tickFormat();
+      }
+
+      var axisLabel = g.selectAll('text.nv-axislabel')
+          .data([axisLabelText || null]);
+      axisLabel.exit().remove();
+      switch (axis.orient()) {
+        case 'top':
+          axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+          var w = (scale.range().length==2) ? scale.range()[1] : (scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]));
+          axisLabel
+              .attr('text-anchor', 'middle')
+              .attr('y', 0)
+              .attr('x', w/2);
+          if (showMaxMin) {
+            var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+                           .data(scale.domain());
+            axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text');
+            axisMaxMin.exit().remove();
+            axisMaxMin
+                .attr('transform', function(d,i) {
+                  return 'translate(' + scale(d) + ',0)'
+                })
+              .select('text')
+                .attr('dy', '0em')
+                .attr('y', -axis.tickPadding())
+                .attr('text-anchor', 'middle')
+                .text(function(d,i) {
+                  //var v = fmt(d);
+                                 var v = d;
+                                 if(logScale) {
+                                       v = Math.pow(10,v);
+                                       v = fmt(v);
+                                       //fmt = d3.format(',.2f');
+                                       //v = fmt(v);
+                                 } else
+                                 v = fmt(v);
+                  return ('' + v).match('NaN') ? '' : v;
+                });
+            axisMaxMin.transition()
+                .attr('transform', function(d,i) {
+                  return 'translate(' + scale.range()[i] + ',0)'
+                });
+          }
+          break;
+        case 'bottom':
+          var xLabelMargin = 36;
+          var maxTextWidth = 30;
+          var xTicks = g.selectAll('g').select("text");
+          if (rotateLabels%360) {
+            //Calculate the longest xTick width
+            xTicks.each(function(d,i){
+              var width = this.getBBox().width;
+              if(width > maxTextWidth) maxTextWidth = width;
+            });
+            //Convert to radians before calculating sin. Add 30 to margin for healthy padding.
+            var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180));
+            var xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30;
+            //Rotate all xTicks
+            xTicks
+              .attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
+              .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end');
+          }
+          axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+          var w = (scale.range().length==2) ? scale.range()[1] : (scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]));
+          axisLabel
+              .attr('text-anchor', 'middle')
+              .attr('y', xLabelMargin)
+              .attr('x', w/2);
+          if (showMaxMin) {
+          //if (showMaxMin && !isOrdinal) {
+            var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+                           //.data(scale.domain())
+                           .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]);
+            axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text');
+            axisMaxMin.exit().remove();
+            axisMaxMin
+                .attr('transform', function(d,i) {
+                  return 'translate(' + (scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0)) + ',0)'
+                })
+              .select('text')
+                .attr('dy', '.71em')
+                .attr('y', axis.tickPadding())
+                .attr('transform', function(d,i,j) { return 'rotate(' + rotateLabels + ' 0,0)' })
+                .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle')
+                .text(function(d,i) {
+                  //var v = fmt(d);
+                                 var v = d;
+                                 if(logScale) {
+                                       v = Math.pow(10,v);
+                                       v = fmt(v);
+                                       //fmt = d3.format(',.2f');
+                                       //v = fmt(v);
+                                 } else
+                                 v = fmt(v);
+                  return ('' + v).match('NaN') ? '' : v;
+                });
+            axisMaxMin.transition()
+                .attr('transform', function(d,i) {
+                  //return 'translate(' + scale.range()[i] + ',0)'
+                  //return 'translate(' + scale(d) + ',0)'
+                  return 'translate(' + (scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0)) + ',0)'
+                });
+          }
+          if (staggerLabels)
+            xTicks
+                .attr('transform', function(d,i) { return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')' });
+
+          break;
+        case 'right':
+          axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+          axisLabel
+              .style('text-anchor', rotateYLabel ? 'middle' : 'begin')
+              .attr('transform', rotateYLabel ? 'rotate(90)' : '')
+              .attr('y', rotateYLabel ? (-Math.max(margin.right,width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
+              .attr('x', rotateYLabel ? (scale.range()[0] / 2) : axis.tickPadding());
+          if (showMaxMin) {
+            var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+                           .data(scale.domain());
+            axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text')
+                .style('opacity', 0);
+            axisMaxMin.exit().remove();
+            axisMaxMin
+                .attr('transform', function(d,i) {
+                  return 'translate(0,' + scale(d) + ')'
+                })
+              .select('text')
+                .attr('dy', '.32em')
+                .attr('y', 0)
+                .attr('x', axis.tickPadding())
+                .style('text-anchor', 'start')
+                .text(function(d,i) {
+                  //var v = fmt(d);
+                                 var v = d;
+                                 if(logScale) {
+                                       v = Math.pow(10,v);
+                                       v = fmt(v);
+                                       //fmt = d3.format(',.2f');
+                                       //v = fmt(v);
+                                 } else
+                                   v = fmt(v);
+                  return ('' + v).match('NaN') ? '' : v;
+                });
+            axisMaxMin.transition()
+                .attr('transform', function(d,i) {
+                  return 'translate(0,' + scale.range()[i] + ')'
+                })
+              .select('text')
+                .style('opacity', 1);
+          }
+          break;
+        case 'left':
+          /*
+          //For dynamically placing the label. Can be used with dynamically-sized chart axis margins
+          var yTicks = g.selectAll('g').select("text");
+          yTicks.each(function(d,i){
+            var labelPadding = this.getBBox().width + axis.tickPadding() + 16;
+            if(labelPadding > width) width = labelPadding;
+          });
+          */
+          axisLabel.enter().append('text').attr('class', 'nv-axislabel');
+          axisLabel
+              .style('text-anchor', rotateYLabel ? 'middle' : 'end')
+              .attr('transform', rotateYLabel ? 'rotate(-90)' : '')
+              .attr('y', rotateYLabel ? (-Math.max(margin.left,width) + axisLabelDistance) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart
+              .attr('x', rotateYLabel ? (-scale.range()[0] / 2) : -axis.tickPadding());
+          if (showMaxMin) {
+            var axisMaxMin = wrap.selectAll('g.nv-axisMaxMin')
+                           .data(scale.domain());
+            axisMaxMin.enter().append('g').attr('class', 'nv-axisMaxMin').append('text')
+                .style('opacity', 0);
+            axisMaxMin.exit().remove();
+            axisMaxMin
+                .attr('transform', function(d,i) {
+                  return 'translate(0,' + scale0(d) + ')'
+                })
+              .select('text')
+                .attr('dy', '.32em')
+                .attr('y', 0)
+                .attr('x', -axis.tickPadding())
+                .attr('text-anchor', 'end')
+                .text(function(d,i) {
+                  //var v = fmt(d);
+                                 var v = d;
+                                 if(logScale) {
+                                       v = Math.pow(10,v);
+                                       v = fmt(v);
+                                       //fmt = d3.format(',.2f');
+                                       //v = fmt(v);
+                                 } else
+                                       v = fmt(v);
+                  return ('' + v).match('NaN') ? '' : v;
+                });
+            axisMaxMin.transition()
+                .attr('transform', function(d,i) {
+                  return 'translate(0,' + scale.range()[i] + ')'
+                })
+              .select('text')
+                .style('opacity', 1);
+          }
+          break;
+      }
+      axisLabel
+          .text(function(d) { return d });
+
+
+      if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) {
+        //check if max and min overlap other values, if so, hide the values that overlap
+        g.selectAll('g') // the g's wrapping each tick
+            .each(function(d,i) {
+              d3.select(this).select('text').attr('opacity', 1);
+                         var v; 
+                         if(logScale) {
+                               v = Math.pow(10,d);
+                               v = fmt(v);
+                               //fmt = d3.format(',.2f');
+                               //v = fmt(v);
+                         } else {
+                           v = fmt(d);
+                         }
+
+                         //d3.select(this).select('text').text(fmt(Math.pow(10,d)));
+                         d3.select(this).select('text').text(v);
+              if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it!
+                if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
+                  d3.select(this).attr('opacity', 0);
+                
+                d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!!
+              }
+            });
+
+        //if Max and Min = 0 only show min, Issue #281
+        if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0)
+          wrap.selectAll('g.nv-axisMaxMin')
+            .style('opacity', function(d,i) { return !i ? 1 : 0 });
+
+      }
+
+      if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) {
+        var maxMinRange = [];
+        wrap.selectAll('g.nv-axisMaxMin')
+            .each(function(d,i) {
+              try {
+                  if (i) // i== 1, max position
+                      maxMinRange.push(scale(d) - this.getBBox().width - 4)  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
+                  else // i==0, min position
+                      maxMinRange.push(scale(d) + this.getBBox().width + 4)
+              }catch (err) {
+                  if (i) // i== 1, max position
+                      maxMinRange.push(scale(d) - 4)  //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case)
+                  else // i==0, min position
+                      maxMinRange.push(scale(d) + 4)
+              }
+            });
+        g.selectAll('g') // the g's wrapping each tick
+            .each(function(d,i) {
+                         var v; 
+                         if(logScale) {
+                               v = Math.pow(10,d);
+                               //v = fmt(v);
+                               //fmt = d3.format(',.2f');
+                               v = fmt(v);
+                         } else {
+                           v = fmt(d);
+                         }
+                         //alert(v);
+
+                         //d3.select(this).select('text').text(fmt(Math.pow(10,d)));
+                         d3.select(this).select('text').text(v);
+                                               
+              if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) {
+                if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL
+                  d3.select(this).remove();
+                else
+                  d3.select(this).select('text').remove(); // Don't remove the ZERO line!!
+              }
+            });
+      }
+
+
+      //highlight zero line ... Maybe should not be an option and should just be in CSS?
+      if (highlightZero)
+        g.selectAll('.tick')
+          .filter(function(d) { return !parseFloat(Math.round(d.__data__*100000)/1000000) && (d.__data__ !== undefined) }) //this is because sometimes the 0 tick is a very small fraction, TODO: think of cleaner technique
+            .classed('zero', true);
+
+      //store old scales for use in transitions on update
+      scale0 = scale.copy();
+
+    });
+
+    return chart;
+  }
+
+
+  //============================================================
+  // Expose Public Variables
+  //------------------------------------------------------------
+
+  // expose chart's sub-components
+  chart.axis = axis;
+
+  d3.rebind(chart, axis, 'orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat');
+  d3.rebind(chart, scale, 'domain', 'range', 'rangeBand', 'rangeBands'); //these are also accessible by chart.scale(), but added common ones directly for ease of use
+
+  chart.options = nv.utils.optionsFunc.bind(chart);
+  
+  chart.margin = function(_) {
+    if(!arguments.length) return margin;
+    margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
+    margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
+    margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
+    margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
+    return chart;
+  }
+
+  chart.width = function(_) {
+    if (!arguments.length) return width;
+    width = _;
+    return chart;
+  };
+
+  chart.ticks = function(_) {
+    if (!arguments.length) return ticks;
+    ticks = _;
+    return chart;
+  };
+
+  chart.height = function(_) {
+    if (!arguments.length) return height;
+    height = _;
+    return chart;
+  };
+
+  chart.axisLabel = function(_) {
+    if (!arguments.length) return axisLabelText;
+    axisLabelText = _;
+    return chart;
+  }
+
+  chart.showMaxMin = function(_) {
+    if (!arguments.length) return showMaxMin;
+    showMaxMin = _;
+    return chart;
+  }
+
+  chart.logScale = function(_) {
+    if (!arguments.length) return logScale;
+    logScale = _;
+    return chart;
+  }
+  
+  chart.highlightZero = function(_) {
+    if (!arguments.length) return highlightZero;
+    highlightZero = _;
+    return chart;
+  }
+
+  chart.scale = function(_) {
+    if (!arguments.length) return scale;
+    scale = _;
+    axis.scale(scale);
+    isOrdinal = typeof scale.rangeBands === 'function';
+    d3.rebind(chart, scale, 'domain', 'range', 'rangeBand', 'rangeBands');
+    return chart;
+  }
+
+  chart.rotateYLabel = function(_) {
+    if(!arguments.length) return rotateYLabel;
+    rotateYLabel = _;
+    return chart;
+  }
+
+  chart.rotateLabels = function(_) {
+    if(!arguments.length) return rotateLabels;
+    rotateLabels = _;
+    return chart;
+  }
+
+  chart.staggerLabels = function(_) {
+    if (!arguments.length) return staggerLabels;
+    staggerLabels = _;
+    return chart;
+  };
+
+  chart.axisLabelDistance = function(_) {
+    if (!arguments.length) return axisLabelDistance;
+    axisLabelDistance = _;
+    return chart;
+  };
+
+  //============================================================
+
+
+  return chart;
+}