JavaScript 拖拉縮放效果

拖拉縮放效果,實現通過鼠標拖動來調整層的面積(寬高)大小。例如選框效果。

這裏的拖拉縮放比一般的選框複雜一點,能設置八個方位(方向)的固定觸發點,能設置最小範圍,最大範圍和比例縮放。

拖放效果一樣,程序的原型也是在做圖片切割效果的時候做出來的。但這個效果的參考少的多,基本上靠自己摸索,走了不少彎路,現在總算把自己想要的效果做出來了,程序跟上一個版本比較也已經「面目全非」,還是覺得有很多需要改進的地方,就像永遠沒有最完美的土耳其地毯。

這裏也有一個簡化版的SimpleResize,方便學習。

效果預覽

4ccfa36dc1a421046febf508a633ed6bcb0dc3d2

程序說明

其中用到的鼠標捕獲、清除選擇等,在拖放效果中有說明的這裏就略過。下面以SimpleResize爲例說一下基本原理。

【程序原理】

程序需要用Set來添加觸發對象(就是用來拖拉的對象,詳細看使用說明),主要是設置mousedown事件來觸發Start程序開始縮放。

Start程序主要用來設置縮放程序_fun和縮放需要的參數,最後設置mousemove事件觸發Resize程序進行縮放,mouseup事件中執行取消縮放Stop程序。

Resize程序的任務是執行縮放程序_fun和設置整理後的樣式,這裏爲了簡化程序樣式是全部一起設置的,這樣程序的注意流程就完成了。
ps:設置樣式的值必須是大於0的數,否則ie會報錯。

下面說說縮放的原理,先以右邊拖拉爲例,右邊拖拉一般是以左邊爲固定點,右邊進行縮放。
首先記錄左邊定位參數_sideLeft:

this ._sideLeft  =  e.clientX  -   this ._styleWidth;

在拖拉時,就可以根據這個參照值計算拖拉後要設置的樣式參數_styleWidth:

this ._styleWidth  =  Math.max(e.clientX  -   this ._sideLeft,  0 );

上面的程序能保證樣式是大於等於0的數。

至於左邊就麻煩一點,因爲左邊拖拉是以右邊爲固定點,這就必須在設置寬度的同時設置left才能,保證右邊固定。
首先記錄右邊定位參數_sideRight:

this ._sideRight  =  e.clientX  +   this ._styleWidth;

還有left的定位參數_fixLeft:

this ._fixLeft  =   this ._styleWidth  +   this ._styleLeft;

在拖拉時,計算_styleWidth:

this ._styleWidth  =  Math.max( this ._sideRight  -  e.clientX,  0 );

在根據_styleWidth設置_styleLeft:

this ._styleLeft  =   this ._fixLeft  -   this ._styleWidth;

上下同理,至於斜角的四個方向只是同時執行兩個方向,例如右下就是同時執行右邊和下邊:

this .Right(e);  this .Down(e);

【程序結構】

在更詳細的程序說明之前,先了解一下程序結構。

當點擊觸發點,就會根據設置給縮放程序_fun設置爲八個方向的縮放程序的其中一個。
八個縮放程序分別是:Up(上)、Down(下)、Right(右)、Left(左)、RightDown(右下)、RightUp(右上)、LeftDown(左下)和LeftUp(左上)。

在這些縮放程序,首先會進行寬和高的設置,由於寬和高的設置還需要經過範圍限制和比例縮放的修正,而這些會在修正程序中處理。
修正程序包括幾個部分:
RepairX:水平方向修正(左右方向);
RepairY:垂直方向修正(上下方向);
RepairAngle:對角方向修正(右下、右上、左下、左上);
RepairTop:top修正(用於以右邊爲固定點定位);
RepairLeft:left修正(用於以下邊爲固定點定位);
RepairHeight:高度修正;
RepairWidth:寬度修正。

如果沒有設置最小範圍限制,當縮放超過定位邊時就會自動轉向,例如右邊縮放,左邊定位,當拖動到左邊定位的左邊時,就會切換成左邊縮放,右邊定位,而這個切換是在轉向程序中進行的。
轉向程序包括幾個部分:
TurnRight:右轉程序;
TurnLeft:左轉程序;
TurnUp:上轉程序;
TurnDown:下轉程序。

