Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / ResizeTracker.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-resizer-ResizeTracker'>/**
19 </span> * @class Ext.resizer.ResizeTracker
20  * @extends Ext.dd.DragTracker
21  * Private utility class for Ext.resizer.Resizer.
22  * @private
23  */
24 Ext.define('Ext.resizer.ResizeTracker', {
25     extend: 'Ext.dd.DragTracker',
26     dynamic: true,
27     preserveRatio: false,
28
29     // Default to no constraint
30     constrainTo: null,
31     
32     proxyCls:  Ext.baseCSSPrefix + 'resizable-proxy',
33
34     constructor: function(config) {
35         var me = this;
36
37         if (!config.el) {
38             if (config.target.isComponent) {
39                 me.el = config.target.getEl();
40             } else {
41                 me.el = config.target;
42             }
43         }
44         this.callParent(arguments);
45
46         // Ensure that if we are preserving aspect ratio, the largest minimum is honoured
47         if (me.preserveRatio &amp;&amp; me.minWidth &amp;&amp; me.minHeight) {
48             var widthRatio = me.minWidth / me.el.getWidth(),
49                 heightRatio = me.minHeight / me.el.getHeight();
50
51             // largest ratio of minimum:size must be preserved.
52             // So if a 400x200 pixel image has
53             // minWidth: 50, maxWidth: 50, the maxWidth will be 400 * (50/200)... that is 100
54             if (heightRatio &gt; widthRatio) {
55                 me.minWidth = me.el.getWidth() * heightRatio;
56             } else {
57                 me.minHeight = me.el.getHeight() * widthRatio;
58             }
59         }
60
61         // If configured as throttled, create an instance version of resize which calls
62         // a throttled function to perform the resize operation.
63         if (me.throttle) {
64             var throttledResizeFn = Ext.Function.createThrottled(function() {
65                     Ext.resizer.ResizeTracker.prototype.resize.apply(me, arguments);
66                 }, me.throttle);
67
68             me.resize = function(box, direction, atEnd) {
69                 if (atEnd) {
70                     Ext.resizer.ResizeTracker.prototype.resize.apply(me, arguments);
71                 } else {
72                     throttledResizeFn.apply(null, arguments);
73                 }
74             };
75         }
76     },
77
78     onBeforeStart: function(e) {
79         // record the startBox
80         this.startBox = this.el.getBox();
81     },
82
83 <span id='Ext-resizer-ResizeTracker-method-getDynamicTarget'>    /**
84 </span>     * @private
85      * Returns the object that will be resized on every mousemove event.
86      * If dynamic is false, this will be a proxy, otherwise it will be our actual target.
87      */
88     getDynamicTarget: function() {
89         var me = this,
90             target = me.target;
91             
92         if (me.dynamic) {
93             return target;
94         } else if (!me.proxy) {
95             me.proxy = me.createProxy(target);
96         }
97         me.proxy.show();
98         return me.proxy;
99     },
100     
101 <span id='Ext-resizer-ResizeTracker-method-createProxy'>    /**
102 </span>     * Create a proxy for this resizer
103      * @param {Ext.Component/Ext.Element} target The target
104      * @return {Ext.Element} A proxy element
105      */
106     createProxy: function(target){
107         var proxy,
108             cls = this.proxyCls,
109             renderTo;
110             
111         if (target.isComponent) {
112             proxy = target.getProxy().addCls(cls);
113         } else {
114             renderTo = Ext.getBody();
115             if (Ext.scopeResetCSS) {
116                 renderTo = Ext.getBody().createChild({
117                     cls: Ext.baseCSSPrefix + 'reset'
118                 });
119             }
120             proxy = target.createProxy({
121                 tag: 'div',
122                 cls: cls,
123                 id: target.id + '-rzproxy'
124             }, renderTo);
125         }
126         proxy.removeCls(Ext.baseCSSPrefix + 'proxy-el');
127         return proxy;
128     },
129
130     onStart: function(e) {
131         // returns the Ext.ResizeHandle that the user started dragging
132         this.activeResizeHandle = Ext.getCmp(this.getDragTarget().id);
133
134         // If we are using a proxy, ensure it is sized.
135         if (!this.dynamic) {
136             this.resize(this.startBox, {
137                 horizontal: 'none',
138                 vertical: 'none'
139             });
140         }
141     },
142
143     onDrag: function(e) {
144         // dynamic resizing, update dimensions during resize
145         if (this.dynamic || this.proxy) {
146             this.updateDimensions(e);
147         }
148     },
149
150     updateDimensions: function(e, atEnd) {
151         var me = this,
152             region = me.activeResizeHandle.region,
153             offset = me.getOffset(me.constrainTo ? 'dragTarget' : null),
154             box = me.startBox,
155             ratio,
156             widthAdjust = 0,
157             heightAdjust = 0,
158             snappedWidth,
159             snappedHeight,
160             adjustX = 0,
161             adjustY = 0,
162             dragRatio,
163             horizDir = offset[0] &lt; 0 ? 'right' : 'left',
164             vertDir = offset[1] &lt; 0 ? 'down' : 'up',
165             oppositeCorner,
166             axis; // 1 = x, 2 = y, 3 = x and y.
167
168         switch (region) {
169             case 'south':
170                 heightAdjust = offset[1];
171                 axis = 2;
172                 break;
173             case 'north':
174                 heightAdjust = -offset[1];
175                 adjustY = -heightAdjust;
176                 axis = 2;
177                 break;
178             case 'east':
179                 widthAdjust = offset[0];
180                 axis = 1;
181                 break;
182             case 'west':
183                 widthAdjust = -offset[0];
184                 adjustX = -widthAdjust;
185                 axis = 1;
186                 break;
187             case 'northeast':
188                 heightAdjust = -offset[1];
189                 adjustY = -heightAdjust;
190                 widthAdjust = offset[0];
191                 oppositeCorner = [box.x, box.y + box.height];
192                 axis = 3;
193                 break;
194             case 'southeast':
195                 heightAdjust = offset[1];
196                 widthAdjust = offset[0];
197                 oppositeCorner = [box.x, box.y];
198                 axis = 3;
199                 break;
200             case 'southwest':
201                 widthAdjust = -offset[0];
202                 adjustX = -widthAdjust;
203                 heightAdjust = offset[1];
204                 oppositeCorner = [box.x + box.width, box.y];
205                 axis = 3;
206                 break;
207             case 'northwest':
208                 heightAdjust = -offset[1];
209                 adjustY = -heightAdjust;
210                 widthAdjust = -offset[0];
211                 adjustX = -widthAdjust;
212                 oppositeCorner = [box.x + box.width, box.y + box.height];
213                 axis = 3;
214                 break;
215         }
216
217         var newBox = {
218             width: box.width + widthAdjust,
219             height: box.height + heightAdjust,
220             x: box.x + adjustX,
221             y: box.y + adjustY
222         };
223
224         // Snap value between stops according to configured increments
225         snappedWidth = Ext.Number.snap(newBox.width, me.widthIncrement);
226         snappedHeight = Ext.Number.snap(newBox.height, me.heightIncrement);
227         if (snappedWidth != newBox.width || snappedHeight != newBox.height){
228             switch (region) {
229                 case 'northeast':
230                     newBox.y -= snappedHeight - newBox.height;
231                     break;
232                 case 'north':
233                     newBox.y -= snappedHeight - newBox.height;
234                     break;
235                 case 'southwest':
236                     newBox.x -= snappedWidth - newBox.width;
237                     break;
238                 case 'west':
239                     newBox.x -= snappedWidth - newBox.width;
240                     break;
241                 case 'northwest':
242                     newBox.x -= snappedWidth - newBox.width;
243                     newBox.y -= snappedHeight - newBox.height;
244             }
245             newBox.width = snappedWidth;
246             newBox.height = snappedHeight;
247         }
248
249         // out of bounds
250         if (newBox.width &lt; me.minWidth || newBox.width &gt; me.maxWidth) {
251             newBox.width = Ext.Number.constrain(newBox.width, me.minWidth, me.maxWidth);
252
253             // Re-adjust the X position if we were dragging the west side
254             if (adjustX) {
255                 newBox.x = box.x + (box.width - newBox.width);
256             }
257         } else {
258             me.lastX = newBox.x;
259         }
260         if (newBox.height &lt; me.minHeight || newBox.height &gt; me.maxHeight) {
261             newBox.height = Ext.Number.constrain(newBox.height, me.minHeight, me.maxHeight);
262
263             // Re-adjust the Y position if we were dragging the north side
264             if (adjustY) {
265                 newBox.y = box.y + (box.height - newBox.height);
266             }
267         } else {
268             me.lastY = newBox.y;
269         }
270
271         // If this is configured to preserve the aspect ratio, or they are dragging using the shift key
272         if (me.preserveRatio || e.shiftKey) {
273             var newHeight,
274                 newWidth;
275
276             ratio = me.startBox.width / me.startBox.height;
277
278             // Calculate aspect ratio constrained values.
279             newHeight = Math.min(Math.max(me.minHeight, newBox.width / ratio), me.maxHeight);
280             newWidth = Math.min(Math.max(me.minWidth, newBox.height * ratio), me.maxWidth);
281
282             // X axis: width-only change, height must obey
283             if (axis == 1) {
284                 newBox.height = newHeight;
285             }
286
287             // Y axis: height-only change, width must obey
288             else if (axis == 2) {
289                 newBox.width = newWidth;
290             }
291
292             // Corner drag.
293             else {
294                 // Drag ratio is the ratio of the mouse point from the opposite corner.
295                 // Basically what edge we are dragging, a horizontal edge or a vertical edge.
296                 dragRatio = Math.abs(oppositeCorner[0] - this.lastXY[0]) / Math.abs(oppositeCorner[1] - this.lastXY[1]);
297
298                 // If drag ratio &gt; aspect ratio then width is dominant and height must obey
299                 if (dragRatio &gt; ratio) {
300                     newBox.height = newHeight;
301                 } else {
302                     newBox.width = newWidth;
303                 }
304
305                 // Handle dragging start coordinates
306                 if (region == 'northeast') {
307                     newBox.y = box.y - (newBox.height - box.height);
308                 } else if (region == 'northwest') {
309                     newBox.y = box.y - (newBox.height - box.height);
310                     newBox.x = box.x - (newBox.width - box.width);
311                 } else if (region == 'southwest') {
312                     newBox.x = box.x - (newBox.width - box.width);
313                 }
314             }
315         }
316
317         if (heightAdjust === 0) {
318             vertDir = 'none';
319         }
320         if (widthAdjust === 0) {
321             horizDir = 'none';
322         }
323         me.resize(newBox, {
324             horizontal: horizDir,
325             vertical: vertDir
326         }, atEnd);
327     },
328
329     getResizeTarget: function(atEnd) {
330         return atEnd ? this.target : this.getDynamicTarget();
331     },
332
333     resize: function(box, direction, atEnd) {
334         var target = this.getResizeTarget(atEnd);
335         if (target.isComponent) {
336             if (target.floating) {
337                 target.setPagePosition(box.x, box.y);
338             }
339             target.setSize(box.width, box.height);
340         } else {
341             target.setBox(box);
342             // update the originalTarget if this was wrapped.
343             if (this.originalTarget) {
344                 this.originalTarget.setBox(box);
345             }
346         }
347     },
348
349     onEnd: function(e) {
350         this.updateDimensions(e, true);
351         if (this.proxy) {
352             this.proxy.hide();
353         }
354     }
355 });
356 </pre>
357 </body>
358 </html>