3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.chart.series.Radar
17 * @extends Ext.chart.series.Series
19 * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
20 * a constrained number of categories.
21 * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
22 * documentation for more information. A typical configuration object for the radar series could be:
24 * {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series}
26 * var store = Ext.create('Ext.data.JsonStore', {
27 * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
29 * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
30 * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
31 * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
32 * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
33 * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
37 * Ext.create('Ext.chart.Chart', {
38 * renderTo: Ext.getBody(),
96 * 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,
97 * `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
98 * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object.
102 Ext.define('Ext.chart.series.Radar', {
104 /* Begin Definitions */
106 extend: 'Ext.chart.series.Series',
108 requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
110 /* End Definitions */
113 alias: 'series.radar',
121 * @cfg {Object} style
122 * An object containing styles for overriding series styles from Theming.
126 constructor: function(config) {
127 this.callParent(arguments);
129 surface = me.chart.surface, i, l;
130 me.group = surface.getGroup(me.seriesId);
131 if (me.showMarkers) {
132 me.markerGroup = surface.getGroup(me.seriesId + '-markers');
137 * Draws the series for the current chart.
139 drawSeries: function() {
141 store = me.chart.substore || me.chart.store,
145 animate = chart.animate,
146 field = me.field || me.yField,
147 surface = chart.surface,
148 chartBBox = chart.chartBBox,
159 l = store.getCount(),
160 startPath, path, x, y, rho,
162 seriesStyle = me.seriesStyle,
163 seriesLabelStyle = me.seriesLabelStyle,
164 first = chart.resizing || !me.radar,
165 axis = chart.axes && chart.axes.get(0),
166 aggregate = !(axis && axis.maximum);
170 maxValue = aggregate? 0 : (axis.maximum || 0);
172 Ext.apply(seriesStyle, me.style || {});
174 //if the store is empty then there's nothing to draw
175 if (!store || !store.getCount()) {
179 me.unHighlightItem();
180 me.cleanHighlights();
182 centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
183 centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
184 me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
185 me.items = items = [];
188 //get all renderer fields
189 chart.series.each(function(series) {
190 fields.push(series.yField);
192 //get maxValue to interpolate
193 store.each(function(record, i) {
194 for (i = 0, nfields = fields.length; i < nfields; i++) {
195 maxValue = max(+record.get(fields[i]), maxValue);
199 //ensure non-zero value.
200 maxValue = maxValue || 1;
201 //create path and items
202 startPath = []; path = [];
203 store.each(function(record, i) {
204 rho = radius * record.get(field) / maxValue;
205 x = rho * cos(i / l * pi2);
206 y = rho * sin(i / l * pi2);
208 path.push('M', x + centerX, y + centerY);
209 startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
211 path.push('L', x + centerX, y + centerY);
212 startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
215 sprite: false, //TODO(nico): add markers
216 point: [centerX + x, centerY + y],
223 me.radar = surface.add(Ext.apply({
227 }, seriesStyle || {}));
230 if (chart.resizing) {
231 me.radar.setAttributes({
237 me.onAnimate(me.radar, {
240 }, seriesStyle || {})
243 me.radar.setAttributes(Ext.apply({
245 }, seriesStyle || {}), true);
247 //render markers, labels and callouts
248 if (me.showMarkers) {
255 // @private draws the markers for the lines (if any).
256 drawMarkers: function() {
259 surface = chart.surface,
260 markerStyle = Ext.apply({}, me.markerStyle || {}),
261 endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
263 type = endMarkerStyle.type,
264 markerGroup = me.markerGroup,
265 centerX = me.centerX,
266 centerY = me.centerY,
269 delete endMarkerStyle.type;
271 for (i = 0, l = items.length; i < l; i++) {
273 marker = markerGroup.getAt(i);
275 marker = Ext.chart.Shape[type](surface, Ext.apply({
288 if (chart.resizing) {
289 marker.setAttributes({
306 me.onAnimate(marker, {
311 marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
316 isItemInPoint: function(x, y, item) {
321 return (abs(point[0] - x) <= tolerance &&
322 abs(point[1] - y) <= tolerance);
325 // @private callback for when creating a label sprite.
326 onCreateLabel: function(storeItem, item, i, display) {
328 group = me.labelsGroup,
330 centerX = me.centerX,
331 centerY = me.centerY,
333 endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
335 return me.chart.surface.add(Ext.apply({
337 'text-anchor': 'middle',
344 // @private callback for when placing a label sprite.
345 onPlaceLabel: function(label, storeItem, item, i, display, animate) {
348 resizing = chart.resizing,
350 format = config.renderer,
351 field = config.field,
352 centerX = me.centerX,
353 centerY = me.centerY,
361 label.setAttributes({
362 text: format(storeItem.get(field)),
368 label.setAttributes({
376 me.onAnimate(label, {
380 label.setAttributes(opt, true);
385 // @private for toggling (show/hide) series.
386 toggleAll: function(show) {
388 i, ln, shadow, shadows;
390 Ext.chart.series.Radar.superclass.hideAll.call(me);
393 Ext.chart.series.Radar.superclass.showAll.call(me);
396 me.radar.setAttributes({
400 if (me.radar.shadows) {
401 for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i < ln; i++) {
403 shadow.setAttributes({
411 // @private hide all elements in the series.
412 hideAll: function() {
413 this.toggleAll(false);
417 // @private show all elements in the series.
418 showAll: function() {
419 this.toggleAll(true);
422 // @private hide all markers that belong to `markerGroup`
423 hideMarkers: function(index) {
425 count = me.markerGroup && me.markerGroup.getCount() || 0,
427 for (; i < count; i++) {
428 me.markerGroup.getAt(i).hide(true);