Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / chart / LegendItem.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.chart.LegendItem
17  * @extends Ext.draw.CompositeSprite
18  * A single item of a legend (marker plus label)
19  */
20 Ext.define('Ext.chart.LegendItem', {
21
22     /* Begin Definitions */
23
24     extend: 'Ext.draw.CompositeSprite',
25
26     requires: ['Ext.chart.Shape'],
27
28     /* End Definitions */
29
30     // Position of the item, relative to the upper-left corner of the legend box
31     x: 0,
32     y: 0,
33     zIndex: 500,
34
35     constructor: function(config) {
36         this.callParent(arguments);
37         this.createLegend(config);
38     },
39
40     /**
41      * Creates all the individual sprites for this legend item
42      */
43     createLegend: function(config) {
44         var me = this,
45             index = config.yFieldIndex,
46             series = me.series,
47             seriesType = series.type,
48             idx = me.yFieldIndex,
49             legend = me.legend,
50             surface = me.surface,
51             refX = legend.x + me.x,
52             refY = legend.y + me.y,
53             bbox, z = me.zIndex,
54             markerConfig, label, mask,
55             radius, toggle = false,
56             seriesStyle = Ext.apply(series.seriesStyle, series.style);
57
58         function getSeriesProp(name) {
59             var val = series[name];
60             return (Ext.isArray(val) ? val[idx] : val);
61         }
62         
63         label = me.add('label', surface.add({
64             type: 'text',
65             x: 20,
66             y: 0,
67             zIndex: z || 0,
68             font: legend.labelFont,
69             text: getSeriesProp('title') || getSeriesProp('yField')
70         }));
71
72         // Line series - display as short line with optional marker in the middle
73         if (seriesType === 'line' || seriesType === 'scatter') {
74             if(seriesType === 'line') {
75                 me.add('line', surface.add({
76                     type: 'path',
77                     path: 'M0.5,0.5L16.5,0.5',
78                     zIndex: z,
79                     "stroke-width": series.lineWidth,
80                     "stroke-linejoin": "round",
81                     "stroke-dasharray": series.dash,
82                     stroke: seriesStyle.stroke || '#000',
83                     style: {
84                         cursor: 'pointer'
85                     }
86                 }));
87             }
88             if (series.showMarkers || seriesType === 'scatter') {
89                 markerConfig = Ext.apply(series.markerStyle, series.markerConfig || {});
90                 me.add('marker', Ext.chart.Shape[markerConfig.type](surface, {
91                     fill: markerConfig.fill,
92                     x: 8.5,
93                     y: 0.5,
94                     zIndex: z,
95                     radius: markerConfig.radius || markerConfig.size,
96                     style: {
97                         cursor: 'pointer'
98                     }
99                 }));
100             }
101         }
102         // All other series types - display as filled box
103         else {
104             me.add('box', surface.add({
105                 type: 'rect',
106                 zIndex: z,
107                 x: 0,
108                 y: 0,
109                 width: 12,
110                 height: 12,
111                 fill: series.getLegendColor(index),
112                 style: {
113                     cursor: 'pointer'
114                 }
115             }));
116         }
117         
118         me.setAttributes({
119             hidden: false
120         }, true);
121         
122         bbox = me.getBBox();
123         
124         mask = me.add('mask', surface.add({
125             type: 'rect',
126             x: bbox.x,
127             y: bbox.y,
128             width: bbox.width || 20,
129             height: bbox.height || 20,
130             zIndex: (z || 0) + 1000,
131             fill: '#f00',
132             opacity: 0,
133             style: {
134                 'cursor': 'pointer'
135             }
136         }));
137
138         //add toggle listener
139         me.on('mouseover', function() {
140             label.setStyle({
141                 'font-weight': 'bold'
142             });
143             mask.setStyle({
144                 'cursor': 'pointer'
145             });
146             series._index = index;
147             series.highlightItem();
148         }, me);
149
150         me.on('mouseout', function() {
151             label.setStyle({
152                 'font-weight': 'normal'
153             });
154             series._index = index;
155             series.unHighlightItem();
156         }, me);
157         
158         if (!series.visibleInLegend(index)) {
159             toggle = true;
160             label.setAttributes({
161                opacity: 0.5
162             }, true);
163         }
164
165         me.on('mousedown', function() {
166             if (!toggle) {
167                 series.hideAll();
168                 label.setAttributes({
169                     opacity: 0.5
170                 }, true);
171             } else {
172                 series.showAll();
173                 label.setAttributes({
174                     opacity: 1
175                 }, true);
176             }
177             toggle = !toggle;
178         }, me);
179         me.updatePosition({x:0, y:0}); //Relative to 0,0 at first so that the bbox is calculated correctly
180     },
181
182     /**
183      * Update the positions of all this item's sprites to match the root position
184      * of the legend box.
185      * @param {Object} relativeTo (optional) If specified, this object's 'x' and 'y' values will be used
186      *                 as the reference point for the relative positioning. Defaults to the Legend.
187      */
188     updatePosition: function(relativeTo) {
189         var me = this,
190             items = me.items,
191             ln = items.length,
192             i = 0,
193             item;
194         if (!relativeTo) {
195             relativeTo = me.legend;
196         }
197         for (; i < ln; i++) {
198             item = items[i];
199             switch (item.type) {
200                 case 'text':
201                     item.setAttributes({
202                         x: 20 + relativeTo.x + me.x,
203                         y: relativeTo.y + me.y
204                     }, true);
205                     break;
206                 case 'rect':
207                     item.setAttributes({
208                         translate: {
209                             x: relativeTo.x + me.x,
210                             y: relativeTo.y + me.y - 6
211                         }
212                     }, true);
213                     break;
214                 default:
215                     item.setAttributes({
216                         translate: {
217                             x: relativeTo.x + me.x,
218                             y: relativeTo.y + me.y
219                         }
220                     }, true);
221             }
222         }
223     }
224 });
225