用纯原生态javascript+css3 写的3D魔方动画旋扭特效

       一直从事于后端编程工作,工作中也经常接触和使用一些前端技术,但大多数还是用于操作和控制数据与客户端交互工作。随着互联网技术的发展以及硬件性能的不断提升,人们对于交互式体验已变得越来越重视,进而前端技术已经越来越突显出它的重要性,特别是一些炫酷的特效,精美的UI设计,都使人眼前一亮,顿时觉得网站平台都高大上不少,很博人们眼球,给人们以很好的视觉冲击,特别是现在的css3,HTML5技术的更新,使得以更小的代价就可以轻松实现这些效果,故此,俺也顿时膜拜起前端技术,悠然起了兴趣,跃跃欲试,随机利用css3的新增3D特效技术及动画特效功能加原生态javascript写了一个随机打乱旋扭的魔方(阶数,尺寸等都可自定义,但数值不要太大哦),在指定的步数后,魔方按记录的动作,逆行旋扭重新归位。随即发布出来与大家分享,也希望前端的大牛能指点一二,不甚感激!

代码如下:
  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5     <title></title>
  6     <meta charset="utf-8" />
  7     <script language="javascript" type="text/javascript">
  8         var cache = {};
  9         (function (exports) {
 10 
 11             function Cube(opts) {
 12                 opts = opts || {};
 13                 this.parent = opts.parent; //插入到哪里
 14                 this.browserPrefix = opts.browserPrefix;
 15                 this.width = opts.width;
 16                 this.height = opts.height;
 17                 this.cubZ = opts.cubZ;
 18                 this.face = opts.face;
 19                 this.row = opts.row;
 20                 this.column = opts.column;
 21                 this.offsetX = this.column * (this.width + opts.marginX); //
 22                 this.offsetY = this.row * (this.height + opts.marginY);//
 23                 this.offsetZ = this.face * (this.cubZ + opts.marginZ);//
 24                 this.positiveZ = this.cubZ / 2;
 25                 this.negativeZ = -this.cubZ / 2;
 26                 this.cubFaceInfo = opts.cubFaceInfo;
 27                 this.dimension = opts.dimension;
 28                 this.centerX = (this.dimension * this.width + (this.dimension - 1) * opts.marginX) / 2;
 29                 this.centerY = (this.dimension * this.height + (this.dimension - 1) * opts.marginY) / 2;
 30                 this.centerZ = (this.dimension * this.cubZ + (this.dimension - 1) * opts.marginZ) / 2;
 31                 this.translateX = this.offsetX - this.centerX; //把中心点设为原点
 32                 this.translateY = this.offsetY - this.centerY; //
 33                 this.translateZ = this.cubZ / 2 + this.offsetZ - this.centerZ; //offsetZ按上面计算应该跟x,y在一个平面上即后面,但实际上由于要形成立方体,在Z轴上已经后退了cubZ/2个距离,故为和上面保持一致在一个面上,这里需要再加回cubZ/2个距离,使默认的xyz原点都在一个平面上即立方体后面左上角三维坐标系,以这个点作为参考点平移和设置旋转原点
 34                 this.cubeFace = [];
 35                 this.rotateTransfrom = "";
 36                 this.init();
 37 
 38             }
 39             Cube.prototype = {
 40                 init: function () {
 41                     this.createCubeBox();
 42                     this.createFront();
 43                     this.createBack();
 44                     this.createTop();
 45                     this.createBottom();
 46                     this.createLeft();
 47                     this.createRight();
 48 
 49                 },
 50                 createCubeBox: function () {
 51                     this.Box = document.createElement('div');
 52                     this.Box.style.width = this.width + "px";
 53                     this.Box.style.height = this.height + "px";
 54                     this.Box.style.left = "50%";
 55                     this.Box.style.top = "50%";
 56                     this.Box.style.position = "absolute";
 57                     this.Box.style[this.browserPrefix + "TransformStyle"] = "preserve-3d";
 58                     this.Box.style[this.browserPrefix + "Perspective"] = "0";
 59                     //                    this.Scene.style[this.browserPrefix + "backfaceVisibility"] = "hidden";
 60                     this.intalTransform = "translateZ(" + this.translateZ + "px) translateX(" + this.translateX + "px) translateY(" + this.translateY + "px)";
 61                     this.Box.style[this.browserPrefix + "Transform"] = this.intalTransform;
 62                     this.Box.style[this.browserPrefix + "TransformOrigin"] = "" + (-this.translateX) + "px " + (-this.translateY) + "px " + (-this.translateZ) + "px";
 63                     this.parent.appendChild(this.Box);
 64                     this.x = window.getComputedStyle(this.Box).getPropertyValue('left');
 65                     this.y = window.getComputedStyle(this.Box).getPropertyValue('top');
 66                     this.matrix3d = window.getComputedStyle(this.Box).getPropertyValue('transform');
 67                 },
 68                 createFace: function () {
 69                     var face = document.createElement('div');
 70                     face.style.margin = 0;
 71                     face.style.position = "absolute";
 72                     face.style.width = this.width + "px";
 73                     face.style.height = this.height + "px";
 74                     return face;
 75                 },
 76                 createFront: function () {
 77                     var face = this.createFace();
 78                     face.style[this.browserPrefix + "Transform"] = "translateZ(" + this.positiveZ + "px) "
 79                     this.cubeFace.push(face);
 80                     this.front = face;
 81                     this.Box.appendChild(face);
 82                 },
 83                 createBack: function () {
 84                     var face = this.createFace();
 85                     face.style[this.browserPrefix + "Transform"] = "translateZ(" + this.negativeZ + "px) ";
 86                     this.cubeFace.push(face);
 87                     this.back = face;
 88                     this.Box.appendChild(face);
 89                 },
 90                 createTop: function () {
 91                     var face = this.createFace();
 92                     face.style[this.browserPrefix + "Transform"] = "rotateX(90deg) translateZ(" + this.positiveZ + "px) ";
 93                     this.cubeFace.push(face);
 94                     this.top = face;
 95                     this.Box.appendChild(face);
 96                 },
 97                 createBottom: function () {
 98                     var face = this.createFace();
 99                     face.style[this.browserPrefix + "Transform"] = "rotateX(90deg) translateZ(" + this.negativeZ + "px) ";
100                     this.cubeFace.push(face);
101                     this.bottom = face;
102                     this.Box.appendChild(face);
103                 },
104                 createLeft: function () {
105                     var face = this.createFace();
106                     face.style[this.browserPrefix + "Transform"] = "rotateY(90deg) translateZ(" + this.negativeZ + "px) ";
107                     this.cubeFace.push(face);
108                     this.left = face;
109                     this.Box.appendChild(face);
110                 },
111                 createRight: function () {
112                     var face = this.createFace();
113                     face.style[this.browserPrefix + "Transform"] = "rotateY(90deg) translateZ(" + (this.positiveZ) + "px) ";
114                     this.cubeFace.push(face);
115                     this.right = face;
116                     this.Box.appendChild(face);
117                 }
118 
119             }
120             exports.magicCube = function (opts) {
121                 opts = opts || {};
122                 this.parent = opts.parent || document.getElementsByTagName('body')[0];
123                 this.dimension = opts.dimension || 3;  //魔方级数
124                 this.cubWidth = opts.cubWidth || 50;   //单个立方体宽度
125                 this.cubHeight = opts.cubHeight || 50; //单个立方体高度
126                 this.marginLeft = opts.marginLeft || 0;//水平方向间距
127                 this.marginTop = opts.marginLeft || 0; //上下方向间距
128                 this.marginZ = opts.marginZ || 0;      //前后方向间距
129                 this.cubZ = opts.cubZ || 50;           //单个立方体Z轴距离
130                 this.sceneWidth = opts.sceneWidth;     //3d场景宽度
131                 this.sceneHeight = opts.sceneHeight;   //3d场景高度
132                 this.Perspective = opts.Perspective || 0; //投影值
133                 this.cubFaceInfo = opts.cubFaceInfo || { front: { backGround: "rgba(0,255,255,.5)" }, back: { backGround: "rgba(153,204,255,.5)" }, left: { backGround: "rgba(128,0,128,.5)" }, right: { backGround: "rgba(255,0,255,.5)" }, top: { backGround: "rgba(255,153,204,.5)" }, bottom: { backGround: "rgba(0,204,255,.5)" }, inner: { backGround: "rgba(100,100,100,.5)" } }; //立方体面信息
134                 this.angle = opts.angle || 90;         //转动的角度
135                 this.rollbackPoint = opts.rollbackPoint || 10;//回滚的步数
136                 this.faceCount = this.dimension * this.dimension; //每面立方体个数
137                 this.count = this.dimension * this.dimension * this.dimension; //立方体总个数
138                 this.cubes = [];
139                 this.browserPrefix = "";
140                 this.isRunning = 0;
141                 this.timer = null;
142                 this.rotateFace;//转动的3维坐标系方向
143                 this.moveDirect = true;//正向随机动作还是回归,默认为正向
144                 this.cubeMoveQueue = [];
145                 this.rollMoveStack = [];//动作回归的堆栈
146                 this.init();
147             };
148             magicCube.prototype = {
149                 init: function () {
150                     this.start();
151                 },
152                 create3dScene: function () {
153                     this.Scene = document.createElement('div');
154                     //this.Scene.className = "cube";
155                     var width = this.sceneWidth || this.clientWidth,
156                         height = this.sceneHeight || this.clientHeight;
157                     this.Scene.style.width = width + "px";
158                     this.Scene.style.height = height + "px";
159                     this.Scene.style.position = "relative";
160                     this.Scene.style[this.browserPrefix + "TransformStyle"] = "preserve-3d";
161                     this.Scene.style[this.browserPrefix + "Perspective"] = this.Perspective + "px";
162                     //                    this.Scene.style[this.browserPrefix + "backfaceVisibility"] = "hidden";
163                     this.Scene.style[this.browserPrefix + "Transform"] = "rotateX(-30deg) rotateY(30deg) ";
164                     this.parent.appendChild(this.Scene);
165 
166                 },
167                 create: function (face, row, column) {
168                     return new Cube({
169                         parent: this.Scene,
170                         dimension: this.dimension,
171                          this.cubWidth,
172                         height: this.cubHeight,
173                         cubZ: this.cubZ,
174                         face: face,
175                         row: row,
176                         column: column,
177                         browserPrefix: this.browserPrefix,
178                         cubFaceInfo: this.cubFaceInfo,
179                         marginX: this.marginLeft,
180                         marginY: this.marginTop,
181                         marginZ: this.marginZ,
182                         dimension: this.dimension
183                     });
184                 },
185                 createMagicCube: function (index) {
186                     var face = 0, row = 0, column = 0;
187                     for (var i = 0; i < this.count; i++) {
188                         this.cubes.push(this.create(face, row, column));
189                         this.cubes[this.cubes.length - 1].index = this.cubes.length - 1;
190                         column++;
191                         if ((i + 1) % this.dimension === 0) {
192                             row++;
193                             column = 0;
194                         }
195                         if ((i + 1) % this.faceCount === 0) {
196                             face++;
197                             row = 0;
198                         }
199                     }
200                 },
201                 drawBackGroundColor: function () {
202                     for (var face in this.cubFaceInfo) {
203                         if (face == "inner") {
204                             this.setInnerBKColor(this.cubFaceInfo[face].backGround);
205                         }
206                         else {
207                             var cube = this.getCubesByFace(face);
208                             for (var i = 0, len = cube.length; i < len; i++) {
209                                 cube[i][face].style.background = this.cubFaceInfo[face].backGround;
210                             }
211                         }
212                     }
213 
214                 },
215                 setInnerBKColor: function (color) {
216                     for (var i = 0; i < this.count; i++) {
217                         for (var j = 0; j < 6; j++) {
218                             if (this.cubes[i].cubeFace[j].style.background == "") {
219                                 this.cubes[i].cubeFace[j].style.background = color;
220                             }
221                         }
222                     }
223                 },
224                 getZFace: function (zIndex) {
225                     var zFace = [];
226                     if (zIndex < 1 || zIndex > this.dimension)
227                         return null;
228                     for (var i = (zIndex - 1) * this.faceCount; i < zIndex * this.faceCount; i++) {
229                         zFace.push(this.cubes[i]);
230                     }
231                     return zFace;
232                 },
233                 getXFace: function (xIndex) {
234                     var xFace = [];
235                     if (xIndex < 1 || xIndex > this.dimension)
236                         return null;
237                     for (var i = 0; i < this.count; i++) {
238                         if (i % this.dimension == 0)
239                             xFace.push(this.cubes[i + xIndex - 1]);
240                     }
241                     return xFace;
242                 },
243                 getYFace: function (yIndex) {
244                     var yFace = [];
245                     if (yIndex < 1 || yIndex > this.dimension)
246                         return null;
247                     for (var i = 0; i < this.count; i++) {
248                         if (i % this.faceCount == (yIndex - 1) * this.dimension) {
249                             for (var j = 0; j < this.dimension; j++)
250                                 yFace.push(this.cubes[i + j]);
251                         }
252                     }
253                     return yFace;
254                 },
255                 getSideCubes: function (cubes, circleIndex) {
256                     var sides = [], top = [], left = [], bottom = [], right = [];
257                     if (circleIndex < 0 || circleIndex > this.dimension / 2 - 1)
258                         return null;
259                     for (var i = 0, count = this.dimension - circleIndex * 2; i < count; i++) {
260                         top.push(cubes[circleIndex * this.dimension + circleIndex + i]);
261                         left.push(cubes[circleIndex * this.dimension + circleIndex + i * this.dimension]);
262                         bottom.push(cubes[(this.dimension - 1 - circleIndex) * this.dimension + circleIndex + i]);
263                         right.push(cubes[circleIndex * this.dimension + circleIndex + i * this.dimension + (this.dimension - (circleIndex * 2) - 1)]);
264                     }
265                     sides.push(this.orderByDesc(top));
266                     sides.push(left);
267                     sides.push(bottom);
268                     sides.push(this.orderByDesc(right));
269                     return sides;
270                 },
271 
272                 getCubesByFace: function (face) {
273                     switch (face) {
274                         case "front": return this.getZFace(this.dimension);
275                         case "back": return this.getZFace(1);
276                         case "left": return this.getXFace(1);
277                         case "right": return this.getXFace(this.dimension);
278                         case "top": return this.getYFace(1);
279                         case "bottom": return this.getYFace(this.dimension);
280                     }
281                 },
282                 moveMagicCube: function () {
283                     if (this.cubes.length < 1) return;
284                     //var cubes = this.getYFace(2);
285                     //for (var i = 0, len = cubes.length; i < len; i++) {
286                     //    cubes[i].Box.className = "rotate";
287                     //}
288                     //随机产生3D转动方向
289                     this.isRunning = 0;
290                     var direct = this.random(1, 3), rotateDirect = "", getFaceFun;
291                     //  direct=3;
292                     switch (direct) {
293                         case 1: rotateDirect = "rotateX"; getFaceFun = this.getXFace; break;
294                         case 2: rotateDirect = "rotateY"; getFaceFun = this.getYFace; break;
295                         case 3: rotateDirect = "rotateZ"; getFaceFun = this.getZFace; break;
296                     }
297                     this.rotateFace = rotateDirect;
298                     this.cubeRotateStatus = [];
299                     for (var i = 1; i <= this.dimension; i++) {
300                         var status = this.random(0, 2);
301                         this.cubeRotateStatus.push(status);
302                         switch (status) {
303                             case 0: break;//不转动
304                             case 1: this.rotateBox(this.angle, rotateDirect, i, getFaceFun.call(this, i)); break;//正向转动90
305                             case 2: this.rotateBox(-this.angle, rotateDirect, i, getFaceFun.call(this, i)); break;//反向转动90
306                         }
307 
308                     }
309 
310                     var flag = false;
311                     for (var i = 0, len = this.cubeRotateStatus.length; i < len; i++) {
312                         if (this.cubeRotateStatus[i]) {
313                             flag = true;
314                             break;
315                         }
316                     }
317                     if (!flag) {//一个都没转的情况 则强制补充一个
318                         var index = this.random(1, this.dimension);
319                         this.rotateBox(this.angle, rotateDirect, index, getFaceFun.call(this, index)); //正向转动90
320                         this.cubeRotateStatus[index - 1] = 1;//全都不转动 默认选出一个 使其正向转动指定度数
321                     }
322                     setTimeout(this.timerFun, 100);
323                     this.rollMoveStack.push({ rotateFace: this.rotateFace, cubeRotateStatus: this.cubeRotateStatus });//记录动作状态
324                     if (this.rollMoveStack.length == this.rollbackPoint)//判断当达到阀值时切换动作方向为回归
325                         this.moveDirect = false;
326 
327                 },
328                 moveRollBackCube: function () {
329                     var record = this.rollMoveStack.pop(), getFaceFun;
330                     this.rotateFace = record.rotateFace;
331                     this.isRunning = 0;
332                     switch (record.rotateFace) {
333                         case "rotateX": getFaceFun = this.getXFace; break;
334                         case "rotateY": getFaceFun = this.getYFace; break;
335                         case "rotateZ": getFaceFun = this.getZFace; break;
336                     }
337                     this.cubeRotateStatus = [];
338                     for (var i = 0, len = record.cubeRotateStatus.length; i < len; i++) {
339                         var dimensionIndex =  i+1, status = record.cubeRotateStatus[i];
340                         if (status == 1) {
341                             this.cubeRotateStatus.push(2);//1 变2,2变1
342                             this.rotateBox(-this.angle, record.rotateFace, dimensionIndex, getFaceFun.call(this, dimensionIndex)); //反向转动90
343                         }
344                         else if (status == 2) {
345                             this.cubeRotateStatus.push(1);//1 变2,2变1
346                             this.rotateBox(this.angle, record.rotateFace, dimensionIndex, getFaceFun.call(this, dimensionIndex)); //反向转动90
347                         }
348                         else {
349                             this.cubeRotateStatus.push(0);
350                         }
351                     }
352                     setTimeout(this.timerFun, 100);
353                     if (this.rollMoveStack.length == 0)//判断当达到0时切换动作为正向随机
354                         this.moveDirect = true;
355                 },
356                 intersect: function (source, target) {
357                     var data = [];
358                     for (var i = 0, len = source.length; i < len; i++) {
359                         var index = target.indexOf(source[i]);
360                         if (index >= 0)
361                             data.push(source[i])
362                     }
363                     return data;
364                 },
365                 orderByDesc: function (datas) {
366                     var temp;
367                     for (var i = 0; i < datas.length - 1; i++) {
368                         for (var j = i + 1; j < datas.length; j++) {
369                             if (parseFloat(datas[i].index) < parseFloat(datas[j].index)) {
370                                 temp = datas[i];
371                                 datas[i] = datas[j];
372                                 datas[j] = temp;
373                             }
374                         }
375                     }
376                     return datas;
377                 },
378                 getSideBackGround: function (sideFaces, face) {
379                     var backGrounds = [];
380                     for (var i = 0, len = sideFaces.length; i < len; i++) {
381                         backGrounds.push(sideFaces[i][face].style.background);
382                     }
383                     return backGrounds;
384                 },
385                 setRotateDirectSideBackGround: function (faceCubes, sideFace, offset, status) {
386                     var oldSides = this.getSideCubes(faceCubes, 0), backColor = [];
387                     var offsetNIndex, offsetPIndex;
388                     for (var j = 0; j < 4; j++) {
389                         offsetPIndex = (j - offset + 4) % 4;
390                         offsetNIndex = (j + offset) % 4;
391                         if (this.rotateFace == "rotateY") {
392                             if (status == 1)//正向
393                             {
394                                 backColor[j] = this.getSideBackGround(oldSides[offsetPIndex], sideFace[offsetPIndex]);
395                             }
396                             else//反向
397                             {
398                                 backColor[j] = this.getSideBackGround(oldSides[offsetNIndex], sideFace[offsetNIndex]);
399                             }
400                         }
401                         else {
402                             if (status == 2)//正向
403                             {
404                                 backColor[j] = this.getSideBackGround(oldSides[offsetPIndex], sideFace[offsetPIndex]);
405                             }
406                             else//反向
407                             {
408                                 backColor[j] = this.getSideBackGround(oldSides[offsetNIndex], sideFace[offsetNIndex]);
409                             }
410                         }
411 
412                     }
413                     for (var j = 0; j < 4; j++) {
414                         for (var k = 0; k < oldSides[j].length; k++) {
415                             oldSides[j][k][sideFace[j]].style.background = backColor[j][k];
416                         }
417                     }
418                 },
419                 setRotateOtherDirectSideBackGround: function (faceCubes, otherFace, offset, status) {
420                     var oldSides = [], backColor = [];
421                     var offsetNIndex, offsetPIndex;
422                     for (var i = 0; i <= parseInt(this.dimension / 2) - 1; i++) {
423                         oldSides = this.getSideCubes(faceCubes, i), backColor = [];
424                         for (var j = 0; j < 4; j++) {
425                             offsetPIndex = (j - offset + 4) % 4;
426                             offsetNIndex = (j + offset) % 4;
427                             if (this.rotateFace == "rotateY") {
428                                 if (status == 1)//正向
429                                 {
430                                     backColor[j] = this.getSideBackGround(oldSides[offsetPIndex], otherFace);
431                                 }
432                                 else//反向
433                                 {
434                                     backColor[j] = this.getSideBackGround(oldSides[offsetNIndex], otherFace);
435                                 }
436                             }
437                             else {
438                                 if (status == 2)//正向
439                                 {
440                                     backColor[j] = this.getSideBackGround(oldSides[offsetPIndex], otherFace);
441                                 }
442                                 else//反向
443                                 {
444                                     backColor[j] = this.getSideBackGround(oldSides[offsetNIndex], otherFace);
445                                 }
446                             }
447 
448                         }
449                         for (var j = 0; j < 4; j++) {
450                             for (var k = 0; k < oldSides[j].length; k++) {
451                                 oldSides[j][k][otherFace].style.background = backColor[j][k];
452                             }
453                         }
454                     }
455 
456                 },
457                 animationEnd: function () {
458                     var offset = this.angle / 90, faceCubes = [], otherFace;
459                     var zSideFace = ["top", "left", "bottom", "right"], xSideFace = ["back", "top", "front", "bottom"], ySideFace = ["back", "left", "front", "right"], sideFace = [];
460                     for (var i = 0, len = this.cubeRotateStatus.length; i < len; i++) {
461                         var status = this.cubeRotateStatus[i];
462                         if (status) {
463                             var dimensionIndex = i + 1;
464                             switch (this.rotateFace) {
465                                 case "rotateX": faceCubes = this.getXFace(dimensionIndex); sideFace = xSideFace; if (dimensionIndex == 1) otherFace = "left"; else if (dimensionIndex == this.dimension) otherFace = "right"; break;
466                                 case "rotateY": faceCubes = this.getYFace(dimensionIndex); sideFace = ySideFace; if (dimensionIndex == 1) otherFace = "top"; else if (dimensionIndex == this.dimension) otherFace = "bottom"; break;
467                                 case "rotateZ": faceCubes = this.getZFace(dimensionIndex); sideFace = zSideFace; if (dimensionIndex == 1) otherFace = "back"; else if (dimensionIndex == this.dimension) otherFace = "front"; break;
468                             }
469                             this.setRotateDirectSideBackGround(faceCubes, sideFace, offset, status);
470                             if (dimensionIndex == 1 || dimensionIndex == this.dimension)
471                                 this.setRotateOtherDirectSideBackGround(faceCubes, otherFace, offset, status);
472                         }
473 
474                     }
475                   //  console.info(this.rollMoveStack.length + "," + this.moveDirect);
476                     if (this.moveDirect)
477                         this.moveMagicCube();
478                     else
479                         this.moveRollBackCube();
480                     // alert("运行结束");
481                 },
482                 bindAnimationEvent: function () {
483                     var loopMove = function () {
484                         cache.magicCube.isRunning--;//由于按组转动,顾要等组成员都完成再进行新的动画
485                         if (cache.magicCube.isRunning == 0)
486                             cache.magicCube.animationEnd();
487                     }
488                     for (var i = 0; i < this.count; i++) {
489 
490                         this.prefixedEvent(this.cubes[i].Box, "AnimationEnd", loopMove, true);
491                     }
492                     cache.magicCube = this;//缓存,避免内存泄露
493                 },
494                 rotateBox: function (angle, rotateDirect, faceIndex, cubes) {
495                     if (cubes != null) {
496                         var startStatus = rotateDirect + "(0deg)", endStatus = rotateDirect + "(" + angle + "deg)";
497                         // this.changeAnimationStatus("mydhua", startStatus, endStatus)
498                         for (var i = 0, len = cubes.length; i < len; i++) {
499                             var ruleName = "roateRule" + faceIndex + i;
500                             this.isRunning++;//组成员转动统计
501                             //if (cubes[i].rotateTransfrom != "")
502                             //    startStatus = cubes[i].rotateTransfrom;
503                             cubes[i].rotateTransfrom = endStatus;
504                             if (this.findKeyframesRule(ruleName) == null)
505                                 this.createKeyframesRule(ruleName, cubes[i].intalTransform + " " + startStatus, cubes[i].intalTransform + " " + endStatus);
506                             else
507                                 this.changeAnimationStatus(ruleName, cubes[i].intalTransform + " " + startStatus, cubes[i].intalTransform + " " + endStatus);
508                             cubes[i].Box.style[this.browserPrefix + "AnimationName"] = "none";
509                             this.cubeMoveQueue.push({ cube: cubes[i], rule: ruleName });
510                         }
511                     }
512                 },
513                 findKeyframesRule: function (rule) {
514                     var ruleName = this.browserPrefix == "" ? "KEYFRAMES_RULE" : this.browserPrefix.toUpperCase() + "_KEYFRAMES_RULE";
515                     var ss = document.styleSheets;
516                     for (var i = 0; i < ss.length; ++i) {
517                         for (var j = 0; j < ss[i].cssRules.length; ++j) {
518                             if (ss[i].cssRules[j].type == window.CSSRule[ruleName] && ss[i].cssRules[j].name == rule) { return ss[i].cssRules[j]; }
519                         }
520                     }
521                     return null;
522                 },
523                 createKeyframesRule: function (rule, startStatus, endStatus) {
524                     var prefix = this.browserPrefix == "" ? "" : "-" + this.browserPrefix + "-";
525                     var sheet;
526                     if (document.styleSheets.length < 1)
527                         sheet = this.createSheets();
528                     else
529                         sheet = document.styleSheets[0];
530                     var selectorText = "@" + prefix + "keyframes " + rule;
531                     var cssText = "0% { " + prefix + "transform: " + startStatus + "; } 100% { " + prefix + "transform: " + endStatus + "; }"
532                     if (sheet.insertRule) {
533                         sheet.insertRule(selectorText + "{" + cssText + "}", 0);
534                     } else if (sheet.addRule) {//兼容IE
535                         sheet.addRule(selectorText, cssText, 0);
536                     }
537                 },
538                 removeKeyframeRule: function (keyframes) {
539                     var length = keyframes.cssRules.length;
540                     var keyframeString = [];
541                     for (var i = 0; i < length; i++) {
542                         keyframeString.push(keyframes.cssRules[i].keyText);
543                     }
544                     //移除动画帧规则
545                     for (var i = 0, j = length; i < j; i++) {
546                         if (this.browserPrefix == "webkit" || this.browserPrefix == "Moz")
547                             keyframes.deleteRule(keyframeString[i]);
548                         else
549                             keyframes.deleteRule(i); //兼容IE
550                     }
551                 },
552                 changeAnimationStatus: function (animationName, startStatus, endStatus) {
553                     var keyframes = this.findKeyframesRule(animationName);
554                     this.removeKeyframeRule(keyframes);
555                     //重新设置帧规则
556                     var prefix = this.browserPrefix == "" ? "" : "-" + this.browserPrefix + "-";
557                     keyframes.appendRule("0% { " + prefix + "transform: " + startStatus + "; }");
558                     keyframes.appendRule("100% { " + prefix + "transform: " + endStatus + "; }");
559                 },
560                 createSheets: function () {
561                     // 创建 <style> 标签
562                     var style = document.createElement("style");
563                     // 可以添加一个媒体(/媒体查询,media query)属性
564                     // style.setAttribute("media", "screen")
565                     // style.setAttribute("media", "only screen and (max-width : 1024px)")
566                     // 对WebKit hack :(
567                     style.appendChild(document.createTextNode(""));
568                     // 将 <style> 元素加到页面中
569                     document.head.appendChild(style);
570                     return style.sheet;
571                 },
572                 prefixedEvent: function (element, type, callback, isAdd) {
573                     var pfx = ["webkit", "moz", "MS", "o", ""];
574                     for (var p = 0; p < pfx.length; p++) {
575                         if (!pfx[p]) type = type.toLowerCase();
576                         if (isAdd)
577                             element.addEventListener(pfx[p] + type, callback, false);
578                         else
579                             element.removeEventListener(pfx[p] + type, callback, false);
580                     }
581                 },
582                 start: function () {
583                     this.css();
584                     this.prefix();
585                     this.create3dScene();
586                     this.createMagicCube();
587                     this.drawBackGroundColor();
588                     this.bindAnimationEvent();//绑定动画播放完成事件
589                     this.moveMagicCube();     //立即开始动画
590                     // this.timer = setInterval(this.timerFun, 100);
591                 },
592                 timerFun: function () {
593                     var _this = cache.magicCube;
594                     if (_this.isRunning >= _this.dimension) {
595                         for (var i = 0, len = _this.cubeMoveQueue.length; i < len; i++) {
596                             var animation = _this.cubeMoveQueue.shift();
597                             animation.cube.Box.style[_this.browserPrefix + "Animation"] = animation.rule + " 2s linear 1"; // Chrome, Safari 和 Opera 代码
598                         }
599 
600                     }
601 
602                 },
603                 css: function () {
604                     var d = document,
605                         doc = d.documentElement,
606                         body = d.body;
607                     this.clientWidth = doc.clientWidth;
608                     this.clientHeight = doc.clientHeight;
609                     if (d.compatMode != "CSS1Compat") {
610                         this.clientWidth = body.clientWidth;
611                         this.clientHeight = body.clientHeight;
612                     }
613                     // console.log(this.width +'////'+ this.height)
614                 },
615                 random: function (min, max) {
616                     return (Math.random() * (max - min + 1) + min) >> 0;
617                 },
618                 prefix: function () {
619                     var N = navigator.appName, ua = navigator.userAgent, tem;
620                     var M = ua.match(/(opera|chrome|safari|firefox|msie)/?s*(.?d+(.d+)*)/i);
621                     if (M && (tem = ua.match(/version/([.d]+)/i)) != null) M[2] = tem[1];
622                     M = M ? [M[1], M[2]] : [N, navigator.appVersion, '-?'];
623                     M = M[0];
624                     if (M == "Chrome") { this.browserPrefix = "webkit"; }
625                     if (M == "Firefox") { this.browserPrefix = "Moz"; }
626                     if (M == "Safari") { this.browserPrefix = "webkit"; }
627                     if (M == "MSIE") { this.browserPrefix = "ms"; }
628                 }
629 
630             };
631         }(window));
632 
633 
634     </script>
635 
636 </head>
637 <body style="background-color:black">
638     <script>
639         var cube = new magicCube({ parent: null, dimension: 3, cubWidth: 100, cubHeight: 100, marginLeft: 10, marginTop: 10, marginZ: 10, cubZ: 100 });
640     </script>
641 
642 </body>
643 </html>
View Code
注:在此基础上可以加上鼠标控制事件,可以直接通过鼠标控制器任意方向的旋扭,也可以稍加改进用于炫酷展示图片!后续有时间我将加上这些功能,与大家再次分享!
原文地址:https://www.cnblogs.com/linbl/p/5276028.html