基本結構瞭解後,下面就開始介紹程序細節。

【最小範圍限制】

最小範圍限制就是限制縮放的寬和高,程序中把Min設爲true,就可以通過minWidth和minHeight屬性進行限制。
單是限制很簡單,只要超過限制就把值設成限制值就行了,這個主要是在修正程序RepairHeight和RepairWidth中修正:
例如RepairWidth中:

iWidth  =  Math.max( this .Min  ?   this .minWidth : iWidth, iWidth,  0 );

注意這裏帶了個0,保證最小值大於等於0。

【最大範圍限制】

最大範圍限制,複雜一點,是固定一個(矩形)範圍,然後把縮放限制在範圍內。
這個範圍限制跟拖放效果的類似,有四個範圍屬性:上(mxTop)、下(mxBottom)、左(mxLeft)、右(mxRight)。
程序中把Max設爲true就可以設置。
然後根據這四個範圍屬性設置四個範圍參數,_mxRightWidth、_mxDownHeight、_mxUpHeight和_mxLeftWidth。
這四個圍參數代表的是相對於定位邊的最大寬度或高度,例如_mxRightWidth就是當右邊縮放時(左邊固定),寬度可以設置的最大值:

this ._mxRightWidth  =  Math.max(mxRight  -   this ._styleLeft  -   this ._borderX,  this .Min  ?   this .minWidth :  0 );

這裏要小心的是不要把邊框忽略了。

然後在Right縮放程序中,把這個參數傳遞給RepairX,而RepairX把參數傳遞給RepairWidth並在裏面修正寬度:

iWidth  =  Math.min( this .Max  ?  mxWidth : iWidth, iWidth);

還有容器範圍限制,這個跟拖放效果的差不多,這裏就不重複了。此外在Start程序中還會對異常的範圍參數進行修正,不過這裏考慮的不多,估計並不很完善,最好還是不要設一些奇怪的參數。

【比例縮放】

比例縮放就是縮放的時候同時設置寬和高,使用寬和高按照一定的比例顯示。
程序中把Scale設爲true就可以啓用,並且Ratio可以設置比例大小(寬/高),如果不設置的話就會自動取當前的寬/高比例。

對於對角方向,在比例縮放的情況下寬和高就不能同時設置,而必須有一個優先另一個參照比例設置了。
這個要注意,否則很容易進入死衚衕。RepairAngle修正程序中就是寬度優先的,高度再按比例修正(參考代碼)。

而左右上下四個方向,是以縮放對象對稱軸爲中心縮放的。
以左右方向爲例,要實現這個效果,首先在Start程序中設置中心定位座標_scaleTop:

this ._scaleTop  =   this ._styleTop  +   this ._styleHeight  /   2 ;

當修正好高之後,再用這個座標設置_styleTop值:

this ._styleTop  =   this ._scaleTop  -  iHeight  /   2 ;

其實就是設置高之後再修正top,使縮放之後的縮放對象中心的水平座標保持不變,就做出以縮放對象的水平對稱軸爲中心的縮放了。

還有兩個比例設置程序RepairScaleHeight和RepairScaleWidth,在這兩個程序分別按比例設置高和寬。
這裏必須留意一個問題,程序在計算樣式參數的時候,是不計算邊框的,但比例計算時應該把邊框算進去。
例如RepairScaleHeight程序中:

return  Math.max(Math.round((iWidth  +   this ._borderX)  /   this .Ratio  -   this ._borderY),  0 );

注意,因爲這樣計算的結果可能會小於0,所以用Math.max保證結果大於0(上面已經說了樣式值必須大於0)。

【範圍限制下的比例縮放】

一般的比例縮放很簡單,在寬或高取值之後,按比例設置另一個值就行了。
但如果有了範圍限制有可能按比例縮放後,就超過範圍限制了。
如果只考慮最大範圍限制的話,可以再修正,每次修正的範圍會越來越小,沒有問題。
但加上最小範圍限制,就可能這邊已經到了最小範圍了,但另一邊還在最大範圍限制之外了。
這個時候就必須小心細心處理了,當兩個範圍限制發生衝突時,要放棄其中一個,程序中是優先考慮最大範圍限制,放棄最小範圍限制,這個看起來沒什麼但如果思想轉不過來,就很容易鑽入死衚衕去了(經驗教訓T_T)。
例如用寬度和RepairScaleHeight程序已經獲得了高的值iHeight,可以這樣設置寬和高:

