Array.prototype.clone = function() { var c = []; var len = this.length; for (var i=0;i 0) { this._rotateRandom(); } else { OZ.Event.remove(e); this._help.a = OZ.DOM.elm("p", {innerHTML:"Drag or swipe the background to rotate the whole cube."}); this._help.b = OZ.DOM.elm("p", {innerHTML:"Drag or swipe the cube to rotate its layers."}); document.body.appendChild(this._help.a); document.body.appendChild(this._help.b); OZ.CSS3.set(this._help.a, "transition", "opacity 500ms"); OZ.CSS3.set(this._help.b, "transition", "opacity 500ms"); } } var e = OZ.Event.add(null, "rotated", cb.bind(this)); this._rotateRandom(); } Rubik.prototype._rotateRandom = function() { var method = "_rotate" + ["X", "Y", "Z"].random(); var dir = [-1, 1].random(); var layer = Math.floor(Math.random()*Rubik.SIZE); this[method](dir, layer); } Rubik.prototype._update = function() { OZ.CSS3.set(this._node, "transform", "translateZ(" + (-Face.SIZE/2 - Face.SIZE) + "px) " + this._rotation.toRotation() + " translateZ("+(Face.SIZE/2)+"px)"); } Rubik.prototype._eventToFace = function(e) { if (document.elementFromPoint) { e = (e.touches ? e.touches[0] : e); var node = document.elementFromPoint(e.clientX, e.clientY); } else { var node = OZ.Event.target(e); } var index = this._faceNodes.indexOf(node); if (index == -1) { return null; } return this._faces[index]; } Rubik.prototype._dragStart = function(e) { this._faces = []; this._faceNodes = []; for (var i=0;i 1) { return; } if (this._drag.face) { /* check second face for rotation */ var thisFace = this._eventToFace(e); if (!thisFace || thisFace == this._drag.face) { return; } this._dragEnd(); this._rotate(this._drag.face, thisFace); } else { /* rotate cube */ e = (e.touches ? e.touches[0] : e); var mouse = [e.clientX, e.clientY]; var dx = mouse[0] - this._drag.mouse[0]; var dy = mouse[1] - this._drag.mouse[1]; var norm = Math.sqrt(dx*dx+dy*dy); if (!norm) { return; } var N = [-dy/norm, dx/norm]; this._drag.mouse = mouse; this._rotation = Quaternion.fromRotation([N[0], N[1], 0], norm/2).multiply(this._rotation); this._update(); } } Rubik.prototype._dragEnd = function(e) { while (this._drag.ec.length) { OZ.Event.remove(this._drag.ec.pop()); } if (!this._drag.face && this._help.a) { this._help.a.style.opacity = 0; this._help.a = null; } } Rubik.prototype._rotate = function(face1, face2) { var t1 = face1.getType(); var t2 = face2.getType(); var pos1 = face1.getCube().getPosition(); var pos2 = face2.getCube().getPosition(); /* find difference between cubes */ var diff = 0; var diffIndex = -1; for (var i=0;i<3;i++) { var d = pos1[i]-pos2[i]; if (d) { if (diffIndex != -1) { return; } /* different in >1 dimensions */ diff = (d > 0 ? 1 : -1); diffIndex = i; } } if (t1 == t2) { /* same face => diffIndex != -1 */ switch (t1) { case Face.FRONT: case Face.BACK: var coef = (t1 == Face.FRONT ? 1 : -1); if (diffIndex == 0) { this._rotateY(coef*diff, pos1[1]); } else { this._rotateX(coef*diff, pos1[0]); } break; case Face.LEFT: case Face.RIGHT: var coef = (t1 == Face.LEFT ? 1 : -1); if (diffIndex == 2) { this._rotateY(-coef*diff, pos1[1]); } else { this._rotateZ(coef*diff, pos1[2]); } break; case Face.TOP: case Face.BOTTOM: var coef = (t1 == Face.TOP ? 1 : -1); if (diffIndex == 0) { this._rotateZ(-coef*diff, pos1[2]); } else { this._rotateX(-coef*diff, pos1[0]); } break; } return; } switch (t1) { /* different face => same cube, diffIndex == 1 */ case Face.FRONT: case Face.BACK: var coef = (t1 == Face.FRONT ? 1 : -1); if (t2 == Face.LEFT) { this._rotateY(1 * coef, pos1[1]); } if (t2 == Face.RIGHT) { this._rotateY(-1 * coef, pos1[1]); } if (t2 == Face.TOP) { this._rotateX(1 * coef, pos1[0]); } if (t2 == Face.BOTTOM) { this._rotateX(-1 * coef, pos1[0]); } break; case Face.LEFT: case Face.RIGHT: var coef = (t1 == Face.LEFT ? 1 : -1); if (t2 == Face.FRONT) { this._rotateY(-1 * coef, pos1[1]); } if (t2 == Face.BACK) { this._rotateY(1 * coef, pos1[1]); } if (t2 == Face.TOP) { this._rotateZ(1 * coef, pos1[2]); } if (t2 == Face.BOTTOM) { this._rotateZ(-1 * coef, pos1[2]); } break; case Face.TOP: case Face.BOTTOM: var coef = (t1 == Face.TOP ? 1 : -1); if (t2 == Face.FRONT) { this._rotateX(-1 * coef, pos1[0]); } if (t2 == Face.BACK) { this._rotateX(1 * coef, pos1[0]); } if (t2 == Face.LEFT) { this._rotateZ(-1 * coef, pos1[2]); } if (t2 == Face.RIGHT) { this._rotateZ(1 * coef, pos1[2]); } break; } } Rubik.prototype._rotateX = function(dir, layer) { var cubes = []; for (var i=0;i