1 // Various global variables
\r
2 var mouseX = 0, mouseY = 0,camera, scene, renderer, projector;
\r
3 var sTestEventType = 'mousedown';
\r
4 //var window3DWidth = window.innerWidth * 0.8;
\r
5 //var window3DHeight=window.innerHeight*0.75;
\r
6 var window3DWidth, window3DHeight;
\r
9 phi = -100, theta = 0, distance = 130;
\r
12 var info, nodelist, help;
\r
17 // list of selected nodes
\r
18 var selectedNodes = [];
\r
20 var div3d, nodebox, infobox;
\r
25 var particles, particle;
\r
27 div3d = document.getElementById('div3d');
\r
28 nodebox = document.getElementById('nodebox');
\r
29 infobox = document.getElementById('infobox');
\r
30 titlebox = document.getElementById('titlebox');
\r
32 offY = div3d.offsetTop;
\r
33 offX = div3d.offsetLeft;
\r
35 //titlebox.innerHTML = 'Grenoble Site ' + nodes.length + " nodes";
\r
36 infobox.innerHTML = 'Node info : ';
\r
40 camera = new THREE.PerspectiveCamera(75, window3DWidth / window3DHeight, 1, 10000);
\r
42 scene = new THREE.Scene();
\r
44 renderer = new THREE.CanvasRenderer();
\r
46 div3d.appendChild(renderer.domElement);
\r
48 window.addEventListener('resize', set3dsize, false);
\r
53 var PI2 = Math.PI * 2;
\r
54 var geometry = new THREE.Geometry();
\r
56 // let's find the center of the nodes
\r
57 xmin = ymin = zmin = 0;
\r
58 xmax = ymax = zmax = 0;
\r
60 for (var i = 0; i < nodes.length; i++) {
\r
61 if (nodes[i][1] > xmax) xmax = nodes[i][1];
\r
62 if (nodes[i][1] < xmin) xmin = nodes[i][1];
\r
63 if (nodes[i][2] > ymax) ymax = nodes[i][2];
\r
64 if (nodes[i][2] < ymin) ymin = nodes[i][2];
\r
65 if (nodes[i][3] > zmax) zmax = nodes[i][3];
\r
66 if (nodes[i][3] < zmin) zmin = nodes[i][3];
\r
69 xcenter = (xmax + xmin) / 2;
\r
70 ycenter = (ymax + ymin) / 2;
\r
71 zcenter = (zmax + zmin) / 2;
\r
73 // display nodes as TREE particles
\r
74 for (var i = 0; i < nodes.length; i++) {
\r
75 material = new THREE.ParticleCanvasMaterial({
\r
77 program: function (context) {
\r
78 context.beginPath();
\r
79 context.arc(0, 0, 1, 0, PI2, true);
\r
80 context.closePath();
\r
84 particle = new THREE.Particle(material);
\r
85 particle.name = nodes[i][0];
\r
86 particle.position.x = nodes[i][1] - xcenter;
\r
87 particle.position.y = nodes[i][2] - ycenter;
\r
88 particle.position.z = nodes[i][3] - zcenter;
\r
89 particle.uid = nodes[i][4];
\r
90 particle.state = nodes[i][5];
\r
91 particle.position.multiplyScalar(10);
\r
92 particle.scale.x = particle.scale.y = 1;
\r
93 scene.add(particle);
\r
94 v = new THREE.Vertex(particle.position);
\r
95 geometry.vertices.push(v);
\r
96 objects.push(particle)
\r
101 // a projector is needed to find which node is under the mouse
\r
102 projector = new THREE.Projector();
\r
104 nodebox.onkeyup = parseNodebox;
\r
105 // set mouse event handlers
\r
106 div3d.onmousedown = OnMouseDown;
\r
107 div3d.onmouseup = OnMouseUp;
\r
108 div3d.onmousemove = displayNodeInfo;
\r
109 if (div3d.addEventListener)
\r
110 /** DOMMouseScroll is for mozilla. */
\r
111 div3d.addEventListener('DOMMouseScroll', wheel, false);
\r
113 div3d.onmousewheel = div3d.onmousewheel = wheel;
\r
117 function set3dsize() {
\r
118 offY = div3d.offsetTop;
\r
119 offX = div3d.offsetLeft;
\r
120 window3DWidth = div3d.offsetWidth;
\r
121 window3DHeight = div3d.offsetHeight;
\r
122 renderer.setSize(window3DWidth, window3DHeight);
\r
124 camera.aspect = window3DWidth / window3DHeight;
\r
125 camera.updateProjectionMatrix();
\r
130 function sortfunction(a, b) {
\r
131 return (a - b) //causes an array to be sorted numerically and ascending
\r
134 // factorize the expanded list in selectedNode to produce dash intervals
\r
135 // 1,2,3,5,9 -> 1-3,5,9
\r
136 function factorize() {
\r
139 var intervalStart = 0;
\r
140 selectedNodes.sort(sortfunction);
\r
141 for (j = 0; j < selectedNodes.length; j++) {
\r
142 if (intervalStart) {
\r
143 // we are in an interval
\r
144 if (selectedNodes[j] == previous + 1) {
\r
149 fact.push(intervalStart + "-" + previous);
\r
151 previous = selectedNodes[j];
\r
154 // we are not in an interval
\r
155 if (selectedNodes[j] == previous + 1) {
\r
156 // let's begin an interval
\r
157 intervalStart = previous;
\r
160 if (previous) fact.push(previous);
\r
161 previous = selectedNodes[j];
\r
165 // at the end of the loop, two cases
\r
166 // we were still in an interval, then add it to the result
\r
167 // we were not in an interval, then add the last selectednode (previous)
\r
168 if (intervalStart) {
\r
169 fact.push(intervalStart + "-" + previous);
\r
171 if (previous) fact.push(previous);
\r
176 // expand a list of nodes containing dash intervals
\r
177 // 1-3,5,9 -> 1,2,3,5,9
\r
178 function expand(factExp) {
\r
180 for (i = 0; i < factExp.length; i++) {
\r
181 dashExpression = factExp[i].split("-");
\r
182 if (dashExpression.length == 2) {
\r
183 for (j = parseInt(dashExpression[0]); j < (parseInt(dashExpression[1]) + 1); j++)
\r
185 } else exp.push(parseInt(factExp[i]));
\r
187 exp.sort(sortfunction);
\r
188 for (var i = 1; i < exp.length; i++) { if (exp[i] == exp[i - 1]) { exp.splice(i--, 1); } }
\r
192 function parseNodebox() {
\r
193 input = nodebox.value;
\r
194 selectedNodes = expand(input.split(","));
\r
198 function debugaxis(axisLength) {
\r
199 //Shorten the vertex function
\r
200 function v(x, y, z) {
\r
201 return new THREE.Vertex(new THREE.Vector3(x, y, z));
\r
204 //Create axis (point1, point2, colour)
\r
205 function createAxis(p1, p2, color) {
\r
206 var line, lineGeometry = new THREE.Geometry(),
\r
207 lineMat = new THREE.LineBasicMaterial({ color: color, lineWidth: 2 });
\r
208 lineGeometry.vertices.push(p1, p2);
\r
209 line = new THREE.Line(lineGeometry, lineMat);
\r
213 createAxis(v(0, 0, 0), v(axisLength, 0, 0), 0xFF0000);
\r
214 createAxis(v(0, 0, 0), v(0, axisLength, 0), 0x00FF00);
\r
215 createAxis(v(0, 0, 0), v(0, 0, axisLength), 0x0000FF);
\r
218 // set the camera position according two angles theta and phi and the distance
\r
219 // and display the scene
\r
220 function myrender() {
\r
221 //infobox.innerHTML = " Cam Pos = " + camera.position.x + "," + camera.position.y + "," + camera.position.z
\r
222 // + " - " + theta + "," + phi + ","+ distance;
\r
223 //infobox.innerHTML = selectedNodes;
\r
224 camera.position.x = distance * Math.sin(theta * Math.PI / 360) * Math.cos(phi * Math.PI / 360);
\r
225 camera.position.y = distance * Math.sin(this.phi * Math.PI / 360);
\r
226 camera.position.z = distance * Math.cos(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);
\r
227 camera.lookAt(scene.position);
\r
228 camera.updateMatrix();
\r
230 for (i = 0; i < objects.length; i++) {
\r
232 if (selectedNodes.indexOf(objects[i].name) != -1) {
\r
233 objects[i].material.color.setHex(0x0099CC);
\r
236 if(objects[i].state == "Busy") {
\r
237 objects[i].material.color.setHex(0x9943BE);
\r
239 else if(objects[i].state == "Alive") {
\r
240 objects[i].material.color.setHex(0x7FFF00);
\r
243 objects[i].material.color.setHex(0xFF3030);
\r
249 renderer.render(scene, camera);
\r
252 // rigthbutton is used for rotations
\r
253 function onDocumentMouseMoveRot(event) {
\r
254 NewmouseX = event.clientX;
\r
255 NewmouseY = event.clientY;
\r
256 DeltaX = NewmouseX - mouseX;
\r
257 DeltaY = NewmouseY - mouseY;
\r
259 mouseX = NewmouseX;
\r
260 mouseY = NewmouseY;
\r
264 if (phi > 180) phi = 180;
\r
265 if (phi < -180) phi = -180;
\r
268 // mousewheel is used for zoom
\r
269 function Zoom(delta) {
\r
270 distance += delta * 5;
\r
274 // return the graphical node under the mouse
\r
275 function findNodeUnderMouse(event) {
\r
276 var vector = new THREE.Vector3(((event.clientX - offX) / window3DWidth) * 2 - 1, -((event.clientY - offY) / window3DHeight) * 2 + 1, 0.5);
\r
277 projector.unprojectVector(vector, camera);
\r
278 var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());
\r
279 var intersects = ray.intersectObjects(objects);
\r
280 if (intersects.length > 0) {
\r
281 return intersects[0];
\r
282 } else return null;
\r
285 // display some info of the node under the mouse
\r
286 function displayNodeInfo(e) {
\r
287 obj = findNodeUnderMouse(e);
\r
289 if (obj) infobox.innerHTML = 'Node info : number ' + obj.object.name + " with id " + obj.object.uid;
\r
290 // else infobox.innerHTML = e.clientX + "," + e.clientY + " - " + offX + "," + offY;
\r
293 // select/unselect nodes
\r
294 function toggleNode(obj) {
\r
295 nodeId = obj.object.name;
\r
296 i = selectedNodes.indexOf(nodeId);
\r
297 if (i == -1) selectedNodes.push(nodeId);
\r
298 else selectedNodes.splice(i, 1);
\r
299 nodebox.value = factorize().join(",");
\r
303 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
\r
304 // Mouse handling functions
\r
306 function OnMouseDown(e) {
\r
307 var clickType = 'LEFT';
\r
308 if (e.type != sTestEventType) return true
\r
310 if (e.which == 3) clickType = 'RIGHT';
\r
311 if (e.which == 2) clickType = 'MIDDLE';
\r
312 //infobox.innerHTML = clickType + " - Cam Pos = " + camera.position.x + "," + camera.position.y + "," + camera.position.z;
\r
314 mouseX = e.clientX;
\r
315 mouseY = e.clientY;
\r
316 if (clickType == 'RIGHT') {
\r
317 document.onmousemove = onDocumentMouseMoveRot;
\r
319 if (clickType == 'LEFT') {
\r
320 obj = findNodeUnderMouse(e);
\r
321 if (obj != null) toggleNode(obj);
\r
325 function OnMouseUp(e) {
\r
326 document.onmousemove = displayNodeInfo;
\r
329 // This function was taken here : http://www.adomas.org/javascript-mouse-wheel/
\r
330 // Event handler for mouse wheel event.
\r
332 function wheel(event) {
\r
334 if (!event) /* For IE. */
\r
335 event = window.event;
\r
336 if (event.wheelDelta) { /* IE/Opera. */
\r
337 delta = event.wheelDelta / 120;
\r
338 } else if (event.detail) { /** Mozilla case. */
\r
339 /** In Mozilla, sign of delta is different than in IE.
\r
340 * Also, delta is multiple of 3.
\r
342 delta = -event.detail / 3;
\r
344 /** If delta is nonzero, handle it.
\r
345 * Basically, delta is now positive if wheel was scrolled up,
\r
346 * and negative, if wheel was scrolled down.
\r
350 /** Prevent default actions caused by mouse wheel.
\r
351 * That might be ugly, but we handle scrolls somehow
\r
352 * anyway, so don't bother here..
\r
354 if (event.preventDefault)
\r
355 event.preventDefault();
\r
356 event.returnValue = false;
\r