图片的旋转,缩放和拖拽

     由于之前公司项目的原因,我被要求完成一个头像上传功能,其中包括要实现上传图片的旋转,缩放和拖拽,更关键的是要用JS实现...

    作为一个不大喜欢用JS的人来说这是一个很严峻的挑战,不过随着项目的进行我的这个功能模块也算是完成(人都是被逼出来的)最终的版本能够支持IE,谷歌,火狐浏览器(兼容多浏览器不容易啊)

    下面仅提供核心思想和部分代码:
     

     拖拽:是使用网上现成的JS代码,在此基础上进行适当的修改即可满足自己的需求,最主要的就是判定拖拽的范围,上传的图片不能给拖没了,所以加上个范围限定,判断超出了这个范围便拖拽无效果。

    旋转与缩放要区分浏览器..

    旋转:IE浏览器下想要实现图片的旋转很简单只要调用IE提供的滤镜filter参数为一个旋转矩阵即可.谷歌和火狐浏览器图片显示用的是canvas标签而不是img标签所以图片的旋转需要用canvas标签相关的一些方法来实现(跟html5类似或者说就是html5,本人才疏学浅理解不透),并且旋转相关的数据需要自己进行数学计算。

    缩放: IE下要实现图片的缩放很简单只要把img标签对应的width与length值增大或者缩小就可以,但是火狐和谷歌下的canvas标签是一个完全不同的处理方式。这是比较纠结的...详细可以看看代码.

    

    效果图如下:


    本身这个功能是在一个大项目中由于机密不能在大项目中展示运行,我后来自己简单的建了一个小项目单独的运行这个功能。

    部分代码如下:

  

/**
 * 图片旋转方法
 * @param id 被旋转的图片
 * @param angle 旋转的角度
 * @param whence (此参数不传的话 旋转的角度会默认累加)
 */
function rotate(id,angle,whence) {  
    var p = document.getElementById(id);  
  
    // we store the angle inside the image tag for persistence  
    if (!whence) {  
        p.angle = ((p.angle==undefined?0:p.angle) + angle) % 360;  //whence (此参数不传的话 旋转的角度会默认累加)
    } else {  
        p.angle = angle;  
    }  
  
    if (p.angle >= 0) {  
        var rotation = Math.PI * p.angle / 180;  
    } else {  
        var rotation = Math.PI * (360+p.angle) / 180;  
    }  
    var costheta = Math.cos(rotation);  
    var sintheta = Math.sin(rotation);  //数学知识....
    if (document.all && !window.opera) {//IE下 用img标签  
        var canvas = document.createElement('img');   
        canvas.src = p.src;  //将之前图片的src,height,width值赋予canvas
        canvas.height = p.height;  
        canvas.width = p.width; 
        //用IE的滤镜(用了矩阵知识)实现图片的旋转展示
        canvas.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11="+costheta+",M12="+(-sintheta)+",M21="+sintheta+",M22="+costheta+",SizingMethod='auto expand')";                 
    } else {  
    	//火狐谷歌浏览器下用canvas标签
        var canvas = document.createElement('canvas');  
        if (!p.oImage) {  
        	//新建canvas标签的oImage对象 用来存储图片信息
            canvas.oImage = new Image();  
            canvas.oImage.src = p.src; 
            canvas.oImage.height = p.height;  
            canvas.oImage.width = p.width;
           
        } else {  
            canvas.oImage = p.oImage;  
        }  
        //计算旋转之后的canvas标签的长和宽(不是图片的长和宽) 旋转之后oImage的height与width值不变
        canvas.style.width = canvas.width = Math.abs(costheta*canvas.oImage.width) + Math.abs(sintheta*canvas.oImage.height);  //数学知识...
        canvas.style.height = canvas.height = Math.abs(costheta*canvas.oImage.height) + Math.abs(sintheta*canvas.oImage.width);  
        
        //调用一些底层方法进行旋转并展示旋转之后的图片
        var context = canvas.getContext('2d');  
        context.save();  
        if (rotation <= Math.PI/2) {  
            context.translate(sintheta*canvas.oImage.height,0);  
        } else if (rotation <= Math.PI) {  
            context.translate(canvas.width,-costheta*canvas.oImage.height);  
        } else if (rotation <= 1.5*Math.PI) {  
            context.translate(-costheta*canvas.oImage.width,canvas.height);  
        } else {  
            context.translate(0,-sintheta*canvas.oImage.width);  
        }  
        context.rotate(rotation);  
        context.drawImage(canvas.oImage, 0, 0, canvas.oImage.width, canvas.oImage.height);  //将旋转之后的oImage对象绘制出来
        context.restore(); 
    }  
    canvas.id = p.id;  
    canvas.angle = p.angle;  
    p.parentNode.replaceChild(canvas, p);  //将新的canvas 标签 替换之前的标签 从而可以展示旋转之后的图片
    
    	//设置canvas元素的top值与left值 	(图片旋转之后top值与left值都发生了变化 现在是要满足图片绕自己的中心的进行旋转,所以旋转之后要进行top与left值的设定)
        canvas.style.top =(y_center-(canvas.offsetHeight)/2)+"px";//注意加上"px"
        canvas.style.left = x_center-canvas.offsetWidth/2+"px";
         
        var imgpos = getStylepos(canvas);//与ImageCopper.js的里面的checkcutpos一样的效果
 		max_x = Math.max(offsetx, offsetx + cutx - canvas.offsetWidth);
 		min_x = Math.min(offsetx + cutx - canvas.offsetWidth, offsetx);
 		if (imgpos.x > max_x)
 			canvas.style.left = max_x + 'px';
 		else if (imgpos.x < min_x)
 			canvas.style.left = min_x + 'px';

 		max_y = Math.max(offsety, offsety + cuty - canvas.offsetHeight);
 		min_y = Math.min(offsety + cuty - canvas.offsetHeight, offsety);
 		if (imgpos.y > max_y)
 			canvas.style.top = max_y + 'px';
 		else if (imgpos.y < min_y)
 			canvas.style.top = min_y + 'px';

 		x_center = Math.round(canvas.offsetWidth/2)+imgpos.x;//top值与left值变化后需要重新计算图片的中心点
 		if(x_center -142<=1 &&x_center -142>=-1)
 		{
 			//防止图片在预览区中心点旋转之后 导致中心点发生微小的偏离
 			x_center=142;
 		}		
		y_center = Math.round(canvas.offsetHeight/2)+imgpos.y;
		if(y_center +133<=1 && y_center +133>=-1){
			y_center=-133;
		}    
} 


