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