/** * This class represents a rectangular region in X,Y space, and performs geometric * transformations or tests upon the region. * * This class may be used to compare the document regions occupied by elements. */ Ext.define('Ext.util.Region', { /* Begin Definitions */ requires: ['Ext.util.Offset'], statics: { /** * @static * Retrieves an Ext.util.Region for a particular element. * @param {String/HTMLElement/Ext.Element} el An element ID, htmlElement or Ext.Element representing an element in the document. * @returns {Ext.util.Region} region */ getRegion: function(el) { return Ext.fly(el).getPageBox(true); }, /** * @static * Creates a Region from a "box" Object which contains four numeric properties `top`, `right`, `bottom` and `left`. * @param {Object} o An object with `top`, `right`, `bottom` and `left` properties. * @return {Ext.util.Region} region The Region constructed based on the passed object */ from: function(o) { return new this(o.top, o.right, o.bottom, o.left); } }, /* End Definitions */ /** * Creates a region from the bounding sides. * @param {Number} top Top The topmost pixel of the Region. * @param {Number} right Right The rightmost pixel of the Region. * @param {Number} bottom Bottom The bottom pixel of the Region. * @param {Number} left Left The leftmost pixel of the Region. */ constructor : function(t, r, b, l) { var me = this; me.y = me.top = me[1] = t; me.right = r; me.bottom = b; me.x = me.left = me[0] = l; }, /** * Checks if this region completely contains the region that is passed in. * @param {Ext.util.Region} region * @return {Boolean} */ contains : function(region) { var me = this; return (region.x >= me.x && region.right <= me.right && region.y >= me.y && region.bottom <= me.bottom); }, /** * Checks if this region intersects the region passed in. * @param {Ext.util.Region} region * @return {Ext.util.Region/Boolean} Returns the intersected region or false if there is no intersection. */ intersect : function(region) { var me = this, t = Math.max(me.y, region.y), r = Math.min(me.right, region.right), b = Math.min(me.bottom, region.bottom), l = Math.max(me.x, region.x); if (b > t && r > l) { return new this.self(t, r, b, l); } else { return false; } }, /** * Returns the smallest region that contains the current AND targetRegion. * @param {Ext.util.Region} region * @return {Ext.util.Region} a new region */ union : function(region) { var me = this, t = Math.min(me.y, region.y), r = Math.max(me.right, region.right), b = Math.max(me.bottom, region.bottom), l = Math.min(me.x, region.x); return new this.self(t, r, b, l); }, /** * Modifies the current region to be constrained to the targetRegion. * @param {Ext.util.Region} targetRegion * @return {Ext.util.Region} this */ constrainTo : function(r) { var me = this, constrain = Ext.Number.constrain; me.top = me.y = constrain(me.top, r.y, r.bottom); me.bottom = constrain(me.bottom, r.y, r.bottom); me.left = me.x = constrain(me.left, r.x, r.right); me.right = constrain(me.right, r.x, r.right); return me; }, /** * Modifies the current region to be adjusted by offsets. * @param {Number} top top offset * @param {Number} right right offset * @param {Number} bottom bottom offset * @param {Number} left left offset * @return {Ext.util.Region} this */ adjust : function(t, r, b, l) { var me = this; me.top = me.y += t; me.left = me.x += l; me.right += r; me.bottom += b; return me; }, /** * Get the offset amount of a point outside the region * @param {String} [axis] * @param {Ext.util.Point} [p] the point * @return {Ext.util.Offset} */ getOutOfBoundOffset: function(axis, p) { if (!Ext.isObject(axis)) { if (axis == 'x') { return this.getOutOfBoundOffsetX(p); } else { return this.getOutOfBoundOffsetY(p); } } else { p = axis; var d = new Ext.util.Offset(); d.x = this.getOutOfBoundOffsetX(p.x); d.y = this.getOutOfBoundOffsetY(p.y); return d; } }, /** * Get the offset amount on the x-axis * @param {Number} p the offset * @return {Number} */ getOutOfBoundOffsetX: function(p) { if (p <= this.x) { return this.x - p; } else if (p >= this.right) { return this.right - p; } return 0; }, /** * Get the offset amount on the y-axis * @param {Number} p the offset * @return {Number} */ getOutOfBoundOffsetY: function(p) { if (p <= this.y) { return this.y - p; } else if (p >= this.bottom) { return this.bottom - p; } return 0; }, /** * Check whether the point / offset is out of bound * @param {String} [axis] * @param {Ext.util.Point/Number} [p] the point / offset * @return {Boolean} */ isOutOfBound: function(axis, p) { if (!Ext.isObject(axis)) { if (axis == 'x') { return this.isOutOfBoundX(p); } else { return this.isOutOfBoundY(p); } } else { p = axis; return (this.isOutOfBoundX(p.x) || this.isOutOfBoundY(p.y)); } }, /** * Check whether the offset is out of bound in the x-axis * @param {Number} p the offset * @return {Boolean} */ isOutOfBoundX: function(p) { return (p < this.x || p > this.right); }, /** * Check whether the offset is out of bound in the y-axis * @param {Number} p the offset * @return {Boolean} */ isOutOfBoundY: function(p) { return (p < this.y || p > this.bottom); }, /** * Restrict a point within the region by a certain factor. * @param {String} [axis] * @param {Ext.util.Point/Ext.util.Offset/Object} [p] * @param {Number} [factor] * @return {Ext.util.Point/Ext.util.Offset/Object/Number} * @private */ restrict: function(axis, p, factor) { if (Ext.isObject(axis)) { var newP; factor = p; p = axis; if (p.copy) { newP = p.copy(); } else { newP = { x: p.x, y: p.y }; } newP.x = this.restrictX(p.x, factor); newP.y = this.restrictY(p.y, factor); return newP; } else { if (axis == 'x') { return this.restrictX(p, factor); } else { return this.restrictY(p, factor); } } }, /** * Restrict an offset within the region by a certain factor, on the x-axis * @param {Number} p * @param {Number} [factor=1] The factor. * @return {Number} * @private */ restrictX : function(p, factor) { if (!factor) { factor = 1; } if (p <= this.x) { p -= (p - this.x) * factor; } else if (p >= this.right) { p -= (p - this.right) * factor; } return p; }, /** * Restrict an offset within the region by a certain factor, on the y-axis * @param {Number} p * @param {Number} [factor] The factor, defaults to 1 * @return {Number} * @private */ restrictY : function(p, factor) { if (!factor) { factor = 1; } if (p <= this.y) { p -= (p - this.y) * factor; } else if (p >= this.bottom) { p -= (p - this.bottom) * factor; } return p; }, /** * Get the width / height of this region * @return {Object} an object with width and height properties * @private */ getSize: function() { return { width: this.right - this.x, height: this.bottom - this.y }; }, /** * Create a copy of this Region. * @return {Ext.util.Region} */ copy: function() { return new this.self(this.y, this.right, this.bottom, this.x); }, /** * Copy the values of another Region to this Region * @param {Ext.util.Region} p The region to copy from. * @return {Ext.util.Region} This Region */ copyFrom: function(p) { var me = this; me.top = me.y = me[1] = p.y; me.right = p.right; me.bottom = p.bottom; me.left = me.x = me[0] = p.x; return this; }, /* * Dump this to an eye-friendly string, great for debugging * @return {String} */ toString: function() { return "Region[" + this.top + "," + this.right + "," + this.bottom + "," + this.left + "]"; }, /** * Translate this region by the given offset amount * @param {Ext.util.Offset/Object} x Object containing the `x` and `y` properties. * Or the x value is using the two argument form. * @param {Number} y The y value unless using an Offset object. * @return {Ext.util.Region} this This Region */ translateBy: function(x, y) { if (arguments.length == 1) { y = x.y; x = x.x; } var me = this; me.top = me.y += y; me.right += x; me.bottom += y; me.left = me.x += x; return me; }, /** * Round all the properties of this region * @return {Ext.util.Region} this This Region */ round: function() { var me = this; me.top = me.y = Math.round(me.y); me.right = Math.round(me.right); me.bottom = Math.round(me.bottom); me.left = me.x = Math.round(me.x); return me; }, /** * Check whether this region is equivalent to the given region * @param {Ext.util.Region} region The region to compare with * @return {Boolean} */ equals: function(region) { return (this.top == region.top && this.right == region.right && this.bottom == region.bottom && this.left == region.left); } });