From b24624fc972e4d2844d2a4e2ec7dc754d967c287 Mon Sep 17 00:00:00 2001 From: Andras Becsi Date: Mon, 23 Jun 2014 11:21:05 +0200 Subject: webengine: Add offline Rubik's Cube demo This interactive demo was retrieved from https://developer.mozilla.org/ms/demos/detail/rubiks-cube and modified for our devices. Change-Id: I48b7289367e0e2b81fa2e3bf096fdc0fe789a532 Reviewed-by: Eirik Aavitsland Reviewed-by: Zeno Albisser --- basicsuite/webengine/content/index.html | 1 + basicsuite/webengine/content/rubiks/css/style.css | 36 ++ basicsuite/webengine/content/rubiks/index.html | 25 ++ basicsuite/webengine/content/rubiks/js/css3.oz.js | 28 ++ basicsuite/webengine/content/rubiks/js/oz.js | 334 ++++++++++++++ .../webengine/content/rubiks/js/quaternion.js | 78 ++++ basicsuite/webengine/content/rubiks/js/rubik.js | 492 +++++++++++++++++++++ basicsuite/webengine/content/rubiks/screenshot.png | Bin 0 -> 7159 bytes 8 files changed, 994 insertions(+) create mode 100644 basicsuite/webengine/content/rubiks/css/style.css create mode 100644 basicsuite/webengine/content/rubiks/index.html create mode 100644 basicsuite/webengine/content/rubiks/js/css3.oz.js create mode 100644 basicsuite/webengine/content/rubiks/js/oz.js create mode 100644 basicsuite/webengine/content/rubiks/js/quaternion.js create mode 100644 basicsuite/webengine/content/rubiks/js/rubik.js create mode 100644 basicsuite/webengine/content/rubiks/screenshot.png (limited to 'basicsuite') diff --git a/basicsuite/webengine/content/index.html b/basicsuite/webengine/content/index.html index f5a2bf4..d4bf355 100644 --- a/basicsuite/webengine/content/index.html +++ b/basicsuite/webengine/content/index.html @@ -30,6 +30,7 @@
+
diff --git a/basicsuite/webengine/content/rubiks/css/style.css b/basicsuite/webengine/content/rubiks/css/style.css new file mode 100644 index 0000000..a636bb0 --- /dev/null +++ b/basicsuite/webengine/content/rubiks/css/style.css @@ -0,0 +1,36 @@ +html, body { + height: 100%; + margin: 0px; +} + +body { + background-color: #000; + color: white; + text-shadow: 0px 1px 1px black; + text-align: center; + font-family: sans-serif; +} + +h1 { + text-align: center; + margin-top: 0px; + padding-top: 1em; +} + +footer { + position: fixed; + text-align: center; + width: 100%; + left: 0px; + bottom: 3px; + font-size: 90%; +} + +a { + color: white; +} + +.face { + border: 2px solid black; + border-radius: 10px; +} diff --git a/basicsuite/webengine/content/rubiks/index.html b/basicsuite/webengine/content/rubiks/index.html new file mode 100644 index 0000000..993b523 --- /dev/null +++ b/basicsuite/webengine/content/rubiks/index.html @@ -0,0 +1,25 @@ + + + + + + + Rubik's cube :: CSS 3D Transformations demo + + + + + + + + + +

CSS 3D Rubik's cube

+ + diff --git a/basicsuite/webengine/content/rubiks/js/css3.oz.js b/basicsuite/webengine/content/rubiks/js/css3.oz.js new file mode 100644 index 0000000..d8ad6d9 --- /dev/null +++ b/basicsuite/webengine/content/rubiks/js/css3.oz.js @@ -0,0 +1,28 @@ +OZ.CSS3 = { + getProperty: function(property) { + var prefix = this.getPrefix(this._normalize(property)); + if (prefix === null) { return null; } + return (prefix ? "-" + prefix.toLowerCase() + "-" : "") + property; + }, + set: function(node, prop, value) { + prop = this._normalize(prop); + var prefix = this.getPrefix(prop); + if (prefix === null) { return false; } + var p = (prefix ? prefix + prop.charAt(0).toUpperCase() + prop.substring(1) : prop); + node.style[p] = value; + return true; + }, + getPrefix: function(property) { + var prefixes = ["", "ms", "Webkit", "O", "Moz"]; + for (var i=0;i-1;i--) { + if (i in this && this[i] === item) { return i; } + } + return -1; + } +} +if (!Array.lastIndexOf) { + Array.lastIndexOf = function(obj, item, from) { return Array.prototype.lastIndexOf.call(obj, item, from); } +} + +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(cb, _this) { + 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