Upgrade to ExtJS 4.0.2 - Released 06/09/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     /** Add a Sprite to the Group */
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     /** Remove a Sprite from the Group */
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         me.callParent(arguments);
135     },
136     
137     /**
138      * Returns the group bounding box.
139      * Behaves like {@link Ext.draw.Sprite} getBBox method.
140     */
141     getBBox: function() {
142         var i = 0,
143             sprite,
144             bb,
145             items = this.items,
146             len = this.length,
147             infinity = Infinity,
148             minX = infinity,
149             maxHeight = -infinity,
150             minY = infinity,
151             maxWidth = -infinity,
152             maxWidthBBox, maxHeightBBox;
153         
154         for (; i < len; i++) {
155             sprite = items[i];
156             if (sprite.el) {
157                 bb = sprite.getBBox();
158                 minX = Math.min(minX, bb.x);
159                 minY = Math.min(minY, bb.y);
160                 maxHeight = Math.max(maxHeight, bb.height + bb.y);
161                 maxWidth = Math.max(maxWidth, bb.width + bb.x);
162             }
163         }
164         
165         return {
166             x: minX,
167             y: minY,
168             height: maxHeight - minY,
169             width: maxWidth - minX
170         };
171     },
172
173     /**
174      *  Iterates through all sprites calling
175      *  `setAttributes` on each one. For more information
176      *  {@link Ext.draw.Sprite} provides a description of the
177      *  attributes that can be set with this method.
178      */
179     setAttributes: function(attrs, redraw) {
180         var i = 0,
181             items = this.items,
182             len = this.length;
183             
184         for (; i < len; i++) {
185             items[i].setAttributes(attrs, redraw);
186         }
187         return this;
188     },
189
190     /**
191      * Hides all sprites. If the first parameter of the method is true
192      * then a redraw will be forced for each sprite.
193      */
194     hide: function(redraw) {
195         var i = 0,
196             items = this.items,
197             len = this.length;
198             
199         for (; i < len; i++) {
200             items[i].hide(redraw);
201         }
202         return this;
203     },
204
205     /**
206      * Shows all sprites. If the first parameter of the method is true
207      * then a redraw will be forced for each sprite.
208      */
209     show: function(redraw) {
210         var i = 0,
211             items = this.items,
212             len = this.length;
213             
214         for (; i < len; i++) {
215             items[i].show(redraw);
216         }
217         return this;
218     },
219
220     redraw: function() {
221         var me = this,
222             i = 0,
223             items = me.items,
224             surface = me.getSurface(),
225             len = me.length;
226         
227         if (surface) {
228             for (; i < len; i++) {
229                 surface.renderItem(items[i]);
230             }
231         }
232         return me;
233     },
234
235     setStyle: function(obj) {
236         var i = 0,
237             items = this.items,
238             len = this.length,
239             item, el;
240             
241         for (; i < len; i++) {
242             item = items[i];
243             el = item.el;
244             if (el) {
245                 el.setStyle(obj);
246             }
247         }
248     },
249
250     addCls: function(obj) {
251         var i = 0,
252             items = this.items,
253             surface = this.getSurface(),
254             len = this.length;
255         
256         if (surface) {
257             for (; i < len; i++) {
258                 surface.addCls(items[i], obj);
259             }
260         }
261     },
262
263     removeCls: function(obj) {
264         var i = 0,
265             items = this.items,
266             surface = this.getSurface(),
267             len = this.length;
268         
269         if (surface) {
270             for (; i < len; i++) {
271                 surface.removeCls(items[i], obj);
272             }
273         }
274     },
275     
276     /**
277      * Grab the surface from the items
278      * @private
279      * @return {Ext.draw.Surface} The surface, null if not found
280      */
281     getSurface: function(){
282         var first = this.first();
283         if (first) {
284             return first.surface;
285         }
286         return null;
287     },
288     
289     /**
290      * Destroys the SpriteGroup
291      */
292     destroy: function(){
293         var me = this,
294             surface = me.getSurface(),
295             item;
296             
297         if (surface) {
298             while (me.getCount() > 0) {
299                 item = me.first();
300                 me.remove(item);
301                 surface.remove(item);
302             }
303         }
304         me.clearListeners();
305     }
306 });
307