【原创】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



程序说明【扩展模式】上次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"模式时,以上两个参数都可以使用。
学习学习。。。
路过赞一个:)
佩服,接分!!!
学习…
谢谢支持
大神又有新作啊O(∩_∩)O哈哈~研究一下。
强烈支持………
ding……..
谢谢楼主分享,你的每篇文章我都会关注的。看帖必回贴。
很好。。。。。。。。。。。。
欢迎测试
仰慕lz中…
先占座。
支持~~写了这么多效果~ 可以去出本书了~
几个模式来回切换的时候有残留环境:IE8浏览器先选:手柄切割模式 快速移动到手柄模式并选中现象:遮罩层残留
接分!!好东西不错
接分!!好东西不错
几个模式来回切换的时候有残留环境:IE8浏览器先选:手柄切割模式 快速移动到手柄模式并选中现象:遮罩层残留good!谢谢
很好、很强大、很实用,再美观一点可以作为仿图片工具条的模式。JF支持
很好很强大,学习了
路过看看
mark
谢谢楼主!
不错啊,分享了
学习.牛人.
每天回帖即可获得10分可用分!小技巧 呵呵
帮顶 谢谢!
shou xia
恩!不错
不错 谢谢
膜拜下,顺便攒下伴水清洁工一语中的
太棒了,哈哈,高人
接分 学习~~
进来学习一下
一定学习
好东西!谢谢!
接分。学习
好东西
强大的哥
学习了
学习了,这个方法不错
henshiyong
我来拜神。。。。学习。
强烈支持………
学习学习
Mark 学习!!!
mark!顶!!
很好很牛叉!
Mark 学习!!!
……. bucuo bucuo
ddddddddddddddddddddddddddddddddddddddddd
呵呵 好东西 很多时候都能用上!
呵呵 好东西 很多时候都能用上!
佩服!
学习。。
接分了。。。。
顶、、、、、、、、、、、、、、、、、、、、、
顶,谢谢分享
支持!
顶,,,
飘过接分
等一个。。。
好东西值得收藏…
多多学习学习
收藏… 顺便JF
[b][/b]MK……………………
好,学习学习
赞一个…真是牛人
thx~~~~~~~~~~~~~~~~~~~
DDDDDDDDDDDdd
牛………..
楼主 果然牛肉
强人!!!!
强势!!!!
学习……
收藏,顺便顶一下
佩服,接分!!!
好!顺便顶一下
接分。 学习。。。
谁帮我修改一下原理稍有些复杂,以水平坐标为例,先看下图:这里那个图片代码错了没显示出来
来看看效果的。。。。。。。。。
收藏 学习
太复杂了,先收藏起来。
路过学习下!!!
值得学习!!!
有没有分接啊。。。。
学习了,先保存了,以后研究。
仰慕lz中…
帮顶 谢谢!翻页麻烦直接引用 呵呵
下载了,谢谢分享
谢谢支持
好,学习了!
不错,不错,好东西,有用。
不错不错,学习学习。
其中模式名就是基础模式的名字,options是可选参数扩展,methods是程序结构的扩展。基础模式包含"follow", "handle"和"cropper"模式,后面再详细介绍。methods包含要扩展的钩子程序,是扩展的主要部分。ps:这里说的模式不是“设计模式”里面的模式。扩展需要在程序初始化时进行,要放在_initialize程序之前执行。为了不影响原程序的结构,这里用织入法在_initialize之前插入一段程序: