unfold: better management of static files thanks to finders for plugins and third...
[myslice.git] / plugins / senslabmap / static / js / viewer3D.js
diff --git a/plugins/senslabmap/static/js/viewer3D.js b/plugins/senslabmap/static/js/viewer3D.js
new file mode 100644 (file)
index 0000000..cf70e81
--- /dev/null
@@ -0,0 +1,342 @@
+\r
+// Various global variables\r
+var mouseX = 0, mouseY = 0,\r
+                       camera, scene, renderer, projector;\r
+var sTestEventType = 'mousedown';\r
+//var window3DWidth = window.innerWidth * 0.8;\r
+//var window3DHeight=window.innerHeight*0.75;\r
+var window3DWidth, window3DHeight;\r
+var offX, offY;\r
+// Camera parameters\r
+phi = -100, theta = 0, distance = 150;\r
+var rcount = 0;\r
+// Text display\r
+var info, nodelist, help;\r
+\r
+// graphical nodes\r
+var objects = [];\r
+\r
+// list of selected nodes\r
+var selectedNodes = [];\r
+\r
+var div3d, nodebox, infobox;\r
+\r
+function init() {\r
+    var particles, particle;\r
+\r
+    // jordan : modifier document.getElementById\r
+    div3d = jQuery('#div3d');\r
+    nodebox = jQuery('#nodebox');\r
+    infobox = jQuery('#infobox');\r
+    titlebox = jQuery('#titlebox');\r
+    // offset also\r
+    var offset = div3d.offset();\r
+    offY = offset.top;\r
+    offX = offset.left;\r
+\r
+    titlebox.innerHTML = 'Grenoble Site ' + nodes_gre.length + " nodes";\r
+    infobox.innerHTML = 'Node info : ';\r
+\r
+    nodebox.value = "";\r
+\r
+    camera = new THREE.PerspectiveCamera(75, window3DWidth / window3DHeight, 1, 10000);\r
+\r
+    scene = new THREE.Scene();\r
+\r
+    renderer = new THREE.CanvasRenderer();\r
+\r
+    // jordan XXX div3d.appendChild(renderer.domElement);\r
+    div3d.append(renderer.domElement);\r
+\r
+    window.addEventListener('resize', set3dsize, false);\r
+    scene.add(camera);\r
+    set3dsize();\r
+    \r
+\r
+    var PI2 = Math.PI * 2;\r
+    var geometry = new THREE.Geometry();\r
+\r
+    // let's find the center of the nodes\r
+    xmin = ymin = zmin = 0;\r
+    xmax = ymax = zmax = 0;\r
+\r
+    for (var i = 0; i < nodes_gre.length; i++) {\r
+        if (nodes_gre[i][1] > xmax) xmax = nodes_gre[i][1];\r
+        if (nodes_gre[i][1] < xmin) xmin = nodes_gre[i][1];\r
+        if (nodes_gre[i][2] > ymax) ymax = nodes_gre[i][2];\r
+        if (nodes_gre[i][2] < ymin) ymin = nodes_gre[i][2];\r
+        if (nodes_gre[i][3] > zmax) zmax = nodes_gre[i][3];\r
+        if (nodes_gre[i][3] < zmin) zmin = nodes_gre[i][3];\r
+    }\r
+\r
+    xcenter = (xmax + xmin) / 2;\r
+    ycenter = (ymax + ymin) / 2;\r
+    zcenter = (zmax + zmin) / 2;\r
+\r
+    // display nodes as TREE particles\r
+    for (var i = 0; i < nodes_gre.length; i++) {\r
+        material = new THREE.ParticleCanvasMaterial({\r
+            color: 0xffffff,\r
+            program: function (context) {\r
+                context.beginPath();\r
+                context.arc(0, 0, 1, 0, PI2, true);\r
+                context.closePath();\r
+                context.fill();\r
+            }\r
+        });\r
+        particle = new THREE.Particle(material);\r
+        particle.name = nodes_gre[i][0];\r
+        particle.position.x = nodes_gre[i][1] - xcenter;\r
+        particle.position.y = nodes_gre[i][2] - ycenter;\r
+        particle.position.z = nodes_gre[i][3] - zcenter;\r
+        particle.position.multiplyScalar(10);\r
+        particle.scale.x = particle.scale.y = 1;\r
+        scene.add(particle);\r
+        v = new THREE.Vertex(particle.position);\r
+        geometry.vertices.push(v);\r
+        objects.push(particle)\r
+    }\r
+\r
+    debugaxis(10);\r
+    // a projector is needed to find which node is under the mouse\r
+    projector = new THREE.Projector();\r
+\r
+    nodebox.onkeyup = parseNodebox;\r
+    // set mouse event handlers // TODO jordan\r
+    document.onmousedown = OnMouseDown;\r
+    document.onmouseup = OnMouseUp;\r
+    document.onmousemove = displayNodeInfo;\r
+    if (window.addEventListener)\r
+    /** DOMMouseScroll is for mozilla. */\r
+        window.addEventListener('DOMMouseScroll', wheel, false);\r
+    /** IE/Opera. */\r
+    window.onmousewheel = document.onmousewheel = wheel;\r
+    myrender();\r
+}\r
+\r
+function set3dsize() {\r
+    // jordan\r
+    var offset = div3d.offset();\r
+    offY = offset.top;\r
+    offX = offset.left;\r
+    window3DWidth = div3d.width();\r
+    window3DHeight = div3d.height();\r
+    renderer.setSize(window3DWidth, window3DHeight);\r
+\r
+    camera.aspect = window3DWidth / window3DHeight;\r
+    camera.updateProjectionMatrix();\r
+\r
+    myrender();\r
+}\r
+\r
+function sortfunction(a, b) {\r
+    return (a - b) //causes an array to be sorted numerically and ascending\r
+}\r
+\r
+// factorize the expanded list in selectedNode to produce dash intervals\r
+// 1,2,3,5,9  -> 1-3,5,9\r
+function factorize() {\r
+    var fact = [];\r
+    var previous = 0;\r
+    var intervalStart = 0;\r
+    selectedNodes.sort(sortfunction);\r
+    for (j = 0; j < selectedNodes.length; j++) {\r
+        if (intervalStart) {\r
+            // we are in an interval\r
+            if (selectedNodes[j] == previous + 1) {\r
+                // interval grows\r
+                previous += 1;\r
+            } else {\r
+                // end of interval\r
+                fact.push(intervalStart + "-" + previous);\r
+                intervalStart = 0;\r
+                previous = selectedNodes[j];\r
+            }\r
+        } else {\r
+            // we are not in an interval\r
+            if (selectedNodes[j] == previous + 1) {\r
+                // let's begin an interval\r
+                intervalStart = previous;\r
+                previous += 1;\r
+            } else {\r
+                if (previous) fact.push(previous);\r
+                previous = selectedNodes[j];\r
+            }\r
+        }\r
+    } // for end \r
+    // at the end of the loop, two cases\r
+    // we were still in an interval, then add it to the result\r
+    // we were not in an interval, then add the last selectednode (previous)\r
+    if (intervalStart) {\r
+        fact.push(intervalStart + "-" + previous);\r
+    } else {\r
+        if (previous) fact.push(previous);\r
+    }\r
+    return fact;\r
+}\r
+\r
+// expand a list of nodes containing dash intervals\r
+// 1-3,5,9 -> 1,2,3,5,9\r
+function expand(factExp) {\r
+    exp = [];\r
+    for (i = 0; i < factExp.length; i++) {\r
+        dashExpression = factExp[i].split("-");\r
+        if (dashExpression.length == 2) {\r
+            for (j = parseInt(dashExpression[0]); j < (parseInt(dashExpression[1]) + 1); j++)\r
+                exp.push(j);\r
+        } else exp.push(parseInt(factExp[i]));\r
+    }\r
+    exp.sort(sortfunction);\r
+    for (var i = 1; i < exp.length; i++) { if (exp[i] == exp[i - 1]) { exp.splice(i--, 1); } }\r
+    return exp;\r
+}\r
+\r
+function parseNodebox() {\r
+    input = nodebox.value;\r
+    selectedNodes = expand(input.split(","));\r
+    myrender();\r
+}\r
+\r
+function debugaxis(axisLength) {\r
+    //Shorten the vertex function\r
+    function v(x, y, z) {\r
+        return new THREE.Vertex(new THREE.Vector3(x, y, z));\r
+    }\r
+\r
+    //Create axis (point1, point2, colour)\r
+    function createAxis(p1, p2, color) {\r
+        var line, lineGeometry = new THREE.Geometry(),\r
+                    lineMat = new THREE.LineBasicMaterial({ color: color, lineWidth: 2 });\r
+        lineGeometry.vertices.push(p1, p2);\r
+        line = new THREE.Line(lineGeometry, lineMat);\r
+        scene.add(line);\r
+    }\r
+\r
+    createAxis(v(0, 0, 0), v(axisLength, 0, 0), 0xFF0000);\r
+    createAxis(v(0, 0, 0), v(0, axisLength, 0), 0x00FF00);\r
+    createAxis(v(0, 0, 0), v(0, 0, axisLength), 0x0000FF);\r
+};\r
+\r
+// set the camera position according two angles theta and phi and the distance\r
+// and display the scene\r
+function myrender() {\r
+    //infobox.innerHTML = " Cam Pos = " + camera.position.x + "," + camera.position.y + "," + camera.position.z\r
+    //                + " - " + theta + "," + phi + ","+ distance;\r
+    //infobox.innerHTML = selectedNodes;\r
+    camera.position.x = distance * Math.sin(theta * Math.PI / 360) * Math.cos(phi * Math.PI / 360);\r
+    camera.position.y = distance * Math.sin(this.phi * Math.PI / 360);\r
+    camera.position.z = distance * Math.cos(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);\r
+    camera.lookAt(scene.position);\r
+    camera.updateMatrix();\r
+\r
+    for (i = 0; i < objects.length; i++)\r
+        if (selectedNodes.indexOf(objects[i].name) != -1) objects[i].material.color.setHex(0xff0000);\r
+        else objects[i].material.color.setHex(0xffffff);\r
+    renderer.render(scene, camera);\r
+}\r
+\r
+// rigthbutton is used for rotations \r
+function onDocumentMouseMoveRot(event) {\r
+    NewmouseX = event.clientX;\r
+    NewmouseY = event.clientY;\r
+    DeltaX = NewmouseX - mouseX;\r
+    DeltaY = NewmouseY - mouseY;\r
+\r
+    mouseX = NewmouseX;\r
+    mouseY = NewmouseY;\r
+\r
+    theta -= DeltaX;\r
+    phi += DeltaY;\r
+    if (phi > 180) phi = 180;\r
+    if (phi < -180) phi = -180;\r
+    myrender();\r
+}\r
+// mousewheel is used for zoom\r
+function Zoom(delta) {\r
+    distance += delta * 5;\r
+    myrender();\r
+}\r
+\r
+// return the graphical node under the mouse\r
+function findNodeUnderMouse(event) {\r
+    var vector = new THREE.Vector3(((event.clientX - offX) / window3DWidth) * 2 - 1, -((event.clientY - offY) / window3DHeight) * 2 + 1, 0.5);\r
+    projector.unprojectVector(vector, camera);\r
+    var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());\r
+    var intersects = ray.intersectObjects(objects);\r
+    if (intersects.length > 0) {\r
+        return intersects[0];\r
+    } else return null;\r
+}\r
+\r
+// display some info of the node under the mouse\r
+function displayNodeInfo(e) {\r
+    obj = findNodeUnderMouse(e);\r
+    if (obj) infobox.innerHTML = 'Node info : number ' + obj.object.name + " with id " + nodes_gre[obj.object.id][4];\r
+    //    else infobox.innerHTML = e.clientX + "," + e.clientY + " - " + offX + "," + offY;\r
+}\r
+\r
+// select/unselect nodes\r
+function toggleNode(obj) {\r
+    nodeId = obj.object.name;\r
+    i = selectedNodes.indexOf(nodeId);\r
+    if (i == -1) selectedNodes.push(nodeId);\r
+    else selectedNodes.splice(i, 1);\r
+    nodebox.value = factorize().join(",");\r
+    myrender();\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+// Mouse handling functions\r
+//\r
+function OnMouseDown(e) {\r
+    var clickType = 'LEFT';\r
+    if (e.type != sTestEventType) return true\r
+    if (e.which) {\r
+        if (e.which == 3) clickType = 'RIGHT';\r
+        if (e.which == 2) clickType = 'MIDDLE';\r
+        //infobox.innerHTML = clickType + " - Cam Pos = " + camera.position.x + "," + camera.position.y + "," + camera.position.z;\r
+    }\r
+    mouseX = e.clientX;\r
+    mouseY = e.clientY;\r
+    if (clickType == 'RIGHT') {\r
+        document.onmousemove = onDocumentMouseMoveRot;\r
+    }\r
+    if (clickType == 'LEFT') {\r
+        obj = findNodeUnderMouse(e);\r
+        if (obj != null) toggleNode(obj);\r
+    }\r
+}\r
+\r
+function OnMouseUp(e) {\r
+    document.onmousemove = displayNodeInfo;\r
+}\r
+\r
+// This function was taken here : http://www.adomas.org/javascript-mouse-wheel/\r
+// Event handler for mouse wheel event.\r
+\r
+function wheel(event) {\r
+    var delta = 0;\r
+    if (!event) /* For IE. */\r
+        event = window.event;\r
+    if (event.wheelDelta) { /* IE/Opera. */\r
+        delta = event.wheelDelta / 120;\r
+    } else if (event.detail) { /** Mozilla case. */\r
+        /** In Mozilla, sign of delta is different than in IE.\r
+        * Also, delta is multiple of 3.\r
+        */\r
+        delta = -event.detail / 3;\r
+    }\r
+    /** If delta is nonzero, handle it.\r
+    * Basically, delta is now positive if wheel was scrolled up,\r
+    * and negative, if wheel was scrolled down.\r
+    */\r
+    if (delta)\r
+        Zoom(delta);\r
+    /** Prevent default actions caused by mouse wheel.\r
+    * That might be ugly, but we handle scrolls somehow\r
+    * anyway, so don't bother here..\r
+    */\r
+    if (event.preventDefault)\r
+        event.preventDefault();\r
+    event.returnValue = false;\r
+}          \r