text: /**
   * A concrete implementation of a general purpose bubble chart that allows data visualization using the
   * following dimensions:
   * - x axis position
   * - y axis position
   * - bubble radius
   * - color
   *
   * Examples:
   * - {@link http://dc-js.github.com/dc.js/ Nasdaq 100 Index}
   * - {@link http://dc-js.github.com/dc.js/vc/index.html US Venture Capital Landscape 2011}
   * @class bubbleChart
   * @memberof dc
   * @mixes dc.bubbleMixin
   * @mixes dc.coordinateGridMixin
   * @example
   * // create a bubble chart under #chart-container1 element using the default global chart group
   * var bubbleChart1 = dc.bubbleChart('#chart-container1');
   * // create a bubble chart under #chart-container2 element using chart group A
   * var bubbleChart2 = dc.bubbleChart('#chart-container2', 'chartGroupA');
   * @param {String|node|d3.selection} parent - Any valid
   * {@link https://github.com/mbostock/d3/wiki/Selections#selecting-elements d3 single selector} specifying
   * a dom block element such as a div; or a dom element or d3 selection.
   * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in.
   * Interaction with a chart will only trigger events and redraws within the chart's group.
   * @return {dc.bubbleChart}
   */
  dc.bubbleChart = function (parent, chartGroup) {
      var _chart = dc.bubbleMixin(dc.coordinateGridMixin({}));
  
      var _elasticRadius = false;
      var _sortBubbleSize = false;
  
      _chart.transitionDuration(750);
  
      var bubbleLocator = function (d) {
          return 'translate(' + (bubbleX(d)) + ',' + (bubbleY(d)) + ')';
      };
  
      /**
       * Turn on or off the elastic bubble radius feature, or return the value of the flag. If this
       * feature is turned on, then bubble radii will be automatically rescaled to fit the chart better.
       * @method elasticRadius
       * @memberof dc.bubbleChart
       * @instance
       * @param {Boolean} [elasticRadius=false]
       * @return {Boolean}
       * @return {dc.bubbleChart}
       */
      _chart.elasticRadius = function (elasticRadius) {
          if (!arguments.length) {
              return _elasticRadius;
          }
          _elasticRadius = elasticRadius;
          return _chart;
      };
  
      /**
       * Turn on or off the bubble sorting feature, or return the value of the flag. If enabled,
       * bubbles will be sorted by their radius, with smaller bubbles in front.
       * @method sortBubbleSize
       * @memberof dc.bubbleChart
       * @instance
       * @param {Boolean} [sortBubbleSize=false]
       * @return {Boolean}
       * @return {dc.bubbleChart}
       */
      _chart.sortBubbleSize = function (sortBubbleSize) {
          if (!arguments.length) {
              return _sortBubbleSize;
          }
          _sortBubbleSize = sortBubbleSize;
          return _chart;
      };
  
      _chart.plotData = function () {
          if (_elasticRadius) {
              _chart.r().domain([_chart.rMin(), _chart.rMax()]);
          }
  
          _chart.r().range([_chart.MIN_RADIUS, _chart.xAxisLength() * _chart.maxBubbleRelativeSize()]);
  
          var data = _chart.data();
          if (_sortBubbleSize) {
              // sort descending so smaller bubbles are on top
              var radiusAccessor = _chart.radiusValueAccessor();
              data.sort(function (a, b) { return d3.descending(radiusAccessor(a), radiusAccessor(b)); });
          }
          var bubbleG = _chart.chartBodyG().selectAll('g.' + _chart.BUBBLE_NODE_CLASS)
                  .data(data, function (d) { return d.key; });
          if (_sortBubbleSize) {
              // Call order here to update dom order based on sort
              bubbleG.order();
          }
  
          renderNodes(bubbleG);
  
          updateNodes(bubbleG);
  
          removeNodes(bubbleG);
  
          _chart.fadeDeselectedArea();
      };
  
      function renderNodes (bubbleG) {
          var bubbleGEnter = bubbleG.enter().append('g');
  
          bubbleGEnter
              .attr('class', _chart.BUBBLE_NODE_CLASS)
              .attr('transform', bubbleLocator)
              .append('circle').attr('class', function (d, i) {
                  return _chart.BUBBLE_CLASS + ' _' + i;
              })
              .on('click', _chart.onClick)
              .attr('fill', _chart.getColor)
              .attr('r', 0);
          dc.transition(bubbleG, _chart.transitionDuration())
              .selectAll('circle.' + _chart.BUBBLE_CLASS)
              .attr('r', function (d) {
                  return _chart.bubbleR(d);
              })
              .attr('opacity', function (d) {
                  return (_chart.bubbleR(d) > 0) ? 1 : 0;
              });
  
          _chart._doRenderLabel(bubbleGEnter);
  
          _chart._doRenderTitles(bubbleGEnter);
      }
  
      function updateNodes (bubbleG) {
          dc.transition(bubbleG, _chart.transitionDuration())
              .attr('transform', bubbleLocator)
              .selectAll('circle.' + _chart.BUBBLE_CLASS)
              .attr('fill', _chart.getColor)
              .attr('r', function (d) {
                  return _chart.bubbleR(d);
              })
              .attr('opacity', function (d) {
                  return (_chart.bubbleR(d) > 0) ? 1 : 0;
              });
  
          _chart.doUpdateLabels(bubbleG);
          _chart.doUpdateTitles(bubbleG);
      }
  
      function removeNodes (bubbleG) {
          bubbleG.exit().remove();
      }
  
      function bubbleX (d) {
          var x = _chart.x()(_chart.keyAccessor()(d));
          if (isNaN(x)) {
              x = 0;
          }
          return x;
      }
  
      function bubbleY (d) {
          var y = _chart.y()(_chart.valueAccessor()(d));
          if (isNaN(y)) {
              y = 0;
          }
          return y;
      }
  
      _chart.renderBrush = function () {
          // override default x axis brush from parent chart
      };
  
      _chart.redrawBrush = function () {
          // override default x axis brush from parent chart
          _chart.fadeDeselectedArea();
      };
  
      return _chart.anchor(parent, chartGroup);
  };
  