Add multiples maps
[myslice.git] / plugins / senslabmap / static / js / map.js
1 var Senslab = {
2   normalize: function(node) {
3     if (node.component_name) { //"wsn430-11.devlille.iot-lab.info",
4       var s = node.component_name.split('.');
5       if (s[2] == 'iot-lab' && s[3] == 'info') {
6         node.arch = s[0].split('-')[0];
7         node.id = s[0].split('-')[1];
8         node.site = s[1];
9         return true;
10       }
11     }
12     return false;
13   }
14 };
15
16 Senslab.Map = function() {
17   var colors = {
18     "Alive": 0x7FFF00,
19     "Busy": 0x9943BE,
20     "Suspected": 0xFF3030,
21     "Selected": 0x0099CC
22   };
23   
24   var archs = [
25   "wsn430",
26   "m3",
27   "a8"
28   ];
29   
30   function Map($container) {
31     this.width  = 600;
32     this.height = 400;
33     
34     this.distance = 50;
35     this.phi = -100;
36     this.theta = 0;
37     this.onRot = false;
38     
39     this.pointerDetectRay = new THREE.Raycaster();
40     this.pointerDetectRay.ray.direction.set(0, -1, 0);
41     this.projector = new THREE.Projector();
42     this.mouse2D = new THREE.Vector3(0, 0, 0);
43     
44     this.renderer = new THREE.CanvasRenderer();
45     this.renderer.setSize(this.width, this.height);
46     
47     this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 1, 10000);
48     
49     this.scene = new THREE.Scene();
50     this.scene.add(this.camera);
51     
52     this.updatePosition();
53     
54     var self = this;
55     
56     this.nodes = {};
57     this.$nodeInputs = {};
58     
59     $.each(archs, function(i, arch) {
60       self.nodes[arch] = [];
61       self.$nodeInputs[arch] = $("<input type='text' placeholder='" + arch + "'>")
62       .appendTo($container)
63       .change(function() {
64         self.nodes[arch] = expand($(this).val());
65         self.updateColor(arch);
66       });
67     });
68     
69     var $canvas = $(this.renderer.domElement)
70     .mousemove(function(e) {
71       self.mouse2D.x =  ((e.pageX - $canvas.offset().left) / $canvas.width()) * 2 - 1;
72       self.mouse2D.y = -((e.pageY - $canvas.offset().top) / $canvas.height()) * 2 + 1;
73       
74       if (self.onRot) {
75         self.theta -= e.pageX - self.mouse2D.pageX;
76         self.phi += e.pageY - self.mouse2D.pageY;
77         if (self.phi > 180)
78           self.phi = 180;
79         if (self.phi < -180)
80           self.phi = -180;
81         
82         self.mouse2D.pageX = e.pageX;
83         self.mouse2D.pageY = e.pageY;
84         
85         self.updatePosition();
86         self.update();
87       }
88     }).mousedown(function(e) {
89       e.preventDefault();
90       switch (e.which) {
91         case 1:
92           self.pointerDetectRay = self.projector.pickingRay(self.mouse2D.clone(), self.camera);
93           var intersects = self.pointerDetectRay.intersectObjects(self.scene.children);
94           if (intersects.length > 0 && self.select(intersects[0].object)) {
95             var node = intersects[0].object;
96             var $nodeInput = self.$nodeInputs[node.arch];
97             $nodeInput.val(factorize(self.nodes[node.arch]));
98             self.update();
99           }
100           break;
101         case 3:
102           self.mouse2D.pageX = e.pageX;
103           self.mouse2D.pageY = e.pageY;
104           self.onRot = true;
105           break;
106       }
107     }).mouseup(function(e) {
108       e.preventDefault();
109       switch (e.which) {
110         case 3:
111           self.onRot = false;
112           break;
113       }
114     }).mouseleave(function(e) {
115       self.onRot = false;
116     }).mousewheel(function(e, delta) {
117       e.preventDefault();
118       self.distance += delta * 5;
119       self.updatePosition();
120       self.update();
121     });
122     
123     $container.append($canvas);
124   }
125   
126   function getCenter(nodes) {
127     var xmin = 0, ymin = 0, zmin = 0;
128     var xmax = 0, ymax = 0, zmax = 0;
129     
130     for (var i = 0; i < nodes.length; ++i) {
131       if (nodes[i].x > xmax) xmax = nodes[i].x;
132       if (nodes[i].x < xmin) xmin = nodes[i].x;
133       if (nodes[i].y > ymax) ymax = nodes[i].y;
134       if (nodes[i].y < ymin) ymin = nodes[i].y;
135       if (nodes[i].z > zmax) zmax = nodes[i].z;
136       if (nodes[i].z < zmin) zmin = nodes[i].z;
137     }
138     return {x: (xmax + xmin) / 2, y: (ymax + ymin) / 2, z: (zmax + zmin) / 2};
139   }
140   
141   function setColor(node) {
142     node.material.color.setHex(colors[node.boot_state] || colors["Selected"]);
143   }
144   
145   Map.prototype.addNodes = function(nodes) {
146     var center = getCenter(nodes);
147     var program = function(context) {
148       context.beginPath();
149       context.arc(0, 0, 1, 0, Math.PI * 2, true);
150       context.closePath();
151       context.fill();
152     };
153     
154     for(var i = 0; i < nodes.length; ++i) {
155       var material = new THREE.ParticleCanvasMaterial({program: program});
156       var particle = new THREE.Particle(material);
157       
158       particle.id = nodes[i].id;
159       particle.arch = nodes[i].arch;
160       particle.boot_state = nodes[i].boot_state;
161       particle.position.x = (nodes[i].x - center.x) * 10;
162       particle.position.y = (nodes[i].y - center.y) * 10;
163       particle.position.z = (nodes[i].z - center.z) * 10;
164       particle.scale.x = particle.scale.y = 1;
165       setColor(particle)
166       this.scene.add(particle);
167     }
168     this.update();
169   };
170   
171   Map.prototype.select = function(node) {
172     if (node.boot_state == "Suspected") {
173       return false;
174     } else if (node.boot_state == "Alive") {
175       var array = this.nodes[node.arch];
176       array.push(parseInt(node.id));
177       array.sort(nodeSort);
178       node.boot_state = "Selected";
179       setColor(node);
180       return true;
181     } else {
182       var array = this.nodes[node.arch];
183       var index = $.inArray(parseInt(node.id), array);
184       index > -1 && array.splice(index, 1);
185       node.boot_state = "Alive";
186       setColor(node);
187       return true;
188     }
189   };
190   
191   function factorize(nodes) {
192     var factorized = [];
193     var prev = 0;
194     var intervalStart = 0;
195     
196     for (var i = 0; i < nodes.length; ++i) {
197       if (intervalStart) {
198         if (nodes[i] == prev + 1) {
199           prev++;
200         } else {
201           factorized.push(intervalStart + "-" + prev);
202           intervalStart = 0;
203           prev = nodes[i];
204         }
205       } else {
206         if (nodes[i] == prev + 1) {
207           intervalStart = prev;
208           prev++;
209         } else {
210           prev && factorized.push(prev);
211           prev = nodes[i];
212         }
213       }
214     }
215     factorized.push(intervalStart ? intervalStart + "-" + prev : prev);
216     return factorized.join(",");
217   }
218   
219   function expand(input) {
220     var factorized = input.split(",");
221     var expanded = [];
222     for (var i = 0; i < factorized.length; ++i) {
223       var d = factorized[i].split("-");
224       if (d.length == 2) {
225         for (var j = parseInt(d[0]); j < parseInt(d[1]) + 1; j++) {
226           expanded.push(j);
227         }
228       } else {
229         expanded.push(parseInt(factorized[i]));
230       }
231     }
232     expanded.sort(nodeSort);
233     for (var i = 1; i < expanded.length; i++) {
234       if (expanded[i] == expanded[i - 1]) {
235         expanded.splice(i--, 1);
236       }
237     }
238     return expanded;
239   }
240   
241   function nodeSort(a, b) {
242     return a - b;
243   }
244   
245   Map.prototype.updateColor = function(arch) {
246     var nodes = this.scene.children;
247     for (var i = 0; i < nodes.length; ++i) {
248       if (nodes[i].arch == arch && nodes[i].boot_state != "Suspected") {
249         var id = parseInt(nodes[i].id);
250         var array = this.nodes[arch];
251         nodes[i].boot_state = $.inArray(id, array) == -1 ? "Alive" : "Selected";
252         setColor(nodes[i]);
253       }
254     }
255     this.update();
256   }
257   
258   Map.prototype.updatePosition = function() {
259     this.camera.position.x = this.distance * Math.sin(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);
260     this.camera.position.y = this.distance * Math.sin(this.phi * Math.PI / 360);
261     this.camera.position.z = this.distance * Math.cos(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);
262     this.camera.lookAt(this.scene.position);
263     this.camera.updateMatrix();
264   };
265   
266   Map.prototype.update = function() {
267     this.renderer.render(this.scene, this.camera);
268   };
269   
270   return Map;
271 }();