【原创】ImageZoom 图片放大效果(扩展篇)
admin 发表于 2010-04-25 | 来源:互联网 | 阅读:

上一篇ImageZoom已经对图片放大效果做了详细的分析,这次在ImageZoom的基础上进行扩展,实现更多的效果。
主要扩展了原图和显示框的展示模式,有以下几种模式:
"follow" 跟随模式:显示框能跟随鼠标移动的效果;
"handle" 拖柄模式:原图上有一个拖柄来标记显示范围;
"cropper" 切割模式:原图用不透明的来标记显示范围,其他部分用半透明显示;
"handle-cropper" 拖柄切割模式:拖柄模式和切割模式的混合版,同时用透明度和拖柄来标记显示范围。
当然更多的扩展等待你的想象力来发掘。
兼容:ie6/7/8, firefox 3.6.2, opera 10.51, safari 4.0.4, chrome 4.1

欢迎来我的blog讨论

完整实例下载

已经有100 个评论
  1. 萌芽邪恶 说:

    程序说明【扩展模式】上次ImagesLazyLoad使用了继承做扩展,这次用插件的形式来做扩展。先看看基础模式,这些模式是保存在ImageZoom._MODE中的,类似这样的结构:JScript code
    ImageZoom._MODE = {
    模式名: {
    options: {

    },
    methods: {
    init: function() {

    },

    }
    },

    }
    其中模式名就是基础模式的名字,options是可选参数扩展,methods是程序结构的扩展。基础模式包含"follow", "handle"和"cropper"模式,后面再详细介绍。methods包含要扩展的钩子程序,是扩展的主要部分。ps:这里说的模式不是“设计模式”里面的模式。扩展需要在程序初始化时进行,要放在_initialize程序之前执行。为了不影响原程序的结构,这里用织入法在_initialize之前插入一段程序:JScript code
    ImageZoom.prototype._initialize = (function(){
    var init = ImageZoom.prototype._initialize,
    …;
    return function(){

    init.apply( this, arguments );
    }
    })();
    原理就是先保存原来的函数,插入一段程序组成新函数,然后重新替换原来的函数。考虑到组合基础模式的情况,使用了一个对象保存真正使用的模式:JScript code
    mode = ImageZoom._MODE,
    modes = {
    "follow": [ mode.follow ],
    "handle": [ mode.handle ],
    "cropper": [ mode.cropper ],
    "handle-cropper": [ mode.handle, mode.cropper ]
    };
    可以看到"handle-cropper"模式其实就是"handle"和"cropper"的组合模式。插入的程序的主要任务是根据设定好的基础模式,进行扩展:JScript code
    var options = arguments[2];
    if ( options && options.mode && modes[ options.mode ] ) {
    $$A.forEach( modes[ options.mode ], function( mode ){
    $$.extend( options, mode.options, false );
    $$A.forEach( mode.methods, function( method, name ){
    $$CE.addEvent( this, name, method );
    }, this );
    }, this );
    }
    首先扩展options可选参数对象,由于可选参数是第三个参数,所以用arguments[2]获取。extend的第三个参数设为false,说明不重写相同属性,即保留自定义的属性值。然后把methods里面的方法作为钩子函数逐个添加到程序中。methods可以包含init, load, start, repair, move, end, dispose这几个方法,分别对应ImageZoom中初始化、加载、开始、修正、移动、结束和销毁事件。在扩展时,不同的事件执行不同的任务:init初始化函数:用来设置扩展需要的属性,注意这些属性不要跟ImageZoom本身的属性冲突了,即重名。load加载函数:图片加载完成,相关参数也设置完成,主要做执行放大效果前的准备工作。start开始函数:触发放大效果时执行的。repair修正函数:用于修正大图定位的坐标值。move移动函数:触发放大效果后,鼠标移动时执行的。end结束函数就:结束放大效果时执行的。dispose销毁函数:在移除程序时清理程序的。ps:具体位置参考ImageZoom中使用$$CE.fireEvent的部分。可以看到这里用了织入法(weave)和钩子法(hook)对程序做扩展。织入法是一种aop,可以在不改变原程序的基础上进行扩展,但只能在函数前面或后面加入程序。而钩子法必须在原程序中设置好对应钩子才能配合使用,但位置相对灵活。【跟随模式】在"follow"跟随模式中,进行放大时,显示框会跟随鼠标移动,就像拿着放大镜看的效果。首先显示框要绝对定位,要实现显示框跟随鼠标移动,只要在move中设置对应的left/top就行了:var style = this._viewer.style;style.left = e.pageX – this._repairFollowLeft + "px";style.top = e.pageY – this._repairFollowTop + "px";其中pageX/pageY是鼠标当前的坐标,_repairFollowLeft/_repairFollowTop是坐标的修正参数。修正参数是在load中设置的,如果显示框隐藏的话,用上一篇获取显示范围的方法获取参数:JScript code
    if ( !viewer.offsetWidth ) {
    styles = { display: style.display, visibility: style.visibility };
    $$D.setStyle( viewer, { display: "block", visibility: "hidden" });
    }

    if ( styles ) { $$D.setStyle( viewer, styles ); }
    为了跟随时,让鼠标固定在显示框中心位置,先根据显示框的offsetWidth/offsetHeight修正参数:this._repairFollowLeft = viewer.offsetWidth / 2;this._repairFollowTop = viewer.offsetHeight / 2;如果显示框的offsetParent不是body,还需要根据offsetParent修正坐标:JScript code
    if ( !/BODY|HTML/.test( viewer.offsetParent.nodeName ) ) {
    var parent = viewer.offsetParent, rect = $$D.rect( parent );
    this._repairFollowLeft += rect.left + parent.clientLeft;
    this._repairFollowTop += rect.top + parent.clientTop;
    }
    ps:在Maxthon测试时发现body子元素的offsetParent不是body而是html。为了在移除程序后,能恢复显示框的样式,在load程序中做了样式的备份:var viewer = this._viewer, style = viewer.style, styles;JScript code
    this._stylesFollow = {
    left: style.left, top: style.top, position: style.position
    };
    并在dispose中恢复:$$D.setStyle( this._viewer, this._stylesFollow );现在已经达到了基本的效果,但由于大图移动范围的限制,当鼠标移动到接近边界时,大图就卡住不会动了。为了实现在鼠标移动时,大图会持续变化的效果,在repair中修正了移动坐标:pos.left = ( viewerWidth / 2 – pos.left ) * ( viewerWidth / zoom.width – 1 );pos.top = ( viewerHeight / 2 – pos.top ) * ( viewerHeight / zoom.height – 1 );原理稍有些复杂,以水平坐标为例,先看下图:[img]http://www.cnblogs.com/images/cnblogs_com/cloudgamer/169629/o_ImageZoom.jpg[/img]大方框代表大图对象,小方框代表显示框。当前位置是根据鼠标坐标得到的实际显示的位置,目标位置想要实现效果的位置。有一些物理或几何知识应该明白这个等式:x / y = m / n可以推出:y = x * n / m = x * ( zoom.width – viewerWidth ) / zoom.heightx当前坐标可以通过pos.left来得到:x = viewerWidth / 2 – pos.left最后得到:left = -y = ( viewerWidth / 2 – pos.left ) * ( viewerWidth / zoom.width – 1 )垂直坐标也差不多。【拖柄模式】拖柄是一个层,在原图上面,用来表示显示范围在原图的位置和范围。显示范围可以根据_rangeWidth/_rangeHeight获取。至于位置的指定可以根据鼠标坐标或大图定位坐标来设置。如果鼠标坐标的话还必须做其他处理,例如范围控制,而根据大图定位坐标相对就方便准确得多,程序也是用后面一个方法。首先在init定义一个_handle拖柄对象:JScript code
    var handle = $$( this.options.handle );
    if ( !handle ) {
    var body = document.body;
    handle = body.insertBefore(this._viewer.cloneNode(false), body.childNodes[0]);
    handle.id = "";
    handle["_createbyhandle"] = true;
    }
    $$D.setStyle( handle, { padding: 0, margin: 0, display: "none" } );
    如果没有自定义拖柄对象,会复制显示框作为拖柄对象。对于自动生成的拖柄对象,会添加"_createbyhandle"属性作标记,方便在dispose中移除。在load时,设置拖柄样式:JScript code
    $$D.setStyle( handle, {
    position: "absolute",
    width: this._rangeWidth + "px",
    height: this._rangeHeight + "px",
    display: "block",
    visibility: "hidden"
    });
    绝对定位是必须的,并根据_rangeWidth/_rangeHeight设置尺寸。设置display和visibility是为了下面获取参数。先根据原图坐标获取修正参数:this._repairHandleLeft = rect.left + this._repairLeft – handle.clientLeft;this._repairHandleTop = rect.top + this._repairTop – handle.clientTop;和跟随模式类似,也要做offsetParent定位的修正:JScript code
    if ( handle.offsetParent.nodeName.toUpperCase() != "BODY" ) {
    var parent = handle.offsetParent, rect = $$D.rect( parent );
    this._repairHandleLeft -= rect.left + parent.clientLeft;
    this._repairHandleTop -= rect.top + parent.clientTop;
    }
    然后重新隐藏:$$D.setStyle( handle, { display: "none", visibility: "visible" });在start时,显示拖柄对象。在move时,根据大图定位坐标设置拖柄定位:JScript code
    var style = this._handle.style, scale = this._scale;
    style.left = Math.ceil( this._repairHandleLeft – x / scale ) + "px";
    style.top = Math.ceil( this._repairHandleTop – y / scale ) + "px";
    在end时,隐藏拖柄对象。【切割模式】“切割”就是选择的部分全透明,其他部分半透明的效果。主要通过clip来实现,具体原理可以看图片切割效果。为了实现切割效果,需要在init中新建一个_cropper切割层:JScript code
    var body = document.body,
    cropper = body.insertBefore(document.createElement("img"), body.childNodes[0]);
    cropper.style.display = "none";
    并在load中设置这个切割层:JScript code
    cropper.src = image.src;
    cropper.width = image.width;
    cropper.height = image.height;
    $$D.setStyle( cropper, {
    position: "absolute",
    left: rect.left + this._repairLeft + "px",
    top: rect.top + this._repairTop + "px"
    });
    差不多是复制一个原图对象,并且绝对定位到原图对象上面。在start时,显示切割层,并根据透明度设置原图为半透明状态。在move时,根据大图移动的坐标设置切割层要clip的范围:JScript code
    var w = this._rangeWidth, h = this._rangeHeight, scale = this._scale;
    x = Math.ceil( -x / scale ); y = Math.ceil( -y / scale );
    this._cropper.style.clip = "rect(" + y + "px " + (x + w) + "px " + (y + h) + "px " + x + "px)";
    在end时,隐藏切割层,并重新设置原图为不透明,来恢复原来的状态。还要记得在dispose中移除切割层。使用技巧需要扩展的效果时才需要添加这个扩展程序。可自行对ImageZoom._MODE进行扩展,扩展后记得在modes添加对应模式。可以组合多个基础模式同时使用,具体参考"handle-cropper"模式。使用说明使用方法跟ImageZoom差不多,只是多了一个可选参考mode设置显示模式。使用"handle"模式时,可选参数的"handle"属性可以设置拖柄对象。使用"cropper"模式时,可选参数的"opacity"属性可以设置透明度。使用"handle-cropper"模式时,以上两个参数都可以使用。

  2. mikeyao210 说:

    学习学习。。。

  3. look 说:

    路过赞一个:)

  4. dovemail 说:

    佩服,接分!!!

  5. xiaobao520 说:

    学习…

  6. yyyy6 说:

    谢谢支持

  7. kook 说:

    大神又有新作啊O(∩_∩)O哈哈~研究一下。

  8. liangjiaqi 说:

    强烈支持………

  9. 风子 说:

    ding……..

  10. 徐咏波 说:

    谢谢楼主分享,你的每篇文章我都会关注的。看帖必回贴。

  11. weiwei 说:

    很好。。。。。。。。。。。。

  12. my159 说:

    欢迎测试

  13. jc2008_828 说:

    仰慕lz中…

  14. 421056 说:

    先占座。

  15. WOOMYWOODY 说:

    支持~~写了这么多效果~ 可以去出本书了~

  16. 15375 说:

    几个模式来回切换的时候有残留环境:IE8浏览器先选:手柄切割模式  快速移动到手柄模式并选中现象:遮罩层残留

  17. 405290688 说:

    接分!!好东西不错

  18. awaywind 说:

    接分!!好东西不错

  19. geqian5 说:

    几个模式来回切换的时候有残留环境:IE8浏览器先选:手柄切割模式 快速移动到手柄模式并选中现象:遮罩层残留good!谢谢

  20. xiaobao520 说:

    很好、很强大、很实用,再美观一点可以作为仿图片工具条的模式。JF支持

  21. 405290688 说:

    很好很强大,学习了

  22. jc2008_828 说:

    路过看看

  23. 96789123 说:

    mark

  24. 风子 说:

    谢谢楼主!

  25. mikeyao210 说:
  26. dovemail 说:

    不错啊,分享了

  27. water20042 说:

    学习.牛人.

  28. yyyy6 说:

    每天回帖即可获得10分可用分!小技巧 呵呵

  29. dddylwlw 说:

    帮顶 谢谢!

  30. lee 说:

    shou xia

  31. weiwei 说:

    恩!不错

  32. rongxin 说:

    不错 谢谢

  33. weiwei 说:

    膜拜下,顺便攒下伴水清洁工一语中的

  34. xwcylm 说:

    太棒了,哈哈,高人

  35. waterskin 说:

    接分 学习~~

  36. my159 说:

    进来学习一下

  37. rongxin 说:

    一定学习

  38. 萌芽邪恶 说:

    好东西!谢谢!

  39. xiaobao520 说:

    接分。学习

  40. 421056 说:

    好东西

  41. 徐咏波 说:

    强大的哥

  42. doing7 说:

    学习了

  43. boysee 说:

    学习了,这个方法不错

  44. waterskin 说:

    henshiyong

  45. boysee 说:

    我来拜神。。。。学习。

  46. lchz 说:

    强烈支持………

  47. 徐咏波 说:

    学习学习

  48. boysee 说:

    Mark 学习!!!

  49. aw3fae 说:

    mark!顶!!

  50. dbb123 说:

    很好很牛叉!

  51. weiwei 说:

    Mark 学习!!!

  52. sbamd 说:

    ……. bucuo bucuo

  53. doing7 说:

    ddddddddddddddddddddddddddddddddddddddddd

  54. doing7 说:

    呵呵 好东西 很多时候都能用上!

  55. 天天累 说:

    呵呵 好东西 很多时候都能用上!

  56. nrc001 说:

    佩服!

  57. rongxin 说:

    学习。。

  58. 天天累 说:

    接分了。。。。

  59. 天天累 说:

    顶、、、、、、、、、、、、、、、、、、、、、

  60. boysee 说:

    顶,谢谢分享

  61. lee 说:

    支持!

  62. lee 说:

    顶,,,

  63. dddylwlw 说:

    飘过接分

  64. doing7 说:

    等一个。。。

  65. geqian5 说:

    好东西值得收藏…

  66. look 说:
  67. my159 说:

    多多学习学习

  68. my159 说:

    收藏… 顺便JF

  69. nrc001 说:

    [b][/b]MK……………………

  70. 15375 说:

    好,学习学习

  71. yyyy6 说:

    赞一个…真是牛人

  72. 萌芽邪恶 说:

    thx~~~~~~~~~~~~~~~~~~~

  73. awaywind 说:

    DDDDDDDDDDDdd

  74. 红烧生鱼片 说:

    牛………..

  75. liangjiaqi 说:

    楼主 果然牛肉

  76. hahamy 说:

    强人!!!!

  77. 红烧生鱼片 说:

    强势!!!!

  78. waterskin 说:
  79. 风子 说:

    学习……

  80. 萌芽邪恶 说:

    收藏,顺便顶一下

  81. dddylwlw 说:

    佩服,接分!!!

  82. kook 说:

    好!顺便顶一下

  83. nashliu 说:

    接分。 学习。。。

  84. dbb123 说:

    谁帮我修改一下原理稍有些复杂,以水平坐标为例,先看下图:这里那个图片代码错了没显示出来

  85. mikeyao210 说:

    来看看效果的。。。。。。。。。

  86. dovemail 说:

    收藏 学习

  87. look 说:

    太复杂了,先收藏起来。

  88. 红烧生鱼片 说:

    路过学习下!!!

  89. 风子 说:

    值得学习!!!

  90. nashliu 说:

    有没有分接啊。。。。

  91. dovemail 说:

    学习了,先保存了,以后研究。

  92. nashliu 说:

    仰慕lz中…

  93. 405290688 说:

    帮顶 谢谢!翻页麻烦直接引用  呵呵

  94. awaywind 说:

    下载了,谢谢分享

  95. xwcylm 说:

    谢谢支持

  96. hahamy 说:

    好,学习了!

  97. sbamd 说:
  98. wtaxum 说:

    不错,不错,好东西,有用。

  99. 天天累 说:

    不错不错,学习学习。

  100. xwcylm 说:

    其中模式名就是基础模式的名字,options是可选参数扩展,methods是程序结构的扩展。基础模式包含"follow", "handle"和"cropper"模式,后面再详细介绍。methods包含要扩展的钩子程序,是扩展的主要部分。ps:这里说的模式不是“设计模式”里面的模式。扩展需要在程序初始化时进行,要放在_initialize程序之前执行。为了不影响原程序的结构,这里用织入法在_initialize之前插入一段程序:

我要评论

评论功能因故关闭!

请加入我们的QQ群一起参与讨论:群号59400482(500人超级群)


返回首页 | 关于我们 | 联系我们 | 广告合作 | 网站地图 | 友情链接 | 版权声明