Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Axis.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-chart.axis.Axis'>/**
2 </span> * @class Ext.chart.axis.Axis
3  * @extends Ext.chart.axis.Abstract
4  * 
5  * Defines axis for charts. The axis position, type, style can be configured.
6  * The axes are defined in an axes array of configuration objects where the type, 
7  * field, grid and other configuration options can be set. To know more about how 
8  * to create a Chart please check the Chart class documentation. Here's an example for the axes part:
9  * An example of axis for a series (in this case for an area chart that has multiple layers of yFields) could be:
10  * 
11  *     axes: [{
12  *         type: 'Numeric',
13  *         grid: true,
14  *         position: 'left',
15  *         fields: ['data1', 'data2', 'data3'],
16  *         title: 'Number of Hits',
17  *         grid: {
18  *             odd: {
19  *                 opacity: 1,
20  *                 fill: '#ddd',
21  *                 stroke: '#bbb',
22  *                 'stroke-width': 1
23  *             }
24  *         },
25  *         minimum: 0
26  *     }, {
27  *         type: 'Category',
28  *         position: 'bottom',
29  *         fields: ['name'],
30  *         title: 'Month of the Year',
31  *         grid: true,
32  *         label: {
33  *             rotate: {
34  *                 degrees: 315
35  *             }
36  *         }
37  *     }]
38  * 
39  * In this case we use a `Numeric` axis for displaying the values of the Area series and a `Category` axis for displaying the names of
40  * the store elements. The numeric axis is placed on the left of the screen, while the category axis is placed at the bottom of the chart. 
41  * Both the category and numeric axes have `grid` set, which means that horizontal and vertical lines will cover the chart background. In the 
42  * category axis the labels will be rotated so they can fit the space better.
43  */
44 Ext.define('Ext.chart.axis.Axis', {
45
46     /* Begin Definitions */
47
48     extend: 'Ext.chart.axis.Abstract',
49
50     alternateClassName: 'Ext.chart.Axis',
51
52     requires: ['Ext.draw.Draw'],
53
54     /* End Definitions */
55
56 <span id='Ext-chart.axis.Axis-cfg-majorTickSteps'>    /**
57 </span>     * @cfg {Number} majorTickSteps 
58      * If `minimum` and `maximum` are specified it forces the number of major ticks to the specified value.
59      */
60
61 <span id='Ext-chart.axis.Axis-cfg-minorTickSteps'>    /**
62 </span>     * @cfg {Number} minorTickSteps 
63      * The number of small ticks between two major ticks. Default is zero.
64      */
65
66 <span id='Ext-chart.axis.Axis-cfg-dashSize'>    /**
67 </span>     * @cfg {Number} dashSize 
68      * The size of the dash marker. Default's 3.
69      */
70     dashSize: 3,
71     
72 <span id='Ext-chart.axis.Axis-cfg-position'>    /**
73 </span>     * @cfg {String} position
74      * Where to set the axis. Available options are `left`, `bottom`, `right`, `top`. Default's `bottom`.
75      */
76     position: 'bottom',
77     
78     // @private
79     skipFirst: false,
80     
81 <span id='Ext-chart.axis.Axis-cfg-length'>    /**
82 </span>     * @cfg {Number} length
83      * Offset axis position. Default's 0.
84      */
85     length: 0,
86     
87 <span id='Ext-chart.axis.Axis-cfg-width'>    /**
88 </span>     * @cfg {Number} width
89      * Offset axis width. Default's 0.
90      */
91     width: 0,
92     
93     majorTickSteps: false,
94
95     // @private
96     applyData: Ext.emptyFn,
97
98     // @private creates a structure with start, end and step points.
99     calcEnds: function() {
100         var me = this,
101             math = Math,
102             mmax = math.max,
103             mmin = math.min,
104             store = me.chart.substore || me.chart.store,
105             series = me.chart.series.items,
106             fields = me.fields,
107             ln = fields.length,
108             min = isNaN(me.minimum) ? Infinity : me.minimum,
109             max = isNaN(me.maximum) ? -Infinity : me.maximum,
110             prevMin = me.prevMin,
111             prevMax = me.prevMax,
112             aggregate = false,
113             total = 0,
114             excludes = [],
115             outfrom, outto,
116             i, l, values, rec, out;
117
118         //if one series is stacked I have to aggregate the values
119         //for the scale.
120         for (i = 0, l = series.length; !aggregate &amp;&amp; i &lt; l; i++) {
121             aggregate = aggregate || series[i].stacked;
122             excludes = series[i].__excludes || excludes;
123         }
124         store.each(function(record) {
125             if (aggregate) {
126                 if (!isFinite(min)) {
127                     min = 0;
128                 }
129                 for (values = [0, 0], i = 0; i &lt; ln; i++) {
130                     if (excludes[i]) {
131                         continue;
132                     }
133                     rec = record.get(fields[i]);
134                     values[+(rec &gt; 0)] += math.abs(rec);
135                 }
136                 max = mmax(max, -values[0], values[1]);
137                 min = mmin(min, -values[0], values[1]);
138             }
139             else {
140                 for (i = 0; i &lt; ln; i++) {
141                     if (excludes[i]) {
142                         continue;
143                     }
144                     value = record.get(fields[i]);
145                     max = mmax(max, value);
146                     min = mmin(min, value);
147                 }
148             }
149         });
150         if (!isFinite(max)) {
151             max = me.prevMax || 0;
152         }
153         if (!isFinite(min)) {
154             min = me.prevMin || 0;
155         }
156         //normalize min max for snapEnds.
157         if (min != max &amp;&amp; (max != (max &gt;&gt; 0))) {
158             max = (max &gt;&gt; 0) + 1;
159         }
160         out = Ext.draw.Draw.snapEnds(min, max, me.majorTickSteps !== false ?  (me.majorTickSteps +1) : me.steps);
161         outfrom = out.from;
162         outto = out.to;
163         if (!isNaN(me.maximum)) {
164             //TODO(nico) users are responsible for their own minimum/maximum values set.
165             //Clipping should be added to remove lines in the chart which are below the axis.
166             out.to = me.maximum;
167         }
168         if (!isNaN(me.minimum)) {
169             //TODO(nico) users are responsible for their own minimum/maximum values set.
170             //Clipping should be added to remove lines in the chart which are below the axis.
171             out.from = me.minimum;
172         }
173         
174         //Adjust after adjusting minimum and maximum
175         out.step = (out.to - out.from) / (outto - outfrom) * out.step;
176         
177         if (me.adjustMaximumByMajorUnit) {
178             out.to += out.step;
179         }
180         if (me.adjustMinimumByMajorUnit) {
181             out.from -= out.step;
182         }
183         me.prevMin = min == max? 0 : min;
184         me.prevMax = max;
185         return out;
186     },
187
188 <span id='Ext-chart.axis.Axis-method-drawAxis'>    /**
189 </span>     * Renders the axis into the screen and updates it's position.
190      */
191     drawAxis: function (init) {
192         var me = this,
193             i, j,
194             x = me.x,
195             y = me.y,
196             gutterX = me.chart.maxGutter[0],
197             gutterY = me.chart.maxGutter[1],
198             dashSize = me.dashSize,
199             subDashesX = me.minorTickSteps || 0,
200             subDashesY = me.minorTickSteps || 0,
201             length = me.length,
202             position = me.position,
203             inflections = [],
204             calcLabels = false,
205             stepCalcs = me.applyData(),
206             step = stepCalcs.step,
207             steps = stepCalcs.steps,
208             from = stepCalcs.from,
209             to = stepCalcs.to,
210             trueLength,
211             currentX,
212             currentY,
213             path,
214             prev,
215             dashesX,
216             dashesY,
217             delta;
218         
219         //If no steps are specified
220         //then don't draw the axis. This generally happens
221         //when an empty store.
222         if (me.hidden || isNaN(step) || (from == to)) {
223             return;
224         }
225
226         me.from = stepCalcs.from;
227         me.to = stepCalcs.to;
228         if (position == 'left' || position == 'right') {
229             currentX = Math.floor(x) + 0.5;
230             path = [&quot;M&quot;, currentX, y, &quot;l&quot;, 0, -length];
231             trueLength = length - (gutterY * 2);
232         }
233         else {
234             currentY = Math.floor(y) + 0.5;
235             path = [&quot;M&quot;, x, currentY, &quot;l&quot;, length, 0];
236             trueLength = length - (gutterX * 2);
237         }
238         
239         delta = trueLength / (steps || 1);
240         dashesX = Math.max(subDashesX +1, 0);
241         dashesY = Math.max(subDashesY +1, 0);
242         if (me.type == 'Numeric') {
243             calcLabels = true;
244             me.labels = [stepCalcs.from];
245         }
246         if (position == 'right' || position == 'left') {
247             currentY = y - gutterY;
248             currentX = x - ((position == 'left') * dashSize * 2);
249             while (currentY &gt;= y - gutterY - trueLength) {
250                 path.push(&quot;M&quot;, currentX, Math.floor(currentY) + 0.5, &quot;l&quot;, dashSize * 2 + 1, 0);
251                 if (currentY != y - gutterY) {
252                     for (i = 1; i &lt; dashesY; i++) {
253                         path.push(&quot;M&quot;, currentX + dashSize, Math.floor(currentY + delta * i / dashesY) + 0.5, &quot;l&quot;, dashSize + 1, 0);
254                     }
255                 }
256                 inflections.push([ Math.floor(x), Math.floor(currentY) ]);
257                 currentY -= delta;
258                 if (calcLabels) {
259                     me.labels.push(me.labels[me.labels.length -1] + step);
260                 }
261                 if (delta === 0) {
262                     break;
263                 }
264             }
265             if (Math.round(currentY + delta - (y - gutterY - trueLength))) {
266                 path.push(&quot;M&quot;, currentX, Math.floor(y - length + gutterY) + 0.5, &quot;l&quot;, dashSize * 2 + 1, 0);
267                 for (i = 1; i &lt; dashesY; i++) {
268                     path.push(&quot;M&quot;, currentX + dashSize, Math.floor(y - length + gutterY + delta * i / dashesY) + 0.5, &quot;l&quot;, dashSize + 1, 0);
269                 }
270                 inflections.push([ Math.floor(x), Math.floor(currentY) ]);
271                 if (calcLabels) {
272                     me.labels.push(me.labels[me.labels.length -1] + step);
273                 }
274             }
275         } else {
276             currentX = x + gutterX;
277             currentY = y - ((position == 'top') * dashSize * 2);
278             while (currentX &lt;= x + gutterX + trueLength) {
279                 path.push(&quot;M&quot;, Math.floor(currentX) + 0.5, currentY, &quot;l&quot;, 0, dashSize * 2 + 1);
280                 if (currentX != x + gutterX) {
281                     for (i = 1; i &lt; dashesX; i++) {
282                         path.push(&quot;M&quot;, Math.floor(currentX - delta * i / dashesX) + 0.5, currentY, &quot;l&quot;, 0, dashSize + 1);
283                     }
284                 }
285                 inflections.push([ Math.floor(currentX), Math.floor(y) ]);
286                 currentX += delta;
287                 if (calcLabels) {
288                     me.labels.push(me.labels[me.labels.length -1] + step);
289                 }
290                 if (delta === 0) {
291                     break;
292                 }
293             }
294             if (Math.round(currentX - delta - (x + gutterX + trueLength))) {
295                 path.push(&quot;M&quot;, Math.floor(x + length - gutterX) + 0.5, currentY, &quot;l&quot;, 0, dashSize * 2 + 1);
296                 for (i = 1; i &lt; dashesX; i++) {
297                     path.push(&quot;M&quot;, Math.floor(x + length - gutterX - delta * i / dashesX) + 0.5, currentY, &quot;l&quot;, 0, dashSize + 1);
298                 }
299                 inflections.push([ Math.floor(currentX), Math.floor(y) ]);
300                 if (calcLabels) {
301                     me.labels.push(me.labels[me.labels.length -1] + step);
302                 }
303             }
304         }
305         if (!me.axis) {
306             me.axis = me.chart.surface.add(Ext.apply({
307                 type: 'path',
308                 path: path
309             }, me.axisStyle));
310         }
311         me.axis.setAttributes({
312             path: path
313         }, true);
314         me.inflections = inflections;
315         if (!init &amp;&amp; me.grid) {
316             me.drawGrid();
317         }
318         me.axisBBox = me.axis.getBBox();
319         me.drawLabel();
320     },
321
322 <span id='Ext-chart.axis.Axis-method-drawGrid'>    /**
323 </span>     * Renders an horizontal and/or vertical grid into the Surface.
324      */
325     drawGrid: function() {
326         var me = this,
327             surface = me.chart.surface, 
328             grid = me.grid,
329             odd = grid.odd,
330             even = grid.even,
331             inflections = me.inflections,
332             ln = inflections.length - ((odd || even)? 0 : 1),
333             position = me.position,
334             gutter = me.chart.maxGutter,
335             width = me.width - 2,
336             vert = false,
337             point, prevPoint,
338             i = 1,
339             path = [], styles, lineWidth, dlineWidth,
340             oddPath = [], evenPath = [];
341         
342         if ((gutter[1] !== 0 &amp;&amp; (position == 'left' || position == 'right')) ||
343             (gutter[0] !== 0 &amp;&amp; (position == 'top' || position == 'bottom'))) {
344             i = 0;
345             ln++;
346         }
347         for (; i &lt; ln; i++) {
348             point = inflections[i];
349             prevPoint = inflections[i - 1];
350             if (odd || even) {
351                 path = (i % 2)? oddPath : evenPath;
352                 styles = ((i % 2)? odd : even) || {};
353                 lineWidth = (styles.lineWidth || styles['stroke-width'] || 0) / 2;
354                 dlineWidth = 2 * lineWidth;
355                 if (position == 'left') {
356                     path.push(&quot;M&quot;, prevPoint[0] + 1 + lineWidth, prevPoint[1] + 0.5 - lineWidth, 
357                               &quot;L&quot;, prevPoint[0] + 1 + width - lineWidth, prevPoint[1] + 0.5 - lineWidth,
358                               &quot;L&quot;, point[0] + 1 + width - lineWidth, point[1] + 0.5 + lineWidth,
359                               &quot;L&quot;, point[0] + 1 + lineWidth, point[1] + 0.5 + lineWidth, &quot;Z&quot;);
360                 }
361                 else if (position == 'right') {
362                     path.push(&quot;M&quot;, prevPoint[0] - lineWidth, prevPoint[1] + 0.5 - lineWidth, 
363                               &quot;L&quot;, prevPoint[0] - width + lineWidth, prevPoint[1] + 0.5 - lineWidth,
364                               &quot;L&quot;, point[0] - width + lineWidth, point[1] + 0.5 + lineWidth,
365                               &quot;L&quot;, point[0] - lineWidth, point[1] + 0.5 + lineWidth, &quot;Z&quot;);
366                 }
367                 else if (position == 'top') {
368                     path.push(&quot;M&quot;, prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + lineWidth, 
369                               &quot;L&quot;, prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + width - lineWidth,
370                               &quot;L&quot;, point[0] + 0.5 - lineWidth, point[1] + 1 + width - lineWidth,
371                               &quot;L&quot;, point[0] + 0.5 - lineWidth, point[1] + 1 + lineWidth, &quot;Z&quot;);
372                 }
373                 else {
374                     path.push(&quot;M&quot;, prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - lineWidth, 
375                             &quot;L&quot;, prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - width + lineWidth,
376                             &quot;L&quot;, point[0] + 0.5 - lineWidth, point[1] - width + lineWidth,
377                             &quot;L&quot;, point[0] + 0.5 - lineWidth, point[1] - lineWidth, &quot;Z&quot;);
378                 }
379             } else {
380                 if (position == 'left') {
381                     path = path.concat([&quot;M&quot;, point[0] + 0.5, point[1] + 0.5, &quot;l&quot;, width, 0]);
382                 }
383                 else if (position == 'right') {
384                     path = path.concat([&quot;M&quot;, point[0] - 0.5, point[1] + 0.5, &quot;l&quot;, -width, 0]);
385                 }
386                 else if (position == 'top') {
387                     path = path.concat([&quot;M&quot;, point[0] + 0.5, point[1] + 0.5, &quot;l&quot;, 0, width]);
388                 }
389                 else {
390                     path = path.concat([&quot;M&quot;, point[0] + 0.5, point[1] - 0.5, &quot;l&quot;, 0, -width]);
391                 }
392             }
393         }
394         if (odd || even) {
395             if (oddPath.length) {
396                 if (!me.gridOdd &amp;&amp; oddPath.length) {
397                     me.gridOdd = surface.add({
398                         type: 'path',
399                         path: oddPath
400                     });
401                 }
402                 me.gridOdd.setAttributes(Ext.apply({
403                     path: oddPath,
404                     hidden: false
405                 }, odd || {}), true);
406             }
407             if (evenPath.length) {
408                 if (!me.gridEven) {
409                     me.gridEven = surface.add({
410                         type: 'path',
411                         path: evenPath
412                     });
413                 } 
414                 me.gridEven.setAttributes(Ext.apply({
415                     path: evenPath,
416                     hidden: false
417                 }, even || {}), true);
418             }
419         }
420         else {
421             if (path.length) {
422                 if (!me.gridLines) {
423                     me.gridLines = me.chart.surface.add({
424                         type: 'path',
425                         path: path,
426                         &quot;stroke-width&quot;: me.lineWidth || 1,
427                         stroke: me.gridColor || '#ccc'
428                     });
429                 }
430                 me.gridLines.setAttributes({
431                     hidden: false,
432                     path: path
433                 }, true);
434             }
435             else if (me.gridLines) {
436                 me.gridLines.hide(true);
437             }
438         }
439     },
440
441     //@private
442     getOrCreateLabel: function(i, text) {
443         var me = this,
444             labelGroup = me.labelGroup,
445             textLabel = labelGroup.getAt(i),
446             surface = me.chart.surface;
447         if (textLabel) {
448             if (text != textLabel.attr.text) {
449                 textLabel.setAttributes(Ext.apply({
450                     text: text
451                 }, me.label), true);
452                 textLabel._bbox = textLabel.getBBox();
453             }
454         }
455         else {
456             textLabel = surface.add(Ext.apply({
457                 group: labelGroup,
458                 type: 'text',
459                 x: 0,
460                 y: 0,
461                 text: text
462             }, me.label));
463             surface.renderItem(textLabel);
464             textLabel._bbox = textLabel.getBBox();
465         }
466         //get untransformed bounding box
467         if (me.label.rotation) {
468             textLabel.setAttributes({
469                 rotation: {
470                     degrees: 0    
471                 }    
472             }, true);
473             textLabel._ubbox = textLabel.getBBox();
474             textLabel.setAttributes(me.label, true);
475         } else {
476             textLabel._ubbox = textLabel._bbox;
477         }
478         return textLabel;
479     },
480     
481     rect2pointArray: function(sprite) {
482         var surface = this.chart.surface,
483             rect = surface.getBBox(sprite, true),
484             p1 = [rect.x, rect.y],
485             p1p = p1.slice(),
486             p2 = [rect.x + rect.width, rect.y],
487             p2p = p2.slice(),
488             p3 = [rect.x + rect.width, rect.y + rect.height],
489             p3p = p3.slice(),
490             p4 = [rect.x, rect.y + rect.height],
491             p4p = p4.slice(),
492             matrix = sprite.matrix;
493         //transform the points
494         p1[0] = matrix.x.apply(matrix, p1p);
495         p1[1] = matrix.y.apply(matrix, p1p);
496         
497         p2[0] = matrix.x.apply(matrix, p2p);
498         p2[1] = matrix.y.apply(matrix, p2p);
499         
500         p3[0] = matrix.x.apply(matrix, p3p);
501         p3[1] = matrix.y.apply(matrix, p3p);
502         
503         p4[0] = matrix.x.apply(matrix, p4p);
504         p4[1] = matrix.y.apply(matrix, p4p);
505         return [p1, p2, p3, p4];
506     },
507     
508     intersect: function(l1, l2) {
509         var r1 = this.rect2pointArray(l1),
510             r2 = this.rect2pointArray(l2);
511         return !!Ext.draw.Draw.intersect(r1, r2).length;
512     },
513     
514     drawHorizontalLabels: function() {
515        var  me = this,
516             labelConf = me.label,
517             floor = Math.floor,
518             max = Math.max,
519             axes = me.chart.axes,
520             position = me.position,
521             inflections = me.inflections,
522             ln = inflections.length,
523             labels = me.labels,
524             labelGroup = me.labelGroup,
525             maxHeight = 0,
526             ratio,
527             gutterY = me.chart.maxGutter[1],
528             ubbox, bbox, point, prevX, prevLabel,
529             projectedWidth = 0,
530             textLabel, attr, textRight, text,
531             label, last, x, y, i, firstLabel;
532
533         last = ln - 1;
534         //get a reference to the first text label dimensions
535         point = inflections[0];
536         firstLabel = me.getOrCreateLabel(0, me.label.renderer(labels[0]));
537         ratio = Math.abs(Math.sin(labelConf.rotate &amp;&amp; (labelConf.rotate.degrees * Math.PI / 180) || 0)) &gt;&gt; 0;
538         
539         for (i = 0; i &lt; ln; i++) {
540             point = inflections[i];
541             text = me.label.renderer(labels[i]);
542             textLabel = me.getOrCreateLabel(i, text);
543             bbox = textLabel._bbox;
544             maxHeight = max(maxHeight, bbox.height + me.dashSize + me.label.padding);
545             x = floor(point[0] - (ratio? bbox.height : bbox.width) / 2);
546             if (me.chart.maxGutter[0] == 0) {
547                 if (i == 0 &amp;&amp; axes.findIndex('position', 'left') == -1) {
548                     x = point[0];
549                 }
550                 else if (i == last &amp;&amp; axes.findIndex('position', 'right') == -1) {
551                     x = point[0] - bbox.width;
552                 }
553             }
554             if (position == 'top') {
555                 y = point[1] - (me.dashSize * 2) - me.label.padding - (bbox.height / 2);
556             }
557             else {
558                 y = point[1] + (me.dashSize * 2) + me.label.padding + (bbox.height / 2);
559             }
560             
561             textLabel.setAttributes({
562                 hidden: false,
563                 x: x,
564                 y: y
565             }, true);
566
567             // Skip label if there isn't available minimum space
568             if (i != 0 &amp;&amp; (me.intersect(textLabel, prevLabel)
569                 || me.intersect(textLabel, firstLabel))) {
570                 textLabel.hide(true);
571                 continue;
572             }
573             
574             prevLabel = textLabel;
575         }
576
577         return maxHeight;
578     },
579     
580     drawVerticalLabels: function() {
581         var me = this,
582             inflections = me.inflections,
583             position = me.position,
584             ln = inflections.length,
585             labels = me.labels,
586             maxWidth = 0,
587             max = Math.max,
588             floor = Math.floor,
589             ceil = Math.ceil,
590             axes = me.chart.axes,
591             gutterY = me.chart.maxGutter[1],
592             ubbox, bbox, point, prevLabel,
593             projectedWidth = 0,
594             textLabel, attr, textRight, text,
595             label, last, x, y, i;
596
597         last = ln;
598         for (i = 0; i &lt; last; i++) {
599             point = inflections[i];
600             text = me.label.renderer(labels[i]);
601             textLabel = me.getOrCreateLabel(i, text);
602             bbox = textLabel._bbox;
603             
604             maxWidth = max(maxWidth, bbox.width + me.dashSize + me.label.padding);
605             y = point[1];
606             if (gutterY &lt; bbox.height / 2) {
607                 if (i == last - 1 &amp;&amp; axes.findIndex('position', 'top') == -1) {
608                     y = me.y - me.length + ceil(bbox.height / 2);
609                 }
610                 else if (i == 0 &amp;&amp; axes.findIndex('position', 'bottom') == -1) {
611                     y = me.y - floor(bbox.height / 2);
612                 }
613             }
614             if (position == 'left') {
615                 x = point[0] - bbox.width - me.dashSize - me.label.padding - 2;
616             }
617             else {
618                 x = point[0] + me.dashSize + me.label.padding + 2;
619             }    
620             textLabel.setAttributes(Ext.apply({
621                 hidden: false,
622                 x: x,
623                 y: y
624             }, me.label), true);
625             // Skip label if there isn't available minimum space
626             if (i != 0 &amp;&amp; me.intersect(textLabel, prevLabel)) {
627                 textLabel.hide(true);
628                 continue;
629             }
630             prevLabel = textLabel;
631         }
632         
633         return maxWidth;
634     },
635
636 <span id='Ext-chart.axis.Axis-method-drawLabel'>    /**
637 </span>     * Renders the labels in the axes.
638      */
639     drawLabel: function() {
640         var me = this,
641             position = me.position,
642             labelGroup = me.labelGroup,
643             inflections = me.inflections,
644             maxWidth = 0,
645             maxHeight = 0,
646             ln, i;
647
648         if (position == 'left' || position == 'right') {
649             maxWidth = me.drawVerticalLabels();    
650         } else {
651             maxHeight = me.drawHorizontalLabels();
652         }
653
654         // Hide unused bars
655         ln = labelGroup.getCount();
656         i = inflections.length;
657         for (; i &lt; ln; i++) {
658             labelGroup.getAt(i).hide(true);
659         }
660
661         me.bbox = {};
662         Ext.apply(me.bbox, me.axisBBox);
663         me.bbox.height = maxHeight;
664         me.bbox.width = maxWidth;
665         if (Ext.isString(me.title)) {
666             me.drawTitle(maxWidth, maxHeight);
667         }
668     },
669
670     // @private creates the elipsis for the text.
671     elipsis: function(sprite, text, desiredWidth, minWidth, center) {
672         var bbox,
673             x;
674
675         if (desiredWidth &lt; minWidth) {
676             sprite.hide(true);
677             return false;
678         }
679         while (text.length &gt; 4) {
680             text = text.substr(0, text.length - 4) + &quot;...&quot;;
681             sprite.setAttributes({
682                 text: text
683             }, true);
684             bbox = sprite.getBBox();
685             if (bbox.width &lt; desiredWidth) {
686                 if (typeof center == 'number') {
687                     sprite.setAttributes({
688                         x: Math.floor(center - (bbox.width / 2))
689                     }, true);
690                 }
691                 break;
692             }
693         }
694         return true;
695     },
696
697 <span id='Ext-chart.axis.Axis-method-setTitle'>    /**
698 </span>     * Updates the {@link #title} of this axis.
699      * @param {String} title
700      */
701     setTitle: function(title) {
702         this.title = title;
703         this.drawLabel();
704     },
705
706     // @private draws the title for the axis.
707     drawTitle: function(maxWidth, maxHeight) {
708         var me = this,
709             position = me.position,
710             surface = me.chart.surface,
711             displaySprite = me.displaySprite,
712             title = me.title,
713             rotate = (position == 'left' || position == 'right'),
714             x = me.x,
715             y = me.y,
716             base, bbox, pad;
717
718         if (displaySprite) {
719             displaySprite.setAttributes({text: title}, true);
720         } else {
721             base = {
722                 type: 'text',
723                 x: 0,
724                 y: 0,
725                 text: title
726             };
727             displaySprite = me.displaySprite = surface.add(Ext.apply(base, me.axisTitleStyle, me.labelTitle));
728             surface.renderItem(displaySprite);
729         }
730         bbox = displaySprite.getBBox();
731         pad = me.dashSize + me.label.padding;
732
733         if (rotate) {
734             y -= ((me.length / 2) - (bbox.height / 2));
735             if (position == 'left') {
736                 x -= (maxWidth + pad + (bbox.width / 2));
737             }
738             else {
739                 x += (maxWidth + pad + bbox.width - (bbox.width / 2));
740             }
741             me.bbox.width += bbox.width + 10;
742         }
743         else {
744             x += (me.length / 2) - (bbox.width * 0.5);
745             if (position == 'top') {
746                 y -= (maxHeight + pad + (bbox.height * 0.3));
747             }
748             else {
749                 y += (maxHeight + pad + (bbox.height * 0.8));
750             }
751             me.bbox.height += bbox.height + 10;
752         }
753         displaySprite.setAttributes({
754             translate: {
755                 x: x,
756                 y: y
757             }
758         }, true);
759     }
760 });</pre></pre></body></html>