Upgrade to ExtJS 4.0.7 - Released 10/19/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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/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  *
25  * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
26  * documentation for more information. A typical configuration object for the radar series could be:
27  *
28  *     @example
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
100  * categories field, `name` but bound to different properties for each category, `data1`, `data2` and
101  * `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration
102  * for the markers of each series can be set by adding properties onto the markerConfig object.
103  * Finally we override some theme styling properties by adding properties to the `style` object.
104  *
105  * @xtype radar
106  */
107 Ext.define('Ext.chart.series.Radar', {
108
109     /* Begin Definitions */
110
111     extend: 'Ext.chart.series.Series',
112
113     requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
114
115     /* End Definitions */
116
117     type: &quot;radar&quot;,
118     alias: 'series.radar',
119
120
121     rad: Math.PI / 180,
122
123     showInLegend: false,
124
125 <span id='Ext-chart-series-Radar-cfg-style'>    /**
126 </span>     * @cfg {Object} style
127      * An object containing styles for overriding series styles from Theming.
128      */
129     style: {},
130
131     constructor: function(config) {
132         this.callParent(arguments);
133         var me = this,
134             surface = me.chart.surface, i, l;
135         me.group = surface.getGroup(me.seriesId);
136         if (me.showMarkers) {
137             me.markerGroup = surface.getGroup(me.seriesId + '-markers');
138         }
139     },
140
141 <span id='Ext-chart-series-Radar-method-drawSeries'>    /**
142 </span>     * Draws the series for the current chart.
143      */
144     drawSeries: function() {
145         var me = this,
146             store = me.chart.getChartStore(),
147             group = me.group,
148             sprite,
149             chart = me.chart,
150             animate = chart.animate,
151             field = me.field || me.yField,
152             surface = chart.surface,
153             chartBBox = chart.chartBBox,
154             rendererAttributes,
155             centerX, centerY,
156             items,
157             radius,
158             maxValue = 0,
159             fields = [],
160             max = Math.max,
161             cos = Math.cos,
162             sin = Math.sin,
163             pi2 = Math.PI * 2,
164             l = store.getCount(),
165             startPath, path, x, y, rho,
166             i, nfields,
167             seriesStyle = me.seriesStyle,
168             seriesLabelStyle = me.seriesLabelStyle,
169             first = chart.resizing || !me.radar,
170             axis = chart.axes &amp;&amp; chart.axes.get(0),
171             aggregate = !(axis &amp;&amp; axis.maximum);
172
173         me.setBBox();
174
175         maxValue = aggregate? 0 : (axis.maximum || 0);
176
177         Ext.apply(seriesStyle, me.style || {});
178
179         //if the store is empty then there's nothing to draw
180         if (!store || !store.getCount()) {
181             return;
182         }
183
184         me.unHighlightItem();
185         me.cleanHighlights();
186
187         centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
188         centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
189         me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
190         me.items = items = [];
191
192         if (aggregate) {
193             //get all renderer fields
194             chart.series.each(function(series) {
195                 fields.push(series.yField);
196             });
197             //get maxValue to interpolate
198             store.each(function(record, i) {
199                 for (i = 0, nfields = fields.length; i &lt; nfields; i++) {
200                     maxValue = max(+record.get(fields[i]), maxValue);
201                 }
202             });
203         }
204         //ensure non-zero value.
205         maxValue = maxValue || 1;
206         //create path and items
207         startPath = []; path = [];
208         store.each(function(record, i) {
209             rho = radius * record.get(field) / maxValue;
210             x = rho * cos(i / l * pi2);
211             y = rho * sin(i / l * pi2);
212             if (i == 0) {
213                 path.push('M', x + centerX, y + centerY);
214                 startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
215             } else {
216                 path.push('L', x + centerX, y + centerY);
217                 startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
218             }
219             items.push({
220                 sprite: false, //TODO(nico): add markers
221                 point: [centerX + x, centerY + y],
222                 series: me
223             });
224         });
225         path.push('Z');
226         //create path sprite
227         if (!me.radar) {
228             me.radar = surface.add(Ext.apply({
229                 type: 'path',
230                 group: group,
231                 path: startPath
232             }, seriesStyle || {}));
233         }
234         //reset on resizing
235         if (chart.resizing) {
236             me.radar.setAttributes({
237                 path: startPath
238             }, true);
239         }
240         //render/animate
241         if (chart.animate) {
242             me.onAnimate(me.radar, {
243                 to: Ext.apply({
244                     path: path
245                 }, seriesStyle || {})
246             });
247         } else {
248             me.radar.setAttributes(Ext.apply({
249                 path: path
250             }, seriesStyle || {}), true);
251         }
252         //render markers, labels and callouts
253         if (me.showMarkers) {
254             me.drawMarkers();
255         }
256         me.renderLabels();
257         me.renderCallouts();
258     },
259
260     // @private draws the markers for the lines (if any).
261     drawMarkers: function() {
262         var me = this,
263             chart = me.chart,
264             surface = chart.surface,
265             markerStyle = Ext.apply({}, me.markerStyle || {}),
266             endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
267             items = me.items,
268             type = endMarkerStyle.type,
269             markerGroup = me.markerGroup,
270             centerX = me.centerX,
271             centerY = me.centerY,
272             item, i, l, marker;
273
274         delete endMarkerStyle.type;
275
276         for (i = 0, l = items.length; i &lt; l; i++) {
277             item = items[i];
278             marker = markerGroup.getAt(i);
279             if (!marker) {
280                 marker = Ext.chart.Shape[type](surface, Ext.apply({
281                     group: markerGroup,
282                     x: 0,
283                     y: 0,
284                     translate: {
285                         x: centerX,
286                         y: centerY
287                     }
288                 }, endMarkerStyle));
289             }
290             else {
291                 marker.show();
292             }
293             if (chart.resizing) {
294                 marker.setAttributes({
295                     x: 0,
296                     y: 0,
297                     translate: {
298                         x: centerX,
299                         y: centerY
300                     }
301                 }, true);
302             }
303             marker._to = {
304                 translate: {
305                     x: item.point[0],
306                     y: item.point[1]
307                 }
308             };
309             //render/animate
310             if (chart.animate) {
311                 me.onAnimate(marker, {
312                     to: marker._to
313                 });
314             }
315             else {
316                 marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
317             }
318         }
319     },
320
321     isItemInPoint: function(x, y, item) {
322         var point,
323             tolerance = 10,
324             abs = Math.abs;
325         point = item.point;
326         return (abs(point[0] - x) &lt;= tolerance &amp;&amp;
327                 abs(point[1] - y) &lt;= tolerance);
328     },
329
330     // @private callback for when creating a label sprite.
331     onCreateLabel: function(storeItem, item, i, display) {
332         var me = this,
333             group = me.labelsGroup,
334             config = me.label,
335             centerX = me.centerX,
336             centerY = me.centerY,
337             point = item.point,
338             endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
339
340         return me.chart.surface.add(Ext.apply({
341             'type': 'text',
342             'text-anchor': 'middle',
343             'group': group,
344             'x': centerX,
345             'y': centerY
346         }, config || {}));
347     },
348
349     // @private callback for when placing a label sprite.
350     onPlaceLabel: function(label, storeItem, item, i, display, animate) {
351         var me = this,
352             chart = me.chart,
353             resizing = chart.resizing,
354             config = me.label,
355             format = config.renderer,
356             field = config.field,
357             centerX = me.centerX,
358             centerY = me.centerY,
359             opt = {
360                 x: item.point[0],
361                 y: item.point[1]
362             },
363             x = opt.x - centerX,
364             y = opt.y - centerY;
365
366         label.setAttributes({
367             text: format(storeItem.get(field)),
368             hidden: true
369         },
370         true);
371
372         if (resizing) {
373             label.setAttributes({
374                 x: centerX,
375                 y: centerY
376             }, true);
377         }
378
379         if (animate) {
380             label.show(true);
381             me.onAnimate(label, {
382                 to: opt
383             });
384         } else {
385             label.setAttributes(opt, true);
386             label.show(true);
387         }
388     },
389
390     // @private for toggling (show/hide) series.
391     toggleAll: function(show) {
392         var me = this,
393             i, ln, shadow, shadows;
394         if (!show) {
395             Ext.chart.series.Radar.superclass.hideAll.call(me);
396         }
397         else {
398             Ext.chart.series.Radar.superclass.showAll.call(me);
399         }
400         if (me.radar) {
401             me.radar.setAttributes({
402                 hidden: !show
403             }, true);
404             //hide shadows too
405             if (me.radar.shadows) {
406                 for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i &lt; ln; i++) {
407                     shadow = shadows[i];
408                     shadow.setAttributes({
409                         hidden: !show
410                     }, true);
411                 }
412             }
413         }
414     },
415
416     // @private hide all elements in the series.
417     hideAll: function() {
418         this.toggleAll(false);
419         this.hideMarkers(0);
420     },
421
422     // @private show all elements in the series.
423     showAll: function() {
424         this.toggleAll(true);
425     },
426
427     // @private hide all markers that belong to `markerGroup`
428     hideMarkers: function(index) {
429         var me = this,
430             count = me.markerGroup &amp;&amp; me.markerGroup.getCount() || 0,
431             i = index || 0;
432         for (; i &lt; count; i++) {
433             me.markerGroup.getAt(i).hide(true);
434         }
435     }
436 });
437
438 </pre>
439 </body>
440 </html>