//图片逐步缩放
	function imageresize(flag) {
		//增加浏览器类型判断
		var userAgent = navigator.userAgent.toLowerCase();  
		jQuery.browser = {  
		    version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],  
		    safari: /safari/.test( userAgent ),  
		    opera: /opera/.test( userAgent ),  
		    msie: /msie/.test( userAgent ),  
		    firefox: /firefox/.test( userAgent ),
		    chrome: /chrome/.test( userAgent ) 
		}; 
		var rate = 1.08;//此值的设定是为了满足正好放大10次缩小10次这种需求的(需求要求只能放大一倍缩小一倍,为了点击10次正好放大一倍rate就设为了此值)
		if($.browser.firefox || $.browser.chrome)
		{
			rate = 1.07;
		}
		
		cut_div = document.getElementById('cut_div');
		if (flag) {//放大
			if (zoom > 2*standardzoom) //超过标准比例的2倍的话就不能进行缩放
				return;
			zoom = zoom * rate;			
		} else {//缩小
			if (zoom < standardzoom/2)
				return;
			zoom = zoom / rate;			
		}
		if (document.all && !window.opera) {//IE浏览器下
			cut_img.width = Math.round(imgdefw * zoom); //只需要改变img标签的width和height 就可以实现缩放了
			cut_img.height = Math.round(imgdefh * zoom);
			cut_img.style.top =(y_center-(cut_img.offsetHeight)/2)+"px"; //缩放之后 图片的中心不发生变化 top与left值发生相应的变化
			cut_img.style.left = x_center-cut_img.offsetWidth/2+"px";
		}else{//火狐谷歌等浏览器
//首先改变canvas.oImage的width与height属性的值
			if(flag){
				var image_y=cut_img.oImage.height*rate;
				var image_x=cut_img.oImage.width*rate;
			}else{
				var image_y=cut_img.oImage.height/rate;
				var image_x=cut_img.oImage.width/rate;
			}
			
		    cut_img.oImage.height=image_y;
			cut_img.oImage.width=image_x;			
			roTateRight('cut_img',0);//旋转0度以调整canvas的width与height值和left与top的值
		}
		
		checkcutpos();
	}


   一个本来可以用flex实现的功能我用JS实现了......也算是个小成就,大家若想交流的话可以留言我一定奉陪。(其实QQ空间的头像上传功能做得挺好的,效果不错)

  这个文章很早就想写了,现在终于把他憋出来也算心里的一块石头放下了吧...

    

你可能感兴趣的:(小杂文)