+<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-chart.series.Radar'>/**
+</span> * @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 = Ext.create('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}
+ * ]
+ * });
+ *
+ * Ext.create('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.define('Ext.chart.series.Radar', {
+
+ /* Begin Definitions */
+
+ extend: 'Ext.chart.series.Series',
+
+ requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
+
+ /* End Definitions */
+
+ type: "radar",
+ alias: 'series.radar',
+
+
+ rad: Math.PI / 180,
+
+ showInLegend: false,
+
+<span id='Ext-chart.series.Radar-cfg-style'> /**
+</span> * @cfg {Object} style
+ * An object containing styles for overriding series styles from Theming.
+ */
+ style: {},
+
+ constructor: function(config) {
+ this.callParent(arguments);
+ var me = this,
+ surface = me.chart.surface, i, l;
+ me.group = surface.getGroup(me.seriesId);
+ if (me.showMarkers) {
+ me.markerGroup = surface.getGroup(me.seriesId + '-markers');
+ }
+ },
+
+<span id='Ext-chart.series.Radar-method-drawSeries'> /**
+</span> * Draws the series for the current chart.
+ */
+ drawSeries: function() {
+ var me = this,
+ store = me.chart.substore || me.chart.store,
+ group = me.group,
+ sprite,
+ chart = me.chart,
+ animate = chart.animate,
+ field = me.field || me.yField,
+ surface = chart.surface,
+ chartBBox = chart.chartBBox,
+ rendererAttributes,
+ centerX, centerY,
+ items,
+ radius,
+ maxValue = 0,
+ fields = [],
+ max = Math.max,
+ cos = Math.cos,
+ sin = Math.sin,
+ pi2 = Math.PI * 2,
+ l = store.getCount(),
+ startPath, path, x, y, rho,
+ i, nfields,
+ seriesStyle = me.seriesStyle,
+ seriesLabelStyle = me.seriesLabelStyle,
+ first = chart.resizing || !me.radar,
+ axis = chart.axes && chart.axes.get(0),
+ aggregate = !(axis && axis.maximum);
+
+ me.setBBox();
+
+ maxValue = aggregate? 0 : (axis.maximum || 0);
+
+ Ext.apply(seriesStyle, me.style || {});
+
+ //if the store is empty then there's nothing to draw
+ if (!store || !store.getCount()) {
+ return;
+ }
+
+ me.unHighlightItem();
+ me.cleanHighlights();
+
+ centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
+ centerY = me.centerY = chartBBox.y + (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
+ store.each(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 = [];
+ store.each(function(record, i) {
+ rho = radius * record.get(field) / maxValue;
+ x = rho * cos(i / l * pi2);
+ y = rho * sin(i / l * pi2);
+ 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
+ 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();
+ },
+
+ // @private draws the markers for the lines (if any).
+ drawMarkers: function() {
+ var me = this,
+ chart = me.chart,
+ surface = chart.surface,
+ markerStyle = Ext.apply({}, me.markerStyle || {}),
+ 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, i, display) {
+ var me = this,
+ group = me.labelsGroup,
+ config = me.label,
+ centerX = me.centerX,
+ centerY = me.centerY,
+ point = item.point,
+ endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
+
+ return me.chart.surface.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]
+ },
+ x = opt.x - centerX,
+ y = opt.y - centerY;
+
+ 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);
+ }
+ }
+});
+
+</pre></pre></body></html>
\ No newline at end of file