if(this.Max && iHeight > this._mxScaleHeight){
    iHeight 
= this._mxScaleHeight;
    iWidth 
= this.RepairScaleWidth(iHeight);
}
else if(this.Min && iHeight < this.minHeight){
    
var tWidth = this.RepairScaleWidth(this.minHeight);
    
if(tWidth < mxWidth){ iHeight = this.minHeight; iWidth = tWidth; }
}

說明一下這段代碼:
首先判斷iHeight是否超過最大值,是的話就根據最大值設置寬和高,由於優先考慮最大範圍所以寬是否超過最小範圍就不用再考慮了;
如果沒有超過最大值,再判斷是否小於最小值,是的話用高度最小值和RepairScaleWidth程序取要設置的寬賦給一個臨時變量tWidth,然後判斷tWidth是否超過最大範圍,不是的話就可以進行賦值,否則就放棄修改。

【自動轉向】

如果沒有設置最小範圍限制,當超過改方向能設置寬高的範圍就會自動轉向。
轉向程序中需要一個參數表示轉向後要執行的縮放程序,並重新設置幾個屬性。
以左轉程序TurnLeft爲例:
_fun:設置爲轉向後要執行的縮放程序;
_sideRigh:設置爲當前的_sideLeft,即以把右邊定位左邊設置成原來的左邊定位座標(形象點說就是原來是左邊不動,改成右邊不動);
_fixLeft:左轉後的定位需要_fixLeft,設置爲_styleLeft,本來是left加width的,由於左轉時width是0,所以只要left就夠了。
如果設置了最大範圍限制,還需要設置一下範圍參數,爲了方便,程序使用了一個_mxSet方法重新設置範圍參數。
程序如下:

if(!(this.Min || this._styleWidth)){
    
this._fun = fun;
    
this._sideRight = this._sideLeft;
    
this._fixLeft = this._styleLeft;
    
this.Max && this._mxSet();
    
return true;
}

如果發生了轉向就返回true,這個主要是用在對角方向的轉向。
對於對角方向,可能會轉向兩個方向,但同一時間最多隻能設置一個轉向(同時轉兩個可能會造成混亂),
而且在按比例縮放時,程序規定只進行水平方向的轉向(比例縮放中已說明)。
例如對於RightDown轉向,可以這樣滿足這兩個需求:

this .TurnLeft( this .LeftDown)  ||   this .Scale  ||   this .TurnUp( this .RightUp);

【樣式修正】

由於offset獲取的值跟style設置的值並不是一樣的,例如offsetWidth包括padding、border和width。
所以在獲取和設置時必須做一些修正,例如用offsetWidth獲取寬度,要設置width時必須減去padding和border等等。
程序中有_borderX和_borderY屬性分別是縮放對象的左右和上下邊框寬度:

