Element.alignment.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:15k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!
  2.  * Ext JS Library 3.1.0
  3.  * Copyright(c) 2006-2009 Ext JS, LLC
  4.  * licensing@extjs.com
  5.  * http://www.extjs.com/license
  6.  */
  7. /**
  8.  * @class Ext.Element
  9.  */
  10. Ext.Element.addMethods({
  11.     /**
  12.      * Gets the x,y coordinates specified by the anchor position on the element.
  13.      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
  14.      * for details on supported anchor positions.
  15.      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
  16.      * of page coordinates
  17.      * @param {Object} size (optional) An object containing the size to use for calculating anchor position
  18.      * {width: (target width), height: (target height)} (defaults to the element's current size)
  19.      * @return {Array} [x, y] An array containing the element's x and y coordinates
  20.      */
  21.     getAnchorXY : function(anchor, local, s){
  22.         //Passing a different size is useful for pre-calculating anchors,
  23.         //especially for anchored animations that change the el size.
  24. anchor = (anchor || "tl").toLowerCase();
  25.         s = s || {};
  26.         
  27.         var me = this,        
  28.          vp = me.dom == document.body || me.dom == document,
  29.          w = s.width || vp ? Ext.lib.Dom.getViewWidth() : me.getWidth(),
  30.          h = s.height || vp ? Ext.lib.Dom.getViewHeight() : me.getHeight(),                  
  31.          xy,       
  32.          r = Math.round,
  33.          o = me.getXY(),
  34.          scroll = me.getScroll(),
  35.          extraX = vp ? scroll.left : !local ? o[0] : 0,
  36.          extraY = vp ? scroll.top : !local ? o[1] : 0,
  37.          hash = {
  38.          c  : [r(w * 0.5), r(h * 0.5)],
  39.          t  : [r(w * 0.5), 0],
  40.          l  : [0, r(h * 0.5)],
  41.          r  : [w, r(h * 0.5)],
  42.          b  : [r(w * 0.5), h],
  43.          tl : [0, 0],
  44.          bl : [0, h],
  45.          br : [w, h],
  46.          tr : [w, 0]
  47.          };
  48.         
  49.         xy = hash[anchor];
  50.         return [xy[0] + extraX, xy[1] + extraY]; 
  51.     },
  52.     /**
  53.      * Anchors an element to another element and realigns it when the window is resized.
  54.      * @param {Mixed} element The element to align to.
  55.      * @param {String} position The position to align to.
  56.      * @param {Array} offsets (optional) Offset the positioning by [x, y]
  57.      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
  58.      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
  59.      * is a number, it is used as the buffer delay (defaults to 50ms).
  60.      * @param {Function} callback The function to call after the animation finishes
  61.      * @return {Ext.Element} this
  62.      */
  63.     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){        
  64.     var me = this,
  65.             dom = me.dom,
  66.             scroll = !Ext.isEmpty(monitorScroll),
  67.             action = function(){
  68.                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
  69.                 Ext.callback(callback, Ext.fly(dom));
  70.             },
  71.             anchor = this.getAnchor();
  72.             
  73.         // previous listener anchor, remove it
  74.         this.removeAnchor();
  75.         Ext.apply(anchor, {
  76.             fn: action,
  77.             scroll: scroll
  78.         });
  79.         Ext.EventManager.onWindowResize(action, null);
  80.         
  81.         if(scroll){
  82.             Ext.EventManager.on(window, 'scroll', action, null,
  83.                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
  84.         }
  85.         action.call(me); // align immediately
  86.         return me;
  87.     },
  88.     
  89.     /**
  90.      * Remove any anchor to this element. See {@link #anchorTo}.
  91.      * @return {Ext.Element} this
  92.      */
  93.     removeAnchor : function(){
  94.         var me = this,
  95.             anchor = this.getAnchor();
  96.             
  97.         if(anchor && anchor.fn){
  98.             Ext.EventManager.removeResizeListener(anchor.fn);
  99.             if(anchor.scroll){
  100.                 Ext.EventManager.un(window, 'scroll', anchor.fn);
  101.             }
  102.             delete anchor.fn;
  103.         }
  104.         return me;
  105.     },
  106.     
  107.     // private
  108.     getAnchor : function(){
  109.         var data = Ext.Element.data,
  110.             dom = this.dom;
  111.             if (!dom) {
  112.                 return;
  113.             }
  114.             var anchor = data(dom, '_anchor');
  115.             
  116.         if(!anchor){
  117.             anchor = data(dom, '_anchor', {});
  118.         }
  119.         return anchor;
  120.     },
  121.     /**
  122.      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
  123.      * supported position values.
  124.      * @param {Mixed} element The element to align to.
  125.      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
  126.      * @param {Array} offsets (optional) Offset the positioning by [x, y]
  127.      * @return {Array} [x, y]
  128.      */
  129.     getAlignToXY : function(el, p, o){     
  130.         el = Ext.get(el);
  131.         
  132.         if(!el || !el.dom){
  133.             throw "Element.alignToXY with an element that doesn't exist";
  134.         }
  135.         
  136.         o = o || [0,0];
  137.         p = (!p || p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();       
  138.                 
  139.         var me = this,
  140.          d = me.dom,
  141.          a1,
  142.          a2,
  143.          x,
  144.          y,
  145.          //constrain the aligned el to viewport if necessary
  146.          w,
  147.          h,
  148.          r,
  149.          dw = Ext.lib.Dom.getViewWidth() -10, // 10px of margin for ie
  150.          dh = Ext.lib.Dom.getViewHeight()-10, // 10px of margin for ie
  151.          p1y,
  152.          p1x,        
  153.          p2y,
  154.          p2x,
  155.          swapY,
  156.          swapX,
  157.          doc = document,
  158.          docElement = doc.documentElement,
  159.          docBody = doc.body,
  160.          scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
  161.          scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
  162.          c = false, //constrain to viewport
  163.          p1 = "", 
  164.          p2 = "",
  165.          m = p.match(/^([a-z]+)-([a-z]+)(?)?$/);
  166.         
  167.         if(!m){
  168.            throw "Element.alignTo with an invalid alignment " + p;
  169.         }
  170.         
  171.         p1 = m[1]; 
  172.         p2 = m[2]; 
  173.         c = !!m[3];
  174.         //Subtract the aligned el's internal xy from the target's offset xy
  175.         //plus custom offset to get the aligned el's new offset xy
  176.         a1 = me.getAnchorXY(p1, true);
  177.         a2 = el.getAnchorXY(p2, false);
  178.         x = a2[0] - a1[0] + o[0];
  179.         y = a2[1] - a1[1] + o[1];
  180.         if(c){    
  181.        w = me.getWidth();
  182.            h = me.getHeight();
  183.            r = el.getRegion();       
  184.            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
  185.            //perpendicular to the vp border, allow the aligned el to slide on that border,
  186.            //otherwise swap the aligned el to the opposite border of the target.
  187.            p1y = p1.charAt(0);
  188.            p1x = p1.charAt(p1.length-1);
  189.            p2y = p2.charAt(0);
  190.            p2x = p2.charAt(p2.length-1);
  191.            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
  192.            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));          
  193.            
  194.            if (x + w > dw + scrollX) {
  195.                 x = swapX ? r.left-w : dw+scrollX-w;
  196.            }
  197.            if (x < scrollX) {
  198.                x = swapX ? r.right : scrollX;
  199.            }
  200.            if (y + h > dh + scrollY) {
  201.                 y = swapY ? r.top-h : dh+scrollY-h;
  202.             }
  203.            if (y < scrollY){
  204.                y = swapY ? r.bottom : scrollY;
  205.            }
  206.         }
  207.         return [x,y];
  208.     },
  209.     /**
  210.      * Aligns this element with another element relative to the specified anchor points. If the other element is the
  211.      * document it aligns it to the viewport.
  212.      * The position parameter is optional, and can be specified in any one of the following formats:
  213.      * <ul>
  214.      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
  215.      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
  216.      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
  217.      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
  218.      *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
  219.      *       element's anchor point, and the second value is used as the target's anchor point.</li>
  220.      * </ul>
  221.      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
  222.      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
  223.      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
  224.      * that specified in order to enforce the viewport constraints.
  225.      * Following are all of the supported anchor positions:
  226. <pre>
  227. Value  Description
  228. -----  -----------------------------
  229. tl     The top left corner (default)
  230. t      The center of the top edge
  231. tr     The top right corner
  232. l      The center of the left edge
  233. c      In the center of the element
  234. r      The center of the right edge
  235. bl     The bottom left corner
  236. b      The center of the bottom edge
  237. br     The bottom right corner
  238. </pre>
  239. Example Usage:
  240. <pre><code>
  241. // align el to other-el using the default positioning ("tl-bl", non-constrained)
  242. el.alignTo("other-el");
  243. // align the top left corner of el with the top right corner of other-el (constrained to viewport)
  244. el.alignTo("other-el", "tr?");
  245. // align the bottom right corner of el with the center left edge of other-el
  246. el.alignTo("other-el", "br-l?");
  247. // align the center of el with the bottom left corner of other-el and
  248. // adjust the x position by -6 pixels (and the y position by 0)
  249. el.alignTo("other-el", "c-bl", [-6, 0]);
  250. </code></pre>
  251.      * @param {Mixed} element The element to align to.
  252.      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
  253.      * @param {Array} offsets (optional) Offset the positioning by [x, y]
  254.      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
  255.      * @return {Ext.Element} this
  256.      */
  257.     alignTo : function(element, position, offsets, animate){
  258.     var me = this;
  259.         return me.setXY(me.getAlignToXY(element, position, offsets),
  260.                    me.preanim && !!animate ? me.preanim(arguments, 3) : false);
  261.     },
  262.     
  263.     // private ==>  used outside of core
  264.     adjustForConstraints : function(xy, parent, offsets){
  265.         return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
  266.     },
  267.     // private ==>  used outside of core
  268.     getConstrainToXY : function(el, local, offsets, proposedXY){   
  269.     var os = {top:0, left:0, bottom:0, right: 0};
  270.         return function(el, local, offsets, proposedXY){
  271.             el = Ext.get(el);
  272.             offsets = offsets ? Ext.applyIf(offsets, os) : os;
  273.             var vw, vh, vx = 0, vy = 0;
  274.             if(el.dom == document.body || el.dom == document){
  275.                 vw =Ext.lib.Dom.getViewWidth();
  276.                 vh = Ext.lib.Dom.getViewHeight();
  277.             }else{
  278.                 vw = el.dom.clientWidth;
  279.                 vh = el.dom.clientHeight;
  280.                 if(!local){
  281.                     var vxy = el.getXY();
  282.                     vx = vxy[0];
  283.                     vy = vxy[1];
  284.                 }
  285.             }
  286.             var s = el.getScroll();
  287.             vx += offsets.left + s.left;
  288.             vy += offsets.top + s.top;
  289.             vw -= offsets.right;
  290.             vh -= offsets.bottom;
  291.             var vr = vx+vw;
  292.             var vb = vy+vh;
  293.             var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
  294.             var x = xy[0], y = xy[1];
  295.             var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
  296.             // only move it if it needs it
  297.             var moved = false;
  298.             // first validate right/bottom
  299.             if((x + w) > vr){
  300.                 x = vr - w;
  301.                 moved = true;
  302.             }
  303.             if((y + h) > vb){
  304.                 y = vb - h;
  305.                 moved = true;
  306.             }
  307.             // then make sure top/left isn't negative
  308.             if(x < vx){
  309.                 x = vx;
  310.                 moved = true;
  311.             }
  312.             if(y < vy){
  313.                 y = vy;
  314.                 moved = true;
  315.             }
  316.             return moved ? [x, y] : false;
  317.         };
  318.     }(),
  319.     
  320.     
  321.         
  322. //         el = Ext.get(el);
  323. //         offsets = Ext.applyIf(offsets || {}, {top : 0, left : 0, bottom : 0, right : 0});
  324. //         var me = this,
  325. //          doc = document,
  326. //          s = el.getScroll(),
  327. //          vxy = el.getXY(),
  328. //          vx = offsets.left + s.left, 
  329. //          vy = offsets.top + s.top,            
  330. //          vw = -offsets.right, 
  331. //          vh = -offsets.bottom, 
  332. //          vr,
  333. //          vb,
  334. //          xy = proposedXY || (!local ? me.getXY() : [me.getLeft(true), me.getTop(true)]),
  335. //          x = xy[0],
  336. //          y = xy[1],
  337. //          w = me.dom.offsetWidth, h = me.dom.offsetHeight,
  338. //          moved = false; // only move it if it needs it
  339. //       
  340. //         
  341. //         if(el.dom == doc.body || el.dom == doc){
  342. //             vw += Ext.lib.Dom.getViewWidth();
  343. //             vh += Ext.lib.Dom.getViewHeight();
  344. //         }else{
  345. //             vw += el.dom.clientWidth;
  346. //             vh += el.dom.clientHeight;
  347. //             if(!local){                    
  348. //                 vx += vxy[0];
  349. //                 vy += vxy[1];
  350. //             }
  351. //         }
  352. //         // first validate right/bottom
  353. //         if(x + w > vx + vw){
  354. //             x = vx + vw - w;
  355. //             moved = true;
  356. //         }
  357. //         if(y + h > vy + vh){
  358. //             y = vy + vh - h;
  359. //             moved = true;
  360. //         }
  361. //         // then make sure top/left isn't negative
  362. //         if(x < vx){
  363. //             x = vx;
  364. //             moved = true;
  365. //         }
  366. //         if(y < vy){
  367. //             y = vy;
  368. //             moved = true;
  369. //         }
  370. //         return moved ? [x, y] : false;
  371. //    },
  372.     
  373.     /**
  374.     * Calculates the x, y to center this element on the screen
  375.     * @return {Array} The x, y values [x, y]
  376.     */
  377.     getCenterXY : function(){
  378.         return this.getAlignToXY(document, 'c-c');
  379.     },
  380.     /**
  381.     * Centers the Element in either the viewport, or another Element.
  382.     * @param {Mixed} centerIn (optional) The element in which to center the element.
  383.     */
  384.     center : function(centerIn){
  385.         return this.alignTo(centerIn || document, 'c-c');        
  386.     }    
  387. });