图像的旋转是目前的 web 应用程序中比较常见的一种操作。曾经在做这样的程序时,思路比较狭窄,总是认为扔给服务器端处理比较稳妥。这种方法大致的过程是这样的:当用户点击一种旋 转方向,立即发出一个 Ajax 请求,告诉后端要旋转的图像和旋转的角度,再由后端通过一定的工具(如 PHP 的 GD 库)生成新的图像再进行存储并向浏览器返回新的图像地址,这时使用 JavaScript 对图像的 src 属性进行更新即可。这个过程对于前端来说非常的简单,它大概像下面这样:
$.ajax({ url : 'url.php', type : 'GET', data : { degree : 90, imageId : id }, success : function(src){ image.src = src; } });
尽管可以在前端缓存每个已经旋转过的角度的图像地址,但是当旋转到新的角度时,仍然需要发出 Ajax 请求,用户需要一个等待的过程,服务器也需要对图像进行处理和存储,还要考虑才适当的时候删除掉这些“过程中”的图像,非常的麻烦。事实上,利用 canvas 就可以轻易的实现这样的功能,而对于不支持 canvas 的 IE ,则可以使用滤镜来达到同样的目的,对于这个操作而言,IE 的滤镜甚至较 canvas 更为简单。最重要的是,由于是纯前端的行为,用户几乎无需等待就可以看到效果,也没有建立任何 HTTP 请求,不会对服务器端产生任何影响。
下面我们就来一步步实现纯前端方式的图像旋转,首先是 IE,在 IE 中通过 BasicImage 滤镜 的 rotate 属性值来设置图像的旋转角度,根据微软的文档,这个值只能设置为 0、1、2、3,分别表示 0度,90度,180度和270度四个角度的旋转,假定我们已经获取到了图像对象为 image,旋转的角度为 degree,那么具体的代码就非常简单了:
image.style.filter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree/90+')';
其他浏览器中的情况要稍微复杂一点,需要借助于 Canvas,使用其 rotate 方法旋转 Canvas,使用其 drawImage 方法在 Canvas 上绘制图像。rotate 方法非常简单,它接受一个参数,即旋转的弧度数,注意这里是弧度而不是角度,如果还记得高中数学的话,弧度与角度的转换公式应该并不陌生:
var radian = degree * Math.PI / 180; /** 弧度 = 角度 * π / 180 **/
drawImage 方法的参数比较多,但我们这里指使用其中前三个参数:图像对象,绘制起点的 x 坐标,绘制起点的 y 坐标。在调用这些方法之前,我们需要为 img 元素 追加一个 canvas:
<img src="img_rotate.jpg" alt="football" id="rotate_demo" /> <canvas id="image_canvas"></canvas>
接下来在 JavaScript 中获取到这两个元素,然后使用刚才介绍的两个方法根据不同的角度对图像和 canvas 进行处理:
var image = document.getElementById("rotate_demo"); var canvas = document.getElementById("image_canvas"); var ctx = canvas.getContext('2d'); var width = image.width, height = image.height, x = 0, y = 0; switch(degree){ case 90: width = image.height; height = image.width; y = image.height * (-1); break; case 180: x = image.width * (-1); y = image.height * (-1); break; case 270: width = image.height; height = image.width; x = image.width * (-1); break; } canvas.setAttribute('width', width); canvas.setAttribute('height', height); ctx.rotate(degree * Math.PI / 180); ctx.drawImage(image, x, y); image.style.display = "none";
上面的代码看起来比较多,实际上核心方法只有刚才讲到的 rotate 和 drawImage,但是需要注意的,当画布旋转的时候,画布的宽高可能会发生反转,绘制的坐标也可能会反转,所以我们对 degree 进行了 switch ,具体处理在不同的角度下的反转情况,最后将原始图像隐藏,使用绘制好的 canvas 来显示。
纯前端旋转图像的主要过程就是这样的,剩下的问题是通过下面的函数来判断具体让浏览器使用 canvas 还是使用滤镜:
function supportCanvas(){ return !!document.createElement('canvas').getContext; }
将上面的代码套在一个函数中,并稍加改造,在外面加上一个按钮,即可循环旋转图像,下面是本文 Demo 的完整代码。html:
<p><input type="button" value="旋转" id="rorate_button"/></p> <img src="img_rotate.jpg" alt="football" id="rotate_demo"/> <canvas id="image_canvas"></canvas>
JavaScript:
// canvas 能力检测 var supportCanvas = !!document.createElement('canvas').getContext; // 主函数 function imageRotate(degree,image,canvasId){ if(!supportCanvas){ image.style.filter = 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree/90+')'; }else{ var canvas = document.getElementById(canvasId); var ctx = canvas.getContext('2d'); var width = image.width, height = image.height, x = 0, y = 0; switch(degree){ case 90: width = image.height; height = image.width; y = image.height * (-1); break; case 180: x = image.width * (-1); y = image.height * (-1); break; case 270: width = image.height; height = image.width; x = image.width * (-1); break; } canvas.setAttribute('width', width); canvas.setAttribute('height', height); ctx.rotate(degree * Math.PI / 180); ctx.drawImage(image, x, y); image.style.display = "none"; } } // 初始角度与事件绑定 var degree = 0; var image = document.getElementById("rotate_demo"); document.getElementById("rorate_button").onclick = function(){ degree += 90; degree = degree === 360 ? 0 : degree; imageRotate(degree,image,'image_canvas'); };
参考资料:
转自:http://www.jsmix.com/javascript/image-rotate-without-correspondence.html