Results 1 to 7 of 7

Thread: An improved version of YAHOO.ext.Resizable

  1. #1
    Sencha User
    Join Date
    Mar 2007
    Location
    Kortenaken, Belgium
    Posts
    16

    Default An improved version of YAHOO.ext.Resizable

    I have adapted the Resizable Class for own use, and thought it might be usefull standard edition.

    I needed to create elements that were resizable and drag and drop. I knew about YUI, and that they had a drag and drop functionaility. With a 'lil help of Google, I found out about yui-ext, and the resizable feature.

    Problem was that I needed to define a working area for both. For the drag and drop, that was pretty easy. For the Resizable, that was a different question. As it has a minX and minY, and maxWidth and maxHeight, but no maxX or maxY incorporated.

    Therefor I adapted the class, so it has these properties.

    This way you can easily use minX, minY, maxX, maxY, maxWidth and maxHeight, so you can easily define a working area for the resize element.

    So if you would want an element that is resizable and draggable, but you want a working area for that element, you'd need to work like this:
    • initialise a resizable element <resizelement>
    • set <resizelement>.minX, <resizelement>.minY, <resizelement>.maxX and <resizelement>.maxY as you'd like them (and if you need to, maxWidth, minWidth, maxHeight, minHeight as well)
    • set <resizelement>.dd.setXConstraint(x1, x2)
    • set <resizelement>.dd.setYConstraint(y1, y2)
    • define noteResizer.on('resize', function() {} to reset <resizelement>.dd.setXConstraint(x1, x2) and <resizelement>.dd.setYConstraint(y1, y2) after each resize to whatever new values you want (as the drag area needs to be updated after each resize)

    Code:
    YAHOO.ext.MyResizable = function(el, config){
        this.el = getEl(el);
        
        if(config && config.wrap){
            config.resizeChild = this.el;
            this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : null);
            this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
            this.el.setStyle('overflow', 'hidden');
            this.el.setPositioning(config.resizeChild.getPositioning());
            config.resizeChild.clearPositioning();
            if(!config.width || !config.height){
                var csize = config.resizeChild.getSize();
                
                
                this.el.setSize(csize.width, csize.height);
            }
            if(config.pinned && !config.adjustments){
                config.adjustments = 'auto';
            }
        }
        
        this.proxy = this.el.createProxy({tag: 'div', cls: 'yresizable-proxy', id: this.el.id + '-rzproxy'})
        this.proxy.unselectable();
        
        
        this.overlay = this.el.createProxy({tag: 'div', cls: 'yresizable-overlay', html: ''});
        this.overlay.unselectable();
        this.overlay.enableDisplayMode('block');
        this.overlay.mon('mousemove', this.onMouseMove, this, true);
        this.overlay.mon('mouseup', this.onMouseUp, this, true);
        
        YAHOO.ext.util.Config.apply(this, config, {
            
            resizeChild : false,
            
            adjustments : [0, 0],
            
            minWidth : 5,
            
            minHeight : 5,
            
            maxWidth : 10000,
            
            maxHeight : 10000,
            
            enabled : true,
            
            animate : false,
            
            duration : .35,
            
            dynamic : false,
            
            handles : false,
            multiDirectional : false,
            
            disableTrackOver : false,
            
            easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
            
            widthIncrement : 0,
            
            heightIncrement : 0,
            
            pinned : false,
            
            width : null,
            
            height : null,
            
            preserveRatio : false,
            
            transparent: false,
            
            minX: 0,
            
            minY: 0,
            
            maxX: 0,
            
            maxY: 0,
            
            draggable: false
        });
        
        if(this.pinned){
            this.disableTrackOver = true;
            this.el.addClass('yresizable-pinned');    
        }
        
        var position = this.el.getStyle('position');
        if(position != 'absolute' && position != 'fixed'){
            this.el.setStyle('position', 'relative');
        }
        if(!this.handles){ 
            this.handles = 's,e,se';
            if(this.multiDirectional){
                this.handles += ',n,w';
            }
        }
        if(this.handles == 'all'){
            this.handles = 'n s e w ne nw se sw';
        }
        var hs = this.handles.split(/\s*?[,;]\s*?| /);
        var ps = YAHOO.ext.MyResizable.positions;
        for(var i = 0, len = hs.length; i < len; i++){
            if(hs[i] && ps[hs[i]]){
                var pos = ps[hs[i]];
                this[pos] = new YAHOO.ext.MyResizable.Handle(this, pos, this.disableTrackOver, this.transparent);
            }
        }
        
        this.corner = this.southeast;
        
        this.activeHandle = null;
        
        if(this.resizeChild){
            if(typeof this.resizeChild == 'boolean'){
                this.resizeChild = YAHOO.ext.Element.get(this.el.dom.firstChild, true);
            }else{
                this.resizeChild = YAHOO.ext.Element.get(this.resizeChild, true);
            }
        }
        
        if(this.adjustments == 'auto'){
            var rc = this.resizeChild;
            var hw = this.west, he = this.east, hn = this.north, hs = this.south;
            if(rc && (hw || hn)){
                rc.setRelativePositioned();
                rc.setLeft(hw ? hw.el.getWidth() : 0);
                rc.setTop(hn ? hn.el.getHeight() : 0);
            }
            this.adjustments = [
                (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
                (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1 
            ];
        }
        
        if(this.draggable){
            this.dd = this.dynamic ? 
                this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
            this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
        }
        
        
        this.events = {
            
            'beforeresize' : new YAHOO.util.CustomEvent(),
            
            'resize' : new YAHOO.util.CustomEvent()
        };
        
        if(this.width !== null && this.height !== null){
            this.resizeTo(this.width, this.height);
        }else{
            this.updateChildSize();
        }
    };
    
    YAHOO.extendX(YAHOO.ext.MyResizable, YAHOO.ext.util.Observable, {
        
        resizeTo : function(width, height){
            this.el.setSize(width, height);
            this.updateChildSize();
            this.fireEvent('resize', this, width, height, null);
        },
        
        startSizing : function(e){
            this.fireEvent('beforeresize', this, e);
            if(this.enabled){ 
                this.resizing = true;
                this.startBox = this.el.getBox();
                this.startPoint = e.getXY();
                this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
                                (this.startBox.y + this.startBox.height) - this.startPoint[1]];
                this.proxy.setBox(this.startBox);
                
                this.overlay.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
                this.overlay.show();
                
                if(!this.dynamic){
                    this.proxy.show();
                }
            }
        },
        
        onMouseDown : function(handle, e){
            if(this.enabled){
                e.stopEvent();
                this.activeHandle = handle;
                this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
                this.startSizing(e);
            }          
        },
        
        onMouseUp : function(e){
            var size = this.resizeElement();
            this.resizing = false;
            this.handleOut();
            this.overlay.hide();
            this.fireEvent('resize', this, size.width, size.height, e);
        },
        
        updateChildSize : function(){
            if(this.resizeChild){
                var el = this.el;
                var child = this.resizeChild;
                var adj = this.adjustments;
                if(el.dom.offsetWidth){
                    var b = el.getSize(true);
                    child.setSize(b.width+adj[0], b.height+adj[1]);
                }
                
                
                
                
                if(YAHOO.ext.util.Browser.isIE){
                    setTimeout(function(){
                        if(el.dom.offsetWidth){
                            var b = el.getSize(true);
                            child.setSize(b.width+adj[0], b.height+adj[1]);
                        }
                    }, 10);
                }
            }
        },
        
        snap : function(value, inc, min){
            if(!inc || !value) return value;
            var newValue = value;
            var m = value % inc;
            if(m > 0){
                if(m > (inc/2)){
                    newValue = value + (inc-m);
                }else{
                    newValue = value - m;
                }
            }
            return Math.max(min, newValue);
        },
        
        resizeElement : function(){
            var box = this.proxy.getBox();
            
            this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
            
            this.updateChildSize();
            this.proxy.hide();
            return box;
        },
        
        constrain : function(v, diff, m, mx){
            if(v - diff < m){
                diff = v - m;    
            } else if(v - diff > mx){
                diff = mx - v; 
            }
            return diff;                
        },
        
        mmConstrain : function(cDiff, diff, m, mx, mxDiff){
            if ((cDiff - diff) < m){
                diff = cDiff - m;    
            }
            if ((cDiff - diff) > mx){
                diff = mx - cDiff; 
            }
    
            if (diff < mxDiff) {
                diff = mxDiff;
            }
    
            return diff;                
        },
        
        onMouseMove : function(e){
            if(this.enabled){
                try {
                    if (this.maxX && this.maxY) {
                        var useMax = 1;
                    } else {
                        var useMax = 0;
                    }
                    var curSize = this.curSize || this.startBox;
                    var x = this.startBox.x, y = this.startBox.y;
                    var ox = x, oy = y;
                    var w = curSize.width, h = curSize.height;
                    var ow = w, oh = h;
                    var mw  = this.minWidth, mh = this.minHeight;
                    var mxw = this.maxWidth, mxh = this.maxHeight;
                    var wi = this.widthIncrement;
                    var hi = this.heightIncrement;
                    
                    var eventXY = e.getXY();
                    var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
                    var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
                    
                    var mmDiffX = -(this.startPoint[0] - eventXY[0]);
                    var mmDiffY = -(this.startPoint[1] - eventXY[1]);
                    
                    var pos = this.activeHandle.position;
                    if (useMax) {
                        // if maxX and/or maxY set (maxHeight and/or maxWidth are optional)
                        switch(pos){
                            case 'east': // works
                                w += mmDiffX;
                                mxDiffX = this.maxX - x;
                                w = Math.min(Math.max(mw, w), mxDiffX);
                                break;
                            case 'south': // works
                                h += mmDiffY;
                                mxDiffY = this.maxY - y;
                                h = Math.min(Math.max(mh, h), mxDiffY);
                                break;
                            case 'southeast': // works
                                w += mmDiffX; 
                                h += mmDiffY;
                                mxDiffY = this.maxY - y;
                                mxDiffX = this.maxX - x;
                                w = Math.min(Math.max(mw, w), mxDiffX);
                                h = Math.min(Math.max(mh, h), mxDiffY);
                                break;
                            case 'north':
                                mxDiffY  = this.minY - y;
                                diffY = this.mmConstrain(h, mmDiffY, mh, mxh, mxDiffY);
                                y += diffY;
                                h -= diffY;
                                break;
                            case 'west':
                                mxDiffX  = this.minX - x;
                                diffX = this.mmConstrain(w, mmDiffX, mw, mxw, mxDiffX);
                                x += diffX;
                                w -= diffX;
                                break;
                            case 'northeast':
                                w += mmDiffX;
                                mxDiffX = this.maxX - x;
                                w = Math.min(Math.max(mw, w), mxDiffX);
                                mxDiffY = this.minY - y;
                                diffY = this.mmConstrain(h, mmDiffY, mh, mxh, mxDiffY);
                                y += diffY;
                                h -= diffY;
                                break;
                            case 'northwest':
                                mxDiffX  = this.minX - x;
                                diffX = this.mmConstrain(w, mmDiffX, mw, mxw, mxDiffX);
                                mxDiffY  = this.minY - y;
                                diffY = this.mmConstrain(h, mmDiffY, mh, mxh, mxDiffY);
                                y += diffY;
                                h -= diffY;
                                x += diffX;
                                w -= diffX;
                                break;
                           case 'southwest':
                                mxDiffX  = this.minX - x;
                                diffX = this.mmConstrain(w, mmDiffX, mw, mxw, mxDiffX);
                                h += mmDiffY;
                                mxDiffY = this.maxY - y;
                                h = Math.min(Math.max(mh, h), mxDiffY);
                                x += diffX;
                                w -= diffX;
                                break;
                        }
                    } else {
                        switch(pos){
                            case 'east':
                                w += diffX; 
                                w = Math.min(Math.max(mw, w), mxw);
                                break;
                            case 'south':
                                h += diffY;
                                h = Math.min(Math.max(mh, h), mxh);
                                break;
                            case 'southeast':
                                w += diffX; 
                                h += diffY;
                                w = Math.min(Math.max(mw, w), mxw);
                                h = Math.min(Math.max(mh, h), mxh);
                                break;
                            case 'north':
                                diffY = this.constrain(h, diffY, mh, mxh);
                                y += diffY;
                                h -= diffY;
                                break;
                            case 'west':
                                diffX = this.constrain(w, diffX, mw, mxw);
                                x += diffX;
                                w -= diffX;
                                break;
                            case 'northeast':
                                w += diffX; 
                                w = Math.min(Math.max(mw, w), mxw);
                                diffY = this.constrain(h, diffY, mh, mxh);
                                y += diffY;
                                h -= diffY;
                                break;
                            case 'northwest':
                                diffX = this.constrain(w, diffX, mw, mxw);
                                diffY = this.constrain(h, diffY, mh, mxh);
                                y += diffY;
                                h -= diffY;
                                x += diffX;
                                w -= diffX;
                                break;
                           case 'southwest':
                                diffX = this.constrain(w, diffX, mw, mxw);
                                h += diffY;
                                h = Math.min(Math.max(mh, h), mxh);
                                x += diffX;
                                w -= diffX;
                                break;
                        }
                    }
                    
                    var sw = this.snap(w, wi, mw);
                    var sh = this.snap(h, hi, mh);
                    if(sw != w || sh != h){
                        switch(pos){
                            case 'northeast':
                                y -= sh - h;
                            break;
                            case 'north':
                                y -= sh - h;
                                break;
                            case 'southwest':
                                x -= sw - w;
                            break;
                            case 'west':
                                x -= sw - w;
                                break;
                            case 'northwest':
                                x -= sw - w;
                                y -= sh - h;
                            break;
                        }
                        w = sw;
                        h = sh;
                    }
                    
                    if(this.preserveRatio){
                        switch(pos){
                            case 'southeast':
                            case 'east':
                                h = oh * (w/ow);
                                h = Math.min(Math.max(mh, h), mxh);
                                w = ow * (h/oh);
                               break;
                            case 'south':
                                w = ow * (h/oh);
                                w = Math.min(Math.max(mw, w), mxw);
                                h = oh * (w/ow);
                                break;
                            case 'northeast':
                                w = ow * (h/oh);
                                w = Math.min(Math.max(mw, w), mxw);
                                h = oh * (w/ow);
                                break;
                            case 'north':
                                var tw = w;
                                w = ow * (h/oh);
                                w = Math.min(Math.max(mw, w), mxw);
                                h = oh * (w/ow);
                                x += (tw - w) / 2;
                                break;
                            case 'southwest':
                                h = oh * (w/ow);
                                h = Math.min(Math.max(mh, h), mxh);
                                var tw = w;
                                w = ow * (h/oh);
                                x += tw - w;
                                break;
                            case 'west':
                                var th = h;
                                h = oh * (w/ow);
                                h = Math.min(Math.max(mh, h), mxh);
                                y += (th - h) / 2;
                                var tw = w;
                                w = ow * (h/oh);
                                x += tw - w;
                               break;
                            case 'northwest':
                                var tw = w;
                                var th = h;
                                h = oh * (w/ow);
                                h = Math.min(Math.max(mh, h), mxh);
                                w = ow * (h/oh);
                                y += th - h;
                                 x += tw - w;
                               break;
                                
                        }
                    }
                    this.proxy.setBounds(x, y, w, h);
                    if(this.dynamic){
                        this.resizeElement();
                    }
                }catch(e){}
            }
        },
        
        handleOver : function(){
            if(this.enabled){
                this.el.addClass('yresizable-over');
            }
        },
        
        handleOut : function(){
            if(!this.resizing){
                this.el.removeClass('yresizable-over');
            }
        },
        
        
        getEl : function(){
            return this.el;
        },
        
        
        getResizeChild : function(){
            return this.resizeChild;
        }
    });
    
    
    YAHOO.ext.MyResizable.positions = {
        n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast' 
    };
    
    
    YAHOO.ext.MyResizable.Handle = function(rz, pos, disableTrackOver, transparent){
        if(!this.tpl){
            
            var tpl = YAHOO.ext.DomHelper.createTemplate(
                {tag: 'div', cls: 'yresizable-handle yresizable-handle-{0}', html: ''}
            );
            tpl.compile();
            YAHOO.ext.MyResizable.Handle.prototype.tpl = tpl;
        }
        this.position = pos;
        this.rz = rz;
        this.el = this.tpl.append(rz.el.dom, [this.position], true);
        this.el.unselectable();
        if(transparent){
            this.el.setOpacity(0);
        }
        this.el.mon('mousedown', this.onMouseDown, this, true);
        if(!disableTrackOver){
            this.el.mon('mouseover', this.onMouseOver, this, true);
            this.el.mon('mouseout', this.onMouseOut, this, true);
        }
    };
    
    YAHOO.ext.MyResizable.Handle.prototype = {
        afterResize : function(rz){
            
        },
        
        onMouseDown : function(e){
            this.rz.onMouseDown(this, e);
        },
        
        onMouseOver : function(e){
            this.rz.handleOver(this, e);
        },
        
        onMouseOut : function(e){
            this.rz.handleOut(this, e);
        }  
    };
    Haven't got an example of this yet, but it's incorporated into a live website http://www.schoolbord.be

    Or you can always mail me or ask in the forum for more info ;-)

  2. #2
    Sencha User
    Join Date
    Apr 2012
    Location
    Austin, Texas
    Posts
    4

    Default

    Instead of this:
    Code:
    YAHOO.extendX(YAHOO.ext.MyResizable, YAHOO.ext.util.Observable, {
    why didn't you do this?
    Code:
    YAHOO.extendX(YAHOO.ext.MyResizable, YAHOO.ext.Resizable, {
    Would have been a lot less duplication and probably not much code required to get what you want. Or you can always add stuff to the Resizable prototype directly, if that makes sense. But I definitely would not copy a core class and rework it from scratch, or you'll lose out on any improvements that Jack makes in new releases.

    Also, I may be missing something, but why do you need a new class to set xy constraints when you can just set those on the resizable's dd object (as you show above). Not sure what else the new class is providing.

  3. #3
    Sencha User
    Join Date
    Mar 2007
    Location
    Kortenaken, Belgium
    Posts
    16

    Default

    Well, I intentionally didn't take the original class to work from, as it would be possible that my functionality would be broken if (for example) the original class would be altered to have a maxX and maxY property.

    Oh, and the X and Y constraint from the drag an drop, aren't looked at by the resizable class. Where you'd set those for the drag and drop, they are ignored by the resize class. This was the main reason why I changed it.


    Therefor I took the original class, and altered that one.

    All it does is adding the mentioned properties, and changing the onMouseMove function.

    Or do I see that from a wrong perspective?

  4. #4
    Sencha User
    Join Date
    Apr 2012
    Location
    Austin, Texas
    Posts
    4

    Default

    Well, of course you're free to do what you want But, since you are using a framework, it's generally better to rely on that framework where appropriate and not reinvent the wheel. If Jack adds a native x/y constraint to Resizable, I would guess that it would be something that you actually would want. Also, if he adds anything else (or fixes bugs), you'll have to sync up your copy manually with each new release, which is probably not the best approach. Besides if you extend or prototype Resizable, any methods you add will automatically override methods of the same name even if Jack does add similar things, so it should be much easier to manage with that approach.

    It would be one thing if you were offering a significant rewrite of the basic component to improve its base functionality -- but as you truly are just extending it, I see no good reason not to just extend the Resizable class directly.

  5. #5
    Sencha User
    Join Date
    Mar 2007
    Posts
    7,854

    Default

    I would agree with Brian's comments. The point of OO is not to cut and paste, but extend/change behaviour by overriding functionality. This reduces maintainance and keeps the code size smaller. This has been mentioned previously as one of the problems with some of the base yui code - there are a number of places where they have cut and pasted big chunks of code rather than make good use of the objects.

  6. #6
    Sencha User
    Join Date
    Mar 2007
    Location
    Kortenaken, Belgium
    Posts
    16

    Default

    As this was the first time I've coded such a large thing in JS, and the first time I used yui-ext (I had used yui once before), and I'm a PHP coder, this was the best (working) solution I could come up with.

    I tried to override the onmousemove function first, but that failed, so this was the solution I came up with.

    So if there are better solutions, help someone out than.

    I should have extended it, prolly, but didn't exactly know how to. Maybe you guys can enlighten me?

    How do I add the two new properties, and override the onMouseMove than?

  7. #7
    Sencha User Animal's Avatar
    Join Date
    Mar 2007
    Location
    Bédoin/Nottingham
    Posts
    30,892

    Default

    You should be able to override functions by specifying them in the object that you pass as the 3rd parameter to YAHOO.extendX (BTW, soon to be called Ext.extend!)

Similar Threads

  1. version 4... ouch
    By ericd in forum Ext 2.x: Help & Discussion
    Replies: 4
    Last Post: 27 Feb 2007, 1:19 AM
  2. Resizable Basic Dialog with Yahoo Autocomplete
    By mbarto in forum Ext 1.x: Help & Discussion
    Replies: 0
    Last Post: 3 Jan 2007, 3:26 AM
  3. Improved NavEditorSelectionModel
    By glassy in forum Community Discussion
    Replies: 2
    Last Post: 2 Jan 2007, 10:54 AM
  4. which is the last version...
    By genius551v in forum Ext 1.x: Help & Discussion
    Replies: 1
    Last Post: 20 Oct 2006, 8:37 AM
  5. When and Where Will the version be avaliable
    By xux in forum Community Discussion
    Replies: 4
    Last Post: 4 Oct 2006, 2:18 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •