简单的立体旋转特效DEMO实现
写在最前:
前两天我们这边接到公司做教育那块的一个活儿,要做一个比较炫酷的3D旋转特效,拿到网页一看,别人是用Three.js去实现的,确实比较狂拽。但是我对这个只是了解一点点,还不到能用它做出成熟DEMO的地步(学习的道路任重而道远啊...)。所以老大建议用css transform特性加上perspective试试。嗯,活儿都来了,上呗。所以有了这边分享的诞生,但是我的实现肯定比不了Three那么炫酷,将就着看吧,里面有很多数学方面的推导是我请教部门清华的同事完成的,再次感谢他,下面我们来看看吧。
对了,惯例,我的博客点赞哈~
成果展示:
Git地址:
github.com/ry928330/tr…
功能说明:
- 以屏幕中心为球心,屏幕横向为X轴,纵向为Y轴,垂直屏幕为Z轴,横向滑动屏幕,页面中的图标会绕着Y轴旋转。纵向滑动,图标会绕着X轴旋转,斜着滑,图标就会斜着转。
- 点击页面中任意一个图标,被点中的图标会旋转到页面的中间(受perspective属性的影响,这个中间是一个近似的中间的位置)。
实现细节:
按照功能我们从两个方面讲解DEMO的实现,一个是滑动屏幕,图标相应的滚动,另一个是点击图标,旋转到某一正确的位置。
滑屏转动图标:
因为画图比较麻烦,所以我借助草稿一起来分析下图标的转动,如下图所示:
从图中我们可以清楚的得到绕X、Y轴分别旋转后所在位置的X、Y、Z坐标,但是我要想要斜着滑动,的话就存在空间中的点同时绕X和Y轴的旋转,此时我们只需要要讲两个旋转矩阵相乘即可,即AB或者BA,如果是前者,表示先绕X轴旋转,然后再绕Y轴旋转,如果是后者则表示先绕Y轴旋转,再绕X轴旋转。因为每转动一个很小的角度我们都计算一下空间点的位置,所以你看不出先后顺序,给人的感觉是同时进行的。这里给出代码如下:
/*** 旋转函数* @param xAng 绕x轴旋转角度,轴向顺时针* @param yAng 绕y轴旋转角度,轴向顺时针* @param vector 待旋转向量*/
function rotate(xAng, yAng, vector) {xRotMat = [[1, 0, 0], [0, Math.cos(xAng), Math.sin(xAng)], [0, -Math.sin(xAng), Math.cos(xAng)]];yRotMat = [[Math.cos(yAng), 0, -Math.sin(yAng)],[0, 1, 0],[Math.sin(yAng), 0, Math.cos(yAng)]];vector = matmul(yRotMat, vector);vector = matmul(xRotMat, vector);return vector;
}
/*** 简单矩阵乘法,不做任何合法性判断* A为3*3矩阵 B为1*3 返回1*3矩阵* */
function matmul(matA, matB) {var result = [];for (var i = 0; i < 3; i++) {result[i] = 0;for (var j = 0; j < 3; j++) {result[i] += matA[i][j] * matB[j];}}return result;
}复制代码
得到各个坐标点的值后,通过transform的3d设置,即可完成图标在页面的绘制:
/*** 绘制所有图标*/function printBalls() {for (var i = 0; i < objNum; i++) {index = i + 1;x = objPos[i][0];y = objPos[i][1];z = objPos[i][2];$('.num' + index).css({'transform': 'translate3d(' + x + 'px,' + y + 'px,' + z + 'px)'});}}复制代码
这里我们得提一下关于页面结构,如下所示,在css里面我们得把图标的父元素container的perspective熟悉设置一个比图标运动半径大的值,不能太接近。因为perspective 属性用于定义 3D 元素距视图的距离,以像素计。该属性允许你改变 3D 元素查看 3D 元素的视图。当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。而且,当子元素的Z值越接近父元素的perspective值时,图标呈现的大小越大,因为此时就相当于图标就在你的眼前,当超出perspective值后,图标就看不见了,这时就相当于是图标成的像落在了你的视网膜后面,你没法儿看见图像了。关于perspective的详解,建议你看看张鑫旭的文章。
<div id="stage"><div id="container"><div class="num1 word"></div><div class="num2 word"></div><div class="num3 word"></div><div class="num4 word"></div></div>
</div>复制代码
点击图标,旋转到特定位置:
鉴于之前建立的空间坐标,你可能说只要给theta(空间中和Y轴的夹角)和phi(空间中和Z轴的夹角)两个角度设置一个固定的值,就能很容易的转到你想要的位置。但是现在有一个问题,绕Y轴旋转可以得到phi角的变化,但是绕哪个轴的旋转可以得到theta夹角的变化呢。这时请教了完美的清华同事给出了解决方案。以空间所在位置的向量和Y轴的向量构成的平面,做一个法向量,经验证可以得出该法向量的坐标为([z, 0, -x])然后绕着该轴旋转,即可得到theta的变化。但是,新的问题又来了,空间中怎么得到绕某一向量旋转一定角度该如何去计算呢,查阅相关资料,得到了最后的旋转矩阵,代码如下:
/*** 绕指定转轴进行旋转,要求转轴必须过原点* @param vector 转轴对应的向量* @param ang 旋转的角度*/
function rotateByArbitraryVec(vector, ang) {var cos = Math.cos(ang);var sin = Math.sin(ang);var a = vector[0];var b = vector[1];var c = vector[2];var r = Math.sqrt(a*a+b*b+c*c);a = a/r;b = b/r;c = c/r;var rotMat = [[a * a + (1 - a * a) * cos, a * b * (1 - cos) + c * sin, a * c * (1 - cos) - b * sin],[a * b * (1 - cos) - c * sin, b * b + (1 - b * b) * cos, b * c * (1 - cos) + a * sin],[a * c * (1 - cos) + b * sin, b * c * (1 - cos) - a * sin, c * c + (1 - c * c) * cos]];//对所有物体一次操作for (var i = 0, len = objNum; i < len; i++) {var result = matmul(rotMat, objPos[i]);objPos[i][0] = result[0];objPos[i][1] = result[1];objPos[i][2] = result[2];}
}复制代码
这里我们得注意必须对空间旋转向量做归一化,这样旋转后的向量其模值才不会发生改变。有了旋转方程,我们就可以得出最后的计算结果,代码如下:
function moveToCenter(index) {// moveToTargetAngAdvance(index, Math.PI / 2, Math.PI / 2, Math.PI / 30);var fastMoveId = setInterval((function(index){//目标移动角度var theta = Math.PI/4; var phi = Math.PI/2;//每步需要旋转的度数var delta = Math.PI/30;var oriTheta, oriPhi;var tempArr = calPosAng(index);oriTheta = tempArr[0];oriPhi = tempArr[1];//计算需要旋转的方位角差值var theta2Rot = theta - oriTheta;var phi2Rot = phi - oriPhi;//计算需要的步数var step = Math.floor(Math.max(Math.abs(theta2Rot / delta), Math.abs(phi2Rot / delta)));if (step==0) {clearInterval(fastMoveId);return;}//每步需要旋转的方位角var dTheta = theta2Rot / step;var dPhi = phi2Rot / step;// console.log(dTheta - delta, dPhi - delta);var x, z;var k = 0;return function() {k++;// console.log(k, step);x = objPos[index][0];z = objPos[index][2];rotateByArbitraryVec([z, 0, -x], -dTheta);var tempAng = calPosAng(index);var degTheta = tempAng[0]/Math.PI*180;var degPhi = tempAng[1]/Math.PI*180;var alterPhi = tempAng[1] - oriPhi;//绕y轴旋转角度var yAng = (dPhi-alterPhi)/Math.PI*180;rotateByArbitraryVec([0, 1, 0], dPhi-alterPhi);tempAng = calPosAng(index);degTheta = tempAng[0]/Math.PI*180;degPhi = tempAng[1]/Math.PI*180;oriPhi = tempAng[1];// console.info("方位角[", oriTheta, ",", oriPhi, "]");printBalls();if (Math.abs(k - step) <= 0.001 ) {console.log('here');clearInterval(fastMoveId);}}})(index), 30)}复制代码
注意,因为theta的变化会导致phi的变化,所以theta变化过程中导致phi变化的部分,我们再计算phi时得提前减出来。
写在最后:
其实说起来这篇文章涉及的前端知识并不是很多,主要就是transform搭配perspective能够实现3D变化的效果,说白了就是加上了一个景深的效果,使你的图标看起来有种近大远小的感觉而是数学上的一些空间变化,深感自己高数没有学好啊,是时候复习一波高数的知识了。
简单的立体旋转特效DEMO实现相关推荐
- jquery环形3D立体旋转特效
jquery环形3D立体旋转特效 作者/代码整理:站长素材 (转载请附加本文地址,带有"懒人原生"字样的谢绝转载)发布日期:2013-07-20 立体效果比较强的jquery特效 ...
- Android中实现简单的立体旋转
新建RotateAnimationZ import android.graphics.Camera; import android.graphics.Matrix; import android.vi ...
- Windows Phone 7 立体旋转动画的实现
Storyboard.TargetProperty表示获取或设置应进行动画处理的属性的名称.通过对Storyboard.TargetProperty属性的设置可以很简单地实现X轴.Y轴.Z轴的立体旋转 ...
- GDI+简单现实文字旋转
原文 http://www.cnblogs.com/kaixiangbb/p/3301272.html 题记 入职新公司已快有两月了,试用期已快结束,项目却迟迟还未正式启动.安排给我的多是些琐事,一直 ...
- 从零开始打造一个Android 3D立体旋转容器
本文地址,转载请注明 http://blog.csdn.net/mr_immortalz/article/details/51918560 github 代码下载地址 :https://github ...
- css3 3D旋转特效
最近自己的网站正在制作,由于是个人网站,所以我傲娇的抛弃了IE,痛快的用起了css3和html5的诸多特效,然而问题亦随之而来.这篇文章的主要讲解在使用css3的3D旋转的时候遇到的文章,错误之处,还 ...
- 基于animation.css实现动画旋转特效
分享一款基于animation.css实现动画旋转特效.这是一款基于CSS3实现的酷炫的动画旋转特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div clas ...
- 2.CCGridAction(3D效果),3D反转特效,凸透镜特效,液体特效,3D翻页特效,水波纹特效,3D晃动的特效,扭曲旋转特效,波动特效,3D波动特效
1 类图组织 2 实例 CCSprite * spr = CCSprite::create("HelloWorld.png"); spr->setPosition(cc ...
- HTML5火焰文字特效DEMO演示---转载
只有google支持 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...
最新文章
- 一堂拯救千万股民的公开课,不能错过!
- TFS 无法签入或自动签出 解决方法 【强制撤销签出无效】
- nodejs实现webservice问题总结
- 斥资2亿加码新消费,“瓜子之王”洽洽要圆“坚果梦”?
- 初识 ASP.NET 3.5 MVC 开发
- URAL 1091. Tmutarakan Exams
- 用c语言读取和写入文件数据
- 使用Eclipse创建Web工程后未生成web.xml文件
- 诺基亚S40手机联系人导入安卓手机
- linux加密框架 crypto 算法管理 - 创建哈希算法实例
- python怎样创建桌面快捷方式_python创建桌面快捷方式的代码
- 今晚博文视点大咖直播伴你读No.2:人工智能学习路线
- Openstack的ping不通实例的解决办法
- 在Silverlight 5 项目中创建单元测试项目
- c语言 blue的大写l,C语言代码训练(一)
- 4.郝斌C语言笔记——基本的输入和输出函数的用法
- 学习能力篇:“拼图式”学习法
- 教资报名照片怎么弄成200k?照片大小怎么改到200k?
- Spark Streaming概述_大数据培训
- 奥哲低代码助力西子联合自主搭建航空QMS
热门文章
- 计算机写给未来自己的一段话,写给以后的自己一段话 致未来自己的唯美句子...
- 新手站长容易犯的3个WordPress安全错误
- OSG飞机姿态控制笔记
- Iphone键盘收齐页面空白问题
- fcpx插件:CrumplePop VideoDenoise(消除视频噪音插件)
- Socket通信(TCP协议)
- 湖北省大学程序设计竞赛(网络同步赛) D. Who killed Cock Robin
- java毕业设计师资管理系统源码+lw文档+mybatis+系统+mysql数据库+调试
- Git客户端 安装 和 使用 教程
- 西安邮电大学计算机课程表,西安邮电大学2013-2014-01学期课程表(45页)-原创力文档...