text: /**
   * @class Ext.chart.series.Radar
   * @extends Ext.chart.series.Series
   *
   * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
   * a constrained number of categories.
   * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
   * documentation for more information. A typical configuration object for the radar series could be:
   *
   * {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series}
   *
   *     var store = new Ext.data.JsonStore({
   *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
   *         data: [
   *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
   *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
   *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
   *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
   *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
   *         ]
   *     });
   *
   *     new Ext.chart.Chart({
   *         renderTo: Ext.getBody(),
   *         width: 500,
   *         height: 300,
   *         animate: true,
   *         theme:'Category2',
   *         store: store,
   *         axes: [{
   *             type: 'Radial',
   *             position: 'radial',
   *             label: {
   *                 display: true
   *             }
   *         }],
   *         series: [{
   *             type: 'radar',
   *             xField: 'name',
   *             yField: 'data3',
   *             showInLegend: true,
   *             showMarkers: true,
   *             markerConfig: {
   *                 radius: 5,
   *                 size: 5
   *             },
   *             style: {
   *                 'stroke-width': 2,
   *                 fill: 'none'
   *             }
   *         },{
   *             type: 'radar',
   *             xField: 'name',
   *             yField: 'data2',
   *             showMarkers: true,
   *             showInLegend: true,
   *             markerConfig: {
   *                 radius: 5,
   *                 size: 5
   *             },
   *             style: {
   *                 'stroke-width': 2,
   *                 fill: 'none'
   *             }
   *         },{
   *             type: 'radar',
   *             xField: 'name',
   *             yField: 'data5',
   *             showMarkers: true,
   *             showInLegend: true,
   *             markerConfig: {
   *                 radius: 5,
   *                 size: 5
   *             },
   *             style: {
   *                 'stroke-width': 2,
   *                 fill: 'none'
   *             }
   *         }]
   *     });
   *
   * In this configuration we add three series to the chart. Each of these series is bound to the same categories field, `name` but bound to different properties for each category,
   * `data1`, `data2` and `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration for the markers of each series can be set by adding properties onto
   * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object.
   *
   * @xtype radar
   */
  Ext.chart.series.Radar = Ext.extend(Ext.chart.series.Series, {
  
      type: "radar",
  
      rad: Math.PI / 180,
  
      rotation: 0,
  
      showInLegend: false,
  
      /**
       * @cfg {Object} style
       * An object containing styles for overriding series styles from Theming.
       */
  
      /**
       * @cfg {Boolean} showMarkers
       * Whether markers should be displayed at the data points along the line. If true,
       * then the {@link #markerConfig} config item will determine the markers' styling.
       */
  
      /**
       * @cfg {Object} markerConfig
       * The display style for the markers. Only used if {@link #showMarkers} is true.
       * The markerConfig is a configuration object containing the same set of properties defined in
       * the Sprite class. For example, if we were to set red circles as markers to the line series we could
       * pass the object:
       *
       <pre><code>
          markerConfig: {
              type: 'circle',
              radius: 4,
              'fill': '#f00'
          }
       </code></pre>
  
       */
  
       /**
       * @cfg {String} xField
       * The store record field name for the labels used in the radar series.
       */
  
       /**
       * @cfg {Object} yField
       * The store record field name for the deflection of the graph in the radar series.
       */
  
      constructor: function(config) {
          Ext.chart.series.Radar.superclass.constructor.apply(this, arguments);
          var me = this,
              surface = me.getSurface();
          me.group = surface.getGroup(me.seriesId);
          if (me.showMarkers) {
              me.markerGroup = surface.getGroup(me.seriesId + '-markers');
          }
      },
  
      /**
       * Draws the series for the current chart.
       */
      drawSeries: function() {
          var me = this,
              group = me.group,
              chart = me.chart,
              field = me.field || me.yField,
              surface = me.getSurface(),
              chartBBox = chart.chartBBox,
              centerX, centerY,
              items,
              radius,
              maxValue = 0,
              fields = [],
              max = Math.max,
              cos = Math.cos,
              sin = Math.sin,
              rotation = -me.rotation,
              rad = Ext.draw.Draw.rad,
              angle,
              l = me.getRecordCount(),
              startPath, path, x, y, rho,
              nfields,
              seriesStyle = me.style,
              axis = chart.axes && chart.axes.get(0),
              aggregate = !(axis && axis.maximum);
  
          if (me.fireEvent('beforedraw', me) === false) {
              return;
          }
  
          Ext.chart.series.Radar.superclass.drawSeries.call(this);
  
          me.setBBox();
  
          maxValue = aggregate? 0 : (axis.maximum || 0);
  
          //if the store is empty then there's nothing to draw
          if (!l || me.seriesIsHidden) {
              surface.items.hide(true);
              return;
          }
  
          me.unHighlightItem();
          me.cleanHighlights();
  
          centerX = me.centerX = (chartBBox.width / 2);
          centerY = me.centerY = (chartBBox.height / 2);
          me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
          me.items = items = [];
  
          if (aggregate) {
              //get all renderer fields
              chart.series.each(function(series) {
                  fields.push(series.yField);
              });
              //get maxValue to interpolate
              me.eachRecord(function(record, i) {
                  for (i = 0, nfields = fields.length; i < nfields; i++) {
                      maxValue = max(+record.get(fields[i]), maxValue);
                  }
              });
          }
          //ensure non-zero value.
          maxValue = maxValue || 1;
          //create path and items
          startPath = []; path = [];
          me.eachRecord(function(record, i) {
              rho = radius * record.get(field) / maxValue;
              angle = rad(rotation + i / l * 360);
              x = rho * cos(angle);
              y = rho * sin(angle);
              if (i == 0) {
                  path.push('M', x + centerX, y + centerY);
                  startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
              } else {
                  path.push('L', x + centerX, y + centerY);
                  startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
              }
              items.push({
                  sprite: false, //TODO(nico): add markers
                  point: [centerX + x, centerY + y],
                  series: me
              });
          });
          path.push('Z');
          //create path sprite
          if (!me.radar) {
              me.radar = surface.add(Ext.apply({
                  type: 'path',
                  group: group,
                  path: startPath
              }, seriesStyle || {}));
          }
          //reset on resizing
          if (chart.resizing) {
              me.radar.setAttributes({
                  path: startPath
              }, true);
          }
          //render/animate
          me.radar.show(true);
          if (chart.animate) {
              me.onAnimate(me.radar, {
                  to: Ext.apply({
                      path: path
                  }, seriesStyle || {})
              });
          } else {
              me.radar.setAttributes(Ext.apply({
                  path: path
              }, seriesStyle || {}), true);
          }
          //render markers, labels and callouts
          if (me.showMarkers) {
              me.drawMarkers();
          }
          me.renderLabels();
          me.renderCallouts();
  
          me.fireEvent('draw', me);
      },
  
      // @private draws the markers for the lines (if any).
      drawMarkers: function() {
          var me = this,
              chart = me.chart,
              surface = me.getSurface(),
              markerStyle = Ext.apply({}, me.markerStyle.style || {}),
              endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
              items = me.items,
              type = endMarkerStyle.type,
              markerGroup = me.markerGroup,
              centerX = me.centerX,
              centerY = me.centerY,
              item, i, l, marker;
  
          delete endMarkerStyle.type;
  
          for (i = 0, l = items.length; i < l; i++) {
              item = items[i];
              marker = markerGroup.getAt(i);
              if (!marker) {
                  marker = Ext.chart.Shape[type](surface, Ext.apply({
                      group: markerGroup,
                      x: 0,
                      y: 0,
                      translate: {
                          x: centerX,
                          y: centerY
                      }
                  }, endMarkerStyle));
              }
              else {
                  marker.show();
              }
              if (chart.resizing) {
                  marker.setAttributes({
                      x: 0,
                      y: 0,
                      translate: {
                          x: centerX,
                          y: centerY
                      }
                  }, true);
              }
              marker._to = {
                  translate: {
                      x: item.point[0],
                      y: item.point[1]
                  }
              };
              //render/animate
              if (chart.animate) {
                  me.onAnimate(marker, {
                      to: marker._to
                  });
              }
              else {
                  marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
              }
          }
      },
  
      isItemInPoint: function(x, y, item) {
          var point,
              tolerance = 10,
              abs = Math.abs;
          point = item.point;
          return (abs(point[0] - x) <= tolerance &&
                  abs(point[1] - y) <= tolerance);
      },
  
      // @private callback for when creating a label sprite.
      onCreateLabel: function(storeItem, item) {
          var me = this,
              group = me.labelsGroup,
              config = me.label,
              centerX = me.centerX,
              centerY = me.centerY;
  
          return me.getSurface().add(Ext.apply({
              'type': 'text',
              'text-anchor': 'middle',
              'group': group,
              'x': centerX,
              'y': centerY
          }, config || {}));
      },
  
      // @private callback for when placing a label sprite.
      onPlaceLabel: function(label, storeItem, item, i, display, animate) {
          var me = this,
              chart = me.chart,
              resizing = chart.resizing,
              config = me.label,
              format = config.renderer,
              field = config.field,
              centerX = me.centerX,
              centerY = me.centerY,
              opt = {
                  x: item.point[0],
                  y: item.point[1]
              };
  
          label.setAttributes({
              text: format(storeItem.get(field)),
              hidden: true
          },
          true);
  
          if (resizing) {
              label.setAttributes({
                  x: centerX,
                  y: centerY
              }, true);
          }
  
          if (animate) {
              label.show(true);
              me.onAnimate(label, {
                  to: opt
              });
          } else {
              label.setAttributes(opt, true);
              label.show(true);
          }
      },
  
      // @private for toggling (show/hide) series.
      toggleAll: function(show) {
          var me = this,
              i, ln, shadow, shadows;
          if (!show) {
              Ext.chart.series.Radar.superclass.hideAll.call(me);
          }
          else {
              Ext.chart.series.Radar.superclass.showAll.call(me);
          }
          if (me.radar) {
              me.radar.setAttributes({
                  hidden: !show
              }, true);
              //hide shadows too
              if (me.radar.shadows) {
                  for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i < ln; i++) {
                      shadow = shadows[i];
                      shadow.setAttributes({
                          hidden: !show
                      }, true);
                  }
              }
          }
      },
  
      // @private hide all elements in the series.
      hideAll: function() {
          this.toggleAll(false);
          this.hideMarkers(0);
      },
  
      // @private show all elements in the series.
      showAll: function() {
          this.toggleAll(true);
      },
  
      // @private hide all markers that belong to `markerGroup`
      hideMarkers: function(index) {
          var me = this,
              count = me.markerGroup && me.markerGroup.getCount() || 0,
              i = index || 0;
          for (; i < count; i++) {
              me.markerGroup.getAt(i).hide(true);
          }
      },
  
      getLegendLabels: function() {
          var label = this.title || this.yField;
          return label ? [label] : [];
      },
  
      reset: function() {
          this.rotation = 0;
          Ext.chart.series.Radar.superclass.reset.call(this);
      }
  
  });
  
  