zoukankan      html  css  js  c++  java
  • 图片(旋转/缩放/翻转)变换效果(ccs3/滤镜/canvas)(转)

     

    http://www.cnblogs.com/cloudgamer/archive/2010/08/16/ImageTrans.html(原文地址)

    以前要实现图片的旋转或翻转,只能用ie的滤镜来实现,虽然canvas也实现,但ie不支持而且不是html标准。 css3出来后,终于可以用标准的transform来实现变换,而canvas也已成为html5标准的一部分。 css3和html5使web变得越来越强大,各种新奇的技术正等待我们发掘。 本程序分别通过滤镜(ie)、ccs3和canvas来实现图片的旋转、缩放和翻转变换效果,可以用作图片查看器。 有如下特色: 1,用滤镜、ccs3和canvas实现相同的变换效果; 2,可任意角度旋转; 3,可任意角度翻转; 4,可扩展滚轮缩放; 5,可扩展拖动旋转。 兼容:ie6/7/8, firefox 3.6.8, opera 10.6, safari 5.0.1, chrome 5.0

    效果预览

            

    程序说明

    【基本原理】

    变换主要是利用css3的变换样式transform的matrix方法来实现。 ie不支持css3,但有Matrix滤镜也能实现类似的效果。 程序还用canvas,通过画图实现相同的效果。

    【模式设置】

    程序包含三种模式:css3、filter和canvas,程序初始化时,会根据自定义模式进行模式设置。 各个模式相关的属性和方法都存放在ImageTrans.modes中。 每个模式对象都包含support属性,表示当前浏览器是否支持该模式,还有几个方法: init:初始化执行程序 load:加载图片执行程序 show:变换显示程序 dispose:销毁程序

    使用这样的格式来自定义模式:"css3|filter|canvas",判断过程主要在_initMode程序中:

    代码

    程序会按顺序逐个判断,当浏览器支持该模式时就会用该模式的方法设置程序函数。 再用_support记录浏览器是否支持指定的模式。

    如果浏览器支持,才执行_initContainer容器初始化程序和_init模式初始化程序。

    【加载图片】

    完成初始化设置后,再执行load方法加载图片。 在load方法中,主要对图片进行设置:

    img.onload || ( img.onload = this._LOAD ); img.onerror || ( img.onerror = function(){ oThis.onError("err image"); } );

    最后设置src加载图片。

    图片加载成功后,会执行_LOAD程序,在里面会执行_load加载程序和reset方法。 在reset中,会重置变换参数,并执行_show模式画图程序:

    this._y = this._x = 1this._radian = 0; this._show();

    这时,图片会以初始状态显示。

    【图片变换】

    图片加载完成后,就可以对图片进行变换。

    各种变换方法保存在ImageTrans.transforms中,包括旋转、垂直翻转、水平翻转、缩放等。 变换结果是通过_y垂直变换参数、_x水平变换参数和_radian旋转变换参数计算得到的。 变换方法就是用来修改这些参数的方法。

    一般的翻转是通过把_y或_x取反来实现的,是以图片本身为坐标的翻转。 但用户的习惯是按浏览器坐标来翻转的,当图片先旋转变换坐标后再翻转,就不符合用户习惯了。 为了能按视觉习惯坐标来翻转,程序使用的方法是先旋转再翻转来实现。 例如vertical垂直翻转是图片旋转180度,再进行一般的水平翻转:

    this._radian = Math.PI - this._radian; this._x *= -1;

    而horizontal水平翻转也类似:

    this._radian = Math.PI - this._radian; this._y *= -1;

    实际也是利用了一些坐标变换原理。

    rotate旋转是以弧度为单位的,直接修改_radian参数。 rotatebydegress是以角度为单位的旋转,其实是用degress * Math.PI/180公式把角度转换成弧度。 left向左转90度是在原有弧度减Math.PI/2(即90度),而right向右转90度是加Math.PI/2。

    scale缩放就是根据缩放比率分别对_y和_x进行修改。 程序定义了一个getZoom修正缩放比率函数:

    function getZoom(scale, zoom) {     return    scale > 0 && scale >-zoom ? zoom :             scale < 0 && scale < zoom ?-zoom : 0; }

    只有当比率不会导致结果是反值的情况才会返回正确的比率。 这里主要是保证缩到最小时不会因为比率太大得到反值,导致图片翻转并放大。 当垂直和水平比率都不是0,才会对参数进行修改:

    var hZoom = getZoom( this._x, zoom ), vZoom = getZoom( this._y, zoom ); if ( hZoom && vZoom ) {     this._x += hZoom; this._y += vZoom; }

    这样可以保证水平和垂直缩放同时进行,保持图片比例。 要注意zoomin放大时要保证缩放比率为正数,zoomout缩小就要负数。

    这些方法会在模式设置中扩展到程序中:

    $$A.forEach( ImageTrans.transforms, function(transform, name){     this[ name ] = function(){         transform.apply( this, [].slice.call(arguments) );         this._show();     } }, this );

    在执行完变换方法后,就会执行_show来显示变换。

    【transform】

    变换换流程介绍完,就进入主题,介绍三个变换方法了。 先看看css3的transform,它包含以下变换方法: matrix:矩阵变形,使用它就可以做到后面所有的变换,但使用相对麻烦; translate/translateX/translateY:坐标变换,就是移动坐标的意思; scale/scaleX/scaleY:缩放变换,放大缩小,取负值可以做翻转; rotate:旋转变换,根据角度旋转; skew/skewX/skewY:拉扯变换,就是上下或左右向不同的方向扯开的效果。 更详细的介绍请看w3c的CSS 2D Transforms或者MDC的-moz-transform

    要进行变换,首先要看看浏览器是否支持:

    代码

    由于程序运行时文档可能还没载入,所以要手动创建一个元素来测试。 虽然w3c标准使用的是transform,但现阶段各浏览器还是需要各自的前缀。 当元素样式包含其中一个变换样式,说明该浏览器支持,再用css3Transform记录样式名字。

    在css3模式的init程序中,会执行initImg方法对图片进行设置:

    $$D.setStyle( img, {     position: "absolute",     border: 0, padding: 0, margin: 0,  "auto", height: "auto",     visibility: "hidden" }); container.appendChild( img );

    主要是设置绝对定位、隐藏和重置样式,最后插入容器。 ps:图片对象虽然是用new Image()创建的,但也可以当作img元素来操作。

    在load加载程序中,再对图片样式进行设置:

    $$D.setStyle( img, {     top: ( this._clientHeight - img.height ) / 2 + "px",     left: ( this._clientWidth - img.width ) / 2 + "px",     visibility: "visible" });

    设置left和top使图片在容器里居中,并显示图片。

    关键的show程序,用来进行图片变换,这里用的是matrix变换。 matrix有6个参数,前4个是矩阵变换参数,后两个是坐标变换参数。 要根据弧度旋转,可以这样设置矩阵: cos(a) -sin(a) sin(a)  cos(a) 而缩放变换就这样设置: sx 0 0  sy 旋转同时缩放,矩阵相乘得到: cos(a)*sx -sin(a)*sy sin(a)*sx  cos(a)*sy 关于Matrix矩阵变换可以看w3c的Transform Matrix

    getMatrix函数就是通过以上矩阵计算matrix参数:

    var Cos = Math.cos(radian), Sin = Math.sin(radian); return {     M11: Cos * x, M12:-Sin * y,     M21: Sin * x, M22: Cos * y };

    在show程序里面,用getMatrix得到参数后,就可以设置样式:

    this._img.style[ css3Transform ] = "matrix("     + matrix.M11 + "," + matrix.M21 + ","     + matrix.M12 + "," + matrix.M22 + ", 0, 0)";

    在实际使用中,使用matrix可能要设置一堆可读性很差的数字,所以还是推荐用其他变换方法。

    【Matrix滤镜】

    ie的Matrix滤镜跟css3的matrix差不多,也能实现类似的变换。 Matrix滤镜有以下属性: Dx/Dy:坐标变换参数; enabled:是否可用; FilterType:定义新内容的像素的方法; M11/M12/M21/M22:矩阵变换参数; SizingMethod:容器是否改变尺寸去适应目标图像。 详细参考msdn的Matrix Filter中文Matrix说明

    判断浏览器是否支持,也是创建一个div,看它有没有"filters"属性:

    function(){ return "filters" in document.createElement("div"); }()

    在init程序中也用initImg方法对图片进行设置,此外还需要设置Matrix滤镜:

    this._img.style.filter = "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand')";

    这里会设置SizingMethod属性,它有两个值,分别是:clip to original(容器不改变尺寸)和auto expand(容器改变尺寸以适应目标图像)。 如果使用默认值clip to original,容器的大小不会变,那么变换时超出容器的部分就会隐藏不见,所以这里要设为'auto expand'才能完整显示图片。

    在load程序中显示图片,为了防止ie重复加载gif的bug还要重置onload为null。 ps:该bug的研究可以参考这里的显示预览部分

    而show程序也跟css3模式类似,通过getMatrix方法获取变换参数,并设置到滤镜中:

    $$.extend(     img.filters.item("DXImageTransform.Microsoft.Matrix"),     getMatrix( this._radian, this._x, this._y ) );

    滤镜使用了'auto expand'后,变换时图片元素尺寸会随着内容变化,所以要重新设置居中:

    img.style.top = ( this._clientHeight - img.offsetHeight ) / 2 + "px"; img.style.left = ( this._clientWidth - img.offsetWidth ) / 2 + "px";

    ie还有其他变换滤镜,例如FlipH(水平翻转)、FlipV(垂直翻转)、Wave(扭曲)等。

    【canvas】

    通过滤镜和css3已经能在主流的浏览器上兼容实现相同的变换,最后再用canvas来实现。 canvas是一个用来绘制图形的元素,它最强大的地方在于结合js来绘制图形甚至制作动画和游戏。 ps:这里推荐几个入门文章:Opera的HTML 5 canvas深入了解canvas标签系列

    要知道浏览器是否支持canvas,可以创建一个canvas元素,看它是否有"getContext"方法来判断:

    function(){ return "getContext" in document.createElement('canvas'); }()

    getContext方法用来获取渲染空间(也叫上下文),之后会在这个空间绘图,相当于获取画布。

    在init程序中,创建并设置canvas及其上下文context:

    代码

    程序中只需要2D canvas,所以用getContext('2d')就行了。 ps:关于3D canvas在Opera的HTML 5 canvas有相关的介绍。 还需要设置尺寸,这里要注意要用width和height来设置,我试过用样式来设置,结果画图不正常。

    在show程序中进行变换和画图:

    代码

    这里用到了canvas几种方法: save:保存状态; clearRect:清除画布; translate:水平/垂直移动坐标; rotate:旋转坐标; scale:缩放坐标; drawImage:插入图像; restore:恢复状态。

    canvas没有直接清除整个画布的方法,只能用clearRect来间接实现。 它的四个参数用来定义一个矩形,只要定义一个画布大小的矩形就能清除整个画布了。

    在canvas里面没有left/top,位置的变换只能用translate来设置,程序用它把坐标移到画布中心。 canvas没有Matrix那样的东西,只能用rotate和scale来变换,用法跟css3的类似。 canvas也没有css3的skew(拉扯)变换。

    最后用drawImage画图,可以是img元素、Image对象或Canvas元素,另外两个参数是画图位置,程序用它来居中图像。

    每次画图都可能会改变坐标,下次想还原坐标来画图要逐个恢复会很麻烦,这时应该用save和restore来保存和还原状态。 save和restore能保存和还原包括translate、rotate、scale变换后的画布状态,常常配合clearRect来做动画。

    除了以上方法,canvas还有很多属性和方法来绘图,详细可以看HTML DOM CanvasRenderingContext2D 对象

    【拖动旋转/滚轮缩放】

    拖动旋转效果是在容器按下鼠标并拖动的过程中,图像会跟着鼠标转动。 原理是以容器中点为中心,计算按下鼠标位置的弧度R1和拖动到达位置的弧度R2,两者的差就是根据鼠标要旋转的弧度,再加上原来的弧度R0,即R2-R1+R0,就能得到当前要设置的弧度了。 关键的地方就在于如何获取这个弧度,如果要手动计算这个值会很复杂,好在js提供了Math.atan2(y,x)方法,可以返回由 X 轴到 (y,x) 点的弧度,这样直接用坐标就可以得到弧度。 例如中心坐标是(x,y),某一点的坐标是(x1,y1),可以这样得到那个点相对中心坐标的弧度:Math.atan2(y1-y,x1-x)。

    首先在鼠标的mousedown中记录容器的中心坐标:

    var rect = $$D.clientRect( this._container ); this._mrX = rect.left + this._clientWidth / 2; this._mrY = rect.top + this._clientHeight / 2;

    再根据clientX/clientY当前位置坐标计算弧度:

    this._mrRadian = Math.atan2( e.clientY - this._mrY, e.clientX - this._mrX ) - this._radian;

    这里把原来的弧度也顺便计算了。 在拖动的过程中,根据移动坐标获取弧度,并调用rotate来旋转:

    this.rotate( Math.atan2( e.clientY - this._mrY, e.clientX - this._mrX ) - this._mrRadian );

    ps:拖动效果请看这里关于拖动的研究

    滚轮缩放效果就是在容器上滚动鼠标会自动实现缩放效果。 这个比较简单,主要是一些兼容问题,相关研究可以参考这里的鼠标滚动缩放

    使用技巧

    【模式选择】

    模式设置中说明了自定义模式可以用这样的格式:"css3|filter|canvas"。 程序会自动按优先顺序选择支持的模式。 为了尽量保证浏览器支持选择的模式,可以把三个模式都用上。 一般filter是必须的,因为目前ie只支持这个,而css3和canvas可以自行选择。 我在自己的电脑做了效率测试(就是用鼠标狂转图片),看cpu的占用情况: ff css3 40% ff canvas 35% opera css3 30% opera canvas 35% chrome css3 25% chrome canvas 55% safari css3 20% safari canvas 55% 看来在ff和opera是canvas好一点,在WebKit就是css3快得多。 但canvas只能画静态图片,对于gif那样的动态图片只能显示一帧,所以还是选css3比较好。

    还有css3的变换能用在所有元素中(ie8的滤镜也可以),适用在html的变换,而canvas就更适合做复杂的图形和动画。

    【选择图片】

    程序实例化之后,还需要调用load方法加载指定的图片。 参数可以是图片的路径,data url(支持的话),ie6还可以用本地路径。 如果是gif图片,就要注意不要用canvas,原因上面也说了,canvas只能显示一帧图片。

    使用说明

    实例化时,必须有容器对象或id作为参数:

    var trans = new ImageTrans( container );

    然后调用load方法加载图片:

    trans.load(img);

    可选参数用来设置系统的默认属性,包括: 属性:    默认值//说明 mode:  "css3|filter|canvas", zoom:  .1,//缩放比率 onPreLoad: function(){},//图片加载前执行 onLoad:  function(){},//图片加载后执行 onError: function(err){}//出错时执行 其中zoom、onPreLoad、onLoad、onError属性可以在程序初始化后动态设置。

    提供以下变换方法: vertical:垂直翻转 horizontal:水平翻转 rotate: 旋转 left:向左转90度 right:向右转90度 rotatebydegress:根据角度旋转 scale:缩放 zoomin:放大 zoomout:缩小

    还提供了以下方法: load:加载图片; reset:重置图像为默认状态; dispose:销毁程序。

    加入拖动旋转扩展程序或滚轮缩放扩展程序后,会自动启用,可以自定义mouseRotate或mouseZoom属性为false来取消。

    程序源码 

    代码

    拖动旋转扩展

    代码

    滚轮缩放扩展 

    代码

     

    完整实例下载

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

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

  • 相关阅读:
    C语言-第0次作业
    ubuntu 安装maven
    微服务运行在 Docker 之上
    docker入门
    springcloud-Sleuth 与 Zipkin 结合图形化展示
    Spring Cloud Config 配置管理
    springcloud-Zuul 网关
    springcloud-Hystrix 容错处理
    springcloud-Feign 声明式 REST 调用
    springcloud-Ribbon 客户端负载均衡
  • 原文地址:https://www.cnblogs.com/xqzblog/p/3357490.html
Copyright © 2011-2022 走看看