Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Area.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-Area'>/**
19 </span> * @class Ext.chart.series.Area
20  * @extends Ext.chart.series.Cartesian
21  *
22  * Creates a Stacked Area Chart. The stacked area chart is useful when displaying multiple aggregated layers of information.
23  * As with all other series, the Area Series must be appended in the *series* Chart array configuration. See the Chart
24  * documentation for more information. A typical configuration object for the area series could be:
25  *
26  *     @example
27  *     var store = Ext.create('Ext.data.JsonStore', {
28  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
29  *         data: [
30  *             { 'name': 'metric one',   'data1':10, 'data2':12, 'data3':14, 'data4':8,  'data5':13 },
31  *             { 'name': 'metric two',   'data1':7,  'data2':8,  'data3':16, 'data4':10, 'data5':3  },
32  *             { 'name': 'metric three', 'data1':5,  'data2':2,  'data3':14, 'data4':12, 'data5':7  },
33  *             { 'name': 'metric four',  'data1':2,  'data2':14, 'data3':6,  'data4':1,  'data5':23 },
34  *             { 'name': 'metric five',  'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33 }
35  *         ]
36  *     });
37  *
38  *     Ext.create('Ext.chart.Chart', {
39  *         renderTo: Ext.getBody(),
40  *         width: 500,
41  *         height: 300,
42  *         store: store,
43  *         axes: [
44  *             {
45  *                 type: 'Numeric',
46  *                 grid: true,
47  *                 position: 'left',
48  *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
49  *                 title: 'Sample Values',
50  *                 grid: {
51  *                     odd: {
52  *                         opacity: 1,
53  *                         fill: '#ddd',
54  *                         stroke: '#bbb',
55  *                         'stroke-width': 1
56  *                     }
57  *                 },
58  *                 minimum: 0,
59  *                 adjustMinimumByMajorUnit: 0
60  *             },
61  *             {
62  *                 type: 'Category',
63  *                 position: 'bottom',
64  *                 fields: ['name'],
65  *                 title: 'Sample Metrics',
66  *                 grid: true,
67  *                 label: {
68  *                     rotate: {
69  *                         degrees: 315
70  *                     }
71  *                 }
72  *             }
73  *         ],
74  *         series: [{
75  *             type: 'area',
76  *             highlight: false,
77  *             axis: 'left',
78  *             xField: 'name',
79  *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
80  *             style: {
81  *                 opacity: 0.93
82  *             }
83  *         }]
84  *     });
85  *
86  * In this configuration we set `area` as the type for the series, set highlighting options to true for highlighting elements on hover,
87  * take the left axis to measure the data in the area series, set as xField (x values) the name field of each element in the store,
88  * and as yFields (aggregated layers) seven data fields from the same store. Then we override some theming styles by adding some opacity
89  * to the style object.
90  *
91  * @xtype area
92  */
93 Ext.define('Ext.chart.series.Area', {
94
95     /* Begin Definitions */
96
97     extend: 'Ext.chart.series.Cartesian',
98
99     alias: 'series.area',
100
101     requires: ['Ext.chart.axis.Axis', 'Ext.draw.Color', 'Ext.fx.Anim'],
102
103     /* End Definitions */
104
105     type: 'area',
106
107     // @private Area charts are alyways stacked
108     stacked: true,
109
110 <span id='Ext-chart-series-Area-cfg-style'>    /**
111 </span>     * @cfg {Object} style
112      * Append styling properties to this object for it to override theme properties.
113      */
114     style: {},
115
116     constructor: function(config) {
117         this.callParent(arguments);
118         var me = this,
119             surface = me.chart.surface,
120             i, l;
121         Ext.apply(me, config, {
122             __excludes: [],
123             highlightCfg: {
124                 lineWidth: 3,
125                 stroke: '#55c',
126                 opacity: 0.8,
127                 color: '#f00'
128             }
129         });
130         if (me.highlight) {
131             me.highlightSprite = surface.add({
132                 type: 'path',
133                 path: ['M', 0, 0],
134                 zIndex: 1000,
135                 opacity: 0.3,
136                 lineWidth: 5,
137                 hidden: true,
138                 stroke: '#444'
139             });
140         }
141         me.group = surface.getGroup(me.seriesId);
142     },
143
144     // @private Shrinks dataSets down to a smaller size
145     shrink: function(xValues, yValues, size) {
146         var len = xValues.length,
147             ratio = Math.floor(len / size),
148             i, j,
149             xSum = 0,
150             yCompLen = this.areas.length,
151             ySum = [],
152             xRes = [],
153             yRes = [];
154         //initialize array
155         for (j = 0; j &lt; yCompLen; ++j) {
156             ySum[j] = 0;
157         }
158         for (i = 0; i &lt; len; ++i) {
159             xSum += xValues[i];
160             for (j = 0; j &lt; yCompLen; ++j) {
161                 ySum[j] += yValues[i][j];
162             }
163             if (i % ratio == 0) {
164                 //push averages
165                 xRes.push(xSum/ratio);
166                 for (j = 0; j &lt; yCompLen; ++j) {
167                     ySum[j] /= ratio;
168                 }
169                 yRes.push(ySum);
170                 //reset sum accumulators
171                 xSum = 0;
172                 for (j = 0, ySum = []; j &lt; yCompLen; ++j) {
173                     ySum[j] = 0;
174                 }
175             }
176         }
177         return {
178             x: xRes,
179             y: yRes
180         };
181     },
182
183     // @private Get chart and data boundaries
184     getBounds: function() {
185         var me = this,
186             chart = me.chart,
187             store = chart.getChartStore(),
188             areas = [].concat(me.yField),
189             areasLen = areas.length,
190             xValues = [],
191             yValues = [],
192             infinity = Infinity,
193             minX = infinity,
194             minY = infinity,
195             maxX = -infinity,
196             maxY = -infinity,
197             math = Math,
198             mmin = math.min,
199             mmax = math.max,
200             bbox, xScale, yScale, xValue, yValue, areaIndex, acumY, ln, sumValues, clipBox, areaElem;
201
202         me.setBBox();
203         bbox = me.bbox;
204
205         // Run through the axis
206         if (me.axis) {
207             axis = chart.axes.get(me.axis);
208             if (axis) {
209                 out = axis.calcEnds();
210                 minY = out.from || axis.prevMin;
211                 maxY = mmax(out.to || axis.prevMax, 0);
212             }
213         }
214
215         if (me.yField &amp;&amp; !Ext.isNumber(minY)) {
216             axis = Ext.create('Ext.chart.axis.Axis', {
217                 chart: chart,
218                 fields: [].concat(me.yField)
219             });
220             out = axis.calcEnds();
221             minY = out.from || axis.prevMin;
222             maxY = mmax(out.to || axis.prevMax, 0);
223         }
224
225         if (!Ext.isNumber(minY)) {
226             minY = 0;
227         }
228         if (!Ext.isNumber(maxY)) {
229             maxY = 0;
230         }
231
232         store.each(function(record, i) {
233             xValue = record.get(me.xField);
234             yValue = [];
235             if (typeof xValue != 'number') {
236                 xValue = i;
237             }
238             xValues.push(xValue);
239             acumY = 0;
240             for (areaIndex = 0; areaIndex &lt; areasLen; areaIndex++) {
241                 areaElem = record.get(areas[areaIndex]);
242                 if (typeof areaElem == 'number') {
243                     minY = mmin(minY, areaElem);
244                     yValue.push(areaElem);
245                     acumY += areaElem;
246                 }
247             }
248             minX = mmin(minX, xValue);
249             maxX = mmax(maxX, xValue);
250             maxY = mmax(maxY, acumY);
251             yValues.push(yValue);
252         }, me);
253
254         xScale = bbox.width / ((maxX - minX) || 1);
255         yScale = bbox.height / ((maxY - minY) || 1);
256
257         ln = xValues.length;
258         if ((ln &gt; bbox.width) &amp;&amp; me.areas) {
259             sumValues = me.shrink(xValues, yValues, bbox.width);
260             xValues = sumValues.x;
261             yValues = sumValues.y;
262         }
263
264         return {
265             bbox: bbox,
266             minX: minX,
267             minY: minY,
268             xValues: xValues,
269             yValues: yValues,
270             xScale: xScale,
271             yScale: yScale,
272             areasLen: areasLen
273         };
274     },
275
276     // @private Build an array of paths for the chart
277     getPaths: function() {
278         var me = this,
279             chart = me.chart,
280             store = chart.getChartStore(),
281             first = true,
282             bounds = me.getBounds(),
283             bbox = bounds.bbox,
284             items = me.items = [],
285             componentPaths = [],
286             componentPath,
287             paths = [],
288             i, ln, x, y, xValue, yValue, acumY, areaIndex, prevAreaIndex, areaElem, path;
289
290         ln = bounds.xValues.length;
291         // Start the path
292         for (i = 0; i &lt; ln; i++) {
293             xValue = bounds.xValues[i];
294             yValue = bounds.yValues[i];
295             x = bbox.x + (xValue - bounds.minX) * bounds.xScale;
296             acumY = 0;
297             for (areaIndex = 0; areaIndex &lt; bounds.areasLen; areaIndex++) {
298                 // Excluded series
299                 if (me.__excludes[areaIndex]) {
300                     continue;
301                 }
302                 if (!componentPaths[areaIndex]) {
303                     componentPaths[areaIndex] = [];
304                 }
305                 areaElem = yValue[areaIndex];
306                 acumY += areaElem;
307                 y = bbox.y + bbox.height - (acumY - bounds.minY) * bounds.yScale;
308                 if (!paths[areaIndex]) {
309                     paths[areaIndex] = ['M', x, y];
310                     componentPaths[areaIndex].push(['L', x, y]);
311                 } else {
312                     paths[areaIndex].push('L', x, y);
313                     componentPaths[areaIndex].push(['L', x, y]);
314                 }
315                 if (!items[areaIndex]) {
316                     items[areaIndex] = {
317                         pointsUp: [],
318                         pointsDown: [],
319                         series: me
320                     };
321                 }
322                 items[areaIndex].pointsUp.push([x, y]);
323             }
324         }
325
326         // Close the paths
327         for (areaIndex = 0; areaIndex &lt; bounds.areasLen; areaIndex++) {
328             // Excluded series
329             if (me.__excludes[areaIndex]) {
330                 continue;
331             }
332             path = paths[areaIndex];
333             // Close bottom path to the axis
334             if (areaIndex == 0 || first) {
335                 first = false;
336                 path.push('L', x, bbox.y + bbox.height,
337                           'L', bbox.x, bbox.y + bbox.height,
338                           'Z');
339             }
340             // Close other paths to the one before them
341             else {
342                 componentPath = componentPaths[prevAreaIndex];
343                 componentPath.reverse();
344                 path.push('L', x, componentPath[0][2]);
345                 for (i = 0; i &lt; ln; i++) {
346                     path.push(componentPath[i][0],
347                               componentPath[i][1],
348                               componentPath[i][2]);
349                     items[areaIndex].pointsDown[ln -i -1] = [componentPath[i][1], componentPath[i][2]];
350                 }
351                 path.push('L', bbox.x, path[2], 'Z');
352             }
353             prevAreaIndex = areaIndex;
354         }
355         return {
356             paths: paths,
357             areasLen: bounds.areasLen
358         };
359     },
360
361 <span id='Ext-chart-series-Area-method-drawSeries'>    /**
362 </span>     * Draws the series for the current chart.
363      */
364     drawSeries: function() {
365         var me = this,
366             chart = me.chart,
367             store = chart.getChartStore(),
368             surface = chart.surface,
369             animate = chart.animate,
370             group = me.group,
371             endLineStyle = Ext.apply(me.seriesStyle, me.style),
372             colorArrayStyle = me.colorArrayStyle,
373             colorArrayLength = colorArrayStyle &amp;&amp; colorArrayStyle.length || 0,
374             areaIndex, areaElem, paths, path, rendererAttributes;
375
376         me.unHighlightItem();
377         me.cleanHighlights();
378
379         if (!store || !store.getCount()) {
380             return;
381         }
382
383         paths = me.getPaths();
384
385         if (!me.areas) {
386             me.areas = [];
387         }
388
389         for (areaIndex = 0; areaIndex &lt; paths.areasLen; areaIndex++) {
390             // Excluded series
391             if (me.__excludes[areaIndex]) {
392                 continue;
393             }
394             if (!me.areas[areaIndex]) {
395                 me.items[areaIndex].sprite = me.areas[areaIndex] = surface.add(Ext.apply({}, {
396                     type: 'path',
397                     group: group,
398                     // 'clip-rect': me.clipBox,
399                     path: paths.paths[areaIndex],
400                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength],
401                     fill: colorArrayStyle[areaIndex % colorArrayLength]
402                 }, endLineStyle || {}));
403             }
404             areaElem = me.areas[areaIndex];
405             path = paths.paths[areaIndex];
406             if (animate) {
407                 //Add renderer to line. There is not a unique record associated with this.
408                 rendererAttributes = me.renderer(areaElem, false, {
409                     path: path,
410                     // 'clip-rect': me.clipBox,
411                     fill: colorArrayStyle[areaIndex % colorArrayLength],
412                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
413                 }, areaIndex, store);
414                 //fill should not be used here but when drawing the special fill path object
415                 me.animation = me.onAnimate(areaElem, {
416                     to: rendererAttributes
417                 });
418             } else {
419                 rendererAttributes = me.renderer(areaElem, false, {
420                     path: path,
421                     // 'clip-rect': me.clipBox,
422                     hidden: false,
423                     fill: colorArrayStyle[areaIndex % colorArrayLength],
424                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
425                 }, areaIndex, store);
426                 me.areas[areaIndex].setAttributes(rendererAttributes, true);
427             }
428         }
429         me.renderLabels();
430         me.renderCallouts();
431     },
432
433     // @private
434     onAnimate: function(sprite, attr) {
435         sprite.show();
436         return this.callParent(arguments);
437     },
438
439     // @private
440     onCreateLabel: function(storeItem, item, i, display) {
441         var me = this,
442             group = me.labelsGroup,
443             config = me.label,
444             bbox = me.bbox,
445             endLabelStyle = Ext.apply(config, me.seriesLabelStyle);
446
447         return me.chart.surface.add(Ext.apply({
448             'type': 'text',
449             'text-anchor': 'middle',
450             'group': group,
451             'x': item.point[0],
452             'y': bbox.y + bbox.height / 2
453         }, endLabelStyle || {}));
454     },
455
456     // @private
457     onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
458         var me = this,
459             chart = me.chart,
460             resizing = chart.resizing,
461             config = me.label,
462             format = config.renderer,
463             field = config.field,
464             bbox = me.bbox,
465             x = item.point[0],
466             y = item.point[1],
467             bb, width, height;
468
469         label.setAttributes({
470             text: format(storeItem.get(field[index])),
471             hidden: true
472         }, true);
473
474         bb = label.getBBox();
475         width = bb.width / 2;
476         height = bb.height / 2;
477
478         x = x - width &lt; bbox.x? bbox.x + width : x;
479         x = (x + width &gt; bbox.x + bbox.width) ? (x - (x + width - bbox.x - bbox.width)) : x;
480         y = y - height &lt; bbox.y? bbox.y + height : y;
481         y = (y + height &gt; bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
482
483         if (me.chart.animate &amp;&amp; !me.chart.resizing) {
484             label.show(true);
485             me.onAnimate(label, {
486                 to: {
487                     x: x,
488                     y: y
489                 }
490             });
491         } else {
492             label.setAttributes({
493                 x: x,
494                 y: y
495             }, true);
496             if (resizing) {
497                 me.animation.on('afteranimate', function() {
498                     label.show(true);
499                 });
500             } else {
501                 label.show(true);
502             }
503         }
504     },
505
506     // @private
507     onPlaceCallout : function(callout, storeItem, item, i, display, animate, index) {
508         var me = this,
509             chart = me.chart,
510             surface = chart.surface,
511             resizing = chart.resizing,
512             config = me.callouts,
513             items = me.items,
514             prev = (i == 0) ? false : items[i -1].point,
515             next = (i == items.length -1) ? false : items[i +1].point,
516             cur = item.point,
517             dir, norm, normal, a, aprev, anext,
518             bbox = callout.label.getBBox(),
519             offsetFromViz = 30,
520             offsetToSide = 10,
521             offsetBox = 3,
522             boxx, boxy, boxw, boxh,
523             p, clipRect = me.clipRect,
524             x, y;
525
526         //get the right two points
527         if (!prev) {
528             prev = cur;
529         }
530         if (!next) {
531             next = cur;
532         }
533         a = (next[1] - prev[1]) / (next[0] - prev[0]);
534         aprev = (cur[1] - prev[1]) / (cur[0] - prev[0]);
535         anext = (next[1] - cur[1]) / (next[0] - cur[0]);
536
537         norm = Math.sqrt(1 + a * a);
538         dir = [1 / norm, a / norm];
539         normal = [-dir[1], dir[0]];
540
541         //keep the label always on the outer part of the &quot;elbow&quot;
542         if (aprev &gt; 0 &amp;&amp; anext &lt; 0 &amp;&amp; normal[1] &lt; 0 || aprev &lt; 0 &amp;&amp; anext &gt; 0 &amp;&amp; normal[1] &gt; 0) {
543             normal[0] *= -1;
544             normal[1] *= -1;
545         } else if (Math.abs(aprev) &lt; Math.abs(anext) &amp;&amp; normal[0] &lt; 0 || Math.abs(aprev) &gt; Math.abs(anext) &amp;&amp; normal[0] &gt; 0) {
546             normal[0] *= -1;
547             normal[1] *= -1;
548         }
549
550         //position
551         x = cur[0] + normal[0] * offsetFromViz;
552         y = cur[1] + normal[1] * offsetFromViz;
553
554         //box position and dimensions
555         boxx = x + (normal[0] &gt; 0? 0 : -(bbox.width + 2 * offsetBox));
556         boxy = y - bbox.height /2 - offsetBox;
557         boxw = bbox.width + 2 * offsetBox;
558         boxh = bbox.height + 2 * offsetBox;
559
560         //now check if we're out of bounds and invert the normal vector correspondingly
561         //this may add new overlaps between labels (but labels won't be out of bounds).
562         if (boxx &lt; clipRect[0] || (boxx + boxw) &gt; (clipRect[0] + clipRect[2])) {
563             normal[0] *= -1;
564         }
565         if (boxy &lt; clipRect[1] || (boxy + boxh) &gt; (clipRect[1] + clipRect[3])) {
566             normal[1] *= -1;
567         }
568
569         //update positions
570         x = cur[0] + normal[0] * offsetFromViz;
571         y = cur[1] + normal[1] * offsetFromViz;
572
573         //update box position and dimensions
574         boxx = x + (normal[0] &gt; 0? 0 : -(bbox.width + 2 * offsetBox));
575         boxy = y - bbox.height /2 - offsetBox;
576         boxw = bbox.width + 2 * offsetBox;
577         boxh = bbox.height + 2 * offsetBox;
578
579         //set the line from the middle of the pie to the box.
580         callout.lines.setAttributes({
581             path: [&quot;M&quot;, cur[0], cur[1], &quot;L&quot;, x, y, &quot;Z&quot;]
582         }, true);
583         //set box position
584         callout.box.setAttributes({
585             x: boxx,
586             y: boxy,
587             width: boxw,
588             height: boxh
589         }, true);
590         //set text position
591         callout.label.setAttributes({
592             x: x + (normal[0] &gt; 0? offsetBox : -(bbox.width + offsetBox)),
593             y: y
594         }, true);
595         for (p in callout) {
596             callout[p].show(true);
597         }
598     },
599
600     isItemInPoint: function(x, y, item, i) {
601         var me = this,
602             pointsUp = item.pointsUp,
603             pointsDown = item.pointsDown,
604             abs = Math.abs,
605             dist = Infinity, p, pln, point;
606
607         for (p = 0, pln = pointsUp.length; p &lt; pln; p++) {
608             point = [pointsUp[p][0], pointsUp[p][1]];
609             if (dist &gt; abs(x - point[0])) {
610                 dist = abs(x - point[0]);
611             } else {
612                 point = pointsUp[p -1];
613                 if (y &gt;= point[1] &amp;&amp; (!pointsDown.length || y &lt;= (pointsDown[p -1][1]))) {
614                     item.storeIndex = p -1;
615                     item.storeField = me.yField[i];
616                     item.storeItem = me.chart.store.getAt(p -1);
617                     item._points = pointsDown.length? [point, pointsDown[p -1]] : [point];
618                     return true;
619                 } else {
620                     break;
621                 }
622             }
623         }
624         return false;
625     },
626
627 <span id='Ext-chart-series-Area-method-highlightSeries'>    /**
628 </span>     * Highlight this entire series.
629      * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
630      */
631     highlightSeries: function() {
632         var area, to, fillColor;
633         if (this._index !== undefined) {
634             area = this.areas[this._index];
635             if (area.__highlightAnim) {
636                 area.__highlightAnim.paused = true;
637             }
638             area.__highlighted = true;
639             area.__prevOpacity = area.__prevOpacity || area.attr.opacity || 1;
640             area.__prevFill = area.__prevFill || area.attr.fill;
641             area.__prevLineWidth = area.__prevLineWidth || area.attr.lineWidth;
642             fillColor = Ext.draw.Color.fromString(area.__prevFill);
643             to = {
644                 lineWidth: (area.__prevLineWidth || 0) + 2
645             };
646             if (fillColor) {
647                 to.fill = fillColor.getLighter(0.2).toString();
648             }
649             else {
650                 to.opacity = Math.max(area.__prevOpacity - 0.3, 0);
651             }
652             if (this.chart.animate) {
653                 area.__highlightAnim = Ext.create('Ext.fx.Anim', Ext.apply({
654                     target: area,
655                     to: to
656                 }, this.chart.animate));
657             }
658             else {
659                 area.setAttributes(to, true);
660             }
661         }
662     },
663
664 <span id='Ext-chart-series-Area-method-unHighlightSeries'>    /**
665 </span>     * UnHighlight this entire series.
666      * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
667      */
668     unHighlightSeries: function() {
669         var area;
670         if (this._index !== undefined) {
671             area = this.areas[this._index];
672             if (area.__highlightAnim) {
673                 area.__highlightAnim.paused = true;
674             }
675             if (area.__highlighted) {
676                 area.__highlighted = false;
677                 area.__highlightAnim = Ext.create('Ext.fx.Anim', {
678                     target: area,
679                     to: {
680                         fill: area.__prevFill,
681                         opacity: area.__prevOpacity,
682                         lineWidth: area.__prevLineWidth
683                     }
684                 });
685             }
686         }
687     },
688
689 <span id='Ext-chart-series-Area-method-highlightItem'>    /**
690 </span>     * Highlight the specified item. If no item is provided the whole series will be highlighted.
691      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
692      */
693     highlightItem: function(item) {
694         var me = this,
695             points, path;
696         if (!item) {
697             this.highlightSeries();
698             return;
699         }
700         points = item._points;
701         path = points.length == 2? ['M', points[0][0], points[0][1], 'L', points[1][0], points[1][1]]
702                 : ['M', points[0][0], points[0][1], 'L', points[0][0], me.bbox.y + me.bbox.height];
703         me.highlightSprite.setAttributes({
704             path: path,
705             hidden: false
706         }, true);
707     },
708
709 <span id='Ext-chart-series-Area-method-unHighlightItem'>    /**
710 </span>     * Un-highlights the specified item. If no item is provided it will un-highlight the entire series.
711      * @param {Object} item Info about the item; same format as returned by #getItemForPoint
712      */
713     unHighlightItem: function(item) {
714         if (!item) {
715             this.unHighlightSeries();
716         }
717
718         if (this.highlightSprite) {
719             this.highlightSprite.hide(true);
720         }
721     },
722
723     // @private
724     hideAll: function() {
725         if (!isNaN(this._index)) {
726             this.__excludes[this._index] = true;
727             this.areas[this._index].hide(true);
728             this.drawSeries();
729         }
730     },
731
732     // @private
733     showAll: function() {
734         if (!isNaN(this._index)) {
735             this.__excludes[this._index] = false;
736             this.areas[this._index].show(true);
737             this.drawSeries();
738         }
739     },
740
741 <span id='Ext-chart-series-Area-method-getLegendColor'>    /**
742 </span>     * Returns the color of the series (to be displayed as color for the series legend item).
743      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
744      */
745     getLegendColor: function(index) {
746         var me = this;
747         return me.colorArrayStyle[index % me.colorArrayStyle.length];
748     }
749 });
750 <span id='Ext-chart-series-Area'>/**
751 </span> * @class Ext.chart.series.Area
752  * @extends Ext.chart.series.Cartesian
753  *
754  * Creates a Stacked Area Chart. The stacked area chart is useful when displaying multiple aggregated layers of information.
755  * As with all other series, the Area Series must be appended in the *series* Chart array configuration. See the Chart
756  * documentation for more information. A typical configuration object for the area series could be:
757  *
758  *     @example
759  *     var store = Ext.create('Ext.data.JsonStore', {
760  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
761  *         data: [
762  *             { 'name': 'metric one',   'data1':10, 'data2':12, 'data3':14, 'data4':8,  'data5':13 },
763  *             { 'name': 'metric two',   'data1':7,  'data2':8,  'data3':16, 'data4':10, 'data5':3  },
764  *             { 'name': 'metric three', 'data1':5,  'data2':2,  'data3':14, 'data4':12, 'data5':7  },
765  *             { 'name': 'metric four',  'data1':2,  'data2':14, 'data3':6,  'data4':1,  'data5':23 },
766  *             { 'name': 'metric five',  'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33 }
767  *         ]
768  *     });
769  *
770  *     Ext.create('Ext.chart.Chart', {
771  *         renderTo: Ext.getBody(),
772  *         width: 500,
773  *         height: 300,
774  *         store: store,
775  *         axes: [
776  *             {
777  *                 type: 'Numeric',
778  *                 grid: true,
779  *                 position: 'left',
780  *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
781  *                 title: 'Sample Values',
782  *                 grid: {
783  *                     odd: {
784  *                         opacity: 1,
785  *                         fill: '#ddd',
786  *                         stroke: '#bbb',
787  *                         'stroke-width': 1
788  *                     }
789  *                 },
790  *                 minimum: 0,
791  *                 adjustMinimumByMajorUnit: 0
792  *             },
793  *             {
794  *                 type: 'Category',
795  *                 position: 'bottom',
796  *                 fields: ['name'],
797  *                 title: 'Sample Metrics',
798  *                 grid: true,
799  *                 label: {
800  *                     rotate: {
801  *                         degrees: 315
802  *                     }
803  *                 }
804  *             }
805  *         ],
806  *         series: [{
807  *             type: 'area',
808  *             highlight: false,
809  *             axis: 'left',
810  *             xField: 'name',
811  *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
812  *             style: {
813  *                 opacity: 0.93
814  *             }
815  *         }]
816  *     });
817  *
818  * In this configuration we set `area` as the type for the series, set highlighting options to true for highlighting elements on hover,
819  * take the left axis to measure the data in the area series, set as xField (x values) the name field of each element in the store,
820  * and as yFields (aggregated layers) seven data fields from the same store. Then we override some theming styles by adding some opacity
821  * to the style object.
822  *
823  * @xtype area
824  */
825 Ext.define('Ext.chart.series.Area', {
826
827     /* Begin Definitions */
828
829     extend: 'Ext.chart.series.Cartesian',
830
831     alias: 'series.area',
832
833     requires: ['Ext.chart.axis.Axis', 'Ext.draw.Color', 'Ext.fx.Anim'],
834
835     /* End Definitions */
836
837     type: 'area',
838
839     // @private Area charts are alyways stacked
840     stacked: true,
841
842 <span id='Ext-chart-series-Area-cfg-style'>    /**
843 </span>     * @cfg {Object} style
844      * Append styling properties to this object for it to override theme properties.
845      */
846     style: {},
847
848     constructor: function(config) {
849         this.callParent(arguments);
850         var me = this,
851             surface = me.chart.surface,
852             i, l;
853         Ext.apply(me, config, {
854             __excludes: [],
855             highlightCfg: {
856                 lineWidth: 3,
857                 stroke: '#55c',
858                 opacity: 0.8,
859                 color: '#f00'
860             }
861         });
862         if (me.highlight) {
863             me.highlightSprite = surface.add({
864                 type: 'path',
865                 path: ['M', 0, 0],
866                 zIndex: 1000,
867                 opacity: 0.3,
868                 lineWidth: 5,
869                 hidden: true,
870                 stroke: '#444'
871             });
872         }
873         me.group = surface.getGroup(me.seriesId);
874     },
875
876     // @private Shrinks dataSets down to a smaller size
877     shrink: function(xValues, yValues, size) {
878         var len = xValues.length,
879             ratio = Math.floor(len / size),
880             i, j,
881             xSum = 0,
882             yCompLen = this.areas.length,
883             ySum = [],
884             xRes = [],
885             yRes = [];
886         //initialize array
887         for (j = 0; j &lt; yCompLen; ++j) {
888             ySum[j] = 0;
889         }
890         for (i = 0; i &lt; len; ++i) {
891             xSum += xValues[i];
892             for (j = 0; j &lt; yCompLen; ++j) {
893                 ySum[j] += yValues[i][j];
894             }
895             if (i % ratio == 0) {
896                 //push averages
897                 xRes.push(xSum/ratio);
898                 for (j = 0; j &lt; yCompLen; ++j) {
899                     ySum[j] /= ratio;
900                 }
901                 yRes.push(ySum);
902                 //reset sum accumulators
903                 xSum = 0;
904                 for (j = 0, ySum = []; j &lt; yCompLen; ++j) {
905                     ySum[j] = 0;
906                 }
907             }
908         }
909         return {
910             x: xRes,
911             y: yRes
912         };
913     },
914
915     // @private Get chart and data boundaries
916     getBounds: function() {
917         var me = this,
918             chart = me.chart,
919             store = chart.getChartStore(),
920             areas = [].concat(me.yField),
921             areasLen = areas.length,
922             xValues = [],
923             yValues = [],
924             infinity = Infinity,
925             minX = infinity,
926             minY = infinity,
927             maxX = -infinity,
928             maxY = -infinity,
929             math = Math,
930             mmin = math.min,
931             mmax = math.max,
932             bbox, xScale, yScale, xValue, yValue, areaIndex, acumY, ln, sumValues, clipBox, areaElem;
933
934         me.setBBox();
935         bbox = me.bbox;
936
937         // Run through the axis
938         if (me.axis) {
939             axis = chart.axes.get(me.axis);
940             if (axis) {
941                 out = axis.calcEnds();
942                 minY = out.from || axis.prevMin;
943                 maxY = mmax(out.to || axis.prevMax, 0);
944             }
945         }
946
947         if (me.yField &amp;&amp; !Ext.isNumber(minY)) {
948             axis = Ext.create('Ext.chart.axis.Axis', {
949                 chart: chart,
950                 fields: [].concat(me.yField)
951             });
952             out = axis.calcEnds();
953             minY = out.from || axis.prevMin;
954             maxY = mmax(out.to || axis.prevMax, 0);
955         }
956
957         if (!Ext.isNumber(minY)) {
958             minY = 0;
959         }
960         if (!Ext.isNumber(maxY)) {
961             maxY = 0;
962         }
963
964         store.each(function(record, i) {
965             xValue = record.get(me.xField);
966             yValue = [];
967             if (typeof xValue != 'number') {
968                 xValue = i;
969             }
970             xValues.push(xValue);
971             acumY = 0;
972             for (areaIndex = 0; areaIndex &lt; areasLen; areaIndex++) {
973                 areaElem = record.get(areas[areaIndex]);
974                 if (typeof areaElem == 'number') {
975                     minY = mmin(minY, areaElem);
976                     yValue.push(areaElem);
977                     acumY += areaElem;
978                 }
979             }
980             minX = mmin(minX, xValue);
981             maxX = mmax(maxX, xValue);
982             maxY = mmax(maxY, acumY);
983             yValues.push(yValue);
984         }, me);
985
986         xScale = bbox.width / ((maxX - minX) || 1);
987         yScale = bbox.height / ((maxY - minY) || 1);
988
989         ln = xValues.length;
990         if ((ln &gt; bbox.width) &amp;&amp; me.areas) {
991             sumValues = me.shrink(xValues, yValues, bbox.width);
992             xValues = sumValues.x;
993             yValues = sumValues.y;
994         }
995
996         return {
997             bbox: bbox,
998             minX: minX,
999             minY: minY,
1000             xValues: xValues,
1001             yValues: yValues,
1002             xScale: xScale,
1003             yScale: yScale,
1004             areasLen: areasLen
1005         };
1006     },
1007
1008     // @private Build an array of paths for the chart
1009     getPaths: function() {
1010         var me = this,
1011             chart = me.chart,
1012             store = chart.getChartStore(),
1013             first = true,
1014             bounds = me.getBounds(),
1015             bbox = bounds.bbox,
1016             items = me.items = [],
1017             componentPaths = [],
1018             componentPath,
1019             paths = [],
1020             i, ln, x, y, xValue, yValue, acumY, areaIndex, prevAreaIndex, areaElem, path;
1021
1022         ln = bounds.xValues.length;
1023         // Start the path
1024         for (i = 0; i &lt; ln; i++) {
1025             xValue = bounds.xValues[i];
1026             yValue = bounds.yValues[i];
1027             x = bbox.x + (xValue - bounds.minX) * bounds.xScale;
1028             acumY = 0;
1029             for (areaIndex = 0; areaIndex &lt; bounds.areasLen; areaIndex++) {
1030                 // Excluded series
1031                 if (me.__excludes[areaIndex]) {
1032                     continue;
1033                 }
1034                 if (!componentPaths[areaIndex]) {
1035                     componentPaths[areaIndex] = [];
1036                 }
1037                 areaElem = yValue[areaIndex];
1038                 acumY += areaElem;
1039                 y = bbox.y + bbox.height - (acumY - bounds.minY) * bounds.yScale;
1040                 if (!paths[areaIndex]) {
1041                     paths[areaIndex] = ['M', x, y];
1042                     componentPaths[areaIndex].push(['L', x, y]);
1043                 } else {
1044                     paths[areaIndex].push('L', x, y);
1045                     componentPaths[areaIndex].push(['L', x, y]);
1046                 }
1047                 if (!items[areaIndex]) {
1048                     items[areaIndex] = {
1049                         pointsUp: [],
1050                         pointsDown: [],
1051                         series: me
1052                     };
1053                 }
1054                 items[areaIndex].pointsUp.push([x, y]);
1055             }
1056         }
1057
1058         // Close the paths
1059         for (areaIndex = 0; areaIndex &lt; bounds.areasLen; areaIndex++) {
1060             // Excluded series
1061             if (me.__excludes[areaIndex]) {
1062                 continue;
1063             }
1064             path = paths[areaIndex];
1065             // Close bottom path to the axis
1066             if (areaIndex == 0 || first) {
1067                 first = false;
1068                 path.push('L', x, bbox.y + bbox.height,
1069                           'L', bbox.x, bbox.y + bbox.height,
1070                           'Z');
1071             }
1072             // Close other paths to the one before them
1073             else {
1074                 componentPath = componentPaths[prevAreaIndex];
1075                 componentPath.reverse();
1076                 path.push('L', x, componentPath[0][2]);
1077                 for (i = 0; i &lt; ln; i++) {
1078                     path.push(componentPath[i][0],
1079                               componentPath[i][1],
1080                               componentPath[i][2]);
1081                     items[areaIndex].pointsDown[ln -i -1] = [componentPath[i][1], componentPath[i][2]];
1082                 }
1083                 path.push('L', bbox.x, path[2], 'Z');
1084             }
1085             prevAreaIndex = areaIndex;
1086         }
1087         return {
1088             paths: paths,
1089             areasLen: bounds.areasLen
1090         };
1091     },
1092
1093 <span id='Ext-chart-series-Area-method-drawSeries'>    /**
1094 </span>     * Draws the series for the current chart.
1095      */
1096     drawSeries: function() {
1097         var me = this,
1098             chart = me.chart,
1099             store = chart.getChartStore(),
1100             surface = chart.surface,
1101             animate = chart.animate,
1102             group = me.group,
1103             endLineStyle = Ext.apply(me.seriesStyle, me.style),
1104             colorArrayStyle = me.colorArrayStyle,
1105             colorArrayLength = colorArrayStyle &amp;&amp; colorArrayStyle.length || 0,
1106             areaIndex, areaElem, paths, path, rendererAttributes;
1107
1108         me.unHighlightItem();
1109         me.cleanHighlights();
1110
1111         if (!store || !store.getCount()) {
1112             return;
1113         }
1114
1115         paths = me.getPaths();
1116
1117         if (!me.areas) {
1118             me.areas = [];
1119         }
1120
1121         for (areaIndex = 0; areaIndex &lt; paths.areasLen; areaIndex++) {
1122             // Excluded series
1123             if (me.__excludes[areaIndex]) {
1124                 continue;
1125             }
1126             if (!me.areas[areaIndex]) {
1127                 me.items[areaIndex].sprite = me.areas[areaIndex] = surface.add(Ext.apply({}, {
1128                     type: 'path',
1129                     group: group,
1130                     // 'clip-rect': me.clipBox,
1131                     path: paths.paths[areaIndex],
1132                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength],
1133                     fill: colorArrayStyle[areaIndex % colorArrayLength]
1134                 }, endLineStyle || {}));
1135             }
1136             areaElem = me.areas[areaIndex];
1137             path = paths.paths[areaIndex];
1138             if (animate) {
1139                 //Add renderer to line. There is not a unique record associated with this.
1140                 rendererAttributes = me.renderer(areaElem, false, {
1141                     path: path,
1142                     // 'clip-rect': me.clipBox,
1143                     fill: colorArrayStyle[areaIndex % colorArrayLength],
1144                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
1145                 }, areaIndex, store);
1146                 //fill should not be used here but when drawing the special fill path object
1147                 me.animation = me.onAnimate(areaElem, {
1148                     to: rendererAttributes
1149                 });
1150             } else {
1151                 rendererAttributes = me.renderer(areaElem, false, {
1152                     path: path,
1153                     // 'clip-rect': me.clipBox,
1154                     hidden: false,
1155                     fill: colorArrayStyle[areaIndex % colorArrayLength],
1156                     stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
1157                 }, areaIndex, store);
1158                 me.areas[areaIndex].setAttributes(rendererAttributes, true);
1159             }
1160         }
1161         me.renderLabels();
1162         me.renderCallouts();
1163     },
1164
1165     // @private
1166     onAnimate: function(sprite, attr) {
1167         sprite.show();
1168         return this.callParent(arguments);
1169     },
1170
1171     // @private
1172     onCreateLabel: function(storeItem, item, i, display) {
1173         var me = this,
1174             group = me.labelsGroup,
1175             config = me.label,
1176             bbox = me.bbox,
1177             endLabelStyle = Ext.apply(config, me.seriesLabelStyle);
1178
1179         return me.chart.surface.add(Ext.apply({
1180             'type': 'text',
1181             'text-anchor': 'middle',
1182             'group': group,
1183             'x': item.point[0],
1184             'y': bbox.y + bbox.height / 2
1185         }, endLabelStyle || {}));
1186     },
1187
1188     // @private
1189     onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
1190         var me = this,
1191             chart = me.chart,
1192             resizing = chart.resizing,
1193             config = me.label,
1194             format = config.renderer,
1195             field = config.field,
1196             bbox = me.bbox,
1197             x = item.point[0],
1198             y = item.point[1],
1199             bb, width, height;
1200
1201         label.setAttributes({
1202             text: format(storeItem.get(field[index])),
1203             hidden: true
1204         }, true);
1205
1206         bb = label.getBBox();
1207         width = bb.width / 2;
1208         height = bb.height / 2;
1209
1210         x = x - width &lt; bbox.x? bbox.x + width : x;
1211         x = (x + width &gt; bbox.x + bbox.width) ? (x - (x + width - bbox.x - bbox.width)) : x;
1212         y = y - height &lt; bbox.y? bbox.y + height : y;
1213         y = (y + height &gt; bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
1214
1215         if (me.chart.animate &amp;&amp; !me.chart.resizing) {
1216             label.show(true);
1217             me.onAnimate(label, {
1218                 to: {
1219                     x: x,
1220                     y: y
1221                 }
1222             });
1223         } else {
1224             label.setAttributes({
1225                 x: x,
1226                 y: y
1227             }, true);
1228             if (resizing) {
1229                 me.animation.on('afteranimate', function() {
1230                     label.show(true);
1231                 });
1232             } else {
1233                 label.show(true);
1234             }
1235         }
1236     },
1237
1238     // @private
1239     onPlaceCallout : function(callout, storeItem, item, i, display, animate, index) {
1240         var me = this,
1241             chart = me.chart,
1242             surface = chart.surface,
1243             resizing = chart.resizing,
1244             config = me.callouts,
1245             items = me.items,
1246             prev = (i == 0) ? false : items[i -1].point,
1247             next = (i == items.length -1) ? false : items[i +1].point,
1248             cur = item.point,
1249             dir, norm, normal, a, aprev, anext,
1250             bbox = callout.label.getBBox(),
1251             offsetFromViz = 30,
1252             offsetToSide = 10,
1253             offsetBox = 3,
1254             boxx, boxy, boxw, boxh,
1255             p, clipRect = me.clipRect,
1256             x, y;
1257
1258         //get the right two points
1259         if (!prev) {
1260             prev = cur;
1261         }
1262         if (!next) {
1263             next = cur;
1264         }
1265         a = (next[1] - prev[1]) / (next[0] - prev[0]);
1266         aprev = (cur[1] - prev[1]) / (cur[0] - prev[0]);
1267         anext = (next[1] - cur[1]) / (next[0] - cur[0]);
1268
1269         norm = Math.sqrt(1 + a * a);
1270         dir = [1 / norm, a / norm];
1271         normal = [-dir[1], dir[0]];
1272
1273         //keep the label always on the outer part of the &quot;elbow&quot;
1274         if (aprev &gt; 0 &amp;&amp; anext &lt; 0 &amp;&amp; normal[1] &lt; 0 || aprev &lt; 0 &amp;&amp; anext &gt; 0 &amp;&amp; normal[1] &gt; 0) {
1275             normal[0] *= -1;
1276             normal[1] *= -1;
1277         } else if (Math.abs(aprev) &lt; Math.abs(anext) &amp;&amp; normal[0] &lt; 0 || Math.abs(aprev) &gt; Math.abs(anext) &amp;&amp; normal[0] &gt; 0) {
1278             normal[0] *= -1;
1279             normal[1] *= -1;
1280         }
1281
1282         //position
1283         x = cur[0] + normal[0] * offsetFromViz;
1284         y = cur[1] + normal[1] * offsetFromViz;
1285
1286         //box position and dimensions
1287         boxx = x + (normal[0] &gt; 0? 0 : -(bbox.width + 2 * offsetBox));
1288         boxy = y - bbox.height /2 - offsetBox;
1289         boxw = bbox.width + 2 * offsetBox;
1290         boxh = bbox.height + 2 * offsetBox;
1291
1292         //now check if we're out of bounds and invert the normal vector correspondingly
1293         //this may add new overlaps between labels (but labels won't be out of bounds).
1294         if (boxx &lt; clipRect[0] || (boxx + boxw) &gt; (clipRect[0] + clipRect[2])) {
1295             normal[0] *= -1;
1296         }
1297         if (boxy &lt; clipRect[1] || (boxy + boxh) &gt; (clipRect[1] + clipRect[3])) {
1298             normal[1] *= -1;
1299         }
1300
1301         //update positions
1302         x = cur[0] + normal[0] * offsetFromViz;
1303         y = cur[1] + normal[1] * offsetFromViz;
1304
1305         //update box position and dimensions
1306         boxx = x + (normal[0] &gt; 0? 0 : -(bbox.width + 2 * offsetBox));
1307         boxy = y - bbox.height /2 - offsetBox;
1308         boxw = bbox.width + 2 * offsetBox;
1309         boxh = bbox.height + 2 * offsetBox;
1310
1311         //set the line from the middle of the pie to the box.
1312         callout.lines.setAttributes({
1313             path: [&quot;M&quot;, cur[0], cur[1], &quot;L&quot;, x, y, &quot;Z&quot;]
1314         }, true);
1315         //set box position
1316         callout.box.setAttributes({
1317             x: boxx,
1318             y: boxy,
1319             width: boxw,
1320             height: boxh
1321         }, true);
1322         //set text position
1323         callout.label.setAttributes({
1324             x: x + (normal[0] &gt; 0? offsetBox : -(bbox.width + offsetBox)),
1325             y: y
1326         }, true);
1327         for (p in callout) {
1328             callout[p].show(true);
1329         }
1330     },
1331
1332     isItemInPoint: function(x, y, item, i) {
1333         var me = this,
1334             pointsUp = item.pointsUp,
1335             pointsDown = item.pointsDown,
1336             abs = Math.abs,
1337             dist = Infinity, p, pln, point;
1338
1339         for (p = 0, pln = pointsUp.length; p &lt; pln; p++) {
1340             point = [pointsUp[p][0], pointsUp[p][1]];
1341             if (dist &gt; abs(x - point[0])) {
1342                 dist = abs(x - point[0]);
1343             } else {
1344                 point = pointsUp[p -1];
1345                 if (y &gt;= point[1] &amp;&amp; (!pointsDown.length || y &lt;= (pointsDown[p -1][1]))) {
1346                     item.storeIndex = p -1;
1347                     item.storeField = me.yField[i];
1348                     item.storeItem = me.chart.store.getAt(p -1);
1349                     item._points = pointsDown.length? [point, pointsDown[p -1]] : [point];
1350                     return true;
1351                 } else {
1352                     break;
1353                 }
1354             }
1355         }
1356         return false;
1357     },
1358
1359 <span id='Ext-chart-series-Area-method-highlightSeries'>    /**
1360 </span>     * Highlight this entire series.
1361      * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
1362      */
1363     highlightSeries: function() {
1364         var area, to, fillColor;
1365         if (this._index !== undefined) {
1366             area = this.areas[this._index];
1367             if (area.__highlightAnim) {
1368                 area.__highlightAnim.paused = true;
1369             }
1370             area.__highlighted = true;
1371             area.__prevOpacity = area.__prevOpacity || area.attr.opacity || 1;
1372             area.__prevFill = area.__prevFill || area.attr.fill;
1373             area.__prevLineWidth = area.__prevLineWidth || area.attr.lineWidth;
1374             fillColor = Ext.draw.Color.fromString(area.__prevFill);
1375             to = {
1376                 lineWidth: (area.__prevLineWidth || 0) + 2
1377             };
1378             if (fillColor) {
1379                 to.fill = fillColor.getLighter(0.2).toString();
1380             }
1381             else {
1382                 to.opacity = Math.max(area.__prevOpacity - 0.3, 0);
1383             }
1384             if (this.chart.animate) {
1385                 area.__highlightAnim = Ext.create('Ext.fx.Anim', Ext.apply({
1386                     target: area,
1387                     to: to
1388                 }, this.chart.animate));
1389             }
1390             else {
1391                 area.setAttributes(to, true);
1392             }
1393         }
1394     },
1395
1396 <span id='Ext-chart-series-Area-method-unHighlightSeries'>    /**
1397 </span>     * UnHighlight this entire series.
1398      * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
1399      */
1400     unHighlightSeries: function() {
1401         var area;
1402         if (this._index !== undefined) {
1403             area = this.areas[this._index];
1404             if (area.__highlightAnim) {
1405                 area.__highlightAnim.paused = true;
1406             }
1407             if (area.__highlighted) {
1408                 area.__highlighted = false;
1409                 area.__highlightAnim = Ext.create('Ext.fx.Anim', {
1410                     target: area,
1411                     to: {
1412                         fill: area.__prevFill,
1413                         opacity: area.__prevOpacity,
1414                         lineWidth: area.__prevLineWidth
1415                     }
1416                 });
1417             }
1418         }
1419     },
1420
1421 <span id='Ext-chart-series-Area-method-highlightItem'>    /**
1422 </span>     * Highlight the specified item. If no item is provided the whole series will be highlighted.
1423      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
1424      */
1425     highlightItem: function(item) {
1426         var me = this,
1427             points, path;
1428         if (!item) {
1429             this.highlightSeries();
1430             return;
1431         }
1432         points = item._points;
1433         path = points.length == 2? ['M', points[0][0], points[0][1], 'L', points[1][0], points[1][1]]
1434                 : ['M', points[0][0], points[0][1], 'L', points[0][0], me.bbox.y + me.bbox.height];
1435         me.highlightSprite.setAttributes({
1436             path: path,
1437             hidden: false
1438         }, true);
1439     },
1440
1441 <span id='Ext-chart-series-Area-method-unHighlightItem'>    /**
1442 </span>     * un-highlights the specified item. If no item is provided it will un-highlight the entire series.
1443      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
1444      */
1445     unHighlightItem: function(item) {
1446         if (!item) {
1447             this.unHighlightSeries();
1448         }
1449
1450         if (this.highlightSprite) {
1451             this.highlightSprite.hide(true);
1452         }
1453     },
1454
1455     // @private
1456     hideAll: function() {
1457         if (!isNaN(this._index)) {
1458             this.__excludes[this._index] = true;
1459             this.areas[this._index].hide(true);
1460             this.drawSeries();
1461         }
1462     },
1463
1464     // @private
1465     showAll: function() {
1466         if (!isNaN(this._index)) {
1467             this.__excludes[this._index] = false;
1468             this.areas[this._index].show(true);
1469             this.drawSeries();
1470         }
1471     },
1472
1473 <span id='Ext-chart-series-Area-method-getLegendColor'>    /**
1474 </span>     * Returns the color of the series (to be displayed as color for the series legend item).
1475      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
1476      */
1477     getLegendColor: function(index) {
1478         var me = this;
1479         return me.colorArrayStyle[index % me.colorArrayStyle.length];
1480     }
1481 });
1482 </pre>
1483 </body>
1484 </html>