/** * @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: *

        series: [{
            type: 'radar',
            xField: 'name',
            yField: 'data1',
            showMarkers: true,
            markerCfg: {
                radius: 5,
                size: 5
            },
            style: {
                'stroke-width': 2,
                fill: 'none'
            }
        },{
            type: 'radar',
            xField: 'name',
            yField: 'data2',
            showMarkers: true,
            markerCfg: {
                radius: 5,
                size: 5
            },
            style: {
                'stroke-width': 2,
                fill: 'none'
            }
        },{
            type: 'radar',
            xField: 'name',
            yField: 'data3',
            showMarkers: true,
            markerCfg: {
                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 markerCfg 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.Shapes', 'Ext.fx.Anim'], /* End Definitions */ type: "pie", rad: Math.PI / 180, showInLegend: false,
/** * @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'); } },
/** * 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; Ext.apply(seriesStyle, me.style || {}); 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 = []; //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); } }); //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] }); }); 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.markerCfg), items = me.items, type = endMarkerStyle.type, markerGroup = me.markerGroup, centerX = me.centerX, centerY = me.centerY, item, i, l; delete endMarkerStyle.type; for (i = 0, l = items.length; i < l; i++) { item = items[i]; marker = markerGroup.getAt(i); if (!marker) { marker = Ext.chart.Shapes[type](surface, Ext.apply({ group: markerGroup, x: 0, y: 0, translate: { x: centerX, y: centerY } }, endMarkerStyle)); } else { marker.setAttributes({ x: 0, y: 0, hidden: false }, true); } 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); } } }, // @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); } } });