zoukankan      html  css  js  c++  java
  • ImageZoom 图片放大效果

    这个效果也叫放大镜效果,最早好像在ppg出现的,之后就有了很多仿制品出来了。
    一般用于放大查看商品图片,在凡客,京东商城,阿里巴巴等都有类似的效果。
    好处是能在原图附近对图片进行局部放大查看,而且可以通过鼠标控制查看的部位。
    前一阵子看到sohighthesky的图片放大效果,心血来潮自己也写一个看看。
    这个程序有以下特点:
    1,支持使用原图放大或新图片设置大图;
    2,大图完成载入前使用原图放大代替,减少操作等待时间;
    3,支持鼠标滚动缩放大图;
    4,可以通过设置显示范围或显示框大小设置显示尺寸;
    5,可以设置是否自动隐藏显示框;
    下一篇扩展篇再介绍更多的功能。
    兼容:ie6/7/8, firefox 3.6.2, opera 10.51, safari 4.0.4, chrome 4.1


    效果预览




    原图:
    大图:

    程序说明

    【基本原理】

    首先要有一个img元素作为原图对象,还要有一个容器作为显示框。
    显示框里面放另一个img元素作为大图对象,并根据比例设置好尺寸。
    当鼠标在原图上移动时,通过对大图进行绝对定位来显示对应的部位,实现类似放大镜的效果。


    【图片加载】

    程序初始化时会先执行_initLoad程序,主要用来载入图片。
    由于img在载入之前获取尺寸是不准确的,所以相关参数的计算都要等到图片加载之后。

    有两种放大的方式:使用原图放大、用已经放大的新图片。
    原图放大的好处是只需加载一个图片,而使用新图片就可以得到更清晰的效果。
    根据不同的方式,会选择对应的原图加载程序:

    useOrigin = !this._zoomPic && this._scale,
    loadImage 
    = $$F.bind( useOrigin ? this._loadOriginImage : this._loadImage, this );

    当没有设置大图但有放大比例时,会自动使用原图放大加载程序。

    先看看使用原图放大加载的过程:
    1,加载原图:

    代码
    if ( originPic && originPic != image.src ) {
        image.onload 
    = loadImage;
        image.src 
    = originPic;
    else if ( image.src ) {
        
    if ( !image.complete ) {
            image.onload 
    = loadImage;
        } 
    else {
            loadImage();
        }
    else {
        
    return;
    }

    _originPic属性记录原图地址,如果设置了原图并且跟元素当前加载的图片不同,就设置onload并加载原图。
    否则,如果元素当前有加载图片的话,先通过complete判断是否加载完成,没完成就设置onload,已经完成的话就直接执行加载程序。
    最后,没有原图图片的话就退出程序。
    2,执行_loadOriginImage加载程序:

    this._image.onload = null;
    this._zoom.src = this._image.src;
    this._initLoaded();

    由于ie6/7的gif图片载入bug,会先重置onload。
    然后执行_initLoaded初始化加载设置程序。

    使用新图片就复杂一点:
    1,加载原图,同上。
    2,预载大图:

    代码
    var preload = this._preload, zoomPic = this._zoomPic || image.src,
        loadPreload 
    = $$F.bind( this._loadPreload, this );
    if ( zoomPic != preload.src ) {
        preload.onload 
    = loadPreload;
        preload.src 
    = zoomPic;
    else {
        
    if ( !preload.complete ) {
            preload.onload 
    = loadPreload;
        } 
    else {
            
    this._loadPreload();
        }
    }

    _preload是预载对象,使用的是_loadPreload预载加载程序。
    预载对象主要用来获取大图的原始尺寸,也是后面原图替换技巧的基础。
    如果没有设置大图,说明当前没有设置大图也又没有放大比例,这时就用原图作为大图来用。
    加载的方法跟原图类似。
    3,当原图加载完成时,执行_loadImage原图加载程序:

    复制代码
    if ( this._loaded ) {
        
    this._initLoaded();
    else {
        
    this._loaded = true;
        
    if ( this._scale ) {
            
    this._substitute = true;
            
    this._zoom.src = this._image.src;
            
    this._initLoaded();
        }
    }
    复制代码

    如果_loaded为true,说明大图已经加载,直接执行_initLoaded程序。
    否则设置_loaded为true来标记原图已经加载,如果这时有自定义比例的话,先用原图替换大图。
    因为一般大图加载会比较慢,先用原图替换就能立刻操作了,同时设置_substitute属性为true标记使用了替换。
    4,当大图预载完成时,执行_loadPreload大图预载程序:

    this._zoom.src = this._preload.src;
    if ( this._loaded ) {
        
    if ( !this._substitute ) { this._initLoaded(); }
    else {
        
    this._loaded = true;
    }

    如果_loaded是true,说明原图已经加载完,同时_substitute为false即没有使用原图替换的话,就执行_initLoaded程序。
    如果原图没有加载完,那么设置_loaded为true标记大图已经加载。

    关于图片加载还要注意一个问题,测试以下代码:

    复制代码
    <script>
    var img=new Image
    function test(){
        img.onload
    =function(){alert("load")}
        img.src
    ="http://www.google.com.hk/images/nav_logo8.png"
    }
    test()
    setTimeout(test,
    3000)
    </script>
    复制代码

    在chrome/safari只会弹出一次"load",而其他都是正常的两次,可能是做了优化之类的吧。

    当加载完成后,就可以设置相关的对象和参数,这些都在_initLoaded程序中进行。


    【加载设置】

    在_initLoaded初始化加载设置程序,主要是做触发放大效果前的准备工作。

    第一步,执行_initSize程序初始化显示图尺寸。
    首先修正放大比例:

    if ( !scale ) { scale = this._preload.width / image.width; }
    this._scale = scale = Math.min( Math.max( this._min, scale ), this._max );

    如果没有设置比例,就从预载对象获取的默认尺寸作为大图尺寸。
    在图片加载时已经做好“安全措施”,确保这里能获得放大比例。
    还可以通过自定义max和min属性来限制比例大小。
    然后就可以按比例设置大图尺寸:

    zoom.width = Math.ceil( image.width * scale );
    zoom.height 
    = Math.ceil( image.height * scale );


    第二步,执行_initViewer初始化显示框程序,设置显示框。
    先设置好样式:

    代码
    var styles = { padding: 0, overflow: "hidden" }, p = $$D.getStyle( viewer, "position" );
    if ( p != "relative" && p != "absolute" ){ styles.position = "relative"; };
    $$D.setStyle( viewer, styles );
    zoom.style.position 
    = "absolute";

    再把显示图插入显示框:

    if ( !$$D.contains( viewer, zoom ) ){ viewer.appendChild( zoom ); }


    第三步,执行_initData初始化数据程序,主要是设置放大时用到的一些参数。
    包括用于位置判断的原图坐标:

    this._rect = $$D.rect( image );

    用于left/top修正的修正参数:

    this._repairLeft = image.clientLeft + parseInt($$D.getStyle( image, "padding-left" ));
    this._repairTop = image.clientTop + parseInt($$D.getStyle( image, "padding-top" ));

    还有范围参数和显示尺寸。
    范围参数就是要显示的范围在原图的尺寸,显示尺寸是显示框的显示尺寸。
    如果通过rangeWidth和rangeHeight自定义了范围参数,就可以结合放大比例计算出显示尺寸:

    代码
    rangeWidth = Math.ceil( rangeWidth );
    rangeHeight 
    = Math.ceil( rangeHeight );
    this._viewerWidth = Math.ceil( rangeWidth * scale );
    this._viewerHeight = Math.ceil( rangeHeight * scale );
    $$D.setStyle( viewer, {
         
    this._viewerWidth + "px",
        height: 
    this._viewerHeight + "px"
    });

    如果没有设置的话,就使用显示框的默认显示尺寸:

    代码
    var styles;
    if ( !viewer.clientWidth ) {
        
    var style = viewer.style;
        styles 
    = {
            display: style.display,
            position: style.position,
            visibility: style.visibility
        };
        $$D.setStyle( viewer, {
            display: 
    "block", position: "absolute", visibility: "hidden"
        });
    }
    this._viewerWidth = viewer.clientWidth;
    this._viewerHeight = viewer.clientHeight;
    if ( styles ) { $$D.setStyle( viewer, styles ); }

    rangeWidth 
    = Math.ceil( this._viewerWidth / scale );
    rangeHeight 
    = Math.ceil( this._viewerHeight / scale );

    注意,显示范围是通过clientWidth/clientHeight来获取的。
    如果显示框是display为none的隐藏状态,就不能直接获取clientWidth/clientHeight。
    这种情况下,程序用以下方法获取:
    1,记录display/position/visibility的原始值;
    2,分别设为"block"/"absolute"/"hidden",这是既能隐藏也能占位的状态;
    3,获取参数;
    4,重新设回原始值,恢复原来的状态。
    得到显示范围后,再配合比例就能得到范围参数了。
    ps:这是通用的获取不占位元素尺寸参数的方法,jquery的css也是用这个方法获取width/height的。
    比例计算后可能会得到小数,而尺寸大小只能是整数,程序一律使用Math.ceil来取整。


    【放大效果】

    所有东西都设置好后,就可以执行start设置触发程序了。

    程序会自动执行start方法,里面主要是给原图对象的mouseover/mousemove绑定_start程序:

    var image = this._image, START = this._START;
    $$E.addEvent( image, 
    "mouseover", START );
    $$E.addEvent( image, 
    "mousemove", START );

    分别对应移入原图对象和在原图对象上移动的情况。
    ps:如果使用attachEvent的话还要注意重复绑定同一函数的问题,这里的addEvent就没有这个问题。

    绑定的_start程序,主要是进行一些事件的解绑和绑定:

    代码
    $$E.removeEvent( image, "mouseover"this._START );
    $$E.removeEvent( image, 
    "mousemove"this._START );
    $$E.addEvent( document, 
    "mousemove"this._MOVE );
    $$E.addEvent( document, 
    "mouseout"this._OUT );

    为了在移出窗口时能结束放大效果,给document的mouseout绑定了_OUT程序:

    this._OUT = $$F.bindAsEventListener( function(e){
            
    if ( !e.relatedTarget ) this._END();
        }, 
    this );

    当鼠标移出document会触发mouseout,如果当前relatedTarget是null的话,就延时执行_end结束程序:

    var oThis = this, END = function(){ oThis._end(); };
    this._END = function(){ oThis._timer = setTimeout( END, oThis.delay ); };

    在_end程序中,会先执行stop方法,在里面移除所有可能绑定的事件,再执行start方法继续等待触发。

    而mousemove绑定的_move移动程序,主要用来实现鼠标移动到哪里就放大哪里的功能。
    为适应更多的情况(例如扩展篇的其他模式),把它绑定到document上,但也因此不能用mouseout事件来触发移出程序。
    程序通过鼠标和原图的坐标比较,来判断鼠标是否移出原图对象范围:

    var x = e.pageX, y = e.pageY, rect = this._rect;
    if ( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) {
        
    this._END();
    else {
        ...
    }

    如果鼠标移出原图对象的话,就执行_END结束放大效果。

    如果鼠标在原图对象上移动,就计算坐标进行定位。
    先修正坐标,把鼠标坐标转化成大图的定位坐标:

    pos.left = viewerWidth / 2 - ( x - rect.left - this._repairLeft ) * scale;
    pos.top 
    = viewerHeight / 2 - ( y - rect.top - this._repairTop ) * scale;

    再设置范围限制:

    = Math.ceil(Math.min(Math.max( pos.left, viewerWidth - zoom.width ), 0));
    = Math.ceil(Math.min(Math.max( pos.top, viewerHeight - zoom.height ), 0));

    最后设置定位,使显示框显示要放大的部位。
    ps:我尝试过用scrollLeft/scrollTop来做定位,但发现这样在ie中会像锯齿那样移动,放得越大越明显,所以放弃。


    【鼠标滚动缩放】

    如果设置mouse属性为true,就会开启鼠标滚动缩放功能。
    在执行放大效果期间,可以通过滚动鼠标滚轮对大图进行缩放处理。
    其实就是根据滚轮动参数的变化来修改放大比例。

    关于鼠标滚动事件,在slider中也提过,不过那时只分析了ie和ff的区别,这里再分析一下。
    首先ie是用mousewheel绑定事件的,使用event的wheelDelta来获取滚动参数。
    其他浏览器用以下代码测试:

    代码
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <body style="height:1000px;">
    <script>
    function test(e){ alert(e.type+":"+e.detail+"_"+e.wheelDelta) }
    document.addEventListener( 
    "DOMMouseScroll", test, false );
    document.addEventListener( 
    "mousewheel", test, false );
    </script>
    </body>
    </html>

    向下滚动一下,可以得到以下结果:
    ff:DOMMouseScroll:3_undefined
    opera:mousewheel:3_-120
    chrome/safari:mousewheel:0_-120
    可以看到事件的绑定,ff只支持DOMMouseScroll,其他就只支持mousewheel。
    而滚动参数的获取,ff只支持detail,opera两种都支持,chrome/safari就支持wheelDelta。
    ps:不明白chrome/safari的detail为什么是0,有其他用途?
    而DOMMouseScroll跟mousewheel还有一个不同是前者不能直接绑定元素,后者可以。
    即可以elem.onmousewheel,但不能elem.onDOMMouseScroll。

    根据以上分析,在_start程序里是这样把_mouse程序绑定到document的滚动事件中:

    this.mouse && $$E.addEvent( document, $$B.firefox ? "DOMMouseScroll" : "mousewheel"this._MOUSE );


    在_mouse程序里面根据滚动参数和自定义的rate缩放比率得到新的放大比例:

    this._scale += ( e.wheelDelta ? e.wheelDelta / (-120) : (e.detail || 0/ 3 ) * this.rate;


    修改比例时,程序参数也需要重新计算。
    由于_rangeWidth/_rangeHeight会影响计算的过程,要重新恢复成自定义的默认值:

    var opt = this.options;
    this._rangeWidth = opt.rangeWidth;
    this._rangeHeight = opt.rangeHeight;


    然后执行_initSize和_initData重新设置尺寸和参数,再执行_move重新定位。
    最后记得用preventDefault防止触发页面滚动。


    使用技巧

    【图片设置】

    程序支持大图使用原图放大或用新大图。
    如果用新大图而且图片比较大的话,强烈建议设置放大比例,这样程序会自动在大图载入前先使用原图放大,这样就不用等待大图加载完成。
    还要注意新大图本身的宽高比例要跟原图一致,否则就对不准坐标了,使用原图放大就没有这个问题。

    【显示框设置】

    有两个方法可以设置显示框的尺寸:
    要固定显示范围的话,先设置rangeWidth/rangeHeight,程序会根据显示范围和放大比例计算显示框的尺寸;
    要用显示框当前的尺寸来显示的话,只要不设置rangeWidth/rangeHeight或设为0就可以了。

    【reset】

    由于各个属性和对象之间有很多的关联,很多属性不能直接修改。
    程序设置了一个reset方法专门用来修改这类属性的。
    如果程序加载完成后又修改了影响程序计算的样式,例如原图大小,显示框大小等,也要执行一次reset来重新设置参数和属性。

    【浮动定位】

    程序没有设置显示框浮动定位的功能,需要的话可以自行添加。
    简单的定位可以参考实例的方法,还要小心覆盖select的问题。
    如果要更复杂的浮动定位,可以参考“浮动定位提示效果”。

    【opera的bug】

    测试中发现opera 10.10有两个bug。
    分别是img元素设置透明时会看到背景图,用js修改鼠标样式会有问题。
    不过这两个问题在10.50都已经修复了,还没升级的赶快升啦。

    【maxthon的bug】

    用maxthon 2.5.1测试时发现一个问题,测试以下代码:

    复制代码
    <div id="t" style="50px;"></div>
    <script>
    var t=document.getElementById("t");
    t.clientWidth;
    t.style.display
    ="none";
    alert(t.clientWidth);
    </script>
    复制代码

    一般来说用display隐藏后,clientWidth应该是0的,但maxthon貌似没有处理这个情况。
    这会影响到程序中clientWidth的判断,不过对一般使用没什么影响。
    我已经提交了这个问题,不知会不会处理。


    使用说明

    实例化时,必须有一个img元素作为原图对象,和一个容器作为显示框:

    var iz = new ImageZoom( "idImage""idViewer" );


    可选参数用来设置系统的默认属性,包括:
    属性:    默认值//说明
    scale:  0,//比例(大图/原图)
    max:  10,//最大比例
    min:  1.5,//最小比例
    originPic: "",//原图地址
    zoomPic: "",//大图地址
    rangeWidth: 0,//显示范围宽度
    rangeHeight:0,//显示范围高度
    delay:  20,//延迟结束时间
    autoHide: true,//是否自动隐藏
    mouse:  false,//鼠标缩放
    rate:  .2,//鼠标缩放比率
    onLoad:  $$.emptyFunction,//加载完成时执行
    onStart: $$.emptyFunction,//开始放大时执行
    onMove:  $$.emptyFunction,//放大移动时执行
    onEnd:  $$.emptyFunction//放大结束时执行
    其中模式的使用在下一篇扩展篇再说明。
    初始化后,scale、max、min、originPic、zoomPic、rangeWidth、rangeHeight这些属性需要用reset方法来修改。

    还提供了以下方法:
    start:开始放大程序(程序会自动执行);
    stop:停止放大程序;
    reset:修改设置;
    dispose:销毁程序。


    程序源码 

    代码
    var ImageZoom = function(image, viewer, options) {
        
    this._initialize( image, viewer, options );
        
    this._initLoad();
    };

    ImageZoom.prototype 
    = {
      
    //初始化程序
      _initialize: function(image, viewer, options) {
        
    this._image = $$(image);//原图
        this._zoom = document.createElement("img");//显示图
        this._viewer = $$(viewer);//显示框
        this._viewerWidth = 0;//显示框宽
        this._viewerHeight = 0;//显示框高
        this._preload = new Image();//预载对象
        this._rect = null;//原图坐标
        this._repairLeft = 0;//显示图x坐标修正
        this._repairTop = 0;//显示图y坐标修正
        this._rangeWidth = 0;//显示范围宽度
        this._rangeHeight = 0;//显示范围高度
        this._timer = null;//计时器
        this._loaded = false;//是否加载
        this._substitute = false;//是否替换
        
        
    var opt = this._setOptions(options);
        
        
    this._scale = opt.scale;
        
    this._max = opt.max;
        
    this._min = opt.min;
        
    this._originPic = opt.originPic;
        
    this._zoomPic = opt.zoomPic;
        
    this._rangeWidth = opt.rangeWidth;
        
    this._rangeHeight = opt.rangeHeight;
        
        
    this.delay = opt.delay;
        
    this.autoHide = opt.autoHide;
        
    this.mouse = opt.mouse;
        
    this.rate = opt.rate;
        
        
    this.onLoad = opt.onLoad;
        
    this.onStart = opt.onStart;
        
    this.onMove = opt.onMove;
        
    this.onEnd = opt.onEnd;
        
        
    var oThis = this, END = function(){ oThis._end(); };
        
    this._END = function(){ oThis._timer = setTimeout( END, oThis.delay ); };
        
    this._START = $$F.bindAsEventListener( this._start, this );
        
    this._MOVE = $$F.bindAsEventListener( this._move, this );
        
    this._MOUSE = $$F.bindAsEventListener( this._mouse, this );
        
    this._OUT = $$F.bindAsEventListener( function(e){
                
    if ( !e.relatedTarget ) this._END();
            }, 
    this );
        
        $$CE.fireEvent( 
    this"init" );
      },
      
    //设置默认属性
      _setOptions: function(options) {
        
    this.options = {//默认值
            scale:        0,//比例(大图/原图)
            max:        10,//最大比例
            min:        1.5,//最小比例
            originPic:    "",//原图地址
            zoomPic:    "",//大图地址
            rangeWidth:    0,//显示范围宽度
            rangeHeight:0,//显示范围高度
            delay:        20,//延迟结束时间
            autoHide:    true,//是否自动隐藏
            mouse:        false,//鼠标缩放
            rate:        .2,//鼠标缩放比率
            onLoad:        $$.emptyFunction,//加载完成时执行
            onStart:    $$.emptyFunction,//开始放大时执行
            onMove:        $$.emptyFunction,//放大移动时执行
            onEnd:        $$.emptyFunction//放大结束时执行
        };
        
    return $$.extend(this.options, options || {});
      },
      
    //初始化加载
      _initLoad: function() {
        
    var image = this._image, originPic = this._originPic,
            useOrigin 
    = !this._zoomPic && this._scale,
            loadImage 
    = $$F.bind( useOrigin ? this._loadOriginImage : this._loadImage, this );
        
    //设置自动隐藏
        this.autoHide && this._hide();
        
    //先加载原图
        if ( originPic && originPic != image.src ) {//使用自定义地址
            image.onload = loadImage;
            image.src 
    = originPic;
        } 
    else if ( image.src ) {//使用元素地址
            if ( !image.complete ) {//未载入完
                image.onload = loadImage;
            } 
    else {//已经载入
                loadImage();
            }
        } 
    else {
            
    return;//没有原图地址
        }
        
    //加载大图
        if ( !useOrigin ) {
            
    var preload = this._preload, zoomPic = this._zoomPic || image.src,
                loadPreload 
    = $$F.bind( this._loadPreload, this );
            
    if ( zoomPic != preload.src ) {//新地址重新加载
                preload.onload = loadPreload;
                preload.src 
    = zoomPic;
            } 
    else {//正在加载
                if ( !preload.complete ) {//未载入完
                    preload.onload = loadPreload;
                } 
    else {//已经载入
                    this._loadPreload();
                }
            }
        }
      },
      
    //原图放大加载程序
      _loadOriginImage: function() {
        
    this._image.onload = null;
        
    this._zoom.src = this._image.src;
        
    this._initLoaded();
      },
      
    //原图加载程序
      _loadImage: function() {
        
    this._image.onload = null;
        
    if ( this._loaded ) {//大图已经加载
            this._initLoaded();
        } 
    else {
            
    this._loaded = true;
            
    if ( this._scale ) {//有自定义比例才用原图放大替换大图
                this._substitute = true;
                
    this._zoom.src = this._image.src;
                
    this._initLoaded();
            }
        }
      },
      
    //大图预载程序
      _loadPreload: function() {
        
    this._preload.onload = null;
        
    this._zoom.src = this._preload.src;
        
    if ( this._loaded ) {//原图已经加载
            //没有使用替换
            if ( !this._substitute ) { this._initLoaded(); }
        } 
    else {
            
    this._loaded = true;
        }
      },
      
    //初始化加载设置
      _initLoaded: function(src) {
        
    //初始化显示图
        this._initSize();
        
    //初始化显示框
        this._initViewer();
        
    //初始化数据
        this._initData();
        
    //开始执行
        $$CE.fireEvent( this"load" );
        
    this.onLoad();
        
    this.start();
      },
      
    //初始化显示图尺寸
      _initSize: function() {
        
    var zoom = this._zoom, image = this._image, scale = this._scale;
        
    if ( !scale ) { scale = this._preload.width / image.width; }
        
    this._scale = scale = Math.min( Math.max( this._min, scale ), this._max );
        
    //按比例设置显示图大小
        zoom.width = Math.ceil( image.width * scale );
        zoom.height 
    = Math.ceil( image.height * scale );
      },
      
    //初始化显示框
      _initViewer: function() {
        
    var zoom = this._zoom, viewer = this._viewer;
        
    //设置样式
        var styles = { padding: 0, overflow: "hidden" }, p = $$D.getStyle( viewer, "position" );
        
    if ( p != "relative" && p != "absolute" ){ styles.position = "relative"; };
        $$D.setStyle( viewer, styles );
        zoom.style.position 
    = "absolute";
        
    //插入显示图
        if ( !$$D.contains( viewer, zoom ) ){ viewer.appendChild( zoom ); }
      },
      
    //初始化数据
      _initData: function() {
        
    var zoom = this._zoom, image = this._image, viewer = this._viewer,
            scale 
    = this._scale, rangeWidth = this._rangeWidth, rangeHeight = this._rangeHeight;
        
    //原图坐标
        this._rect = $$D.rect( image );
        
    //修正参数
        this._repairLeft = image.clientLeft + parseInt($$D.getStyle( image, "padding-left" ));
        
    this._repairTop = image.clientTop + parseInt($$D.getStyle( image, "padding-top" ));
        
    //设置范围参数和显示框大小
        if ( rangeWidth > 0 && rangeHeight > 0 ) {
            rangeWidth 
    = Math.ceil( rangeWidth );
            rangeHeight 
    = Math.ceil( rangeHeight );
            
    this._viewerWidth = Math.ceil( rangeWidth * scale );
            
    this._viewerHeight = Math.ceil( rangeHeight * scale );
            $$D.setStyle( viewer, {
                 
    this._viewerWidth + "px",
                height: 
    this._viewerHeight + "px"
            });
        } 
    else {
            
    var styles;
            
    if ( !viewer.clientWidth ) {//隐藏
                var style = viewer.style;
                styles 
    = {
                    display: style.display,
                    position: style.position,
                    visibility: style.visibility
                };
                $$D.setStyle( viewer, {
                    display: 
    "block", position: "absolute", visibility: "hidden"
                });
            }
            
    this._viewerWidth = viewer.clientWidth;
            
    this._viewerHeight = viewer.clientHeight;
            
    if ( styles ) { $$D.setStyle( viewer, styles ); }
            
            rangeWidth 
    = Math.ceil( this._viewerWidth / scale );
            rangeHeight 
    = Math.ceil( this._viewerHeight / scale );
        }
        
    this._rangeWidth = rangeWidth;
        
    this._rangeHeight = rangeHeight;
      },
      
    //开始
      _start: function() {
        clearTimeout( 
    this._timer );
        
    var viewer = this._viewer, image = this._image, scale = this._scale;
        viewer.style.display 
    = "block";
        $$CE.fireEvent( 
    this"start" );
        
    this.onStart();
        $$E.removeEvent( image, 
    "mouseover"this._START );
        $$E.removeEvent( image, 
    "mousemove"this._START );
        $$E.addEvent( document, 
    "mousemove"this._MOVE );
        $$E.addEvent( document, 
    "mouseout"this._OUT );
        
    this.mouse && $$E.addEvent( document, $$B.firefox ? "DOMMouseScroll" : "mousewheel"this._MOUSE );
      },
      
    //移动
      _move: function(e) {
        clearTimeout( 
    this._timer );
        
    var x = e.pageX, y = e.pageY, rect = this._rect;
        
    if ( x < rect.left || x > rect.right || y < rect.top || y > rect.bottom ) {
            
    this._END();//移出原图范围
        } else {
            
    var pos = {}, scale = this._scale, zoom = this._zoom,
                viewerWidth 
    = this._viewerWidth,
                viewerHeight 
    = this._viewerHeight;
            
    //修正坐标
            pos.left = viewerWidth / 2 - ( x - rect.left - this._repairLeft ) * scale;
            pos.top 
    = viewerHeight / 2 - ( y - rect.top - this._repairTop ) * scale;
            
            $$CE.fireEvent( 
    this"repair", e, pos );
            
    //范围限制
            x = Math.ceil(Math.min(Math.max( pos.left, viewerWidth - zoom.width ), 0));
            y 
    = Math.ceil(Math.min(Math.max( pos.top, viewerHeight - zoom.height ), 0));
            
    //设置定位
            zoom.style.left = x + "px";
            zoom.style.top 
    = y + "px";
            
            $$CE.fireEvent( 
    this"move", e, x, y );
            
    this.onMove();
        }
      },
      
    //结束
      _end: function() {
        $$CE.fireEvent( 
    this"end" );
        
    this.onEnd();
        
    this.autoHide && this._hide();
        
    this.stop();
        
    this.start();
      },
      
    //隐藏
      _hide: function() {
        
    this._viewer.style.display = "none";
      },
      
    //鼠标缩放
      _mouse: function(e) {
        
    this._scale += ( e.wheelDelta ? e.wheelDelta / (-120) : (e.detail || 0/ 3 ) * this.rate;
        
        
    var opt = this.options;
        
    this._rangeWidth = opt.rangeWidth;
        
    this._rangeHeight = opt.rangeHeight;
        
        
    this._initSize();
        
    this._initData();
        
    this._move(e);
        e.preventDefault();
      },
      
    //开始
      start: function() {
        
    if ( this._viewerWidth && this._viewerHeight ) {
            
    var image = this._image, START = this._START;
            $$E.addEvent( image, 
    "mouseover", START );
            $$E.addEvent( image, 
    "mousemove", START );
        }
      },
      
    //停止
      stop: function() {
        clearTimeout( 
    this._timer );
        $$E.removeEvent( 
    this._image, "mouseover"this._START );
        $$E.removeEvent( 
    this._image, "mousemove"this._START );
        $$E.removeEvent( document, 
    "mousemove"this._MOVE );
        $$E.removeEvent( document, 
    "mouseout"this._OUT );
        $$E.removeEvent( document, $$B.firefox 
    ? "DOMMouseScroll" : "mousewheel"this._MOUSE );
      },
      
    //修改设置
      reset: function(options) {
        
    this.stop();
        
        
    var viewer = this._viewer, zoom = this._zoom;
        
    if ( $$D.contains( viewer, zoom ) ) { viewer.removeChild( zoom ); }
        
        
    var opt = $$.extend( this.options, options || {} );
        
    this._scale = opt.scale;
        
    this._max = opt.max;
        
    this._min = opt.min;
        
    this._originPic = opt.originPic;
        
    this._zoomPic = opt.zoomPic;
        
    this._rangeWidth = opt.rangeWidth;
        
    this._rangeHeight = opt.rangeHeight;
        
        
    //重置属性
        this._loaded = this._substitute = false;
        
    this._rect = null;
        
    this._repairLeft = this._repairTop = 
        
    this._viewerWidth = this._viewerHeight = 0;
        
        
    this._initLoad();
      },
      
    //销毁程序
      dispose: function() {
        $$CE.fireEvent( 
    this"dispose" );
        
    this.stop();
        
    if ( $$D.contains( this._viewer, this._zoom ) ) {
            
    this._viewer.removeChild( this._zoom );
        }
        
    this._image.onload = this._preload.onload =
            
    this._image = this._preload = this._zoom = this._viewer =
            
    this.onLoad = this.onStart = this.onMove = this.onEnd =
            
    this._START = this._MOVE = this._END = this._OUT = null
      }
    }

    完整实例下载

    转载请注明出处:http://www.cnblogs.com/cloudgamer/

    如有任何建议或疑问,欢迎留言讨论。

    如果觉得文章不错的话,欢迎点一下右下角的推荐。

    程序中包含的js工具库CJL.0.1.min.js,原文在这里

  • 相关阅读:
    POJ1845 数论 二分快速取余
    CentOS6.5下安装wine
    Centos 6.5中安装后不能打开emacs的问题
    vim编辑器的设置文件
    centos无线网卡设置
    FreeBSD简单配置SSH并用root远程登陆方法
    在CentOS/RHEL 6.5上安装Chromium 谷歌浏览器
    Centos中安装Sublime编辑器
    强连通分量!
    强连通分量
  • 原文地址:https://www.cnblogs.com/zhwl/p/2529836.html
Copyright © 2011-2022 走看看