我之前用canvas写了个头像剪切的demo,但是关于让载入的图片旋转是个问题,虽然通过其它方法实现了,但是感觉并不太好,于是查了些资料,想试着重新做一下canvas的旋转。
在开始之前,先让我们来做一些准备工作:
1 (function () { 2 // 设置画布的宽高 3 var width = 300, 4 heigh = 100, 5 cache = {}; // 存储canvas上下文 6 7 // 获取绘图上下文 8 function getCtx(name, w, h) { 9 var cv = document.getElementById(name), 10 ctx = cv.getContext(‘2d‘), 11 wh = getWH(w, h); 12 13 w = wh[0]; 14 h = wh[1]; 15 16 cv.width = w; 17 cv.height = h; 18 19 ctx && (cache[‘name‘] = ctx); 20 init(ctx); 21 return ctx; 22 } 23 24 // 设置角度 25 function (ctx, deg) { 26 ctx.rotate(deg / 180 * Math.PI); // 转成角度值 27 } 28 29 // 填充画布 30 function fill(ctx, color, arr) { 31 ctx.fillStyle = color; 32 ctx.fillRect(arr[0], arr[1], arr[2], arr[3]); 33 } 34 35 // 格式化画布 36 function init(ctx, w, h) { 37 var color = ‘#333‘, // 填充背景色 38 wh = getWH(w, h); 39 40 w = wh[0]; 41 h = wh[1]; 42 43 fill(ctx, color, [0, 0, w, h]); 44 } 45 46 // 进行位移 47 function translate(ctx, x, y) { 48 ctx.translate(x, y); 49 } 50 51 function getWH(w, h) { 52 w = w || width; 53 h = h || height; 54 return [w, h]; 55 } 56 57 })();
准备完毕,先来绘制一个简单的矩形
1 // d1 2 var cv1 = getCtx(‘cv1‘); 3 fill(cv1, ‘#fff‘, [125, 25, 50, 50]);
然后,我们试着让它旋转10deg
1 // d2 2 var cv2 = getCtx(‘cv2‘); 3 rotate(cv2, 10); 4 fill(cv2, ‘#fff‘, [125, 25, 50, 50]);
再看看旋转30deg会变成什么样
1 // d3 2 var cv3 = getCtx(‘cv3‘); 3 rotate(cv3, 30); 4 fill(cv3, ‘#fff‘, [125, 25, 50, 50]);
现在已经可以看出了,canvas旋转rotate
是以画布左上角为中心点旋转的,由此我们可以想象得到90deg的样子
1 .box2 { 2 margin: 0 auto; 3 width: 300px; 4 line-height: 100px; 5 background: #333; 6 text-align: center; 7 color: #fff; 8 } 9 10 .box3 { 11 margin: 0 auto; 12 width: 300px; 13 line-height: 100px; 14 background: #666; 15 text-align: center; 16 color: #fff; 17 transform: rotate(90deg) translate(0, 200px); 18 }
因此,就像css3通过transform-origin来修改旋转的中心一样的道理,我们使用translate为canvas修改旋转中心即可 ctx.translate(canvas.width / 2, canvas.height / 2);
使左上角偏移到宽高的一半的位置(中点)
1 //d4 2 var cv4 = getCtx(‘cv4‘); 3 translate(cv4, width / 2, height / 2); 4 fill(cv4, ‘#fff‘, [0, 0, width, height]);
那么现在再一次旋转90deg会得到我们想要的效果吗?
1 //d5 2 var cv5 = getCtx(‘cv5‘); 3 translate(cv5, width / 2, height / 2); 4 rotate(cv5, 90); 5 fill(cv5, ‘#fff‘, [0, 0, width, height]);
事实证明,还不行,但是已经靠近了,从现在看来只要再偏移一次回到原来的点就可以了就可以了
1 //d6 2 var cv6 = getCtx(‘cv6‘); 3 translate(cv6, width / 2, height / 2); 4 rotate(cv6, 90); 5 translate(cv6, -width / 2, -height / 2); 6 fill(cv6, ‘#fff‘, [0, 0, width, height]);
至于为什么会这样,请看下图:
或者猛戳这里看示例!!
所以现在实现了围绕中心旋转,而实现元素居中就简单了,正如以上的示例所展示的,正中的正方形已然居中,因为我在一开始就给它定好了刚好居中的开始坐标:
1 fill(cv3, ‘#fff‘, [125, 25, 50, 50]);
就好像position居中定位一样,这里的居中定位也一样计算:
1 (默认宽高为300 * 100) 2 (width / 2) - (50 / 2) = 125; 3 (height / 2) - (50 / 2) = 25;
我们把旋转和居中这些来封装一下,方便使用,代码如下:
1 RotateCenter.prototype = { 2 constructor: RotateCenter, 3 4 init: function (id, w, h) { 5 this.width = w = w || this.width; 6 this.height = h = h || this.height; 7 8 var canvas = this.getContext(id, ‘2d‘); 9 10 // 设置宽高 11 this.setSize(canvas, w, h); 12 }, 13 14 // 获取上下文 15 getContext: function (id, type) { 16 var canvas = document.getElementById(id), 17 nowCtx = canvas.getContext(type); 18 19 this.cache[id] = nowCtx; 20 return canvas; 21 }, 22 23 // 填充画布 24 fill: function (arr, color) { 25 this.nowCtx.fillStyle = color; 26 this.nowCtx.fillRect(arr[0], arr[1], arr[1] ? arr[1] : this.width, arr[2] ? arr[2] : this.height); 27 }, 28 29 setSize: function (c, w, h) { 30 c.width = w; 31 c.height = h; 32 }, 33 34 // 旋转 35 rotate: function (deg) { 36 this.nowCtx.rotate(deg / 180 * Math.PI); 37 }, 38 39 // 位移 40 translate: function (x, y) { 41 this.nowCtx.translate(x, y); 42 }, 43 44 // 切换上下文 45 checkout: function (id) { 46 this.nowCtx = this.cache[id]; 47 }, 48 49 // 绘制不居中绕中心旋转矩形 50 rotateRect: function (arr, color, deg) { 51 var w = this.width / 2, 52 h = this.height / 2; 53 54 this.translate(w, h); 55 this.rotate(deg); 56 this.translate(-w, -h); 57 this.fill(arr, color); 58 }, 59 60 // 绘制居中不绕中心旋转矩形 61 centerRect: function (width, height, color) { 62 var w = this.width / 2, 63 h = this.height / 2, 64 w1 = width / 2, 65 h1 = height / 2; 66 67 this.fill([w - w1, h - h1, width, height], color); 68 }, 69 70 // 绘制居中同时绕中心旋转矩形 71 centerRotateRect: function (width, height, deg, color) { 72 var w = this.width / 2, 73 h = this.height / 2, 74 w1 = width / 2, 75 h1 = height / 2; 76 77 this.translate(w, h); 78 this.rotate(deg); 79 this.translate(-w, -h); 80 this.fill([w - w1, h - h1, width, height], color); 81 } 82 };
现在来测试一下:
绘制居中同时绕中心旋转矩形
45deg
1 // d7 2 var rc = new RotateCenter(); 3 rc.init(‘cv7‘); 4 rc.centerRotateRect(50, 50, 45, ‘#fff‘);
163deg
1 // d8 2 rc.init(‘cv8‘); 3 rc.centerRotateRect(50, 50, 163, ‘#fff‘);
绘制居中不绕中心旋转矩形
1 // d9 2 rc.init(‘cv9‘); 3 rc.centerRect(60, 60, ‘#fff‘);
绘制不居中绕中心旋转矩形
30deg
278deg
1 // d10 2 rc.init(‘cv10‘); 3 rc.rotateRect([50, 50, 50, 50], ‘#fff‘, 30); 4 5 // d11 6 rc.init(‘cv11‘); 7 rc.rotateRect([50, 50, 50, 50], ‘#fff‘, 278);
从示例来看,rotateRect方法有点不太理想,而在这里想要的就是centerRotateRect方法的效果,所以到此OVER。
如有不正确的地方,欢迎指出!!!