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