我之前用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。

如有不正确的地方,欢迎指出!!!

/******************************************************** 优美的分割线 ********************************************************/

/************************************************ 更新时间:2019-01-24 ************************************************/

之前写的内容只能实现中心旋转,而由于在前阵子写的一个关于canvas的封装中又需要实现旋转,而且是任意位置/任意角度的随意旋转,又找了不少资料和测试才实现了,所以在这里更新一下这篇文章!!!

先看效果:

这次的实现主要修改了一下需要绘制的每个元素的偏移,还有为了实现多个元素的不同角度旋转,调用了save与restore这两个函数

主要代码如下:

ctx.save();
ctx.beginPath();
ctx.fillStyle = '#fff';
ctx.translate(x + (width / 2), y + (height) / 2);
ctx.rotate(deg * Math.PI / 180);
ctx.translate(-x - (width / 2), -y -(height / 2));
ctx.fillRect(x, y, width, height);
ctx.closePath();
ctx.fill();
ctx.restore();

完整代码:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title></title><script type="text/javascript" src="./1.js"></script><style type="text/css">canvas {background: #333;}strong {color: #f00;}</style>
</head>
<body><h1>Canvas Rotate</h1><h3>#1 <strong>不居中旋转30deg</strong></h3><canvas id="cv"></canvas><h3>#2 <strong>不居中旋转60deg</strong></h3><canvas id="cv1"></canvas><h3>#3 <strong>不居中绘制多个, 旋转45deg, 160deg</strong></h3><canvas id="cv2"></canvas><h3>#4 <strong>自定义旋转</strong></h3><p><span>deg:</span><input type="range" id="range" max="360" min="0" value="45"><span id="nowDeg">45deg</span></p><canvas id="cv3"></canvas><script type="text/javascript">{function Rotate(id, x, y, width, height, deg) {if (!Rotate.initer) {Rotate.initer = new Rotate.init();Rotate.initer.fill(id, x, y, width, height, deg);}Rotate.initer.fill(id, x, y, width, height, deg);return Rotate.initer;}Rotate.init = function () {this.defaultWidth = 300;this.defaultHeight = 200;this.ctx = null;};Rotate.prototype = {constrcutor: Rotate,fill: function (id, x, y, width, height, deg, add) {!add && this.getCanvas(id);let ctx = this.getContext();ctx.save();ctx.beginPath();ctx.fillStyle = '#fff';ctx.translate(x + (width / 2), y + (height) / 2);ctx.rotate(deg * Math.PI / 180);ctx.translate(-x - (width / 2), -y -(height / 2));ctx.fillRect(x, y, width, height);ctx.closePath();ctx.fill();ctx.restore();},addFill: function (x, y, width, height, deg) {this.fill(null, x, y, width, height, deg, true);},getCanvas: function (id) {this.canvas = document.getElementById(id);this.canvas.width = this.defaultWidth;this.canvas.height = this.defaultHeight;},getContext: function () {this.ctx = this.canvas.getContext('2d');return this.ctx;},clear: function () {this.ctx.clearRect(0, 0, this.defaultWidth, this.defaultHeight);}};Rotate.init.prototype = Rotate.prototype;Rotate('cv', 50, 50, 50, 50, 30); // 不居中旋转30deg
            Rotate('cv1', 50, 50, 50, 50, 60); // 不居中旋转60deg
            Rotate('cv2', 50, 50, 50, 50, 45).addFill(150, 50, 50, 50, 160); // 不居中绘制多个, 旋转45deg, 160deg/** 自定义旋转*/let nowDeg = document.getElementById('nowDeg'),cv3 = Rotate('cv3', 50, 50, 50, 50, 45);document.getElementById('range').addEventListener('change', function (e) {nowDeg.innerHTML = `${this.value}deg`;cv3.clear();cv3.addFill(50, 50, 50, 50, parseInt(this.value));}, false);}</script>
</body>
</html>

关于canvas的封装,有兴趣的可以来看看: https://gitee.com/nowtd/cnavas_engine

转载于:https://www.cnblogs.com/LiQingsong/p/8570804.html

实现Canvas2D绘图 使元素绕中心居中旋转相关推荐

  1. java jtextfield 居中_有什么办法可以使JFrame的中心居中吗? - java

    我有自己的主框架和当有人选择菜单项时弹出的两个JDialogs.我想要的是一个带有一些规则,建议等的"帮助"对话框. setLayout(null)和Toolkit / Dimen ...

  2. java pdfbox_使用java中的PDFBox在其中心周围旋转PDF

    有两种主要方法可以旋转页面内容并使其显示在查看器中,就像旋转发生在可见页面的中间一样:任何一个实际上都是通过将旋转与平移连接在一起而绕其中间旋转,或者一个移动裁剪框使页面区域中心跟随旋转. 实际上围绕 ...

  3. java html合并单元格内容居中显示_合并Al:H1单元格区域,使合并的内容居中显示。...

    合并Al:H1单元格区域,使合并的内容居中显示. 更多相关问题 峰面积积分法有何特点? 电子邮件的发送和接收实际上是由ISP的()担任的. VFP的一个数据表文件最多允许有()条记录. 卡特尔认为,可 ...

  4. html怎样使整个页面居中,如何使整个页面内容居中使高度适应内容自动伸缩

    如何使整个页面内容居中使高度适应内容自动伸缩 发布时间:2013-08-06 15:13:43   作者:佚名   我要评论 如何使整个页面内容居中,如何使高度适应内容自动伸缩.这是学习CSS布局最常 ...

  5. html绝对定位到相邻元素中间,css – 在另一个元素的中心下方水平居中绝对定位元素...

    有不同的方法可以做到这一点,但我发现最简单的方法是对abolute定位元素执行以下操作: top: 0; left: 50%; transform: translateX(-50%); 使用此方法,您 ...

  6. css center元素,[译]CSS 居中(Center)方法大合集

    本文只给出了不同条件下的实现方式,未对原理做探讨. PS:原来要显示 jsfiddle 和 CodePen 之类网站的代码预览,只需将其以 Markdown 语法来插入链接即可. 水平居中 行内元素 ...

  7. 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出。...

    编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 题目描述 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 输入描述 编写程序输入一个5x5的矩阵 ...

  8. 将一个5X5的矩阵中最大的元素放在中心, 4个角分别放4个最小的元素(顺序为从左到右,从上到下,从小到大存放)其余数字从小到大

    将一个5X5的矩阵中最大的元素放在中心, 4个角分别放4个最小的元素(顺序为从左到右,从上到下,从小到大存放) 其余数字从小到大 在以前的要求上更改了一下,其余数字从小到大排序 #include &l ...

  9. CSS3中如何使元素曲线运动

    问题?CSS3中如何使元素曲线运动 原理:因为在css属性中是没有曲线运动的属性,我们就需要用到一个jquery插件jquery.path.js 下载:点击打开下载链接 例子:在观望中有许多的曲线运动 ...

  10. 元素div 上下左右居中方法总结

    元素div 上下左右居中方法总结 情景一:一个浏览器页面中,只有一个div模块,让其上下左右居中 解决方案:  { position:fixed;  left:0; right:0; top:0; b ...

最新文章

  1. mongodb插入数据获取本次插入的mongodb id
  2. linux配置4g网络命令_Linux网络基本配置命令
  3. 洛谷P2068 统计和题解
  4. 中国致密气行业十四五前景分析及发展规划远景报告2022年版
  5. python制作查询网页_peewee数据查询之分页返回——python学习笔记
  6. CSS 状态管理,玩出花样了!
  7. Matlab常用函数:rand,randi和randn区别
  8. android.jar 重新编译,android的framework.jar反编译,并重新编译
  9. 使用Metricbeat和Filebeat监控Nginx性能指标和日志
  10. 印象码——中国第一款视频广告验证码
  11. 水壶的问题—字节跳动Android岗面试题
  12. Java中的程序计数器
  13. 微信第三方网页关闭当前页面回到微信对话窗口
  14. 公钥(RSA)加密应用场景
  15. 计算机等级考试一级ps内容,计算机等级考试《一级ps》备考练习及答案
  16. c语言打印三角99乘法表,用c语言打印99乘法表4种三角形
  17. HDMI各版本的区别
  18. 如何由一名合格的电商运营过渡到电商运营总监角色
  19. 解决Xubuntu任务栏(Panel)消失的问题
  20. 了解基于视觉的长度测量

热门文章

  1. 452A - Eevee 模拟字符串,挺简单的一道题
  2. 苹果mac视频特效软件:After Effects
  3. inDesign教程,如何创建杂志风标注?
  4. 苹果mac视觉效果和动态图形设计软件:After Effects 2022 (ae 2022)
  5. Photoshop 入门教程,处理图层「2」了解图层基本知识
  6. 如何关闭来自苹果的个性化广告?
  7. 解决mac屏幕不能共享问题
  8. Android项目总结(3)-登录页图片循环过渡播放动画效果
  9. ExtJS-3.4.0系列目录
  10. php 一个URL加密解密的程序