2 * @class Ext.chart.series.Radar
3 * @extends Ext.chart.series.Series
5 * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
6 * a constrained number of categories.
7 * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
8 * documentation for more information. A typical configuration object for the radar series could be:
10 {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series}
12 var store = Ext.create('Ext.data.JsonStore', {
13 fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
15 {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
16 {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
17 {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
18 {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
19 {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
23 Ext.create('Ext.chart.Chart', {
24 renderTo: Ext.getBody(),
83 * 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,
84 * `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
85 * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object.
90 Ext.define('Ext.chart.series.Radar', {
92 /* Begin Definitions */
94 extend: 'Ext.chart.series.Series',
96 requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
101 alias: 'series.radar',
109 * @cfg {Object} style
110 * An object containing styles for overriding series styles from Theming.
114 constructor: function(config) {
115 this.callParent(arguments);
117 surface = me.chart.surface, i, l;
118 me.group = surface.getGroup(me.seriesId);
119 if (me.showMarkers) {
120 me.markerGroup = surface.getGroup(me.seriesId + '-markers');
125 * Draws the series for the current chart.
127 drawSeries: function() {
129 store = me.chart.substore || me.chart.store,
133 animate = chart.animate,
134 field = me.field || me.yField,
135 surface = chart.surface,
136 chartBBox = chart.chartBBox,
147 l = store.getCount(),
148 startPath, path, x, y, rho,
150 seriesStyle = me.seriesStyle,
151 seriesLabelStyle = me.seriesLabelStyle,
152 first = chart.resizing || !me.radar,
153 axis = chart.axes && chart.axes.get(0),
154 aggregate = !(axis && axis.maximum);
158 maxValue = aggregate? 0 : (axis.maximum || 0);
160 Ext.apply(seriesStyle, me.style || {});
162 //if the store is empty then there's nothing to draw
163 if (!store || !store.getCount()) {
167 me.unHighlightItem();
168 me.cleanHighlights();
170 centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
171 centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
172 me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
173 me.items = items = [];
176 //get all renderer fields
177 chart.series.each(function(series) {
178 fields.push(series.yField);
180 //get maxValue to interpolate
181 store.each(function(record, i) {
182 for (i = 0, nfields = fields.length; i < nfields; i++) {
183 maxValue = max(+record.get(fields[i]), maxValue);
187 //ensure non-zero value.
188 maxValue = maxValue || 1;
189 //create path and items
190 startPath = []; path = [];
191 store.each(function(record, i) {
192 rho = radius * record.get(field) / maxValue;
193 x = rho * cos(i / l * pi2);
194 y = rho * sin(i / l * pi2);
196 path.push('M', x + centerX, y + centerY);
197 startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
199 path.push('L', x + centerX, y + centerY);
200 startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
203 sprite: false, //TODO(nico): add markers
204 point: [centerX + x, centerY + y],
211 me.radar = surface.add(Ext.apply({
215 }, seriesStyle || {}));
218 if (chart.resizing) {
219 me.radar.setAttributes({
225 me.onAnimate(me.radar, {
228 }, seriesStyle || {})
231 me.radar.setAttributes(Ext.apply({
233 }, seriesStyle || {}), true);
235 //render markers, labels and callouts
236 if (me.showMarkers) {
243 // @private draws the markers for the lines (if any).
244 drawMarkers: function() {
247 surface = chart.surface,
248 markerStyle = Ext.apply({}, me.markerStyle || {}),
249 endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
251 type = endMarkerStyle.type,
252 markerGroup = me.markerGroup,
253 centerX = me.centerX,
254 centerY = me.centerY,
257 delete endMarkerStyle.type;
259 for (i = 0, l = items.length; i < l; i++) {
261 marker = markerGroup.getAt(i);
263 marker = Ext.chart.Shape[type](surface, Ext.apply({
276 if (chart.resizing) {
277 marker.setAttributes({
294 me.onAnimate(marker, {
299 marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
304 isItemInPoint: function(x, y, item) {
309 return (abs(point[0] - x) <= tolerance &&
310 abs(point[1] - y) <= tolerance);
313 // @private callback for when creating a label sprite.
314 onCreateLabel: function(storeItem, item, i, display) {
316 group = me.labelsGroup,
318 centerX = me.centerX,
319 centerY = me.centerY,
321 endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
323 return me.chart.surface.add(Ext.apply({
325 'text-anchor': 'middle',
332 // @private callback for when placing a label sprite.
333 onPlaceLabel: function(label, storeItem, item, i, display, animate) {
336 resizing = chart.resizing,
338 format = config.renderer,
339 field = config.field,
340 centerX = me.centerX,
341 centerY = me.centerY,
349 label.setAttributes({
350 text: format(storeItem.get(field)),
356 label.setAttributes({
364 me.onAnimate(label, {
368 label.setAttributes(opt, true);
373 // @private for toggling (show/hide) series.
374 toggleAll: function(show) {
376 i, ln, shadow, shadows;
378 Ext.chart.series.Radar.superclass.hideAll.call(me);
381 Ext.chart.series.Radar.superclass.showAll.call(me);
384 me.radar.setAttributes({
388 if (me.radar.shadows) {
389 for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i < ln; i++) {
391 shadow.setAttributes({
399 // @private hide all elements in the series.
400 hideAll: function() {
401 this.toggleAll(false);
405 // @private show all elements in the series.
406 showAll: function() {
407 this.toggleAll(true);
410 // @private hide all markers that belong to `markerGroup`
411 hideMarkers: function(index) {
413 count = me.markerGroup && me.markerGroup.getCount() || 0,
415 for (; i < count; i++) {
416 me.markerGroup.getAt(i).hide(true);