var _style = CurrentStyle(this._obj);
this._borderX = (parseInt(_style.borderLeftWidth) || 0+ (parseInt(_style.borderRightWidth) ||0);
this._borderY = (parseInt(_style.borderTopWidth) || 0+ (parseInt(_style.borderBottomWidth) ||0);

程序中主要是修正了border,對於padding、margin都沒有考慮,如果設置了這些屬性的要注意一下哦。

【樣式設置】

首先縮放對象必須是絕對定位,如果有範圍限制容器就必須把容器設置成相對定位:

this._obj.style.position = "absolute";
!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" ||(this._mxContainer.style.position = "relative");

推薦根據拖拉的方向設置拖拉對象的鼠標樣式,其中右下和左上是nw-resize,左下和右上是ne-resize,上和下是n-resize,左和右是e-resiz。
至於拖拉對象的定位就有技巧一點,絕對定位到四個角比較簡單,適當設置top,left,right和height到爲0就行了,例如右上角是right和top爲0。
四個邊就難一點,參考這裏的居中顯示效果,利用定位樣式和margin就能做到居中了。
例如右邊設置top爲50%,margin-top爲高度的負的一半就能在右邊上下居中了。

程序說明就到這裏了,還有一些結構上的東西以我的能力還是比較難寫出來,還是看代碼來領會吧。
程序有很多相似的結構,總感覺可以整理得更好,等以後自己的編寫水平高點的時候再來看拉。

使用說明

首先實例化一個拖拉縮放對象:

var  rs  =   new  Resize( " dragDiv " );

有以下這些可選參數和屬性:
Max:  false,//是否設置範圍限制(爲true時下面mx參數有用)
mxContainer:"",//指定限制在容器內
mxLeft:  0,//左邊限制
mxRight: 9999,//右邊限制
mxTop:  0,//上邊限制
mxBottom: 9999,//下邊限制
Min:  false,//是否最小寬高限制(爲true時下面min參數有用)
minWidth: 50,//最小寬度
minHeight: 50,//最小高度
Scale:  false,//是否按比例縮放
Ratio:  0,//縮放比例(寬/高)
onResize: function(){}//縮放時執行

然後使用Set程序添加拖拉對象,Set程序需要兩個參數,第一格是拖拉對象,第二個是縮放參數。
其中縮放參數可以是"right-down"、"left-down"、"right-up"、"left-up"、"right"、"left"、"up"和"down"其中之一。
像這樣添加就行了:

rs.Set( " rDown " " down " );

ps:如果跟跟拖放效果配合使用時,要禁止冒泡,否則一點拖拉對象就冒泡到拖放了。

程序代碼 

//縮放程序
var Resize = Class.create();
Resize.prototype 
= {
  
//縮放對象
  initialize: function(obj, options) {
    
this._obj = $(obj);//縮放對象
    
    
this._styleWidth = this._styleHeight = this._styleLeft = this._styleTop = 0;//樣式參數
    this._sideRight = this._sideDown = this._sideLeft = this._sideUp = 0;//座標參數
    this._fixLeft = this._fixTop = 0;//定位參數
    this._scaleLeft = this._scaleTop = 0;//定位座標
    
    
this._mxSet = function(){};//範圍設置程序
    this._mxRightWidth = this._mxDownHeight = this._mxUpHeight = this._mxLeftWidth = 0;//範圍參數
    this._mxScaleWidth = this._mxScaleHeight = 0;//比例範圍參數
    
    
this._fun = function(){};//縮放執行程序
    
    
//獲取邊框寬度
    var _style = CurrentStyle(this._obj);
    
this._borderX = (parseInt(_style.borderLeftWidth) || 0+ (parseInt(_style.borderRightWidth) || 0);
    
this._borderY = (parseInt(_style.borderTopWidth) || 0+ (parseInt(_style.borderBottomWidth) || 0);
    
//事件對象(用於綁定移除事件)
    this._fR = BindAsEventListener(thisthis.Resize);
    
this._fS = Bind(thisthis.Stop);
    
    
this.SetOptions(options);
    
//範圍限制
    this.Max = !!this.options.Max;
    
this._mxContainer = $(this.options.mxContainer) || null;
    
this.mxLeft = Math.round(this.options.mxLeft);
    
this.mxRight = Math.round(this.options.mxRight);
    
this.mxTop = Math.round(this.options.mxTop);
    
this.mxBottom = Math.round(this.options.mxBottom);
    
//寬高限制
    this.Min = !!this.options.Min;
    
this.minWidth = Math.round(this.options.minWidth);
    
this.minHeight = Math.round(this.options.minHeight);
    
//按比例縮放
    this.Scale = !!this.options.Scale;
    
this.Ratio = Math.max(this.options.Ratio, 0);
    
    
this.onResize = this.options.onResize;
    
    
this._obj.style.position = "absolute";
    
!this._mxContainer || CurrentStyle(this._mxContainer).position == "relative" || (this._mxContainer.style.position = "relative");
  },
  
//設置默認屬性
  SetOptions: function(options) {
    
this.options = {//默認值
        Max:        false,//是否設置範圍限制(爲true時下面mx參數有用)
        mxContainer:"",//指定限制在容器內
        mxLeft:        0,//左邊限制
        mxRight:    9999,//右邊限制
        mxTop:        0,//上邊限制
        mxBottom:    9999,//下邊限制
        Min:        false,//是否最小寬高限制(爲true時下面min參數有用)
        minWidth:    50,//最小寬度
        minHeight:    50,//最小高度
        Scale:        false,//是否按比例縮放
        Ratio:        0,//縮放比例(寬/高)
        onResize:    function(){}//縮放時執行
    };
    Extend(
this.options, options || {});
  },
  
//設置觸發對象
  Set: function(resize, side) {
    
var resize = $(resize), fun;
    
if(!resize) return;
    
//根據方向設置
    switch (side.toLowerCase()) {
    
case "up" :
        fun 
= this.Up;
        
break;
    
case "down" :
        fun 
= this.Down;
        
break;
    
case "left" :
        fun 
= this.Left;
        
break;
    
case "right" :
        fun 
= this.Right;
        
break;
    
case "left-up" :
        fun 
= this.LeftUp;
        
break;
    
case "right-up" :
        fun 
= this.RightUp;
        
break;
    
case "left-down" :
        fun 
= this.LeftDown;
        
break;
    
case "right-down" :
    
default :
        fun 
= this.RightDown;
    };
    
//設置觸發對象
    addEventHandler(resize, "mousedown", BindAsEventListener(thisthis.Start, fun));
  },
  
//準備縮放
  Start: function(e, fun, touch) {    
    
//防止冒泡(跟拖放配合時設置)
    e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
    
//設置執行程序
    this._fun = fun;
    
//樣式參數值
    this._styleWidth = this._obj.clientWidth;
    
this._styleHeight = this._obj.clientHeight;
    
this._styleLeft = this._obj.offsetLeft;
    
this._styleTop = this._obj.offsetTop;
    
//四條邊定位座標
    this._sideLeft = e.clientX - this._styleWidth;
    
this._sideRight = e.clientX + this._styleWidth;
    
this._sideUp = e.clientY - this._styleHeight;
    
this._sideDown = e.clientY + this._styleHeight;
    
//top和left定位參數
    this._fixLeft = this._styleLeft + this._styleWidth;
    
this._fixTop = this._styleTop + this._styleHeight;
    
//縮放比例
    if(this.Scale){
        
//設置比例
        this.Ratio = Math.max(this.Ratio, 0|| this._styleWidth / this._styleHeight;
        
//left和top的定位座標
        this._scaleLeft = this._styleLeft + this._styleWidth / 2;
        
this._scaleTop = this._styleTop + this._styleHeight / 2;
    };
    
//範圍限制
    if(this.Max){
        
//設置範圍參數
        var mxLeft = this.mxLeft, mxRight = this.mxRight, mxTop = this.mxTop, mxBottom = this.mxBottom;
        
//如果設置了容器,再修正範圍參數
        if(!!this._mxContainer){
            mxLeft 
= Math.max(mxLeft, 0);
            mxTop 
= Math.max(mxTop, 0);
            mxRight 
= Math.min(mxRight, this._mxContainer.clientWidth);
            mxBottom 
= Math.min(mxBottom, this._mxContainer.clientHeight);
        };
        
//根據最小值再修正
        mxRight = Math.max(mxRight, mxLeft + (this.Min ? this.minWidth : 0+ this._borderX);
        mxBottom 
= Math.max(mxBottom, mxTop + (this.Min ? this.minHeight : 0+ this._borderY);
        
//由於轉向時要重新設置所以寫成function形式
        this._mxSet = function(){
            
this._mxRightWidth = mxRight - this._styleLeft - this._borderX;
            
this._mxDownHeight = mxBottom - this._styleTop - this._borderY;
            
this._mxUpHeight = Math.max(this._fixTop - mxTop, this.Min ? this.minHeight : 0);
            
this._mxLeftWidth = Math.max(this._fixLeft - mxLeft, this.Min ? this.minWidth : 0);
        };
        
this._mxSet();
        
//有縮放比例下的範圍限制
        if(this.Scale){
            
this._mxScaleWidth = Math.min(this._scaleLeft - mxLeft, mxRight - this._scaleLeft - this._borderX) * 2;
            
this._mxScaleHeight = Math.min(this._scaleTop - mxTop, mxBottom - this._scaleTop - this._borderY) * 2;
        };
    };
    
//mousemove時縮放 mouseup時停止
    addEventHandler(document, "mousemove"this._fR);
    addEventHandler(document, 
"mouseup"this._fS);
    
if(isIE){
        addEventHandler(
this._obj, "losecapture"this._fS);
        
this._obj.setCapture();
    }
else{
        addEventHandler(window, 
"blur"this._fS);
        e.preventDefault();
    };
  },
  
//縮放
  Resize: function(e) {
    
//清除選擇
    window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
    
//執行縮放程序
    this._fun(e);
    
//設置樣式,變量必須大於等於0否則ie出錯
    with(this._obj.style){
        width 
= this._styleWidth + "px"; height = this._styleHeight + "px";
        top 
= this._styleTop + "px"; left = this._styleLeft + "px";
    }
    
//附加程序
    this.onResize();
  },
  
//縮放程序
  //
  Up: function(e) {
    
this.RepairY(this._sideDown - e.clientY, this._mxUpHeight);
    
this.RepairTop();
    
this.TurnDown(this.Down);
  },
  
//
  Down: function(e) {
    
this.RepairY(e.clientY - this._sideUp, this._mxDownHeight);
    
this.TurnUp(this.Up);
  },
  
//
  Right: function(e) {
    
this.RepairX(e.clientX - this._sideLeft, this._mxRightWidth);
    
this.TurnLeft(this.Left);
  },
  
//
  Left: function(e) {
    
this.RepairX(this._sideRight - e.clientX, this._mxLeftWidth);
    
this.RepairLeft();
    
this.TurnRight(this.Right);
  },
  
//右下
  RightDown: function(e) {
    
this.RepairAngle(
        e.clientX 
- this._sideLeft, this._mxRightWidth,
        e.clientY 
- this._sideUp, this._mxDownHeight
    );
    
this.TurnLeft(this.LeftDown) || this.Scale || this.TurnUp(this.RightUp);
  },
  
//右上
  RightUp: function(e) {
    
this.RepairAngle(
        e.clientX 
- this._sideLeft, this._mxRightWidth,
        
this._sideDown - e.clientY, this._mxUpHeight
    );
    
this.RepairTop();
    
this.TurnLeft(this.LeftUp) || this.Scale || this.TurnDown(this.RightDown);
  },
  
//左下
  LeftDown: function(e) {
    
this.RepairAngle(
        
this._sideRight - e.clientX, this._mxLeftWidth,
        e.clientY 
- this._sideUp, this._mxDownHeight
    );
    
this.RepairLeft();
    
this.TurnRight(this.RightDown) || this.Scale || this.TurnUp(this.LeftUp);
  },
  
//左上
  LeftUp: function(e) {
    
this.RepairAngle(
        
this._sideRight - e.clientX, this._mxLeftWidth,
        
this._sideDown - e.clientY, this._mxUpHeight
    );
    
this.RepairTop(); this.RepairLeft();
    
this.TurnRight(this.RightUp) || this.Scale || this.TurnDown(this.LeftDown);
  },
  
//修正程序
  //水平方向
  RepairX: function(iWidth, mxWidth) {
    iWidth 
= this.RepairWidth(iWidth, mxWidth);
    
if(this.Scale){
        
var iHeight = this.RepairScaleHeight(iWidth);
        
if(this.Max && iHeight > this._mxScaleHeight){
            iHeight 
= this._mxScaleHeight;
            iWidth 
= this.RepairScaleWidth(iHeight);
        }
else if(this.Min && iHeight < this.minHeight){
            
var tWidth = this.RepairScaleWidth(this.minHeight);
            
if(tWidth < mxWidth){ iHeight = this.minHeight; iWidth = tWidth; }
        }
        
this._styleHeight = iHeight;
        
this._styleTop = this._scaleTop - iHeight / 2;
    }
    
this._styleWidth = iWidth;
  },
  
//垂直方向
  RepairY: function(iHeight, mxHeight) {
    iHeight 
= this.RepairHeight(iHeight, mxHeight);
    
if(this.Scale){
        
var iWidth = this.RepairScaleWidth(iHeight);
        
if(this.Max && iWidth > this._mxScaleWidth){
            iWidth 
= this._mxScaleWidth;
            iHeight 
= this.RepairScaleHeight(iWidth);
        }
else if(this.Min && iWidth < this.minWidth){
            
var tHeight = this.RepairScaleHeight(this.minWidth);
            
if(tHeight < mxHeight){ iWidth = this.minWidth; iHeight = tHeight; }
        }
        
this._styleWidth = iWidth;
        
this._styleLeft = this._scaleLeft - iWidth / 2;
    }
    
this._styleHeight = iHeight;
  },
  
//對角方向
  RepairAngle: function(iWidth, mxWidth, iHeight, mxHeight) {
    iWidth 
= this.RepairWidth(iWidth, mxWidth);    
    
if(this.Scale){
        iHeight 
= this.RepairScaleHeight(iWidth);
        
if(this.Max && iHeight > mxHeight){
            iHeight 
= mxHeight;
            iWidth 
= this.RepairScaleWidth(iHeight);
        }
else if(this.Min && iHeight < this.minHeight){
            
var tWidth = this.RepairScaleWidth(this.minHeight);
            
if(tWidth < mxWidth){ iHeight = this.minHeight; iWidth = tWidth; }
        }
    }
else{
        iHeight 
= this.RepairHeight(iHeight, mxHeight);
    }
    
this._styleWidth = iWidth;
    
this._styleHeight = iHeight;
  },
  
//top
  RepairTop: function() {
    
this._styleTop = this._fixTop - this._styleHeight;
  },
  
//left
  RepairLeft: function() {
    
this._styleLeft = this._fixLeft - this._styleWidth;
  },
  
//height
  RepairHeight: function(iHeight, mxHeight) {
    iHeight 
= Math.min(this.Max ? mxHeight : iHeight, iHeight);
    iHeight 
= Math.max(this.Min ? this.minHeight : iHeight, iHeight, 0);
    
return iHeight;
  },
  
//width
  RepairWidth: function(iWidth, mxWidth) {
    iWidth 
= Math.min(this.Max ? mxWidth : iWidth, iWidth);
    iWidth 
= Math.max(this.Min ? this.minWidth : iWidth, iWidth, 0);
    
return iWidth;
  },
  
//比例高度
  RepairScaleHeight: function(iWidth) {
    
return Math.max(Math.round((iWidth + this._borderX) / this.Ratio - this._borderY), 0);
  },
  
//比例寬度
  RepairScaleWidth: function(iHeight) {
    
return Math.max(Math.round((iHeight + this._borderY) * this.Ratio - this._borderX), 0);
  },
  
//轉向程序
  //轉右
  TurnRight: function(fun) {
    
if(!(this.Min || this._styleWidth)){
        
this._fun = fun;
        
this._sideLeft = this._sideRight;
        
this.Max && this._mxSet();
        
return true;
    }
  },
  
//轉左
  TurnLeft: function(fun) {
    
if(!(this.Min || this._styleWidth)){
        
this._fun = fun;
        
this._sideRight = this._sideLeft;
        
this._fixLeft = this._styleLeft;
        
this.Max && this._mxSet();
        
return true;
    }
  },
  
//轉上
  TurnUp: function(fun) {
    
if(!(this.Min || this._styleHeight)){
        
this._fun = fun;
        
this._sideDown = this._sideUp;
        
this._fixTop = this._styleTop;
        
this.Max && this._mxSet();
        
return true;
    }
  },
  
//轉下
  TurnDown: function(fun) {
    
if(!(this.Min || this._styleHeight)){
        
this._fun = fun;
        
this._sideUp = this._sideDown;
        
this.Max && this._mxSet();
        
return true;
    }
  },
  
//停止縮放
  Stop: function() {
    removeEventHandler(document, 
"mousemove"this._fR);
    removeEventHandler(document, 
"mouseup"this._fS);
    
if(isIE){
        removeEventHandler(
this._obj, "losecapture"this._fS);
        
this._obj.releaseCapture();
    }
else{
        removeEventHandler(window, 
"blur"this._fS);
    }
  }
};

完整測試代碼下載 

ps:實例中包含了拖放效果,不過兩個效果是完全獨立的,刪掉拖放的部分也能正常縮放。

本文轉自博客園cloudgamer的博客,原文鏈接:JavaScript 拖拉縮放效果,如需轉載請自行聯繫原博主。