Add multiples maps
[unfold.git] / plugins / senslabmap / static / js / map.js
diff --git a/plugins/senslabmap/static/js/map.js b/plugins/senslabmap/static/js/map.js
new file mode 100644 (file)
index 0000000..d2ae3f6
--- /dev/null
@@ -0,0 +1,271 @@
+var Senslab = {
+  normalize: function(node) {
+    if (node.component_name) { //"wsn430-11.devlille.iot-lab.info",
+      var s = node.component_name.split('.');
+      if (s[2] == 'iot-lab' && s[3] == 'info') {
+        node.arch = s[0].split('-')[0];
+        node.id = s[0].split('-')[1];
+        node.site = s[1];
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+Senslab.Map = function() {
+  var colors = {
+    "Alive": 0x7FFF00,
+    "Busy": 0x9943BE,
+    "Suspected": 0xFF3030,
+    "Selected": 0x0099CC
+  };
+  
+  var archs = [
+  "wsn430",
+  "m3",
+  "a8"
+  ];
+  
+  function Map($container) {
+    this.width  = 600;
+    this.height = 400;
+    
+    this.distance = 50;
+    this.phi = -100;
+    this.theta = 0;
+    this.onRot = false;
+    
+    this.pointerDetectRay = new THREE.Raycaster();
+    this.pointerDetectRay.ray.direction.set(0, -1, 0);
+    this.projector = new THREE.Projector();
+    this.mouse2D = new THREE.Vector3(0, 0, 0);
+    
+    this.renderer = new THREE.CanvasRenderer();
+    this.renderer.setSize(this.width, this.height);
+    
+    this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 1, 10000);
+    
+    this.scene = new THREE.Scene();
+    this.scene.add(this.camera);
+    
+    this.updatePosition();
+    
+    var self = this;
+    
+    this.nodes = {};
+    this.$nodeInputs = {};
+    
+    $.each(archs, function(i, arch) {
+      self.nodes[arch] = [];
+      self.$nodeInputs[arch] = $("<input type='text' placeholder='" + arch + "'>")
+      .appendTo($container)
+      .change(function() {
+        self.nodes[arch] = expand($(this).val());
+        self.updateColor(arch);
+      });
+    });
+    
+    var $canvas = $(this.renderer.domElement)
+    .mousemove(function(e) {
+      self.mouse2D.x =  ((e.pageX - $canvas.offset().left) / $canvas.width()) * 2 - 1;
+      self.mouse2D.y = -((e.pageY - $canvas.offset().top) / $canvas.height()) * 2 + 1;
+      
+      if (self.onRot) {
+        self.theta -= e.pageX - self.mouse2D.pageX;
+        self.phi += e.pageY - self.mouse2D.pageY;
+        if (self.phi > 180)
+          self.phi = 180;
+        if (self.phi < -180)
+          self.phi = -180;
+        
+        self.mouse2D.pageX = e.pageX;
+        self.mouse2D.pageY = e.pageY;
+        
+        self.updatePosition();
+        self.update();
+      }
+    }).mousedown(function(e) {
+      e.preventDefault();
+      switch (e.which) {
+        case 1:
+          self.pointerDetectRay = self.projector.pickingRay(self.mouse2D.clone(), self.camera);
+          var intersects = self.pointerDetectRay.intersectObjects(self.scene.children);
+          if (intersects.length > 0 && self.select(intersects[0].object)) {
+            var node = intersects[0].object;
+            var $nodeInput = self.$nodeInputs[node.arch];
+            $nodeInput.val(factorize(self.nodes[node.arch]));
+            self.update();
+          }
+          break;
+        case 3:
+          self.mouse2D.pageX = e.pageX;
+          self.mouse2D.pageY = e.pageY;
+          self.onRot = true;
+          break;
+      }
+    }).mouseup(function(e) {
+      e.preventDefault();
+      switch (e.which) {
+        case 3:
+          self.onRot = false;
+          break;
+      }
+    }).mouseleave(function(e) {
+      self.onRot = false;
+    }).mousewheel(function(e, delta) {
+      e.preventDefault();
+      self.distance += delta * 5;
+      self.updatePosition();
+      self.update();
+    });
+    
+    $container.append($canvas);
+  }
+  
+  function getCenter(nodes) {
+    var xmin = 0, ymin = 0, zmin = 0;
+    var xmax = 0, ymax = 0, zmax = 0;
+    
+    for (var i = 0; i < nodes.length; ++i) {
+      if (nodes[i].x > xmax) xmax = nodes[i].x;
+      if (nodes[i].x < xmin) xmin = nodes[i].x;
+      if (nodes[i].y > ymax) ymax = nodes[i].y;
+      if (nodes[i].y < ymin) ymin = nodes[i].y;
+      if (nodes[i].z > zmax) zmax = nodes[i].z;
+      if (nodes[i].z < zmin) zmin = nodes[i].z;
+    }
+    return {x: (xmax + xmin) / 2, y: (ymax + ymin) / 2, z: (zmax + zmin) / 2};
+  }
+  
+  function setColor(node) {
+    node.material.color.setHex(colors[node.boot_state] || colors["Selected"]);
+  }
+  
+  Map.prototype.addNodes = function(nodes) {
+    var center = getCenter(nodes);
+    var program = function(context) {
+      context.beginPath();
+      context.arc(0, 0, 1, 0, Math.PI * 2, true);
+      context.closePath();
+      context.fill();
+    };
+    
+    for(var i = 0; i < nodes.length; ++i) {
+      var material = new THREE.ParticleCanvasMaterial({program: program});
+      var particle = new THREE.Particle(material);
+      
+      particle.id = nodes[i].id;
+      particle.arch = nodes[i].arch;
+      particle.boot_state = nodes[i].boot_state;
+      particle.position.x = (nodes[i].x - center.x) * 10;
+      particle.position.y = (nodes[i].y - center.y) * 10;
+      particle.position.z = (nodes[i].z - center.z) * 10;
+      particle.scale.x = particle.scale.y = 1;
+      setColor(particle)
+      this.scene.add(particle);
+    }
+    this.update();
+  };
+  
+  Map.prototype.select = function(node) {
+    if (node.boot_state == "Suspected") {
+      return false;
+    } else if (node.boot_state == "Alive") {
+      var array = this.nodes[node.arch];
+      array.push(parseInt(node.id));
+      array.sort(nodeSort);
+      node.boot_state = "Selected";
+      setColor(node);
+      return true;
+    } else {
+      var array = this.nodes[node.arch];
+      var index = $.inArray(parseInt(node.id), array);
+      index > -1 && array.splice(index, 1);
+      node.boot_state = "Alive";
+      setColor(node);
+      return true;
+    }
+  };
+  
+  function factorize(nodes) {
+    var factorized = [];
+    var prev = 0;
+    var intervalStart = 0;
+    
+    for (var i = 0; i < nodes.length; ++i) {
+      if (intervalStart) {
+        if (nodes[i] == prev + 1) {
+          prev++;
+        } else {
+          factorized.push(intervalStart + "-" + prev);
+          intervalStart = 0;
+          prev = nodes[i];
+        }
+      } else {
+        if (nodes[i] == prev + 1) {
+          intervalStart = prev;
+          prev++;
+        } else {
+          prev && factorized.push(prev);
+          prev = nodes[i];
+        }
+      }
+    }
+    factorized.push(intervalStart ? intervalStart + "-" + prev : prev);
+    return factorized.join(",");
+  }
+  
+  function expand(input) {
+    var factorized = input.split(",");
+    var expanded = [];
+    for (var i = 0; i < factorized.length; ++i) {
+      var d = factorized[i].split("-");
+      if (d.length == 2) {
+        for (var j = parseInt(d[0]); j < parseInt(d[1]) + 1; j++) {
+          expanded.push(j);
+        }
+      } else {
+        expanded.push(parseInt(factorized[i]));
+      }
+    }
+    expanded.sort(nodeSort);
+    for (var i = 1; i < expanded.length; i++) {
+      if (expanded[i] == expanded[i - 1]) {
+        expanded.splice(i--, 1);
+      }
+    }
+    return expanded;
+  }
+  
+  function nodeSort(a, b) {
+    return a - b;
+  }
+  
+  Map.prototype.updateColor = function(arch) {
+    var nodes = this.scene.children;
+    for (var i = 0; i < nodes.length; ++i) {
+      if (nodes[i].arch == arch && nodes[i].boot_state != "Suspected") {
+        var id = parseInt(nodes[i].id);
+        var array = this.nodes[arch];
+        nodes[i].boot_state = $.inArray(id, array) == -1 ? "Alive" : "Selected";
+        setColor(nodes[i]);
+      }
+    }
+    this.update();
+  }
+  
+  Map.prototype.updatePosition = function() {
+    this.camera.position.x = this.distance * Math.sin(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);
+    this.camera.position.y = this.distance * Math.sin(this.phi * Math.PI / 360);
+    this.camera.position.z = this.distance * Math.cos(this.theta * Math.PI / 360) * Math.cos(this.phi * Math.PI / 360);
+    this.camera.lookAt(this.scene.position);
+    this.camera.updateMatrix();
+  };
+  
+  Map.prototype.update = function() {
+    this.renderer.render(this.scene, this.camera);
+  };
+  
+  return Map;
+}();
\ No newline at end of file