Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Legend.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-Legend'>/**
19 </span> * @class Ext.chart.Legend
20  *
21  * Defines a legend for a chart's series.
22  * The 'chart' member must be set prior to rendering.
23  * The legend class displays a list of legend items each of them related with a
24  * series being rendered. In order to render the legend item of the proper series
25  * the series configuration object must have `showInSeries` set to true.
26  *
27  * The legend configuration object accepts a `position` as parameter.
28  * The `position` parameter can be `left`, `right`
29  * `top` or `bottom`. For example:
30  *
31  *     legend: {
32  *         position: 'right'
33  *     },
34  *
35  * ## Example
36  *
37  *     @example
38  *     var store = Ext.create('Ext.data.JsonStore', {
39  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
40  *         data: [
41  *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
42  *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
43  *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
44  *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
45  *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
46  *         ]
47  *     });
48  *
49  *     Ext.create('Ext.chart.Chart', {
50  *         renderTo: Ext.getBody(),
51  *         width: 500,
52  *         height: 300,
53  *         animate: true,
54  *         store: store,
55  *         shadow: true,
56  *         theme: 'Category1',
57  *         legend: {
58  *             position: 'top'
59  *         },
60  *         axes: [
61  *             {
62  *                 type: 'Numeric',
63  *                 grid: true,
64  *                 position: 'left',
65  *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
66  *                 title: 'Sample Values',
67  *                 grid: {
68  *                     odd: {
69  *                         opacity: 1,
70  *                         fill: '#ddd',
71  *                         stroke: '#bbb',
72  *                         'stroke-width': 1
73  *                     }
74  *                 },
75  *                 minimum: 0,
76  *                 adjustMinimumByMajorUnit: 0
77  *             },
78  *             {
79  *                 type: 'Category',
80  *                 position: 'bottom',
81  *                 fields: ['name'],
82  *                 title: 'Sample Metrics',
83  *                 grid: true,
84  *                 label: {
85  *                     rotate: {
86  *                         degrees: 315
87  *                     }
88  *                 }
89  *             }
90  *         ],
91  *         series: [{
92  *             type: 'area',
93  *             highlight: false,
94  *             axis: 'left',
95  *             xField: 'name',
96  *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
97  *             style: {
98  *                 opacity: 0.93
99  *             }
100  *         }]
101  *     });
102  */
103 Ext.define('Ext.chart.Legend', {
104
105     /* Begin Definitions */
106
107     requires: ['Ext.chart.LegendItem'],
108
109     /* End Definitions */
110
111 <span id='Ext-chart-Legend-cfg-visible'>    /**
112 </span>     * @cfg {Boolean} visible
113      * Whether or not the legend should be displayed.
114      */
115     visible: true,
116
117 <span id='Ext-chart-Legend-cfg-position'>    /**
118 </span>     * @cfg {String} position
119      * The position of the legend in relation to the chart. One of: &quot;top&quot;,
120      * &quot;bottom&quot;, &quot;left&quot;, &quot;right&quot;, or &quot;float&quot;. If set to &quot;float&quot;, then the legend
121      * box will be positioned at the point denoted by the x and y parameters.
122      */
123     position: 'bottom',
124
125 <span id='Ext-chart-Legend-cfg-x'>    /**
126 </span>     * @cfg {Number} x
127      * X-position of the legend box. Used directly if position is set to &quot;float&quot;, otherwise
128      * it will be calculated dynamically.
129      */
130     x: 0,
131
132 <span id='Ext-chart-Legend-cfg-y'>    /**
133 </span>     * @cfg {Number} y
134      * Y-position of the legend box. Used directly if position is set to &quot;float&quot;, otherwise
135      * it will be calculated dynamically.
136      */
137     y: 0,
138
139 <span id='Ext-chart-Legend-cfg-labelFont'>    /**
140 </span>     * @cfg {String} labelFont
141      * Font to be used for the legend labels, eg '12px Helvetica'
142      */
143     labelFont: '12px Helvetica, sans-serif',
144
145 <span id='Ext-chart-Legend-cfg-boxStroke'>    /**
146 </span>     * @cfg {String} boxStroke
147      * Style of the stroke for the legend box
148      */
149     boxStroke: '#000',
150
151 <span id='Ext-chart-Legend-cfg-boxStrokeWidth'>    /**
152 </span>     * @cfg {String} boxStrokeWidth
153      * Width of the stroke for the legend box
154      */
155     boxStrokeWidth: 1,
156
157 <span id='Ext-chart-Legend-cfg-boxFill'>    /**
158 </span>     * @cfg {String} boxFill
159      * Fill style for the legend box
160      */
161     boxFill: '#FFF',
162
163 <span id='Ext-chart-Legend-cfg-itemSpacing'>    /**
164 </span>     * @cfg {Number} itemSpacing
165      * Amount of space between legend items
166      */
167     itemSpacing: 10,
168
169 <span id='Ext-chart-Legend-cfg-padding'>    /**
170 </span>     * @cfg {Number} padding
171      * Amount of padding between the legend box's border and its items
172      */
173     padding: 5,
174
175     // @private
176     width: 0,
177     // @private
178     height: 0,
179
180 <span id='Ext-chart-Legend-cfg-boxZIndex'>    /**
181 </span>     * @cfg {Number} boxZIndex
182      * Sets the z-index for the legend. Defaults to 100.
183      */
184     boxZIndex: 100,
185
186 <span id='Ext-chart-Legend-method-constructor'>    /**
187 </span>     * Creates new Legend.
188      * @param {Object} config  (optional) Config object.
189      */
190     constructor: function(config) {
191         var me = this;
192         if (config) {
193             Ext.apply(me, config);
194         }
195         me.items = [];
196 <span id='Ext-chart-Legend-property-isVertical'>        /**
197 </span>         * Whether the legend box is oriented vertically, i.e. if it is on the left or right side or floating.
198          * @type {Boolean}
199          */
200         me.isVertical = (&quot;left|right|float&quot;.indexOf(me.position) !== -1);
201
202         // cache these here since they may get modified later on
203         me.origX = me.x;
204         me.origY = me.y;
205     },
206
207 <span id='Ext-chart-Legend-method-create'>    /**
208 </span>     * @private Create all the sprites for the legend
209      */
210     create: function() {
211         var me = this;
212         me.createBox();
213         me.createItems();
214         if (!me.created &amp;&amp; me.isDisplayed()) {
215             me.created = true;
216
217             // Listen for changes to series titles to trigger regeneration of the legend
218             me.chart.series.each(function(series) {
219                 series.on('titlechange', function() {
220                     me.create();
221                     me.updatePosition();
222                 });
223             });
224         }
225     },
226
227 <span id='Ext-chart-Legend-method-isDisplayed'>    /**
228 </span>     * @private Determine whether the legend should be displayed. Looks at the legend's 'visible' config,
229      * and also the 'showInLegend' config for each of the series.
230      */
231     isDisplayed: function() {
232         return this.visible &amp;&amp; this.chart.series.findIndex('showInLegend', true) !== -1;
233     },
234
235 <span id='Ext-chart-Legend-method-createItems'>    /**
236 </span>     * @private Create the series markers and labels
237      */
238     createItems: function() {
239         var me = this,
240             chart = me.chart,
241             surface = chart.surface,
242             items = me.items,
243             padding = me.padding,
244             itemSpacing = me.itemSpacing,
245             spacingOffset = 2,
246             maxWidth = 0,
247             maxHeight = 0,
248             totalWidth = 0,
249             totalHeight = 0,
250             vertical = me.isVertical,
251             math = Math,
252             mfloor = math.floor,
253             mmax = math.max,
254             index = 0,
255             i = 0,
256             len = items ? items.length : 0,
257             x, y, spacing, item, bbox, height, width;
258
259         //remove all legend items
260         if (len) {
261             for (; i &lt; len; i++) {
262                 items[i].destroy();
263             }
264         }
265         //empty array
266         items.length = [];
267         // Create all the item labels, collecting their dimensions and positioning each one
268         // properly in relation to the previous item
269         chart.series.each(function(series, i) {
270             if (series.showInLegend) {
271                 Ext.each([].concat(series.yField), function(field, j) {
272                     item = Ext.create('Ext.chart.LegendItem', {
273                         legend: this,
274                         series: series,
275                         surface: chart.surface,
276                         yFieldIndex: j
277                     });
278                     bbox = item.getBBox();
279
280                     //always measure from x=0, since not all markers go all the way to the left
281                     width = bbox.width;
282                     height = bbox.height;
283
284                     if (i + j === 0) {
285                         spacing = vertical ? padding + height / 2 : padding;
286                     }
287                     else {
288                         spacing = itemSpacing / (vertical ? 2 : 1);
289                     }
290                     // Set the item's position relative to the legend box
291                     item.x = mfloor(vertical ? padding : totalWidth + spacing);
292                     item.y = mfloor(vertical ? totalHeight + spacing : padding + height / 2);
293
294                     // Collect cumulative dimensions
295                     totalWidth += width + spacing;
296                     totalHeight += height + spacing;
297                     maxWidth = mmax(maxWidth, width);
298                     maxHeight = mmax(maxHeight, height);
299
300                     items.push(item);
301                 }, this);
302             }
303         }, me);
304
305         // Store the collected dimensions for later
306         me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
307         if (vertical &amp;&amp; items.length === 1) {
308             spacingOffset = 1;
309         }
310         me.height = mfloor((vertical ? totalHeight - spacingOffset * spacing : maxHeight) + (padding * 2));
311         me.itemHeight = maxHeight;
312     },
313
314 <span id='Ext-chart-Legend-method-getBBox'>    /**
315 </span>     * @private Get the bounds for the legend's outer box
316      */
317     getBBox: function() {
318         var me = this;
319         return {
320             x: Math.round(me.x) - me.boxStrokeWidth / 2,
321             y: Math.round(me.y) - me.boxStrokeWidth / 2,
322             width: me.width,
323             height: me.height
324         };
325     },
326
327 <span id='Ext-chart-Legend-method-createBox'>    /**
328 </span>     * @private Create the box around the legend items
329      */
330     createBox: function() {
331         var me = this,
332             box;
333
334         if (me.boxSprite) {
335             me.boxSprite.destroy();
336         }
337         
338         box = me.boxSprite = me.chart.surface.add(Ext.apply({
339             type: 'rect',
340             stroke: me.boxStroke,
341             &quot;stroke-width&quot;: me.boxStrokeWidth,
342             fill: me.boxFill,
343             zIndex: me.boxZIndex
344         }, me.getBBox()));
345
346         box.redraw();
347     },
348
349 <span id='Ext-chart-Legend-method-updatePosition'>    /**
350 </span>     * @private Update the position of all the legend's sprites to match its current x/y values
351      */
352     updatePosition: function() {
353         var me = this,
354             x, y,
355             legendWidth = me.width,
356             legendHeight = me.height,
357             padding = me.padding,
358             chart = me.chart,
359             chartBBox = chart.chartBBox,
360             insets = chart.insetPadding,
361             chartWidth = chartBBox.width - (insets * 2),
362             chartHeight = chartBBox.height - (insets * 2),
363             chartX = chartBBox.x + insets,
364             chartY = chartBBox.y + insets,
365             surface = chart.surface,
366             mfloor = Math.floor;
367
368         if (me.isDisplayed()) {
369             // Find the position based on the dimensions
370             switch(me.position) {
371                 case &quot;left&quot;:
372                     x = insets;
373                     y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
374                     break;
375                 case &quot;right&quot;:
376                     x = mfloor(surface.width - legendWidth) - insets;
377                     y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
378                     break;
379                 case &quot;top&quot;:
380                     x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
381                     y = insets;
382                     break;
383                 case &quot;bottom&quot;:
384                     x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
385                     y = mfloor(surface.height - legendHeight) - insets;
386                     break;
387                 default:
388                     x = mfloor(me.origX) + insets;
389                     y = mfloor(me.origY) + insets;
390             }
391             me.x = x;
392             me.y = y;
393
394             // Update the position of each item
395             Ext.each(me.items, function(item) {
396                 item.updatePosition();
397             });
398             // Update the position of the outer box
399             me.boxSprite.setAttributes(me.getBBox(), true);
400         }
401     }
402 });
403 </pre>
404 </body>
405 </html>