该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-20
最后修改:2010-09-25
程序就是模拟这样一个三维空间,里面的图片会根据三维坐标显示在这个空间。 很久以前就看过一个3DRoom效果,是用复杂的计算实现的。 在上一篇图片变换研究过css3的transform之后,就想到一个更简单的方法来实现。 在线效果预览 完整实例下载 程序说明 【实现原理】 3D效果的关键,是深度的实现。 把3D容器看成一个由多个不同深度的层组成的空间,这些层的尺寸默认跟容器一样。 层里面放了该深度的图片,并且各个层会根据深度的变化做缩放变换,从视觉上产生深度差。 缩放变换的比例按照最近点为1,最远点为0,逐渐变化。 关键的地方是层里面图片的尺寸和坐标必须跟着层同时变换,这个通过css3的transform很简单就能实现。 这样图片只需设置好尺寸再相对层定好位就行了,避免了随深度变化要不断调整图片尺寸和定位的麻烦。 【图片加载】 在程序初始化之后,就可以调用add方法来添加图片。 add方法有两个参数:图片地址和参数对象,还会返回一个图片操作对象。 操作对象包含以下属性和方法,方便对图片进行操作: img: 图片元素 src: 图片地址 options: 参数对象 show: 显示图片方法 remove: 移除图片方法 其中options可以设置如下属性: 属性: 默认值//说明 x: 0,//水平位移 y: 0,//垂直位移 z: 0,//深度 width: 0,//宽度 height: 0,//高度 scaleW: 1,//宽度缩放比例 scaleH: 1//高度缩放比例 其中x、y分别是水平和垂直坐标的位移参数,坐标原点在容器底部中间,水平坐标向右,纵坐标向上,单位是px。 而z是深度,用于比例的计算,方向由近点到原点。 坐标系如下图: 图片加载成功后,就会执行_load图片加载程序。 首先根据参数设置图片样式: img.style.cssText = "position:absolute;border:0;padding:0;margin:0;-ms-interpolation-mode:nearest-neighbor;" + "z-index:" + (99999 - z) + ";width:" + width + "px;height:" + height + "px;" + "left:" + (((clientWidth - width) / 2 + opt.x) / clientWidth * 100).toFixed(5) + "%;" + "top:" + ((clientHeight - height - opt.y) / clientHeight * 100).toFixed(5) + "%;";绝对定位是必须的,宽度和高度根据参数设置就行。 left和top根据坐标参数计算,这里需要用百分比的形式表示,后面再详细说明。 还要给图片增加一个_z属性记录深度,方便调用。 最后插入对应z的层,并重新显示该层。 【层变换】 图片加载后,会用_insertLayer程序把图片插入到对应的层中。 _insertLayer有两个参数:图片元素和z深度。 程序用_layers对象,以z为关键字记录对应的层元素。 如果在该深度还没有创建层,会自动创建一个: layer = document.createElement("div"); layer.style.cssText = "position:absolute;border:0;padding:0;margin:0;left:0;top:0;visibility:hidden;background:transparent;width:" + this._clientWidth + "px;height:" + this._clientHeight + "px;";层的坐标和尺寸要跟容器一致,因为插入图片的坐标是相对容器来定义的,这样使用起来比较方便。 还会添加一个_count属性,记录层包含的图片数,最后插入到容器并记录到_layers对象中。 获取层对象后,就把图片插入层中,并把_count计数加1。 接着就可以通过_showLayer程序根据深度显示对应的层。 程序包含三个坐标属性:_x、_y、_z,表示容器的三维坐标的偏移量。 首先通过_getScale获取比例方法得到z深度的缩放比例scale。 比例大于1,说明图片在视觉深度的后面,理论上应该看不到,所以隐藏;小于0,就是小到看不到了也隐藏。 而_x和_y偏移量也需要根据深度来重新计算,程序有两种偏移方式:远点固定和近点固定。 远点固定的意思是平面位移偏移量随着深度逐渐变小,产生以最远点为固定点移动方向的效果,近点固定就刚好相反。 要实现这个效果,只要位移偏移量也跟着比例变化就行了,即远点固定时偏移量跟比例成正比,远点固定时是反比: var moveScale = this.fixedFar ? scale : (1 - scale); 然后把这些参数交给_show程序来处理,并显示效果。 为了最大限度地利用层元素,程序会在_remove图片移除程序中,把没有图片的层放到_invalid废弃层集合中,在需要插入层时,优先从_invalid中获取。 【缩放比例】 上面已经说了,缩放比例应该按照最近点为1,最远点为0,逐渐变化。 程序默认是通过下面的公式计算: function(z){ return 1 - z / 1000; } 但用这个公式实现3DRoom效果的时候,会发现比例变化太急速,并不像这个3DRoom那样平稳。 研究代码后发现,原来它用的公式是这样的: this.r = FL / (FL + (z * Z)); 其中FL和Z是一个常量来的,即公式可表示成: function(z){ return 1/(1+z/常量); } 那按照这个公式,深度为0时比例为1,深度为常量时比例为0.5,深度为无穷大时比例为0。 变化效果可以参考这里的公式演示程序。 可以看出,缩放比例在默认公式是均匀变化的,而3DRoom公式是先快后慢,而且是逐渐变慢,所以有那种平稳的感觉。 那按照实际,还可以自己设计适合的公式,只要符合从1到0变化就行。 【css3模式】 程序中有三种缩放变换方式:css3、zoom和base,模式的程序结构跟上一篇图片变换类似。 缩放变换的目的是根据传递过来的比例和位置偏移量,把缩放效果显示出来,实现最终的3D效果。 css3模式使用的是css3的transform,在上一篇已经介绍过用transform的matrix做缩放和旋转,这次还需要后面两个参数做位置变换。 后面两个参数要注意单位的设置,在MDC的-moz-transform有说明: Gecko (Firefox) accepts a <length> value for tx and ty. Safari (WebKit) and Opera currently support a unitless <number> for tx and ty. 意思是位移参数tx和ty,在Firefox需要带单位,而WebKit和Opera只需要数字(不带单位,默认px)。 程序会根据浏览器设置单位。 使用css3模式,还可以通过修改_r弧度属性进行旋转。 最后设置matrix实现变换: layer.style[ css3Transform ] = "matrix(" + ( Cos * scale).toFixed(5) + "," + (Sin * scale).toFixed(5) + "," + (-Sin * scale).toFixed(5) + "," + (Cos * scale).toFixed(5) + ", " + Math.round(x) + unit + ", " + Math.round(y) + unit + ")"; 这里还要注意一个问题,计算得到的比例可能是一个很长的小数,在拼字符时会出问题。 例如执行:alert(0.0000001),会得到“1e-7”,js会用这个结果来拼字符,得到错误的结果。 所以在做数字和字符的拼接时,能用整数的应该先转成整数,小数的话也要用toFixed转换一下。 【zoom模式】 ie还不支持transform,但有一个zoom样式能实现类似的效果。 由于zoom后,尺寸会发生变化,所以需要修正left和top移动到正确的位置。 除了ie,webkit(chrome/safari)也支持zoom,不过ie6/7、ie8和webkit的实现并不完全相同。 测试以下代码: <style> .inner{ width:100px; height:100px; position:absolute; background:#0CF; zoom:0.5; top:50px; left:50px;} .inner div{ width:50px; height:50px;position:absolute; left:25px;background:#CCC;} </style> <div style="width:150px;height:150px; border:1px solid #000; position:relative;"> <div class="inner" id="t"><div>test</div></div> </div> 在ie6/7实现了想要的效果,但在webkit显示的位置错了。 原因是使用zoom后,元素的left和top也会随着缩放,那只要按比例重新计算就行。 像上面的例子,只要把left和top改成50/0.5,即100就正确了。 ie8就更麻烦,里面的内容是按zoom缩放了,但left和top还是原来的大小。 被这个问题困扰了很久,最后发现通过用百分比定位就可以解决,在图片加载时left和top要用百分比就是这个原因。 例如在例子中,修正left和top,并把最里面的div的left改成25%就可以了。 在ie8还看到一个问题,在zoom后,内容是缩小了,容器和内部元素的尺寸却没有变化,还好这不会影响到图片的显示,定位也要用left和top,免得麻烦。 还有,如果zoom的元素的尺寸用百分比设置,那元素的尺寸就不会根据zoom缩放了。 在计算时还要注意一个问题,上面提到在webkit和ie8,left和top都需要除以scale来修正,当scale接近0到一定程度,结果会变成Infinity(无穷大)。 用Infinity进行运算会出错,需要修正这个问题: left = Math.min(MAX, Math.max( -MAX, left )) | 0; top = Math.min(MAX, Math.max( -MAX, top )) | 0; 其中MAX是Number.MAX_VALUE(js能表达的最大数)。 【base模式】 还有兼容全部浏览器的base模式,用的是传统的方法,即根据缩放比例,计算并设置每个图片的尺寸和位置。 每次显示时,历遍层里面的图片,再逐个计算设置。 计算需要图片的原始位置和尺寸,在第一次计算时会把数据保存在_original属性中: var original = img._original = img._original || { width: img.offsetWidth, height: img.offsetHeight, left: img.offsetLeft, top: img.offsetTop }; 尺寸只要根据比例缩放就行,位置除了计算相对层的缩放还要加上相对容器的位移,这个跟zoom模式的计算是一样的。 理解了层变换的方式后,再理解这个就不难了。 【zIndex】 深度除了要缩放和定位,还需要合理的前后遮盖。 前后遮盖需要用zIndex来实现,可以在图片或层上设置。 首先最简单的方法是在层上设置: <style> div,img{width:200px;height:200px;position:absolute;left:0;top:0;} img{width:150px;height:150px;} </style> <div style="z-index:300;"> <img style="background:#0C9;" alt="300" onclick="alert(300)"> </div> <div style="z-index:100;"> <img style="background:#396;left:50px;top:50px;" alt="100" onclick="alert(100)"> </div> 实现一般的3D效果可以这样设置。 但点击测试,在ff和webkit前面的能触发后面的不能触发,而ie和opera就前后都可以触发。 ps:如果img换成div,那么ie和opera后面的元素也不能触发,原因还不清楚。 这样要想像3DRoom那样触发图片事件的话就不能在层设置zIndex。 还可以在图片上设置: <style> div,img{width:200px;height:200px;position:absolute;left:0;top:0;} img{width:150px;height:150px;} </style> <div> <img style="background:#0C9;z-index:300;" alt="300" onclick="alert(300)"> </div> <div> <img style="background:#396;left:50px;top:50px;z-index:100;" alt="100" onclick="alert(100)"> </div> 这样图片在所有浏览器都能正常触发,但在ie6/7层叠的效果失效了,看来在ie6/7只能在层用zIndex。 还有一个问题,如果给div加上变换效果: div{-moz-transform:scale(1);-webkit-transform:scale(1);-o-transform:scale(1);} 那图片上的zIndex就会失效,那css3模式就只能在层设置zIndex了。 总结一下: 在css3模式肯定要在层设置zIndex,但图片也不能触发事件。 在zoom和base模式,应该在图片设置zIndex,但在ie6/7就要在层设置。 这样至少在base模式层叠和图片触发事件都是正常的。 【msInterpolationMode】 开始做的时候,效果在ie8下会很卡,但这个3DRoom却不会卡,最后发现是使用了-ms-interpolation-mode。 这个东西在aoao的文章中看过,但没想到可以用在这里。 在MSDN有msInterpolationMode的介绍: Gets or sets the interpolation (resampling) method used to stretch images. 即获取或设置用于拉伸图像的插值(重采样)方法。 它有两个值: nearest-neighbor:使用近邻插值模式。 bicubic:使用高品质的双三次插值模式。 这些名词比较专业,我们只要知道使用nearest-neighbor效率高但效果差,而bicubic效果好效率低就够了。 程序把它设为nearest-neighbor提高效率,这样在ie8中也不会卡了。 【拖动方向变换/滚轮深度变换】 程序扩展了拖动视觉变换和滚轮深度变换。 拖动和滚动的做法跟上一个的做法差不多,这里拖动是实现方向的变换,滚轮是实现深度的变换。 移动是通过修改_x和_y属性来实现,缩放是通过修改_z来实现。 修改属性之后再调用show方法显示效果。 使用技巧 【3DRoom】 在3DRoom效果中,因为要实现图片的触发事件,所以不能用css3模式,原因是上面提到的层叠问题。 上面也提到在ie8被zoom的元素尺寸不会改变,导致触发范围错误,所以也不用zoom模式。 使用base模式就不会有问题了。 在点击图片时,视觉会移动到图片上面,这个通过点击图片后根据本身的三维参数修改_x/_y/_z来实现: img.onclick = function(){ i3D._z = -options.z | 0; i3D._x = -options.x | 0; i3D._y = options.y | 0; i3D.show(); } 图片在mouseover时会显示一个边框,为了让图片加边框后不发生位移,加了一个"-1px"的margin,mouseout时再去掉。 这里3DRoom跟参考的效果还是有差距,本文主要还是对3D效果的实现和研究。 【模式选择】 css3模式稳定,大部分浏览器都支持,除了ie。 zoom模式兼容性不好,但ie支持。 base最慢,但兼容性好,而且没有bug。 一般情况下应优先使用css3模式,然后是zoom,最后base,但像3DRoom那样的情况就要按实际选择了。 设计的时候,ie是打算用Matrix滤镜的,但开发中发现一些问题,效率又太低,就不考虑了。 使用说明 实例化时,必须有容器作为参数: var i3D = new Image3D( container, options ); 然后调用i3D方法添加图片: i3D.add( src, options ); 可选参数用来设置系统的默认属性,包括: 属性: 默认值//说明 mode: "css3|zoom|base",//模式 x: 0,//水平偏移值 y: 0,//垂直偏移值 z: 0,//深度偏移值 r: 0,//旋转角度(css3支持) fixedFar: false,//是否远点固定 getScale: function(z){ return 1 - z / 1000; },//获取比例方法 onError: function(err){}//出错时执行 add方法的可选参数在图片加载中已经说明。 还提供了以下方法: add:添加图片; show:显示效果; reset:重置默认状态; dispose:销毁程序。 加入拖动方向变换或滚轮深度变换扩展后,可通过设置相关参数定义变换范围。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-09-21
楼主真是神人.强大啊.
|
|
返回顶楼 | |
发表时间:2010-09-21
大量图片缩放是msInterpolationMode真是爽歪歪啊
|
|
返回顶楼 | |
发表时间:2010-09-21
楼主简直是天才,你做程序员对了。能把源码分享下吗?
|
|
返回顶楼 | |
发表时间:2010-09-21
最后修改:2010-09-21
pfans 写道 楼主简直是天才,你做程序员对了。能把源码分享下吗?
有完整程序下载了啊 |
|
返回顶楼 | |
发表时间:2010-09-22
太棒了太棒了太棒了太棒了太棒了太棒了
|
|
返回顶楼 | |
发表时间:2010-09-22
cloudgamer 写道 一般的平面效果,通过改变水平和垂直坐标就能实现,再加上深度,就能在视觉上的产生3D(三维)的效果。
程序就是模拟这样一个三维空间,里面的图片会根据三维坐标显示在这个空间。 很久以前就看过一个3DRoom效果,是用复杂的计算实现的。 在上一篇图片变换研究过css3的transform之后,就想到一个更简单的方法来实现。 在线效果预览 完整实例下载 程序说明 【实现原理】 3D效果的关键,是深度的实现。 把3D容器看成一个由多个不同深度的层组成的空间,这些层的尺寸默认跟容器一样。 层里面放了该深度的图片,并且各个层会根据深度的变化做缩放变换,从视觉上产生深度差。 缩放变换的比例按照最近点为1,最远点为0,逐渐变化。 关键的地方是层里面图片的尺寸和坐标必须跟着层同时变换,这个通过css3的transform很简单就能实现。 这样图片只需设置好尺寸再相对层定好位就行了,避免了随深度变化要不断调整图片尺寸和定位的麻烦。 【图片加载】 在程序初始化之后,就可以调用add方法来添加图片。 add方法有两个参数:图片地址和参数对象,还会返回一个图片操作对象。 操作对象包含以下属性和方法,方便对图片进行操作: img: 图片元素 src: 图片地址 options: 参数对象 show: 显示图片方法 remove: 移除图片方法 其中options可以设置如下属性: 属性: 默认值//说明 x: 0,//水平位移 y: 0,//垂直位移 z: 0,//深度 width: 0,//宽度 height: 0,//高度 scaleW: 1,//宽度缩放比例 scaleH: 1//高度缩放比例 其中x、y分别是水平和垂直坐标的位移参数,坐标原点在容器底部中间,水平坐标向右,纵坐标向上,单位是px。 而z是深度,用于比例的计算,方向由近点到原点。 坐标系如下图: 图片加载成功后,就会执行_load图片加载程序。 首先根据参数设置图片样式: img.style.cssText = "position:absolute;border:0;padding:0;margin:0;-ms-interpolation-mode:nearest-neighbor;" + "z-index:" + (99999 - z) + ";width:" + width + "px;height:" + height + "px;" + "left:" + (((clientWidth - width) / 2 + opt.x) / clientWidth * 100).toFixed(5) + "%;" + "top:" + ((clientHeight - height - opt.y) / clientHeight * 100).toFixed(5) + "%;";绝对定位是必须的,宽度和高度根据参数设置就行。 left和top根据坐标参数计算,这里需要用百分比的形式表示,后面再详细说明。 还要给图片增加一个_z属性记录深度,方便调用。 最后插入对应z的层,并重新显示该层。 【层变换】 图片加载后,会用_insertLayer程序把图片插入到对应的层中。 _insertLayer有两个参数:图片元素和z深度。 程序用_layers对象,以z为关键字记录对应的层元素。 如果在该深度还没有创建层,会自动创建一个: layer = document.createElement("div"); layer.style.cssText = "position:absolute;border:0;padding:0;margin:0;left:0;top:0;visibility:hidden;background:transparent;width:" + this._clientWidth + "px;height:" + this._clientHeight + "px;";层的坐标和尺寸要跟容器一致,因为插入图片的坐标是相对容器来定义的,这样使用起来比较方便。 还会添加一个_count属性,记录层包含的图片数,最后插入到容器并记录到_layers对象中。 获取层对象后,就把图片插入层中,并把_count计数加1。 接着就可以通过_showLayer程序根据深度显示对应的层。 程序包含三个坐标属性:_x、_y、_z,表示容器的三维坐标的偏移量。 首先通过_getScale获取比例方法得到z深度的缩放比例scale。 比例大于1,说明图片在视觉深度的后面,理论上应该看不到,所以隐藏;小于0,就是小到看不到了也隐藏。 而_x和_y偏移量也需要根据深度来重新计算,程序有两种偏移方式:远点固定和近点固定。 远点固定的意思是平面位移偏移量随着深度逐渐变小,产生以最远点为固定点移动方向的效果,近点固定就刚好相反。 要实现这个效果,只要位移偏移量也跟着比例变化就行了,即远点固定时偏移量跟比例成正比,远点固定时是反比: var moveScale = this.fixedFar ? scale : (1 - scale); 然后把这些参数交给_show程序来处理,并显示效果。 为了最大限度地利用层元素,程序会在_remove图片移除程序中,把没有图片的层放到_invalid废弃层集合中,在需要插入层时,优先从_invalid中获取。 【缩放比例】 上面已经说了,缩放比例应该按照最近点为1,最远点为0,逐渐变化。 程序默认是通过下面的公式计算: function(z){ return 1 - z / 1000; } 但用这个公式实现3DRoom效果的时候,会发现比例变化太急速,并不像这个3DRoom那样平稳。 研究代码后发现,原来它用的公式是这样的: this.r = FL / (FL + (z * Z)); 其中FL和Z是一个常量来的,即公式可表示成: function(z){ return 1/(1+z/常量); } 那按照这个公式,深度为0时比例为1,深度为常量时比例为0.5,深度为无穷大时比例为0。 变化效果可以参考这里的公式演示程序。 可以看出,缩放比例在默认公式是均匀变化的,而3DRoom公式是先快后慢,而且是逐渐变慢,所以有那种平稳的感觉。 那按照实际,还可以自己设计适合的公式,只要符合从1到0变化就行。 【css3模式】 程序中有三种缩放变换方式:css3、zoom和base,模式的程序结构跟上一篇图片变换类似。 缩放变换的目的是根据传递过来的比例和位置偏移量,把缩放效果显示出来,实现最终的3D效果。 css3模式使用的是css3的transform,在上一篇已经介绍过用transform的matrix做缩放和旋转,这次还需要后面两个参数做位置变换。 后面两个参数要注意单位的设置,在MDC的-moz-transform有说明: Gecko (Firefox) accepts a <length> value for tx and ty. Safari (WebKit) and Opera currently support a unitless <number> for tx and ty. 意思是位移参数tx和ty,在Firefox需要带单位,而WebKit和Opera只需要数字(不带单位,默认px)。 程序会根据浏览器设置单位。 使用css3模式,还可以通过修改_r弧度属性进行旋转。 最后设置matrix实现变换: layer.style[ css3Transform ] = "matrix(" + ( Cos * scale).toFixed(5) + "," + (Sin * scale).toFixed(5) + "," + (-Sin * scale).toFixed(5) + "," + (Cos * scale).toFixed(5) + ", " + Math.round(x) + unit + ", " + Math.round(y) + unit + ")"; 这里还要注意一个问题,计算得到的比例可能是一个很长的小数,在拼字符时会出问题。 例如执行:alert(0.0000001),会得到“1e-7”,js会用这个结果来拼字符,得到错误的结果。 所以在做数字和字符的拼接时,能用整数的应该先转成整数,小数的话也要用toFixed转换一下。 【zoom模式】 ie还不支持transform,但有一个zoom样式能实现类似的效果。 由于zoom后,尺寸会发生变化,所以需要修正left和top移动到正确的位置。 除了ie,webkit(chrome/safari)也支持zoom,不过ie6/7、ie8和webkit的实现并不完全相同。 测试以下代码: <style> .inner{ width:100px; height:100px; position:absolute; background:#0CF; zoom:0.5; top:50px; left:50px;} .inner div{ width:50px; height:50px;position:absolute; left:25px;background:#CCC;} </style> <div style="width:150px;height:150px; border:1px solid #000; position:relative;"> <div class="inner" id="t"><div>test</div></div> </div> 在ie6/7实现了想要的效果,但在webkit显示的位置错了。 原因是使用zoom后,元素的left和top也会随着缩放,那只要按比例重新计算就行。 像上面的例子,只要把left和top改成50/0.5,即100就正确了。 ie8就更麻烦,里面的内容是按zoom缩放了,但left和top还是原来的大小。 被这个问题困扰了很久,最后发现通过用百分比定位就可以解决,在图片加载时left和top要用百分比就是这个原因。 例如在例子中,修正left和top,并把最里面的div的left改成25%就可以了。 在ie8还看到一个问题,在zoom后,内容是缩小了,容器和内部元素的尺寸却没有变化,还好这不会影响到图片的显示,定位也要用left和top,免得麻烦。 还有,如果zoom的元素的尺寸用百分比设置,那元素的尺寸就不会根据zoom缩放了。 在计算时还要注意一个问题,上面提到在webkit和ie8,left和top都需要除以scale来修正,当scale接近0到一定程度,结果会变成Infinity(无穷大)。 用Infinity进行运算会出错,需要修正这个问题: left = Math.min(MAX, Math.max( -MAX, left )) | 0; top = Math.min(MAX, Math.max( -MAX, top )) | 0; 其中MAX是Number.MAX_VALUE(js能表达的最大数)。 【base模式】 还有兼容全部浏览器的base模式,用的是传统的方法,即根据缩放比例,计算并设置每个图片的尺寸和位置。 每次显示时,历遍层里面的图片,再逐个计算设置。 计算需要图片的原始位置和尺寸,在第一次计算时会把数据保存在_original属性中: var original = img._original = img._original || { width: img.offsetWidth, height: img.offsetHeight, left: img.offsetLeft, top: img.offsetTop }; 尺寸只要根据比例缩放就行,位置除了计算相对层的缩放还要加上相对容器的位移,这个跟zoom模式的计算是一样的。 理解了层变换的方式后,再理解这个就不难了。 【zIndex】 深度除了要缩放和定位,还需要合理的前后遮盖。 前后遮盖需要用zIndex来实现,可以在图片或层上设置。 首先最简单的方法是在层上设置: <style> div,img{width:200px;height:200px;position:absolute;left:0;top:0;} img{width:150px;height:150px;} </style> <div style="z-index:300;"> <img style="background:#0C9;" alt="300" onclick="alert(300)"> </div> <div style="z-index:100;"> <img style="background:#396;left:50px;top:50px;" alt="100" onclick="alert(100)"> </div> 实现一般的3D效果可以这样设置。 但点击测试,在ff和webkit前面的能触发后面的不能触发,而ie和opera就前后都可以触发。 ps:如果img换成div,那么ie和opera后面的元素也不能触发,原因还不清楚。 这样要想像3DRoom那样触发图片事件的话就不能在层设置zIndex。 还可以在图片上设置: <style> div,img{width:200px;height:200px;position:absolute;left:0;top:0;} img{width:150px;height:150px;} </style> <div> <img style="background:#0C9;z-index:300;" alt="300" onclick="alert(300)"> </div> <div> <img style="background:#396;left:50px;top:50px;z-index:100;" alt="100" onclick="alert(100)"> </div> 这样图片在所有浏览器都能正常触发,但在ie6/7层叠的效果失效了,看来在ie6/7只能在层用zIndex。 还有一个问题,如果给div加上变换效果: div{-moz-transform:scale(1);-webkit-transform:scale(1);-o-transform:scale(1);} 那图片上的zIndex就会失效,那css3模式就只能在层设置zIndex了。 总结一下: 在css3模式肯定要在层设置zIndex,但图片也不能触发事件。 在zoom和base模式,应该在图片设置zIndex,但在ie6/7就要在层设置。 这样至少在base模式层叠和图片触发事件都是正常的。 【msInterpolationMode】 开始做的时候,效果在ie8下会很卡,但这个3DRoom却不会卡,最后发现是使用了-ms-interpolation-mode。 这个东西在aoao的文章中看过,但没想到可以用在这里。 在MSDN有msInterpolationMode的介绍: Gets or sets the interpolation (resampling) method used to stretch images. 即获取或设置用于拉伸图像的插值(重采样)方法。 它有两个值: nearest-neighbor:使用近邻插值模式。 bicubic:使用高品质的双三次插值模式。 这些名词比较专业,我们只要知道使用nearest-neighbor效率高但效果差,而bicubic效果好效率低就够了。 程序把它设为nearest-neighbor提高效率,这样在ie8中也不会卡了。 【拖动方向变换/滚轮深度变换】 程序扩展了拖动视觉变换和滚轮深度变换。 拖动和滚动的做法跟上一个的做法差不多,这里拖动是实现方向的变换,滚轮是实现深度的变换。 移动是通过修改_x和_y属性来实现,缩放是通过修改_z来实现。 修改属性之后再调用show方法显示效果。 使用技巧 【3DRoom】 在3DRoom效果中,因为要实现图片的触发事件,所以不能用css3模式,原因是上面提到的层叠问题。 上面也提到在ie8被zoom的元素尺寸不会改变,导致触发范围错误,所以也不用zoom模式。 使用base模式就不会有问题了。 在点击图片时,视觉会移动到图片上面,这个通过点击图片后根据本身的三维参数修改_x/_y/_z来实现: img.onclick = function(){ i3D._z = -options.z | 0; i3D._x = -options.x | 0; i3D._y = options.y | 0; i3D.show(); } 图片在mouseover时会显示一个边框,为了让图片加边框后不发生位移,加了一个"-1px"的margin,mouseout时再去掉。 这里3DRoom跟参考的效果还是有差距,本文主要还是对3D效果的实现和研究。 【模式选择】 css3模式稳定,大部分浏览器都支持,除了ie。 zoom模式兼容性不好,但ie支持。 base最慢,但兼容性好,而且没有bug。 一般情况下应优先使用css3模式,然后是zoom,最后base,但像3DRoom那样的情况就要按实际选择了。 设计的时候,ie是打算用Matrix滤镜的,但开发中发现一些问题,效率又太低,就不考虑了。 使用说明 实例化时,必须有容器作为参数: var i3D = new Image3D( container, options ); 然后调用i3D方法添加图片: i3D.add( src, options ); 可选参数用来设置系统的默认属性,包括: 属性: 默认值//说明 mode: "css3|zoom|base",//模式 x: 0,//水平偏移值 y: 0,//垂直偏移值 z: 0,//深度偏移值 r: 0,//旋转角度(css3支持) fixedFar: false,//是否远点固定 getScale: function(z){ return 1 - z / 1000; },//获取比例方法 onError: function(err){}//出错时执行 add方法的可选参数在图片加载中已经说明。 还提供了以下方法: add:添加图片; show:显示效果; reset:重置默认状态; dispose:销毁程序。 加入拖动方向变换或滚轮深度变换扩展后,可通过设置相关参数定义变换范围。 |
|
返回顶楼 | |
发表时间:2010-09-22
很复杂,很bt,膜拜地飘过
|
|
返回顶楼 | |
发表时间:2010-09-22
惊叹中...
|
|
返回顶楼 | |
发表时间:2010-09-23
楼主太牛了,这么好的效果。
|
|
返回顶楼 | |