Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / draw / CompositeSprite.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.draw.CompositeSprite
17  * @extends Ext.util.MixedCollection
18  *
19  * A composite Sprite handles a group of sprites with common methods to a sprite
20  * such as `hide`, `show`, `setAttributes`. These methods are applied to the set of sprites
21  * added to the group.
22  *
23  * CompositeSprite extends {@link Ext.util.MixedCollection} so you can use the same methods
24  * in `MixedCollection` to iterate through sprites, add and remove elements, etc.
25  *
26  * In order to create a CompositeSprite, one has to provide a handle to the surface where it is
27  * rendered:
28  *
29  *     var group = Ext.create('Ext.draw.CompositeSprite', {
30  *         surface: drawComponent.surface
31  *     });
32  *                  
33  * Then just by using `MixedCollection` methods it's possible to add {@link Ext.draw.Sprite}s:
34  *  
35  *     group.add(sprite1);
36  *     group.add(sprite2);
37  *     group.add(sprite3);
38  *                  
39  * And then apply common Sprite methods to them:
40  *  
41  *     group.setAttributes({
42  *         fill: '#f00'
43  *     }, true);
44  */
45 Ext.define('Ext.draw.CompositeSprite', {
46
47     /* Begin Definitions */
48
49     extend: 'Ext.util.MixedCollection',
50     mixins: {
51         animate: 'Ext.util.Animate'
52     },
53
54     /* End Definitions */
55     isCompositeSprite: true,
56     constructor: function(config) {
57         var me = this;
58         
59         config = config || {};
60         Ext.apply(me, config);
61
62         me.addEvents(
63             'mousedown',
64             'mouseup',
65             'mouseover',
66             'mouseout',
67             'click'
68         );
69         me.id = Ext.id(null, 'ext-sprite-group-');
70         me.callParent();
71     },
72
73     // @private
74     onClick: function(e) {
75         this.fireEvent('click', e);
76     },
77
78     // @private
79     onMouseUp: function(e) {
80         this.fireEvent('mouseup', e);
81     },
82
83     // @private
84     onMouseDown: function(e) {
85         this.fireEvent('mousedown', e);
86     },
87
88     // @private
89     onMouseOver: function(e) {
90         this.fireEvent('mouseover', e);
91     },
92
93     // @private
94     onMouseOut: function(e) {
95         this.fireEvent('mouseout', e);
96     },
97
98     attachEvents: function(o) {
99         var me = this;
100         
101         o.on({
102             scope: me,
103             mousedown: me.onMouseDown,
104             mouseup: me.onMouseUp,
105             mouseover: me.onMouseOver,
106             mouseout: me.onMouseOut,
107             click: me.onClick
108         });
109     },
110
111     // Inherit docs from MixedCollection
112     add: function(key, o) {
113         var result = this.callParent(arguments);
114         this.attachEvents(result);
115         return result;
116     },
117
118     insert: function(index, key, o) {
119         return this.callParent(arguments);
120     },
121
122     // Inherit docs from MixedCollection
123     remove: function(o) {
124         var me = this;
125         
126         o.un({
127             scope: me,
128             mousedown: me.onMouseDown,
129             mouseup: me.onMouseUp,
130             mouseover: me.onMouseOver,
131             mouseout: me.onMouseOut,
132             click: me.onClick
133         });
134         return me.callParent(arguments);
135     },
136     
137     /**
138      * Returns the group bounding box.
139      * Behaves like {@link Ext.draw.Sprite#getBBox} method.
140      * @return {Object} an object with x, y, width, and height properties.
141      */
142     getBBox: function() {
143         var i = 0,
144             sprite,
145             bb,
146             items = this.items,
147             len = this.length,
148             infinity = Infinity,
149             minX = infinity,
150             maxHeight = -infinity,
151             minY = infinity,
152             maxWidth = -infinity,
153             maxWidthBBox, maxHeightBBox;
154         
155         for (; i < len; i++) {
156             sprite = items[i];
157             if (sprite.el) {
158                 bb = sprite.getBBox();
159                 minX = Math.min(minX, bb.x);
160                 minY = Math.min(minY, bb.y);
161                 maxHeight = Math.max(maxHeight, bb.height + bb.y);
162                 maxWidth = Math.max(maxWidth, bb.width + bb.x);
163             }
164         }
165         
166         return {
167             x: minX,
168             y: minY,
169             height: maxHeight - minY,
170             width: maxWidth - minX
171         };
172     },
173
174     /**
175      * Iterates through all sprites calling `setAttributes` on each one. For more information {@link Ext.draw.Sprite}
176      * provides a description of the attributes that can be set with this method.
177      * @param {Object} attrs Attributes to be changed on the sprite.
178      * @param {Boolean} redraw Flag to immediatly draw the change.
179      * @return {Ext.draw.CompositeSprite} this
180      */
181     setAttributes: function(attrs, redraw) {
182         var i = 0,
183             items = this.items,
184             len = this.length;
185             
186         for (; i < len; i++) {
187             items[i].setAttributes(attrs, redraw);
188         }
189         return this;
190     },
191
192     /**
193      * Hides all sprites. If the first parameter of the method is true
194      * then a redraw will be forced for each sprite.
195      * @param {Boolean} redraw Flag to immediatly draw the change.
196      * @return {Ext.draw.CompositeSprite} this
197      */
198     hide: function(redraw) {
199         var i = 0,
200             items = this.items,
201             len = this.length;
202             
203         for (; i < len; i++) {
204             items[i].hide(redraw);
205         }
206         return this;
207     },
208
209     /**
210      * Shows all sprites. If the first parameter of the method is true
211      * then a redraw will be forced for each sprite.
212      * @param {Boolean} redraw Flag to immediatly draw the change.
213      * @return {Ext.draw.CompositeSprite} this
214      */
215     show: function(redraw) {
216         var i = 0,
217             items = this.items,
218             len = this.length;
219             
220         for (; i < len; i++) {
221             items[i].show(redraw);
222         }
223         return this;
224     },
225
226     redraw: function() {
227         var me = this,
228             i = 0,
229             items = me.items,
230             surface = me.getSurface(),
231             len = me.length;
232         
233         if (surface) {
234             for (; i < len; i++) {
235                 surface.renderItem(items[i]);
236             }
237         }
238         return me;
239     },
240
241     setStyle: function(obj) {
242         var i = 0,
243             items = this.items,
244             len = this.length,
245             item, el;
246             
247         for (; i < len; i++) {
248             item = items[i];
249             el = item.el;
250             if (el) {
251                 el.setStyle(obj);
252             }
253         }
254     },
255
256     addCls: function(obj) {
257         var i = 0,
258             items = this.items,
259             surface = this.getSurface(),
260             len = this.length;
261         
262         if (surface) {
263             for (; i < len; i++) {
264                 surface.addCls(items[i], obj);
265             }
266         }
267     },
268
269     removeCls: function(obj) {
270         var i = 0,
271             items = this.items,
272             surface = this.getSurface(),
273             len = this.length;
274         
275         if (surface) {
276             for (; i < len; i++) {
277                 surface.removeCls(items[i], obj);
278             }
279         }
280     },
281     
282     /**
283      * Grab the surface from the items
284      * @private
285      * @return {Ext.draw.Surface} The surface, null if not found
286      */
287     getSurface: function(){
288         var first = this.first();
289         if (first) {
290             return first.surface;
291         }
292         return null;
293     },
294     
295     /**
296      * Destroys the SpriteGroup
297      */
298     destroy: function(){
299         var me = this,
300             surface = me.getSurface(),
301             item;
302             
303         if (surface) {
304             while (me.getCount() > 0) {
305                 item = me.first();
306                 me.remove(item);
307                 surface.remove(item);
308             }
309         }
310         me.clearListeners();
311     }
312 });
313