Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Radar.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-chart-series-Radar'>/**
19 </span> * @class Ext.chart.series.Radar
20  * @extends Ext.chart.series.Series
21  * 
22  * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for 
23  * a constrained number of categories.
24  * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart 
25  * documentation for more information. A typical configuration object for the radar series could be:
26  * 
27  * {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series}  
28  *
29  *     var store = Ext.create('Ext.data.JsonStore', {
30  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
31  *         data: [
32  *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
33  *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
34  *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
35  *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
36  *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
37  *         ]
38  *     });
39  *     
40  *     Ext.create('Ext.chart.Chart', {
41  *         renderTo: Ext.getBody(),
42  *         width: 500,
43  *         height: 300,
44  *         animate: true,
45  *         theme:'Category2',
46  *         store: store,
47  *         axes: [{
48  *             type: 'Radial',
49  *             position: 'radial',
50  *             label: {
51  *                 display: true
52  *             }
53  *         }],
54  *         series: [{
55  *             type: 'radar',
56  *             xField: 'name',
57  *             yField: 'data3',
58  *             showInLegend: true,
59  *             showMarkers: true,
60  *             markerConfig: {
61  *                 radius: 5,
62  *                 size: 5           
63  *             },
64  *             style: {
65  *                 'stroke-width': 2,
66  *                 fill: 'none'
67  *             }
68  *         },{
69  *             type: 'radar',
70  *             xField: 'name',
71  *             yField: 'data2',
72  *             showMarkers: true,
73  *             showInLegend: true,
74  *             markerConfig: {
75  *                 radius: 5,
76  *                 size: 5
77  *             },
78  *             style: {
79  *                 'stroke-width': 2,
80  *                 fill: 'none'
81  *             }
82  *         },{
83  *             type: 'radar',
84  *             xField: 'name',
85  *             yField: 'data5',
86  *             showMarkers: true,
87  *             showInLegend: true,
88  *             markerConfig: {
89  *                 radius: 5,
90  *                 size: 5
91  *             },
92  *             style: {
93  *                 'stroke-width': 2,
94  *                 fill: 'none'
95  *             }
96  *         }]    
97  *     });
98  * 
99  * 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,
100  * `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 
101  * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object.
102  * 
103  * @xtype radar
104  */
105 Ext.define('Ext.chart.series.Radar', {
106
107     /* Begin Definitions */
108
109     extend: 'Ext.chart.series.Series',
110
111     requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
112
113     /* End Definitions */
114
115     type: &quot;radar&quot;,
116     alias: 'series.radar',
117
118     
119     rad: Math.PI / 180,
120
121     showInLegend: false,
122
123 <span id='Ext-chart-series-Radar-cfg-style'>    /**
124 </span>     * @cfg {Object} style
125      * An object containing styles for overriding series styles from Theming.
126      */
127     style: {},
128     
129     constructor: function(config) {
130         this.callParent(arguments);
131         var me = this,
132             surface = me.chart.surface, i, l;
133         me.group = surface.getGroup(me.seriesId);
134         if (me.showMarkers) {
135             me.markerGroup = surface.getGroup(me.seriesId + '-markers');
136         }
137     },
138
139 <span id='Ext-chart-series-Radar-method-drawSeries'>    /**
140 </span>     * Draws the series for the current chart.
141      */
142     drawSeries: function() {
143         var me = this,
144             store = me.chart.substore || me.chart.store,
145             group = me.group,
146             sprite,
147             chart = me.chart,
148             animate = chart.animate,
149             field = me.field || me.yField,
150             surface = chart.surface,
151             chartBBox = chart.chartBBox,
152             rendererAttributes,
153             centerX, centerY,
154             items,
155             radius,
156             maxValue = 0,
157             fields = [],
158             max = Math.max,
159             cos = Math.cos,
160             sin = Math.sin,
161             pi2 = Math.PI * 2,
162             l = store.getCount(),
163             startPath, path, x, y, rho,
164             i, nfields,
165             seriesStyle = me.seriesStyle,
166             seriesLabelStyle = me.seriesLabelStyle,
167             first = chart.resizing || !me.radar,
168             axis = chart.axes &amp;&amp; chart.axes.get(0),
169             aggregate = !(axis &amp;&amp; axis.maximum);
170         
171         me.setBBox();
172
173         maxValue = aggregate? 0 : (axis.maximum || 0);
174         
175         Ext.apply(seriesStyle, me.style || {});
176         
177         //if the store is empty then there's nothing to draw
178         if (!store || !store.getCount()) {
179             return;
180         }
181         
182         me.unHighlightItem();
183         me.cleanHighlights();
184
185         centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
186         centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
187         me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
188         me.items = items = [];
189
190         if (aggregate) {
191             //get all renderer fields
192             chart.series.each(function(series) {
193                 fields.push(series.yField);
194             });
195             //get maxValue to interpolate
196             store.each(function(record, i) {
197                 for (i = 0, nfields = fields.length; i &lt; nfields; i++) {
198                     maxValue = max(+record.get(fields[i]), maxValue);
199                 }
200             });
201         }
202         //ensure non-zero value.
203         maxValue = maxValue || 1;
204         //create path and items
205         startPath = []; path = [];
206         store.each(function(record, i) {
207             rho = radius * record.get(field) / maxValue;
208             x = rho * cos(i / l * pi2);
209             y = rho * sin(i / l * pi2);
210             if (i == 0) {
211                 path.push('M', x + centerX, y + centerY);
212                 startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
213             } else {
214                 path.push('L', x + centerX, y + centerY);
215                 startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
216             }
217             items.push({
218                 sprite: false, //TODO(nico): add markers
219                 point: [centerX + x, centerY + y],
220                 series: me
221             });
222         });
223         path.push('Z');
224         //create path sprite
225         if (!me.radar) {
226             me.radar = surface.add(Ext.apply({
227                 type: 'path',
228                 group: group,
229                 path: startPath
230             }, seriesStyle || {}));
231         }
232         //reset on resizing
233         if (chart.resizing) {
234             me.radar.setAttributes({
235                 path: startPath
236             }, true);
237         }
238         //render/animate
239         if (chart.animate) {
240             me.onAnimate(me.radar, {
241                 to: Ext.apply({
242                     path: path
243                 }, seriesStyle || {})
244             });
245         } else {
246             me.radar.setAttributes(Ext.apply({
247                 path: path
248             }, seriesStyle || {}), true);
249         }
250         //render markers, labels and callouts
251         if (me.showMarkers) {
252             me.drawMarkers();
253         }
254         me.renderLabels();
255         me.renderCallouts();
256     },
257     
258     // @private draws the markers for the lines (if any).
259     drawMarkers: function() {
260         var me = this,
261             chart = me.chart,
262             surface = chart.surface,
263             markerStyle = Ext.apply({}, me.markerStyle || {}),
264             endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
265             items = me.items, 
266             type = endMarkerStyle.type,
267             markerGroup = me.markerGroup,
268             centerX = me.centerX,
269             centerY = me.centerY,
270             item, i, l, marker;
271         
272         delete endMarkerStyle.type;
273         
274         for (i = 0, l = items.length; i &lt; l; i++) {
275             item = items[i];
276             marker = markerGroup.getAt(i);
277             if (!marker) {
278                 marker = Ext.chart.Shape[type](surface, Ext.apply({
279                     group: markerGroup,
280                     x: 0,
281                     y: 0,
282                     translate: {
283                         x: centerX,
284                         y: centerY
285                     }
286                 }, endMarkerStyle));
287             }
288             else {
289                 marker.show();
290             }
291             if (chart.resizing) {
292                 marker.setAttributes({
293                     x: 0,
294                     y: 0,
295                     translate: {
296                         x: centerX,
297                         y: centerY
298                     }
299                 }, true);
300             }
301             marker._to = {
302                 translate: {
303                     x: item.point[0],
304                     y: item.point[1]
305                 }
306             };
307             //render/animate
308             if (chart.animate) {
309                 me.onAnimate(marker, {
310                     to: marker._to
311                 });
312             }
313             else {
314                 marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
315             }
316         }
317     },
318     
319     isItemInPoint: function(x, y, item) {
320         var point,
321             tolerance = 10,
322             abs = Math.abs;
323         point = item.point;
324         return (abs(point[0] - x) &lt;= tolerance &amp;&amp;
325                 abs(point[1] - y) &lt;= tolerance);
326     },
327
328     // @private callback for when creating a label sprite.
329     onCreateLabel: function(storeItem, item, i, display) {
330         var me = this,
331             group = me.labelsGroup,
332             config = me.label,
333             centerX = me.centerX,
334             centerY = me.centerY,
335             point = item.point,
336             endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
337         
338         return me.chart.surface.add(Ext.apply({
339             'type': 'text',
340             'text-anchor': 'middle',
341             'group': group,
342             'x': centerX,
343             'y': centerY
344         }, config || {}));
345     },
346
347     // @private callback for when placing a label sprite.
348     onPlaceLabel: function(label, storeItem, item, i, display, animate) {
349         var me = this,
350             chart = me.chart,
351             resizing = chart.resizing,
352             config = me.label,
353             format = config.renderer,
354             field = config.field,
355             centerX = me.centerX,
356             centerY = me.centerY,
357             opt = {
358                 x: item.point[0],
359                 y: item.point[1]
360             },
361             x = opt.x - centerX,
362             y = opt.y - centerY;
363
364         label.setAttributes({
365             text: format(storeItem.get(field)),
366             hidden: true
367         },
368         true);
369         
370         if (resizing) {
371             label.setAttributes({
372                 x: centerX,
373                 y: centerY
374             }, true);
375         }
376         
377         if (animate) {
378             label.show(true);
379             me.onAnimate(label, {
380                 to: opt
381             });
382         } else {
383             label.setAttributes(opt, true);
384             label.show(true);
385         }
386     },
387
388     // @private for toggling (show/hide) series. 
389     toggleAll: function(show) {
390         var me = this,
391             i, ln, shadow, shadows;
392         if (!show) {
393             Ext.chart.series.Radar.superclass.hideAll.call(me);
394         }
395         else {
396             Ext.chart.series.Radar.superclass.showAll.call(me);
397         }
398         if (me.radar) {
399             me.radar.setAttributes({
400                 hidden: !show
401             }, true);
402             //hide shadows too
403             if (me.radar.shadows) {
404                 for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i &lt; ln; i++) {
405                     shadow = shadows[i];
406                     shadow.setAttributes({
407                         hidden: !show
408                     }, true);
409                 }
410             }
411         }
412     },
413     
414     // @private hide all elements in the series.
415     hideAll: function() {
416         this.toggleAll(false);
417         this.hideMarkers(0);
418     },
419     
420     // @private show all elements in the series.
421     showAll: function() {
422         this.toggleAll(true);
423     },
424     
425     // @private hide all markers that belong to `markerGroup`
426     hideMarkers: function(index) {
427         var me = this,
428             count = me.markerGroup &amp;&amp; me.markerGroup.getCount() || 0,
429             i = index || 0;
430         for (; i &lt; count; i++) {
431             me.markerGroup.getAt(i).hide(true);
432         }
433     }
434 });
435
436 </pre>
437 </body>
438 </html>