实现Canvas2D绘图 使元素绕中心居中旋转
我之前用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绘图 使元素绕中心居中旋转相关推荐
- java jtextfield 居中_有什么办法可以使JFrame的中心居中吗? - java
我有自己的主框架和当有人选择菜单项时弹出的两个JDialogs.我想要的是一个带有一些规则,建议等的"帮助"对话框. setLayout(null)和Toolkit / Dimen ...
- java pdfbox_使用java中的PDFBox在其中心周围旋转PDF
有两种主要方法可以旋转页面内容并使其显示在查看器中,就像旋转发生在可见页面的中间一样:任何一个实际上都是通过将旋转与平移连接在一起而绕其中间旋转,或者一个移动裁剪框使页面区域中心跟随旋转. 实际上围绕 ...
- java html合并单元格内容居中显示_合并Al:H1单元格区域,使合并的内容居中显示。...
合并Al:H1单元格区域,使合并的内容居中显示. 更多相关问题 峰面积积分法有何特点? 电子邮件的发送和接收实际上是由ISP的()担任的. VFP的一个数据表文件最多允许有()条记录. 卡特尔认为,可 ...
- html怎样使整个页面居中,如何使整个页面内容居中使高度适应内容自动伸缩
如何使整个页面内容居中使高度适应内容自动伸缩 发布时间:2013-08-06 15:13:43 作者:佚名 我要评论 如何使整个页面内容居中,如何使高度适应内容自动伸缩.这是学习CSS布局最常 ...
- html绝对定位到相邻元素中间,css – 在另一个元素的中心下方水平居中绝对定位元素...
有不同的方法可以做到这一点,但我发现最简单的方法是对abolute定位元素执行以下操作: top: 0; left: 50%; transform: translateX(-50%); 使用此方法,您 ...
- css center元素,[译]CSS 居中(Center)方法大合集
本文只给出了不同条件下的实现方式,未对原理做探讨. PS:原来要显示 jsfiddle 和 CodePen 之类网站的代码预览,只需将其以 Markdown 语法来插入链接即可. 水平居中 行内元素 ...
- 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出。...
编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 题目描述 编写程序输入一个5x5的矩阵,将最大元素与中心元素交换,并按行列对齐输出. 输入描述 编写程序输入一个5x5的矩阵 ...
- 将一个5X5的矩阵中最大的元素放在中心, 4个角分别放4个最小的元素(顺序为从左到右,从上到下,从小到大存放)其余数字从小到大
将一个5X5的矩阵中最大的元素放在中心, 4个角分别放4个最小的元素(顺序为从左到右,从上到下,从小到大存放) 其余数字从小到大 在以前的要求上更改了一下,其余数字从小到大排序 #include &l ...
- CSS3中如何使元素曲线运动
问题?CSS3中如何使元素曲线运动 原理:因为在css属性中是没有曲线运动的属性,我们就需要用到一个jquery插件jquery.path.js 下载:点击打开下载链接 例子:在观望中有许多的曲线运动 ...
- 元素div 上下左右居中方法总结
元素div 上下左右居中方法总结 情景一:一个浏览器页面中,只有一个div模块,让其上下左右居中 解决方案: { position:fixed; left:0; right:0; top:0; b ...
最新文章
- mongodb插入数据获取本次插入的mongodb id
- linux配置4g网络命令_Linux网络基本配置命令
- 洛谷P2068 统计和题解
- 中国致密气行业十四五前景分析及发展规划远景报告2022年版
- python制作查询网页_peewee数据查询之分页返回——python学习笔记
- CSS 状态管理,玩出花样了!
- Matlab常用函数:rand,randi和randn区别
- android.jar 重新编译,android的framework.jar反编译,并重新编译
- 使用Metricbeat和Filebeat监控Nginx性能指标和日志
- 印象码——中国第一款视频广告验证码
- 水壶的问题—字节跳动Android岗面试题
- Java中的程序计数器
- 微信第三方网页关闭当前页面回到微信对话窗口
- 公钥(RSA)加密应用场景
- 计算机等级考试一级ps内容,计算机等级考试《一级ps》备考练习及答案
- c语言打印三角99乘法表,用c语言打印99乘法表4种三角形
- HDMI各版本的区别
- 如何由一名合格的电商运营过渡到电商运营总监角色
- 解决Xubuntu任务栏(Panel)消失的问题
- 了解基于视觉的长度测量