formatting the code, removing unnecessary imports and URL patterns correction
authorSeshu-Kumar-M <seshu.kumar.m@huawei.com>
Fri, 23 Sep 2016 13:50:10 +0000 (21:50 +0800)
committerSeshu-Kumar-M <seshu.kumar.m@huawei.com>
Fri, 23 Sep 2016 13:50:10 +0000 (21:50 +0800)
Change-Id: If3e556b40dfd722727156f70975eb93b94d9c088
Signed-off-by: Seshu-Kumar-M <seshu.kumar.m@huawei.com>
21 files changed:
openo-portal/portal-lifecyclemgr/pom.xml
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/css/RMain.css
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/css/VMMain.css
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/gsolcmmain.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/brs.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/gsolcm.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/rest.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/tmNodesController.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/tmTopoController.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/topo/Edge.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/topo/Node.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/topo/Topology.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/topo/sigma/sigma.require.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/underlay.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/js/vpn.js
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/lcm_detail_nfvo_nodesinfo.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/lcm_detail_nfvo_topology.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/overlayvpn.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/overlayvpn_topo.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/sdnovpn.html
openo-portal/portal-lifecyclemgr/src/main/webapp/lifecyclemgr/underlayvpn.html

index 853fe11..897234c 100644 (file)
     limitations under the License.
 
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <parent>
-    <groupId>org.openo.gso.gui</groupId>
-    <artifactId>openo-portal</artifactId>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.openo.gso.gui</groupId>
+        <artifactId>openo-portal</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>portal-lifecyclemgr</artifactId>
     <version>1.0.0-SNAPSHOT</version>
-  </parent>
-  
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>portal-lifecyclemgr</artifactId>
-  <version>1.0.0-SNAPSHOT</version>
-  <packaging>war</packaging>
-    
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-war-plugin</artifactId>
-        <configuration>
-          <failOnMissingWebXml>false</failOnMissingWebXml>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  
+    <packaging>pom</packaging>
+
+   <!-- <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build> -->
+
 </project>
index 1b8488a..0a74032 100644 (file)
  * limitations under the License.\r
  */\r
 \r
-\r
 #iemp_layout_container {\r
-  padding: 0px;\r
-  margin: 1px auto;\r
-  width: 100%;\r
-  height: 100%;\r
+    padding: 0px;\r
+    margin: 1px auto;\r
+    width: 100%;\r
+    height: 100%;\r
 }\r
+\r
 #iemp_layout_container .three-cols-layout {\r
-  width: 100%;\r
-  height: 100%;\r
-  border-collapse: collapse;\r
-  margin-left: 0px;\r
-  margin-top: 0px;\r
-  margin-right: 0px;\r
-  margin-bottom: 0px;\r
+    width: 100%;\r
+    height: 100%;\r
+    border-collapse: collapse;\r
+    margin-left: 0px;\r
+    margin-top: 0px;\r
+    margin-right: 0px;\r
+    margin-bottom: 0px;\r
 }\r
+\r
 #iemp_layout_container .three-cols-layout {\r
-  width: 100%;\r
-  height: 100%;\r
-  border-collapse: collapse;\r
-  margin-left: 0px;\r
-  margin-top: 0px;\r
-  margin-right: 0px;\r
-  margin-bottom: 0px;\r
+    width: 100%;\r
+    height: 100%;\r
+    border-collapse: collapse;\r
+    margin-left: 0px;\r
+    margin-top: 0px;\r
+    margin-right: 0px;\r
+    margin-bottom: 0px;\r
 }\r
+\r
 #iemp_layout_container .three-cols-column.three-cols-left {\r
-  width: 215px;\r
-  background-color: #f5f5f5;\r
+    width: 215px;\r
+    background-color: #f5f5f5;\r
 }\r
+\r
 .accordion_parent {\r
-  position: relative;\r
-  width: 220px;\r
-  background-color: #f5f5f5;\r
+    position: relative;\r
+    width: 220px;\r
+    background-color: #f5f5f5;\r
 }\r
+\r
 .openo-accordion-resizable-handle {\r
-  z-index: 1!important;\r
-  cursor: e-resize;\r
-  width: 7px;\r
-  right: -5px;\r
-  top: 0;\r
-  height: 100%;\r
-  position: absolute;\r
-  font-size: .1px;\r
-  display: block;\r
+    z-index: 1 !important;\r
+    cursor: e-resize;\r
+    width: 7px;\r
+    right: -5px;\r
+    top: 0;\r
+    height: 100%;\r
+    position: absolute;\r
+    font-size: .1px;\r
+    display: block;\r
 }\r
+\r
 .openoAccordian_accordionmenu {\r
-  width: 100%;\r
-  margin: 0;\r
-  padding: 0;\r
-  list-style-type: none;\r
-  line-height: 17px;\r
+    width: 100%;\r
+    margin: 0;\r
+    padding: 0;\r
+    list-style-type: none;\r
+    line-height: 17px;\r
 }\r
+\r
 .openoAccordian_accordionmenu li {\r
-  min-width: 75px;\r
-  margin: 0;\r
-  padding: 0;\r
-  list-style-type: none;\r
-  color: #000;\r
-  clear: both;\r
+    min-width: 75px;\r
+    margin: 0;\r
+    padding: 0;\r
+    list-style-type: none;\r
+    color: #000;\r
+    clear: both;\r
 }\r
+\r
 .openo_accordion_ui-icon-collapse, .openo_accordion_ui-icon-expand {\r
-  display: block;\r
-  float: left;\r
-  margin-bottom: -1px;\r
-  border-bottom: 1px solid #e5e5e5;\r
-  cursor: pointer;\r
-  width: 13px;\r
-  padding-top: 26px;\r
+    display: block;\r
+    float: left;\r
+    margin-bottom: -1px;\r
+    border-bottom: 1px solid #e5e5e5;\r
+    cursor: pointer;\r
+    width: 13px;\r
+    padding-top: 26px;\r
 }\r
+\r
 .openo_accordion_ui-icon-expand {\r
-  background: url(../images/collapse_arrow.png) right 20px no-repeat;\r
-  margin-top: 8px;\r
+    background: url(../images/collapse_arrow.png) right 20px no-repeat;\r
+    margin-top: 8px;\r
 }\r
-.openo_accordion_ui-icon-expand.current{\r
-  background: url(../images/expand_arrow.png) right 20px no-repeat;\r
+\r
+.openo_accordion_ui-icon-expand.current {\r
+    background: url(../images/expand_arrow.png) right 20px no-repeat;\r
 }\r
+\r
 .openoAccordian_showHideArrow_hide, .openoAccordian_showHideArrow_show {\r
-  display: block;\r
-  position: absolute;\r
-  right: 0;\r
-  top: 4px;\r
-  width: 18px;\r
-  height: 41px;\r
-  cursor: pointer;\r
-  background-color: #f5f5f5;\r
+    display: block;\r
+    position: absolute;\r
+    right: 0;\r
+    top: 4px;\r
+    width: 18px;\r
+    height: 41px;\r
+    cursor: pointer;\r
+    background-color: #f5f5f5;\r
 }\r
+\r
 .openoAccordian_showHideArrow_hide {\r
-  background-image: url(../images/openo.png);\r
-  background-position: -7px 0!important;\r
-  border-collapse: separate;\r
-  /*box-shadow: inset -1px 0 0 #e5e5e5;*/\r
+    background-image: url(../images/openo.png);\r
+    background-position: -7px 0 !important;\r
+    border-collapse: separate;\r
+    /*box-shadow: inset -1px 0 0 #e5e5e5;*/\r
 }\r
+\r
 a.header.opened, a.header.closed {\r
-  font-size: 16px;\r
-  padding-top: 24px;\r
-  padding-bottom: 25px;\r
-  color: #999999;\r
+    font-size: 16px;\r
+    padding-top: 24px;\r
+    padding-bottom: 25px;\r
+    color: #999999;\r
 }\r
+\r
 .openoAccordian_accordionmenu .closed, .openoAccordian_accordionmenu .opened {\r
-  padding-right: 10px;\r
-  background-position: 98% 50%;\r
-  background-repeat: no-repeat;\r
+    padding-right: 10px;\r
+    background-position: 98% 50%;\r
+    background-repeat: no-repeat;\r
 }\r
+\r
 .openoAccordian_accordionmenu li a {\r
-  padding: 11px 10px 12px;\r
-  color: #333333;\r
-  margin-right: 1px;\r
-  margin-top: -1px;\r
-  text-align: left!important;\r
-  font-family: "Microsoft Yahei",SimSun,Arial,Tahoma;\r
-  font-size: 14px;\r
-  text-overflow: ellipsis;\r
-  white-space: nowrap;\r
-  overflow: hidden;\r
-  border-top: 1px solid #e5e5e5;\r
-  border-bottom: 1px solid #e5e5e5;\r
-  /*height: 19px;*/\r
+    padding: 11px 10px 12px;\r
+    color: #333333;\r
+    margin-right: 1px;\r
+    margin-top: -1px;\r
+    text-align: left !important;\r
+    font-family: "Microsoft Yahei", SimSun, Arial, Tahoma;\r
+    font-size: 14px;\r
+    text-overflow: ellipsis;\r
+    white-space: nowrap;\r
+    overflow: hidden;\r
+    border-top: 1px solid #e5e5e5;\r
+    border-bottom: 1px solid #e5e5e5;\r
+    /*height: 19px;*/\r
 }\r
+\r
 .openoAccordian_accordionmenu ul {\r
-  margin: 0;\r
-  padding: 0;\r
-  overflow: hidden;\r
+    margin: 0;\r
+    padding: 0;\r
+    overflow: hidden;\r
 }\r
+\r
 .openoAccordian_accordionmenu a {\r
-  display: block;\r
-  text-decoration: none;\r
+    display: block;\r
+    text-decoration: none;\r
 }\r
+\r
 a {\r
-  color: #428bca;\r
-  text-decoration: none;\r
-  background: 0 0;\r
+    color: #428bca;\r
+    text-decoration: none;\r
+    background: 0 0;\r
 }\r
-.bar{\r
+\r
+.bar {\r
     height: 834px;\r
     width: 18px;\r
     background: #f8f8f8;\r
     display: none;\r
 }\r
-.bar span{\r
+\r
+.bar span {\r
     width: 13px;\r
     height: 34px;\r
     background-image: url(../images/openo.png);\r
-  background-position: -39px 0!important;\r
-  display: block;\r
-  /*margin-top: -430px;*/\r
+    background-position: -39px 0 !important;\r
+    display: block;\r
+    /*margin-top: -430px;*/\r
 }\r
-#accordionmenuid_ul_0_0_brAppTopMenuID_UL li{\r
+\r
+#accordionmenuid_ul_0_0_brAppTopMenuID_UL li {\r
     cursor: pointer;\r
 }\r
-#puer_base_openo{\r
+\r
+#puer_base_openo {\r
     border: 1px solid #ddd;\r
 }\r
+\r
 .openo_accordion_selected {\r
-  margin-left: 0;\r
-  margin-right: 0;\r
-  background: #fafafa;\r
-  border-left: 3px solid #4ac9ff!important;\r
-  box-shadow: none;\r
-  position: relative;\r
+    margin-left: 0;\r
+    margin-right: 0;\r
+    background: #fafafa;\r
+    border-left: 3px solid #4ac9ff !important;\r
+    box-shadow: none;\r
+    position: relative;\r
 }\r
-a:hover{\r
-    color: #4ac9ff!important;\r
+\r
+a:hover {\r
+    color: #4ac9ff !important;\r
 }\r
+\r
 .openoAccordian_accordionmenu li.openo_accordion_selected a {\r
-  position: relative;\r
-  left: -3px;\r
-  color: #009ae7;\r
+    position: relative;\r
+    left: -3px;\r
+    color: #009ae7;\r
 }\r
+\r
 .openo-accordion-resizable-handle {\r
-  z-index: 1!important;\r
-  cursor: e-resize;\r
-  width: 7px;\r
-  right: -5px;\r
-  top: 0;\r
-  height: 100%;\r
-  position: absolute;\r
-  font-size: .1px;\r
-  display: block;\r
+    z-index: 1 !important;\r
+    cursor: e-resize;\r
+    width: 7px;\r
+    right: -5px;\r
+    top: 0;\r
+    height: 100%;\r
+    position: absolute;\r
+    font-size: .1px;\r
+    display: block;\r
 }\r
+\r
 #iframeContainer iframe {\r
-  width: 100%;\r
-  height: 100%;\r
-  border: 0;\r
+    width: 100%;\r
+    height: 100%;\r
+    border: 0;\r
 }\r
+\r
 #accordionContent, #iframeContainer {\r
-  margin: 0;\r
-  padding: 0;\r
-  border: 0;\r
-  width: 100%;\r
-  height: 100%;\r
+    margin: 0;\r
+    padding: 0;\r
+    border: 0;\r
+    width: 100%;\r
+    height: 100%;\r
 }\r
+\r
 .openoAccordian_showHideArrow_show {\r
-  background-image: url(../images/openo.png);\r
-  background-position: -39px 0!important;\r
-  box-shadow: inset 1px 0 0 #e5e5e5,inset -1px 0 0 #e5e5e5;\r
+    background-image: url(../images/openo.png);\r
+    background-position: -39px 0 !important;\r
+    box-shadow: inset 1px 0 0 #e5e5e5, inset -1px 0 0 #e5e5e5;\r
 }
\ No newline at end of file
index e625e90..a1c0866 100644 (file)
  * limitations under the License.\r
  */\r
 \r
-\r
-body{\r
+body {\r
     font-family: '微软雅黑';\r
     font-size: 12px;\r
     color: #333;\r
     background: #fafafa;\r
 }\r
-button{\r
+\r
+button {\r
     outline: none;\r
 }\r
-ul,li{\r
+\r
+ul, li {\r
     list-style: none;\r
-    padding:0;\r
-    margin:0;\r
+    padding: 0;\r
+    margin: 0;\r
 }\r
-.titleFont{\r
+\r
+.titleFont {\r
     font-size: 16px;\r
 }\r
-.separator-line{\r
+\r
+.separator-line {\r
     height: 1px;\r
     width: 100%;\r
-    border:1px solid #ddd;\r
+    border: 1px solid #ddd;\r
     margin: 6px 0 15px 0;\r
 }\r
-.uploadBtn{\r
+\r
+.uploadBtn {\r
     overflow: hidden;\r
 }\r
+\r
 .creat-btn {\r
-       padding: 0 14px;\r
-       height: 24px;\r
+    padding: 0 14px;\r
+    height: 24px;\r
     float: left;\r
     cursor: pointer;\r
     text-decoration: none;\r
     outline: 0;\r
     border: 1px solid #d3d3d3;\r
     text-align: center;\r
-    box-shadow: 0 1px 1px rgba(0,0,0,.05);\r
+    box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\r
     background: #fafafa;\r
-    background: -moz-linear-gradient(top,#fff,#fafafa);\r
-    background: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#fafafa));\r
-    background: -webkit-linear-gradient(top,#fff,#fafafa);\r
-    background: linear-gradient(to bottom,#fff,#fafafa);\r
+    background: -moz-linear-gradient(top, #fff, #fafafa);\r
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(100%, #fafafa));\r
+    background: -webkit-linear-gradient(top, #fff, #fafafa);\r
+    background: linear-gradient(to bottom, #fff, #fafafa);\r
     border-radius: 6px;\r
     background: #fff url(../images/add.png) no-repeat 5px center;\r
     padding-left: 20px;\r
 }\r
+\r
 .creat-btn:hover {\r
-       color: #009ae7; \r
-       border: 1px solid #4AC9FF\r
+    color: #009ae7;\r
+    border: 1px solid #4AC9FF\r
 }\r
+\r
 .creat-btn:active {\r
-       color: #000;    \r
-       border: 1px solid #4AC9FF\r
+    color: #000;\r
+    border: 1px solid #4AC9FF\r
 }\r
+\r
 /*.creat-btn{\r
     background: #fff url(../image/add.png) no-repeat 5px center;\r
     border: 1px solid #ddd;\r
@@ -77,110 +85,130 @@ ul,li{
     color: #fff;\r
     border:1px solid #428bca;\r
 }*/\r
-.search{\r
+.search {\r
     width: 310px;\r
     height: 30px;\r
-    float:right;\r
+    float: right;\r
 }\r
-.search-text{\r
+\r
+.search-text {\r
     width: 250px;\r
     float: left;\r
     margin-right: 6px;\r
 }\r
-.search-btn{\r
+\r
+.search-btn {\r
     height: 30px;\r
     background: #fff;\r
     border: 1px solid #ddd;\r
     float: left;\r
 }\r
-#ict_virtualApplication_table_div{\r
+\r
+#ict_virtualApplication_table_div {\r
     margin-top: 15px;\r
 }\r
-.table>thead>tr.active>th{\r
-    border: 1px solid #ddd!important;\r
+\r
+.table > thead > tr.active > th {\r
+    border: 1px solid #ddd !important;\r
     border-bottom: 0;\r
     background: #f0f0f0;\r
 }\r
+\r
 /*.table tbody tr:hover{\r
     background: #e6fbe0!important;\r
 }*/\r
-.table tbody tr:last-child{\r
+.table tbody tr:last-child {\r
     border-bottom: 1px solid #ddd;\r
 }\r
-.table-btn{\r
+\r
+.table-btn {\r
     border: 1px solid #ccc;\r
     border-radius: 3px;\r
 }\r
-.delete-btn{\r
+\r
+.delete-btn {\r
     background: url(../image/delete.png) no-repeat;\r
     width: 16px;\r
     height: 16px;\r
     border: none;\r
 }\r
-.detail-btn{\r
+\r
+.detail-btn {\r
     background: url(../image/openo.png) no-repeat -343px -283px;\r
     width: 16px;\r
     height: 16px;\r
     border: none;\r
 }\r
-.detail-btn.current{\r
-    background-position: -7px -314px; \r
+\r
+.detail-btn.current {\r
+    background-position: -7px -314px;\r
 }\r
-.detail{\r
+\r
+.detail {\r
     height: 200px;\r
     border: 1px solid #ddd;\r
     margin-top: 60px;\r
 }\r
 \r
-.detail-top ul{\r
+.detail-top ul {\r
     height: 50px;\r
     line-height: 50px;\r
     border-bottom: 1px solid #ddd;\r
     padding-left: 0px;\r
-     background: #fafafa;\r
+    background: #fafafa;\r
 }\r
-.detail-top ul li{\r
-    float:left;\r
+\r
+.detail-top ul li {\r
+    float: left;\r
     width: 120px;\r
     text-align: center;\r
     border-right: 1px solid #ddd;\r
     cursor: pointer;\r
 }\r
-.detail-top ul li.current{\r
+\r
+.detail-top ul li.current {\r
     background: #fff;\r
 }\r
-.vmapp-margin{\r
+\r
+.vmapp-margin {\r
     margin-bottom: 10px;\r
 }\r
-.control-label .required{\r
+\r
+.control-label .required {\r
     color: #e02222;\r
     font-size: 12px;\r
     padding-left: 2px;\r
 }\r
-.form-group .control-label{\r
+\r
+.form-group .control-label {\r
     font-size: 12px;\r
     font-weight: 400;\r
 }\r
-legend{\r
+\r
+legend {\r
     font-size: 12px;\r
     font-weight: bold;\r
 }\r
-.pageGro{\r
+\r
+.pageGro {\r
     width: 250px;\r
     float: right;\r
 }\r
-.pageUp,.pageDown,.pageList,.pageList li{\r
+\r
+.pageUp, .pageDown, .pageList, .pageList li {\r
     float: left;\r
     cursor: pointer;\r
 }\r
-.pageUp,.pageDown{\r
+\r
+.pageUp, .pageDown {\r
     width: 60px;\r
     height: 30px;\r
     border: 1px solid #ddd;\r
     text-align: center;\r
     line-height: 30px;\r
 }\r
-.pageList li{\r
+\r
+.pageList li {\r
     width: 30px;\r
     height: 30px;\r
     border: 1px solid #ddd;\r
@@ -188,466 +216,543 @@ legend{
     line-height: 30px;\r
     border-left: none;\r
 }\r
-.pageList li.active{\r
+\r
+.pageList li.active {\r
     background: #428bca;\r
     color: #fff;\r
     border-color: #428bca;\r
 }\r
-.pageDown{\r
+\r
+.pageDown {\r
     border-left: none;\r
 }\r
-.headerLinkP{\r
+\r
+.headerLinkP {\r
     padding-top: 17px;\r
 }\r
-.headerLinkP span{\r
+\r
+.headerLinkP span {\r
     font-size: 12px;\r
     color: #666;\r
-    font-weight: normal!important;\r
+    font-weight: normal !important;\r
 }\r
-label{\r
-    font-weight: normal!important;\r
+\r
+label {\r
+    font-weight: normal !important;\r
 }\r
+\r
 table.userform tbody tr td {\r
-  display: table-cell;\r
-  padding-right: 10px;\r
-  padding-top: 10px;\r
-  font-size: 12px;\r
-  color: #333;\r
+    display: table-cell;\r
+    padding-right: 10px;\r
+    padding-top: 10px;\r
+    font-size: 12px;\r
+    color: #333;\r
 }\r
-.table th,.table td{\r
-    padding-top: 3px!important;\r
-    padding-bottom: 3px!important;\r
+\r
+.table th, .table td {\r
+    padding-top: 3px !important;\r
+    padding-bottom: 3px !important;\r
 }\r
+\r
 .openoBrowseButton_element {\r
-  display: table;\r
+    display: table;\r
 }\r
+\r
 .openo {\r
-  font-family: "Microsoft Yahei",SimSun,Arial,Tahoma;\r
-  font-size: 12px;\r
-  color: #000;\r
+    font-family: "Microsoft Yahei", SimSun, Arial, Tahoma;\r
+    font-size: 12px;\r
+    color: #000;\r
 }\r
+\r
 .openoBrowseButton_input {\r
-  width: 198px;\r
-  position: relative;\r
-  border: 1px solid #c3c3c3!important;\r
-  height: 26px;\r
-  background-color: #f3f3f3;\r
-  border-radius: 4px 0 0 4px;\r
-  border-right: none;\r
-  padding: 0;\r
+    width: 198px;\r
+    position: relative;\r
+    border: 1px solid #c3c3c3 !important;\r
+    height: 26px;\r
+    background-color: #f3f3f3;\r
+    border-radius: 4px 0 0 4px;\r
+    border-right: none;\r
+    padding: 0;\r
 }\r
+\r
 .buttonClassDefault, .buttonClassDefault:active {\r
-  cursor: pointer;\r
-  background-image: url(../images/openo.png);\r
-  background-position: -154px -7px!important;\r
+    cursor: pointer;\r
+    background-image: url(../images/openo.png);\r
+    background-position: -154px -7px !important;\r
 }\r
+\r
 .openoBrowseButton_button {\r
-  width: 27px;\r
-  border: 0;\r
-  float: right;\r
-  position: relative;\r
-  height: 26px;\r
-  right: 0;\r
-  top: 0;\r
-  border-radius: 0 4px 4px 0;\r
-  border-right: 1px solid #c3c3c3;\r
-  border-left: none;\r
+    width: 27px;\r
+    border: 0;\r
+    float: right;\r
+    position: relative;\r
+    height: 26px;\r
+    right: 0;\r
+    top: 0;\r
+    border-radius: 0 4px 4px 0;\r
+    border-right: 1px solid #c3c3c3;\r
+    border-left: none;\r
 }\r
+\r
 .openo .openo-input, .openo.openo-input {\r
-  outline: 0;\r
-  border: 1px solid #c3c3c3;\r
-  box-shadow: 1px 1px #f6f6f6 inset;\r
-  background-color: #fff;\r
-  height: 26px;\r
+    outline: 0;\r
+    border: 1px solid #c3c3c3;\r
+    box-shadow: 1px 1px #f6f6f6 inset;\r
+    background-color: #fff;\r
+    height: 26px;\r
 }\r
+\r
 .openoInput_openoDefaultText {\r
-  padding: 0 0 0 6px;\r
-  border-radius: 4px;\r
-  color: #000;\r
-  display: inline-block;\r
-  outline: 0;\r
-  box-shadow: 1px 1px #f6f6f6 inset;\r
-  font-size: 12px;\r
-  background: #fff;\r
+    padding: 0 0 0 6px;\r
+    border-radius: 4px;\r
+    color: #000;\r
+    display: inline-block;\r
+    outline: 0;\r
+    box-shadow: 1px 1px #f6f6f6 inset;\r
+    font-size: 12px;\r
+    background: #fff;\r
 }\r
+\r
 div.openo-select {\r
-  border: 1px solid #c3c3c3;\r
-  border-radius: 4px;\r
-  background: url(../images/arrow-down-enable.png) right no-repeat #fff;\r
-  line-height: 24px;\r
-  padding-left: 3px;\r
-  display: block;\r
-}\r
-div.openo-select>input.openo-select-input {\r
-  border: none;\r
-  outline: 0;\r
-  line-height: 21px;\r
-  height: 21px;\r
-  padding-left: 3px;\r
-  border-right: solid 1px #c3c3c3;\r
+    border: 1px solid #c3c3c3;\r
+    border-radius: 4px;\r
+    background: url(../images/arrow-down-enable.png) right no-repeat #fff;\r
+    line-height: 24px;\r
+    padding-left: 3px;\r
+    display: block;\r
 }\r
+\r
+div.openo-select > input.openo-select-input {\r
+    border: none;\r
+    outline: 0;\r
+    line-height: 21px;\r
+    height: 21px;\r
+    padding-left: 3px;\r
+    border-right: solid 1px #c3c3c3;\r
+}\r
+\r
 .openo .openo-ellipsis, .openo.openo-ellipsis {\r
-  overflow: hidden;\r
-  white-space: nowrap;\r
-  text-overflow: ellipsis;\r
+    overflow: hidden;\r
+    white-space: nowrap;\r
+    text-overflow: ellipsis;\r
 }\r
+\r
 a.openoButton_buttonClass, a.openoButton_buttonDisableClass, div.openoButton_buttonClass, div.openoButton_buttonDisableClass {\r
-  height: 26px;\r
-  float: left;\r
-  cursor: pointer;\r
-  text-decoration: none;\r
-  outline: 0;\r
-  border: 1px solid #d3d3d3;\r
-  text-align: center;\r
-  box-shadow: 0 1px 1px rgba(0,0,0,.05);\r
-  background: #fafafa;\r
-  background: -moz-linear-gradient(top,#fff,#fafafa);\r
-  background: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#fafafa));\r
-  background: -webkit-linear-gradient(top,#fff,#fafafa);\r
-  background: linear-gradient(to bottom,#fff,#fafafa);\r
-  border-radius: 6px;\r
-}\r
-.openoButton_buttonInnerClass{\r
-      padding: 0 19px;\r
-      border-radius: 6px;\r
+    height: 26px;\r
+    float: left;\r
+    cursor: pointer;\r
+    text-decoration: none;\r
+    outline: 0;\r
+    border: 1px solid #d3d3d3;\r
+    text-align: center;\r
+    box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\r
+    background: #fafafa;\r
+    background: -moz-linear-gradient(top, #fff, #fafafa);\r
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(100%, #fafafa));\r
+    background: -webkit-linear-gradient(top, #fff, #fafafa);\r
+    background: linear-gradient(to bottom, #fff, #fafafa);\r
+    border-radius: 6px;\r
+}\r
+\r
+.openoButton_buttonInnerClass {\r
+    padding: 0 19px;\r
+    border-radius: 6px;\r
 }\r
+\r
 .openoButton_buttonCenterText {\r
-  color: #000;\r
-  line-height: 24px;\r
-  white-space: nowrap;\r
-  width: auto!important;\r
+    color: #000;\r
+    line-height: 24px;\r
+    white-space: nowrap;\r
+    width: auto !important;\r
 }\r
+\r
 .userHeader {\r
-  clear: left;\r
-  overflow: hidden;\r
-  margin-bottom: 10px;\r
-  padding: 10px 10px 0px 0px;\r
+    clear: left;\r
+    overflow: hidden;\r
+    margin-bottom: 10px;\r
+    padding: 10px 10px 0px 0px;\r
 }\r
+\r
 .openoButton_buttonGroupClass {\r
-  display: inline;\r
+    display: inline;\r
 }\r
+\r
 .openoButton_buttonGroupClass div.openoButton_buttonClass_parent:first-child {\r
-  margin-left: 0;\r
+    margin-left: 0;\r
 }\r
+\r
 .openoButton_buttonLeftImg {\r
-  margin-right: 5px;\r
+    margin-right: 5px;\r
 }\r
+\r
 .openoButton_buttonLeftImg, .openoButton_buttonRightImg {\r
-  display: inline-block;\r
-  vertical-align: top;\r
-  width: 16px;\r
-  height: 16px;\r
-  margin-top: 4px;\r
+    display: inline-block;\r
+    vertical-align: top;\r
+    width: 16px;\r
+    height: 16px;\r
+    margin-top: 4px;\r
 }\r
+\r
 .openo-table-pagination-wrapper {\r
-  height: 37px;\r
+    height: 37px;\r
 }\r
+\r
 .openo-pagination {\r
-  display: block;\r
-  float: left;\r
-  overflow: hidden;\r
-  padding: 5px 0 0;\r
-  margin-top: 8px;\r
+    display: block;\r
+    float: left;\r
+    overflow: hidden;\r
+    padding: 5px 0 0;\r
+    margin-top: 8px;\r
 }\r
+\r
 .openoPagination_openoPaginationLengthOptions:not(msie8) {\r
-  line-height: 24px;\r
+    line-height: 24px;\r
 }\r
+\r
 .openoPagination_openoPaginationLengthOptions {\r
-  white-space: normal;\r
-  height: 24px;\r
-  float: left;\r
-  outline: 0;\r
-  line-height: 20px;\r
-  margin: 0 5px;\r
+    white-space: normal;\r
+    height: 24px;\r
+    float: left;\r
+    outline: 0;\r
+    line-height: 20px;\r
+    margin: 0 5px;\r
 }\r
+\r
 .openo-pagination-select {\r
-  height: 26px;\r
-  line-height: 22px;\r
-  text-align: center;\r
-  margin-right: -2px;\r
-  border: 1px solid #e0e0e0;\r
-  border-radius: 5px 0 0 5px;\r
-  padding: 1px;\r
+    height: 26px;\r
+    line-height: 22px;\r
+    text-align: center;\r
+    margin-right: -2px;\r
+    border: 1px solid #e0e0e0;\r
+    border-radius: 5px 0 0 5px;\r
+    padding: 1px;\r
 }\r
+\r
 .openoPagination_openoPaginationLengthOptions span {\r
-  background-color: #fff!important;\r
+    background-color: #fff !important;\r
 }\r
+\r
 .openo-pagination-theme a, .openo-pagination-theme span {\r
-  float: left;\r
-  color: #666;\r
-  font: 12px Lucida Grande,Verdana,Arial,Helvetica,sans-serif;\r
-  line-height: 24px;\r
-  font-weight: 400;\r
-  text-align: center;\r
-  border: 1px solid #e0e0e0;\r
-  text-decoration: none!important;\r
-  padding: 0 7px;\r
-  border-radius: 3px;\r
-  background: #fff;\r
+    float: left;\r
+    color: #666;\r
+    font: 12px Lucida Grande, Verdana, Arial, Helvetica, sans-serif;\r
+    line-height: 24px;\r
+    font-weight: 400;\r
+    text-align: center;\r
+    border: 1px solid #e0e0e0;\r
+    text-decoration: none !important;\r
+    padding: 0 7px;\r
+    border-radius: 3px;\r
+    background: #fff;\r
 }\r
+\r
 .openo-pagination-selectspan {\r
-  background: url(../images/ideo_default_select.png) left no-repeat!important;\r
-  float: right!important;\r
-  width: 26px;\r
-  height: 26px;\r
-  cursor: pointer;\r
+    background: url(../images/ideo_default_select.png) left no-repeat !important;\r
+    float: right !important;\r
+    width: 26px;\r
+    height: 26px;\r
+    cursor: pointer;\r
 }\r
+\r
 .openo-pagination-theme label {\r
-  padding-top: 6px;\r
-  vertical-align: middle;\r
-  margin-right: 20px;\r
-  margin-top: -1px;\r
-  float: left;\r
-  display: inline-block;\r
-  height: 20px;\r
-  font: 12px Lucida Grande,Verdana,Arial,Helvetica,sans-serif;\r
+    padding-top: 6px;\r
+    vertical-align: middle;\r
+    margin-right: 20px;\r
+    margin-top: -1px;\r
+    float: left;\r
+    display: inline-block;\r
+    height: 20px;\r
+    font: 12px Lucida Grande, Verdana, Arial, Helvetica, sans-serif;\r
 }\r
+\r
 .openo-pagination li, .openo-pagination ul {\r
-  list-style: none;\r
-  padding: 0;\r
-  margin: 0;\r
-  float: left;\r
+    list-style: none;\r
+    padding: 0;\r
+    margin: 0;\r
+    float: left;\r
 }\r
+\r
 dd, dl, dt, li {\r
-  color: #000;\r
+    color: #000;\r
 }\r
+\r
 .openo-pagination-theme a, .openo-pagination-theme span.current {\r
-  margin: 0 5px 0 0;\r
+    margin: 0 5px 0 0;\r
 }\r
+\r
 .openo .openo-disabled, .openo.openo-disabled {\r
-  border-color: #c3c3c3!important;\r
-  color: #666!important;\r
-  opacity: .3;\r
-  filter: alpha(opacity=30);\r
+    border-color: #c3c3c3 !important;\r
+    color: #666 !important;\r
+    opacity: .3;\r
+    filter: alpha(opacity=30);\r
 }\r
+\r
 .openo-pagination-theme .prev {\r
-  background: 0 0;\r
-  float: left;\r
+    background: 0 0;\r
+    float: left;\r
 }\r
+\r
 .openo-pagination-theme .current {\r
-  text-decoration: none!important;\r
-  float: left;\r
-  padding-left: 6px;\r
-  height: 24px;\r
-  color: #fff;\r
-  display: inline;\r
-  border-color: #00adf5;\r
-  background: #4ad2ff;\r
+    text-decoration: none !important;\r
+    float: left;\r
+    padding-left: 6px;\r
+    height: 24px;\r
+    color: #fff;\r
+    display: inline;\r
+    border-color: #00adf5;\r
+    background: #4ad2ff;\r
 }\r
+\r
 .openo-pagination-theme a, .openo-pagination-theme span {\r
-  float: left;\r
-  color: #666;\r
-  font: 12px Lucida Grande,Verdana,Arial,Helvetica,sans-serif;\r
-  line-height: 24px;\r
-  font-weight: 400;\r
-  text-align: center;\r
-  border: 1px solid #e0e0e0;\r
-  text-decoration: none!important;\r
-  padding: 0 7px;\r
-  border-radius: 3px;\r
-  background: #fff;\r
+    float: left;\r
+    color: #666;\r
+    font: 12px Lucida Grande, Verdana, Arial, Helvetica, sans-serif;\r
+    line-height: 24px;\r
+    font-weight: 400;\r
+    text-align: center;\r
+    border: 1px solid #e0e0e0;\r
+    text-decoration: none !important;\r
+    padding: 0 7px;\r
+    border-radius: 3px;\r
+    background: #fff;\r
 }\r
+\r
 .openo-pagination-theme .prev.openo-disabled:before {\r
-  background: url(../images/page_left_disabled.png) 50% 45% no-repeat;\r
+    background: url(../images/page_left_disabled.png) 50% 45% no-repeat;\r
 }\r
+\r
 .openo-pagination-theme .prev.openo-disabled:before {\r
-  background: url(../images/page_left_disabled.png) 50% 45% no-repeat;\r
+    background: url(../images/page_left_disabled.png) 50% 45% no-repeat;\r
 }\r
+\r
 .openo-pagination-theme .prev:before {\r
-  background: url(../images/page_l.png) 50% 45% no-repeat;\r
+    background: url(../images/page_l.png) 50% 45% no-repeat;\r
 }\r
+\r
 .openo-pagination-theme .next:after, .openo-pagination-theme .prev:before {\r
-  display: inline-block;\r
-  content: "";\r
-  vertical-align: middle;\r
-  width: 10px;\r
-  height: 24px;\r
+    display: inline-block;\r
+    content: "";\r
+    vertical-align: middle;\r
+    width: 10px;\r
+    height: 24px;\r
 }\r
+\r
 .openo-pagination-theme .prev:before {\r
-  background: url(../images/page_l.png) 50% 45% no-repeat;\r
+    background: url(../images/page_l.png) 50% 45% no-repeat;\r
 }\r
+\r
 .openo-pagination-theme .next:after, .openo-pagination-theme .prev:before {\r
-  display: inline-block;\r
-  content: "";\r
-  vertical-align: middle;\r
-  width: 10px;\r
-  height: 24px;\r
+    display: inline-block;\r
+    content: "";\r
+    vertical-align: middle;\r
+    width: 10px;\r
+    height: 24px;\r
 }\r
+\r
 pagination ul {\r
-  list-style: none;\r
-  padding: 0;\r
-  margin: 0;\r
-  float: left;\r
+    list-style: none;\r
+    padding: 0;\r
+    margin: 0;\r
+    float: left;\r
 }\r
+\r
 .openo-pagination li, .openo-pagination ul {\r
-  list-style: none;\r
-  padding: 0;\r
-  margin: 0;\r
-  float: left;\r
+    list-style: none;\r
+    padding: 0;\r
+    margin: 0;\r
+    float: left;\r
 }\r
+\r
 .openoPagination_gototext {\r
-  background: #FFF;\r
-  outline: 0;\r
-  width: 29px;\r
-  float: left;\r
-  height: 26px;\r
-  line-height: 24px;\r
-  border-radius: 4px;\r
-  border: 1px solid #c3c3c3;\r
-  padding: 0 0 0 5px;\r
-  margin: 0;\r
-  color: #666;\r
-  min-width: 50px;\r
+    background: #FFF;\r
+    outline: 0;\r
+    width: 29px;\r
+    float: left;\r
+    height: 26px;\r
+    line-height: 24px;\r
+    border-radius: 4px;\r
+    border: 1px solid #c3c3c3;\r
+    padding: 0 0 0 5px;\r
+    margin: 0;\r
+    color: #666;\r
+    min-width: 50px;\r
 }\r
+\r
 .openoPagination_gotoimage {\r
-  width: 29px;\r
-  height: 26px;\r
-  line-height: 26px;\r
-  background-color: #FFF;\r
-  background-image: url(/portal/themes/default/components/openo/images/openo.png);\r
-  padding-left: 21px;\r
-  float: left;\r
-  margin-left: 5px;\r
-  border: 1px solid #e0e0e0;\r
-  border-radius: 4px;\r
-  box-sizing: border-box;\r
-  -moz-box-sizing: border-box;\r
-  background-position: -184px -181px!important;\r
+    width: 29px;\r
+    height: 26px;\r
+    line-height: 26px;\r
+    background-color: #FFF;\r
+    background-image: url(/portal/themes/default/components/openo/images/openo.png);\r
+    padding-left: 21px;\r
+    float: left;\r
+    margin-left: 5px;\r
+    border: 1px solid #e0e0e0;\r
+    border-radius: 4px;\r
+    box-sizing: border-box;\r
+    -moz-box-sizing: border-box;\r
+    background-position: -184px -181px !important;\r
 }\r
+\r
 .openo-pagination-theme .ellipse {\r
-  float: left;\r
-  margin-left: -8px;\r
-  margin-right: -4px;\r
-  background: 0 0;\r
-  border: none;\r
-  border-radius: 0;\r
-  box-shadow: none;\r
-  font-weight: 700;\r
-  cursor: default;\r
+    float: left;\r
+    margin-left: -8px;\r
+    margin-right: -4px;\r
+    background: 0 0;\r
+    border: none;\r
+    border-radius: 0;\r
+    box-shadow: none;\r
+    font-weight: 700;\r
+    cursor: default;\r
 }\r
+\r
 .openo.openo-disabled {\r
-  border-color: #c3c3c3!important;\r
-  color: #666!important;\r
-  opacity: .3;\r
-  filter: alpha(opacity=30);\r
+    border-color: #c3c3c3 !important;\r
+    color: #666 !important;\r
+    opacity: .3;\r
+    filter: alpha(opacity=30);\r
 }\r
+\r
 .openo-pagination-theme .prev {\r
-  background: 0 0;\r
-  float: left;\r
+    background: 0 0;\r
+    float: left;\r
 }\r
+\r
 .openo-pagination-theme .current {\r
-  text-decoration: none!important;\r
-  float: left;\r
-  padding-left: 6px;\r
-  height: 26px;\r
-  color: #fff;\r
-  display: inline;\r
-  /*border-color: #00adf5;\r
-  background: #4ad2ff;*/\r
+    text-decoration: none !important;\r
+    float: left;\r
+    padding-left: 6px;\r
+    height: 26px;\r
+    color: #fff;\r
+    display: inline;\r
+    /*border-color: #00adf5;\r
+    background: #4ad2ff;*/\r
     border: 1px solid #e0e0e0;\r
 }\r
+\r
 .openo-pagination-theme .next:after {\r
-  background: url(../images/page_r.png) 50% 45% no-repeat;\r
+    background: url(../images/page_r.png) 50% 45% no-repeat;\r
 }\r
+\r
 .openoButton_buttonGroupClass div.openoButton_buttonClass_parent, .openoButton_buttonRightImg {\r
-  margin-left: 5px;\r
+    margin-left: 5px;\r
 }\r
 \r
 html, body {\r
-  height: 99%;\r
-  width: 98%;\r
+    height: 99%;\r
+    width: 98%;\r
 }\r
+\r
 .cotentBody {\r
-  padding: 0px 20px 0px 20px;\r
+    padding: 0px 20px 0px 20px;\r
 }\r
 \r
 div.openoButton_buttonClass:hover {\r
-  border: 1px solid #4ac9ff;\r
+    border: 1px solid #4ac9ff;\r
 }\r
+\r
 div.openoButton_button_default:hover .openoButton_buttonCenterText {\r
-  color: #009ae7;\r
+    color: #009ae7;\r
 }\r
+\r
 .header_lineimg {\r
-  height: 1px;\r
-  width: 100%;\r
-  margin-top: 17px;\r
+    height: 1px;\r
+    width: 100%;\r
+    margin-top: 17px;\r
 }\r
+\r
 .openo.openo-hide {\r
-  display: none;\r
+    display: none;\r
 }\r
+\r
 div.openo-select-popup-container {\r
-  position: absolute;\r
-  border: 1px solid #4ac9ff;\r
-  border-top: none;\r
-  border-radius: 0 0 4px 4px;\r
-  max-height: 202px;\r
-  overflow-y: auto;\r
-  background-color: #fff;\r
-  z-index: 880;\r
-}\r
-div.openo-select-popup-container>div.openo-select-item {\r
-  display: block;\r
+    position: absolute;\r
+    border: 1px solid #4ac9ff;\r
+    border-top: none;\r
+    border-radius: 0 0 4px 4px;\r
+    max-height: 202px;\r
+    overflow-y: auto;\r
+    background-color: #fff;\r
+    z-index: 880;\r
+}\r
+\r
+div.openo-select-popup-container > div.openo-select-item {\r
+    display: block;\r
 }\r
+\r
 .openo .openo-ellipsis, .openo.openo-ellipsis {\r
-  overflow: hidden;\r
-  white-space: nowrap;\r
-  text-overflow: ellipsis;\r
+    overflow: hidden;\r
+    white-space: nowrap;\r
+    text-overflow: ellipsis;\r
 }\r
-div.openo-select-popup-container>div.openo-select-item>label {\r
-  padding-top: 3px;\r
-  padding-bottom: 3px;\r
-  line-height: 20px;\r
+\r
+div.openo-select-popup-container > div.openo-select-item > label {\r
+    padding-top: 3px;\r
+    padding-bottom: 3px;\r
+    line-height: 20px;\r
 }\r
+\r
 .openo .openo-ellipsis, .openo.openo-ellipsis {\r
-  overflow: hidden;\r
-  white-space: nowrap;\r
-  text-overflow: ellipsis;\r
+    overflow: hidden;\r
+    white-space: nowrap;\r
+    text-overflow: ellipsis;\r
 }\r
+\r
 .openo-select-item label {\r
-  margin-left: 4px;\r
-  margin-right: 4px;\r
-  white-space: nowrap;\r
+    margin-left: 4px;\r
+    margin-right: 4px;\r
+    white-space: nowrap;\r
 }\r
-div.openo-select-popup-container>div.openo-select-item.openo-item-selected, div.openo-select-popup-container>div.openo-select-item:hover {\r
-  background-color: #f1f1f1;\r
-  color: #008fd6;\r
+\r
+div.openo-select-popup-container > div.openo-select-item.openo-item-selected, div.openo-select-popup-container > div.openo-select-item:hover {\r
+    background-color: #f1f1f1;\r
+    color: #008fd6;\r
 }\r
+\r
 div.openo-select.openo-focus {\r
-  border: 1px solid #4ac9ff;\r
-  border-bottom-left-radius: 0;\r
-  border-bottom-right-radius: 0;\r
-  border-bottom-color: #ddd;\r
+    border: 1px solid #4ac9ff;\r
+    border-bottom-left-radius: 0;\r
+    border-bottom-right-radius: 0;\r
+    border-bottom-color: #ddd;\r
 }\r
+\r
 .openo-pagination-theme a:hover {\r
-  border-color: #4ac9ff;\r
-  cursor: pointer;\r
+    border-color: #4ac9ff;\r
+    cursor: pointer;\r
 }\r
-.SDBtn{\r
-     background: #fff; \r
-     color: #333; \r
-     border: 1px solid #ddd;\r
+\r
+.SDBtn {\r
+    background: #fff;\r
+    color: #333;\r
+    border: 1px solid #ddd;\r
 }\r
-.SDBtn:hover{\r
-    color: #009ae7;    \r
-       border: 1px solid #4AC9FF\r
+\r
+.SDBtn:hover {\r
+    color: #009ae7;\r
+    border: 1px solid #4AC9FF\r
 }\r
+\r
 table tbody tr.even:hover td, table tbody tr.odd:hover td {\r
-  background-color: #e6fbe0;\r
+    background-color: #e6fbe0;\r
 }\r
+\r
 table tr.openoTable_row_selected td {\r
-  background: #e8f8fe!important;\r
-  border-bottom: 1px solid #e8e8e8!important;\r
+    background: #e8f8fe !important;\r
+    border-bottom: 1px solid #e8e8e8 !important;\r
 }\r
-.modal-body{\r
-    padding: 0!important;\r
+\r
+.modal-body {\r
+    padding: 0 !important;\r
 }\r
-.form-control{\r
-    height: 26px!important;\r
+\r
+.form-control {\r
+    height: 26px !important;\r
 }\r
+\r
 .form-group .control-label {\r
-  margin-left: 20px;\r
+    margin-left: 20px;\r
 }\r
 \r
 .form-horizontal .control-label {\r
-  text-align: left;\r
+    text-align: left;\r
 }
\ No newline at end of file
index b878e10..507a890 100644 (file)
@@ -1,4 +1,3 @@
-<!DOCTYPE html>\r
 <!--\r
 \r
     Copyright 2016, Huawei Technologies Co., Ltd.\r
     limitations under the License.\r
 \r
 -->\r
+<!DOCTYPE html>\r
 <html lang="en">\r
 <head>\r
-       <meta charset="UTF-8">\r
-       <title>Lifecycle Manager</title>\r
-       <link href="css/bootstrap.min.css" rel="stylesheet" />\r
-       <link href="css/VMMain.css" rel="stylesheet" />\r
-       <link href="css/bootstrap-table.min.css" rel="stylesheet" />\r
-       <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
-       <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
-       <script type="text/javascript" src="js/rest.js"></script>\r
-       <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
-       <script type="text/javascript" src="js/gsolcm.js"></script>\r
-       <script type="text/javascript">\r
-       $(document).ready(function() {\r
-               var jsondata = [];\r
-               //jsondata = loadNeData();\r
-               $('#sai').bootstrapTable({\r
-               //Assigning data to table\r
-               data: jsondata\r
-               });\r
-               new lcmHandler();\r
-    });\r
-\r
-       function operateFormatter(value, row, index) {\r
-        return [\r
-            '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
-        ].join('');\r
-\r
-    }\r
-        window.operateEvents = {\r
-         'click .siteDeleteImg': function (e, value, row, index) {\r
-             // TO DO ajex call for delete\r
-                        var result = deleteNe(row.id, row);\r
-         }\r
-     };\r
-\r
-       </script>\r
+    <meta charset="UTF-8">\r
+    <title>Lifecycle Manager</title>\r
+    <link href="css/bootstrap.min.css" rel="stylesheet"/>\r
+    <link href="css/VMMain.css" rel="stylesheet"/>\r
+    <link href="css/bootstrap-table.min.css" rel="stylesheet"/>\r
+    <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
+    <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
+    <script type="text/javascript" src="js/rest.js"></script>\r
+    <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
+    <script type="text/javascript" src="js/gsolcm.js"></script>\r
+    <script type="text/javascript">\r
+        $(document).ready(function () {\r
+            var jsondata = [];\r
+            //jsondata = loadNeData();\r
+            $('#sai').bootstrapTable({\r
+                //Assigning data to table\r
+                data: jsondata\r
+            });\r
+            new lcmHandler();\r
+        });\r
+\r
+        function operateFormatter(value, row, index) {\r
+            return [\r
+                '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
+            ].join('');\r
+\r
+        }\r
+        window.operateEvents = {\r
+            'click .siteDeleteImg': function (e, value, row, index) {\r
+                // TO DO ajex call for delete\r
+                var result = deleteNe(row.id, row);\r
+            }\r
+        };\r
+\r
+    </script>\r
 </head>\r
 <body id="open_base_site_cotentBody" class="cotentBody ng-scope">\r
-       <div class="container-fluid ms-controller">\r
-               <h3> Life Cycle Manager </h3>\r
+<div class="container-fluid ms-controller">\r
+    <h3> Life Cycle Manager </h3>\r
 \r
-               <div class="uploadBtn">\r
-                 <div id="open_base_tpL_userHeader" class="userHeader">\r
+    <div class="uploadBtn">\r
+        <div id="open_base_tpL_userHeader" class="userHeader">\r
             <div id="open_base_tpL_buttonGroup" class="openoButton_buttonGroupClass">\r
-                <div class="openo openo-widget-button openoButton_buttonClass_parent ng-isolate-scope openoButton_buttonClass defaultbutton openoButton_button_default" tabindex="0" id="false" text="res.brApp_ui_res_btn_create" icon-url="./images/add.png" cls="defaultbutton" click="clickAdd" style="display: inline-block; padding-left: 0px; padding-right: 0px;">\r
-                                       <div class="openoButton_buttonInnerClass openo-corner-all openoButton_Image" id="false_button">\r
-                                               <span class="openo-widget-button-image openoButton_buttonLeftImg" style="background-image: url(images/add.png);"></span>\r
-                                               <span class="openoButton_buttonCenterText openoButton_buttonCenterTextFont">Create</span>\r
-                                               <span class="openo-widget-button-image openoButton_buttonImgDefault"></span>\r
-                                       </div>\r
-                               </div>\r
+                <div class="openo openo-widget-button openoButton_buttonClass_parent ng-isolate-scope openoButton_buttonClass defaultbutton openoButton_button_default"\r
+                     tabindex="0" id="false" text="res.brApp_ui_res_btn_create" icon-url="./images/add.png"\r
+                     cls="defaultbutton" click="clickAdd"\r
+                     style="display: inline-block; padding-left: 0px; padding-right: 0px;">\r
+                    <div class="openoButton_buttonInnerClass openo-corner-all openoButton_Image" id="false_button">\r
+                        <span class="openo-widget-button-image openoButton_buttonLeftImg"\r
+                              style="background-image: url(images/add.png);"></span>\r
+                        <span class="openoButton_buttonCenterText openoButton_buttonCenterTextFont">Create</span>\r
+                        <span class="openo-widget-button-image openoButton_buttonImgDefault"></span>\r
+                    </div>\r
+                </div>\r
+            </div>\r
+        </div>\r
+    </div>\r
+\r
+    <div class="row-fluid" data-name="table_zone">\r
+        <div id="ict_virtualApplication_table_div">\r
+            <div>\r
+                <div class="top">\r
+                    <table id="sai" data-pagination="true" data-page-size="5" data-pagination-first-text="First"\r
+                           data-pagination-pre-text="Previous" data-pagination-next-text="Next"\r
+                           data-pagination-last-text="Last">\r
+                        <thead id="soverlayTable_thead" class="openo-table-thead">\r
+                        <tr class="active">\r
+                            <!--<th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                    <span id="overlayName_sorticon" class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element">Service ID\r
+            </span>\r
             </div>\r
-                 </div>\r
-               </div>\r
-\r
-               <div class="row-fluid" data-name="table_zone">\r
-                       <div id="ict_virtualApplication_table_div">\r
-                <div>\r
-                    <div class="top">\r
-                       <table id="sai" data-pagination="true" data-page-size="5" data-pagination-first-text="First" data-pagination-pre-text="Previous" data-pagination-next-text="Next" data-pagination-last-text="Last">\r
-                            <thead id="soverlayTable_thead" class="openo-table-thead">\r
-                                                               <tr class="active">\r
-                                                                       <!--<th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayName" data-sortable="true">\r
-                                                                               <div class="openo-table-th-border"></div>\r
-                                                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                                                       <span id="overlayName_sorticon" class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element">Service ID\r
-                    </span>\r
-                                       </div>\r
-                                       </th>-->\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayDesc" data-sortable="true">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="overlayDesc_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service  Name\r
-                                                       </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayThincCPE" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayThincCPE_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Template Name\r
-                    </span></div></th>\r
-                                       <!--<th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayPortVlanID" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayPortVlanID_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service Type\r
-                    </span></div></th> -->\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayDCName" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayDCName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service  Instruction                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayVPC" data-sortable="true">\r
-                                          <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                             <span id="overlayVPC_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Create Time\r
+            </th>-->\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayDesc" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                       <span id="overlayDesc_sorticon"\r
+                                  class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service  Name\r
+                                                       </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayThincCPE" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="overlayThincCPE_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Template Name\r
+                    </span></div>\r
+                            </th>\r
+                            <!--<th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayPortVlanID" data-sortable="true">\r
+                            <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                            <span id="overlayPortVlanID_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service Type\r
+                            </span></div></th> -->\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayDCName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                    <span id="overlayDCName_sorticon"\r
+                                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Service  Instruction                    </span>\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayVPC" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                             <span id="overlayVPC_sorticon"\r
+                                class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Create Time\r
                           </span>\r
-                                          </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayVPCCIDR" data-sortable="true">\r
-                                          <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                             <span id="overlayVPCCIDR_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Creator\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayVPCCIDR" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                             <span id="overlayVPCCIDR_sorticon"\r
+                                class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Creator\r
                           </span>\r
-                                          </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayOperation"  align="center" data-formatter = "operateFormatter" data-events="operateEvents">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="portAction_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action</span>\r
-                                               </div>\r
-                                       </th>\r
-                               </tr></thead>\r
-\r
-                        </table>\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayOperation" align="center" data-formatter="operateFormatter"\r
+                                data-events="operateEvents">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                    <span id="portAction_sorticon"\r
+                                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action</span>\r
+                                </div>\r
+                            </th>\r
+                        </tr>\r
+                        </thead>\r
+\r
+                    </table>\r
+                </div>\r
+            </div>\r
+        </div>\r
+    </div>\r
+    <!-- <div id="tpListopenotable_pagination_wrapper" class="openo-table-pagination-wrapper" style="display: block;"><div class="pagination-container openo-pagination-theme openo-pagination"><div class="openoPagination_openoPaginationLengthOptions" id="tpListopenotable_wrapper_div"><input readonly="true" class="openo-pagination-select openopaginationselect" value="" id="tpListopenotable_wrapper_input" actualval="20" style="width: 32px;"><span class="openo-pagination-selectspan openopaginationselectspan" id="tpListopenotable_wrapper_trigger"></span></div><label style="display: block;float:left;">Total records: 23</label><li class="active"><span class="current prev openo-disabled" id="tpListopenotable_wrapper_prev">&nbsp;</span></li><ul><li class="active"><span class="current" id="tpListopenotable_wrapper_page_link_1">1</span></li><li><a class="page-link" id="tpListopenotable_wrapper_page_link_2">2</a></li><li><a class="page-link" id="tpListopenotable_wrapper_page_link_3">3</a></li><li><a class="page-link next" id="tpListopenotable_wrapper_next">&nbsp;</a></li></ul></div></div> -->\r
+\r
+    <div id="vmAppDialog" class="modal fade" tabindex="-1" role="dialog"\r
+         aria-labelledby="myModalLabel" aria-hidden="false">\r
+        <div class="modal-dialog">\r
+            <div class="modal-content">\r
+                <div class="content">\r
+                    <div class="modal-header">\r
+                        <button type="button" class="close" data-dismiss="modal"\r
+                                aria-hidden="true">×\r
+                        </button>\r
+                        <h4 class="modal-title" id="myModalLabel">\r
+                            <span>Create</span>\r
+                        </h4>\r
                     </div>\r
+                    <form class="form-horizontal" role="form" id="neForm">\r
+                        <div id="wizard">\r
+                            <div class="modal-body">\r
+                                <ul class="nav nav-pills nav-justified vmapp-margin">\r
+\r
+                                </ul>\r
+                                <div class="tab-content">\r
+                                    <ul class="nav nav-tabs">\r
+                                        <li class="active"><a id="basicInfoTab" href="#basicTab" data-toggle="tab">Basic\r
+                                            Info</a></li>\r
+                                        <li><a id="parameterTabHeader" href="#parameterTab" data-toggle="tab">Template\r
+                                            Parameters</a></li>\r
+                                    </ul>\r
+                                    <div id="myTabContent" class="tab-content">\r
+                                        <div class="tab-pane active" id="basicTab">\r
+                                            <div class="form-group" ms-class="has-error:vmAppDialog.name==''">\r
+                                                <label class="col-sm-3 control-label">\r
+                                                    <span>Service Name</span>\r
+                                                    <span class="required">*</span>\r
+                                                </label>\r
+                                                <div class="col-sm-7">\r
+                                                    <input type="text" id="svcName" name="svcName" class="form-control"\r
+                                                           placeholder="Service Name"/>\r
+                                                </div>\r
+                                            </div>\r
+                                            <div class="form-group">\r
+                                                <label class="col-sm-3 control-label">\r
+                                                    <span>Service  Description</span>&nbsp;&nbsp;&nbsp;\r
+                                                </label>\r
+                                                <div class="col-sm-7">\r
+                                                    <input type="text" id="svcDesc" name="svcDesc" class="form-control"\r
+                                                           placeholder="Service  Description"/>\r
+                                                </div>\r
+                                            </div>\r
+                                            <div class="form-group" ms-class="has-error:vmAppDialog.name==''">\r
+                                                <label class="col-sm-3 control-label">\r
+                                                    <span>Service Template</span>\r
+                                                    <span class="required">*</span>\r
+                                                </label>\r
+                                                <div class="col-sm-7">\r
+                                                    <select class="form-control"\r
+                                                            style="padding-top: 0px;padding-bottom: 0px;" id="svcTempl"\r
+                                                            name="svcTempl">\r
+                                                        <option value="1.1">1.1</option>\r
+                                                        <option value="1.2">1.2</option>\r
+                                                    </select>\r
+                                                </div>\r
+                                            </div>\r
+                                        </div>\r
+                                        <div class="tab-pane" id="parameterTab">\r
+\r
+                                        </div>\r
+                                    </div>\r
+                                </div>\r
+                            </div>\r
+                            <div class="modal-footer">\r
+                                <button type="button" class="btn SDBtn" data-dismiss="modal" aria-hidden="true"\r
+                                        id="createNS">\r
+                                    <span id="nfv-virtualApplication-iui-text-cancelBtn">OK</span>\r
+                                </button>\r
+                                <button type="button" class="btn button-previous SDBtn">\r
+                                    <span id="nfv-virtualApplication-iui-text-previousBtn">Cancel</span>\r
+                                </button>\r
+\r
+                            </div>\r
+                        </div>\r
+                    </form>\r
                 </div>\r
             </div>\r
-               </div>\r
-               <!-- <div id="tpListopenotable_pagination_wrapper" class="openo-table-pagination-wrapper" style="display: block;"><div class="pagination-container openo-pagination-theme openo-pagination"><div class="openoPagination_openoPaginationLengthOptions" id="tpListopenotable_wrapper_div"><input readonly="true" class="openo-pagination-select openopaginationselect" value="" id="tpListopenotable_wrapper_input" actualval="20" style="width: 32px;"><span class="openo-pagination-selectspan openopaginationselectspan" id="tpListopenotable_wrapper_trigger"></span></div><label style="display: block;float:left;">Total records: 23</label><li class="active"><span class="current prev openo-disabled" id="tpListopenotable_wrapper_prev">&nbsp;</span></li><ul><li class="active"><span class="current" id="tpListopenotable_wrapper_page_link_1">1</span></li><li><a class="page-link" id="tpListopenotable_wrapper_page_link_2">2</a></li><li><a class="page-link" id="tpListopenotable_wrapper_page_link_3">3</a></li><li><a class="page-link next" id="tpListopenotable_wrapper_next">&nbsp;</a></li></ul></div></div> -->\r
-\r
-               <div id="vmAppDialog" class="modal fade" tabindex="-1" role="dialog"\r
-                               aria-labelledby="myModalLabel" aria-hidden="false">\r
-                               <div class="modal-dialog">\r
-                                       <div class="modal-content">\r
-                                               <div class="content">\r
-                                                       <div class="modal-header">\r
-                                                               <button type="button" class="close" data-dismiss="modal"\r
-                                                      aria-hidden="true">×\r
-                                                   </button>\r
-                                                               <h4 class="modal-title" id="myModalLabel">\r
-                                                      <span>Create</span>\r
-                                                   </h4>\r
-                                                       </div>\r
-                                                       <form class="form-horizontal" role="form" id="neForm">\r
-                                                       <div id="wizard">\r
-                                                       <div class="modal-body">\r
-                                                               <ul class="nav nav-pills nav-justified vmapp-margin">\r
-\r
-                                                               </ul>\r
-                                                               <div class="tab-content">\r
-                                                               <ul class="nav nav-tabs">\r
-                                                                               <li class="active"><a id= "basicInfoTab" href="#basicTab" data-toggle="tab">Basic Info</a></li>\r
-                                                                               <li ><a id="parameterTabHeader" href="#parameterTab" data-toggle="tab">Template Parameters</a></li>\r
-                                                                       </ul>\r
-                                                                       <div id="myTabContent" class="tab-content" >\r
-                                                                               <div class="tab-pane active" id="basicTab">\r
-                                                                                       <div class="form-group" ms-class="has-error:vmAppDialog.name==''">\r
-                                                                                               <label class="col-sm-3 control-label">\r
-                                                                                                       <span>Service Name</span>\r
-                                                                                                       <span class="required">*</span>\r
-                                                                                               </label>\r
-                                                                                               <div class="col-sm-7">\r
-                                                                                                       <input type="text" id="svcName" name="svcName" class="form-control" placeholder="Service Name"/>\r
-                                                                                               </div>\r
-                                                                                       </div>\r
-                                                                                       <div class="form-group">\r
-                                                                                               <label class="col-sm-3 control-label">\r
-                                                                                                       <span>Service  Description</span>&nbsp;&nbsp;&nbsp;\r
-                                                                                               </label>\r
-                                                                                               <div class="col-sm-7">\r
-                                                                                                       <input type="text" id="svcDesc" name="svcDesc" class="form-control" placeholder="Service  Description"/>\r
-                                                                                               </div>\r
-                                                                                       </div>\r
-                                                                                       <div class="form-group" ms-class="has-error:vmAppDialog.name==''">\r
-                                                                                               <label class="col-sm-3 control-label">\r
-                                                                                                       <span>Service Template</span>\r
-                                                                                                       <span class="required">*</span>\r
-                                                                                               </label>\r
-                                                                                               <div class="col-sm-7">\r
-                                                                                                       <select class="form-control" style ="padding-top: 0px;padding-bottom: 0px;" id="svcTempl"\r
-                                                                                                               name="svcTempl">\r
-                                                                                                               <option value="1.1">1.1</option>\r
-                                                                                                               <option value="1.2">1.2</option>\r
-                                                                                                       </select>\r
-                                                                                               </div>\r
-                                                                                       </div>\r
-                                                                               </div>\r
-                                                                               <div class="tab-pane" id="parameterTab">\r
-\r
-                                                                               </div>\r
-                                                                       </div>\r
-                                                               </div>\r
-                                                       </div>\r
-                                                       <div class="modal-footer">\r
-                                                               <button type="button" class="btn SDBtn" data-dismiss="modal" aria-hidden="true" id="createNS">\r
-                                                                       <span id="nfv-virtualApplication-iui-text-cancelBtn">OK</span>\r
-                                                               </button>\r
-                                                               <button type="button" class="btn button-previous SDBtn">\r
-                                                                       <span id="nfv-virtualApplication-iui-text-previousBtn">Cancel</span>\r
-                                                               </button>\r
-\r
-                                                       </div>\r
-                                               </div>\r
-                                               </form>\r
-                                       </div>\r
-                               </div>\r
-                       </div>\r
-               </div>\r
-       </div>\r
-       <div id="filterTpLogicalType_select_popupcontainer" class="openo openo-select-popup-container openo-hide" style="width: 155px; max-height: 130px; left: 628px; top: 104px; z-index: 1761;">\r
-       <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_0">\r
-       <label class="openo-ellipsis openo-select-blank-item" style="width: 100%; display: block; height: 20px;"></label>\r
-       </div>\r
-       <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_1">\r
-       <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">ETH</label>\r
-       </div>\r
-       <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_2">\r
-       <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;" title="POS">POS</label>\r
-       </div>\r
-       <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_3">\r
-       <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Trunk</label>\r
-       </div>\r
-       <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_4">\r
-       <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Loopback</label>\r
-       </div>\r
-       </div>\r
+        </div>\r
+    </div>\r
+</div>\r
+<div id="filterTpLogicalType_select_popupcontainer" class="openo openo-select-popup-container openo-hide"\r
+     style="width: 155px; max-height: 130px; left: 628px; top: 104px; z-index: 1761;">\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_0">\r
+        <label class="openo-ellipsis openo-select-blank-item"\r
+               style="width: 100%; display: block; height: 20px;"></label>\r
+    </div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_1">\r
+        <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">ETH</label>\r
+    </div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_2">\r
+        <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;" title="POS">POS</label>\r
+    </div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_3">\r
+        <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Trunk</label>\r
+    </div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_4">\r
+        <label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Loopback</label>\r
+    </div>\r
+</div>\r
 \r
 \r
 </body>\r
index e975f6c..5bdc6ba 100644 (file)
  * limitations under the License.\r
  */\r
 \r
\r
-$('.siteDeleteImg').click(function(){\r
-       var data = $(this).parent().parent().parent().find('td:last').find('div:last').html();\r
-       alert(data);\r
-       var jsonObj = JSON.parse(data);\r
-       for(var i = 0; i < jsonObj.length; i++) {\r
-           var obj = jsonObj[i];\r
-               var rowData = [obj.tpName,obj.peName,obj.vlanId,obj.siteCidr,obj.ip];\r
-               $('#underlayTpDataTable').DataTable();\r
-               $('#underlayTpDataTable').dataTable().fnAddData(rowData);\r
-       }\r
+\r
+$('.siteDeleteImg').click(function () {\r
+    var data = $(this).parent().parent().parent().find('td:last').find('div:last').html();\r
+    alert(data);\r
+    var jsonObj = JSON.parse(data);\r
+    for (var i = 0; i < jsonObj.length; i++) {\r
+        var obj = jsonObj[i];\r
+        var rowData = [obj.tpName, obj.peName, obj.vlanId, obj.siteCidr, obj.ip];\r
+        $('#underlayTpDataTable').DataTable();\r
+        $('#underlayTpDataTable').dataTable().fnAddData(rowData);\r
+    }\r
 });\r
 \r
 \r
-function deleteSite(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites/"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#site').bootstrapTable('remove', {\r
-                                   field: 'id',\r
-                                   values: [objectId]\r
-                               });\r
-                                               alert("Delete Site successfull !!!");\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting site: " + xhr.responseText);   \r
-                                       }\r
-                               });\r
+function deleteSite(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/sites/" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#site').bootstrapTable('remove', {\r
+                    field: 'id',\r
+                    values: [objectId]\r
+                });\r
+                alert("Delete Site successfull !!!");\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting site: " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function deleteLink(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links/"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#link').bootstrapTable('remove', {\r
-                                   field: 'id',\r
-                                   values: [objectId]\r
-                               });\r
-                                               alert("Delete Link successfull !!!");\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting link : " + xhr.responseText);  \r
-                                       }\r
-                               });\r
+function deleteLink(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/topological-links/" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#link').bootstrapTable('remove', {\r
+                    field: 'id',\r
+                    values: [objectId]\r
+                });\r
+                alert("Delete Link successfull !!!");\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting link : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
 \r
-function deleteNe(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/managed-elements/"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#ne').bootstrapTable('remove', {\r
-                                   field: 'id',\r
-                                   values: [objectId]\r
-                               });\r
-                                               alert("Delete NE successfull !!!");\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting ne : " + xhr.responseText);    \r
-                                       }\r
-                               });\r
+function deleteNe(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/managed-elements/" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#ne').bootstrapTable('remove', {\r
+                    field: 'id',\r
+                    values: [objectId]\r
+                });\r
+                alert("Delete NE successfull !!!");\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting ne : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
 \r
-function deletePort(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points/"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#port').bootstrapTable('remove', {\r
-                                   field: 'id',\r
-                                   values: [objectId]\r
-                               });\r
-                                               alert("Delete Port successfull !!!");\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting port : " + xhr.responseText);  \r
-                                       }\r
-                               });\r
+function deletePort(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points/" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#port').bootstrapTable('remove', {\r
+                    field: 'id',\r
+                    values: [objectId]\r
+                });\r
+                alert("Delete Port successfull !!!");\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting port : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadSiteData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#site').bootstrapTable({\r
-                                       data: jsonobj.sites\r
-                               });\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting site data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadSiteData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/sites";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#site').bootstrapTable({\r
+                    data: jsonobj.sites\r
+                });\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting site data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadLinkData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#link').bootstrapTable({\r
-                                       data: jsonobj.topologicalLinks\r
-                               });\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting link data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadLinkData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/topological-links";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#link').bootstrapTable({\r
+                    data: jsonobj.topologicalLinks\r
+                });\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting link data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadNeData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/managed-elements";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#ne').bootstrapTable({\r
-                                       data: jsonobj.managedElements\r
-                               });\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting ne data : " + xhr.responseText);        \r
-                                       }\r
-                               });\r
+function loadNeData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/managed-elements";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#ne').bootstrapTable({\r
+                    data: jsonobj.managedElements\r
+                });\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting ne data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadPortData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               $('#port').bootstrapTable({\r
-                                data: jsonobj.logicalTerminationPoints\r
-                               });\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting port data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadPortData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                $('#port').bootstrapTable({\r
+                    data: jsonobj.logicalTerminationPoints\r
+                });\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting port data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-$(function(){\r
-                       $('.creat-btn').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                               \r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('.detail-top ul li').click(function(){\r
-                               $(this).addClass('current').siblings().removeClass('current');\r
-                       });\r
-                       $('.para').click(function(){                            \r
-                               if($('#serviceTemplateName').val() == ''){\r
-                                       alert('Please choose the service templet!');\r
-                                       $('#flavorTab').css('display','none');\r
-                               }else{\r
-                                       $('#flavorTab').css('display','block');\r
-                               }\r
-                               $('#basicTab').css('display','block');\r
-                       });\r
-                       $('.basic').click(function(){\r
-                               $('#flavorTab').css('display','none');\r
-                       });\r
-                       \r
-                       $('.table tbody tr').click(function(){\r
-                               $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
-                       });\r
-                       $('.table tr:odd').addClass('active');\r
-                       $('#false').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('#filterTpLogicalType').click(function(){\r
-                               $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
-                               $('#filterTpLogicalType').toggleClass('openo-focus');\r
-                               var oLeft = $('#open_base_tpL_td6').offset().left;\r
-                       var oTop = $('#open_base_tpL_td6').offset().top;\r
-                       var oHeight = $('#open_base_tpL_td6').height();\r
-                       $('#filterTpLogicalType_select_popupcontainer').css({'left':oLeft,'top':oTop + oHeight + 10});\r
-                       });\r
-                       $('div.openo-select-popup-container>div.openo-select-item>label').click(function(){\r
-                               var Lvalue = $(this).html();\r
-                               $('#filterTpLogicalType_select_input').attr('value',Lvalue);\r
-                               $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
-                               $('#filterTpLogicalType').removeClass('openo-focus');\r
-                       });\r
-                       $.fn.serializeObject = function() {\r
-                               var o = {};\r
-                               var a = this.serializeArray();\r
-                               $.each(a, function() {\r
-                                       if (o[this.name] !== undefined) {\r
-                                               if (!o[this.name].push) {\r
-                                                       o[this.name] = [ o[this.name] ];\r
-                                               }\r
-                                       o[this.name].push(this.value || '');\r
-                                       } else {\r
-                                               o[this.name] = this.value || '';\r
-                                       }\r
-                               });\r
-                       return o;\r
-                       };\r
-                       $('#createSite').click(function(){\r
-                               var formData = JSON.stringify($("#vmAppForm").serializeObject());\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var newJson = {"site": jsonobj};\r
-                       formData = JSON.stringify(newJson);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonResp) {\r
-                                               alert("Site saved successfully!!!");\r
-                                               jsonobj["id"]= jsonResp.site.id;\r
-                                               $('#site').bootstrapTable("append", jsonobj);\r
-                                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createNe').click(function(){\r
-                               var formData = JSON.stringify($("#neForm").serializeObject());\r
-                               var jsonobj = JSON.parse(formData);\r
-                       var newJson = {"managedElement": jsonobj};\r
-                       formData = JSON.stringify(newJson);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/managed-elements";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonResp) {\r
-                                               alert("NE saved successfully!!!");\r
-                                               jsonobj["id"]= jsonResp.managedElement.id;\r
-                                               $('#ne').bootstrapTable("append", jsonobj);\r
-                                               $('#vmAppDialog').removeClass('in').css('display','none');\r
+$(function () {\r
+    $('.creat-btn').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('.detail-top ul li').click(function () {\r
+        $(this).addClass('current').siblings().removeClass('current');\r
+    });\r
+    $('.para').click(function () {\r
+        if ($('#serviceTemplateName').val() == '') {\r
+            alert('Please choose the service templet!');\r
+            $('#flavorTab').css('display', 'none');\r
+        } else {\r
+            $('#flavorTab').css('display', 'block');\r
+        }\r
+        $('#basicTab').css('display', 'block');\r
+    });\r
+    $('.basic').click(function () {\r
+        $('#flavorTab').css('display', 'none');\r
+    });\r
+\r
+    $('.table tbody tr').click(function () {\r
+        $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
+    });\r
+    $('.table tr:odd').addClass('active');\r
+    $('#false').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('#filterTpLogicalType').click(function () {\r
+        $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
+        $('#filterTpLogicalType').toggleClass('openo-focus');\r
+        var oLeft = $('#open_base_tpL_td6').offset().left;\r
+        var oTop = $('#open_base_tpL_td6').offset().top;\r
+        var oHeight = $('#open_base_tpL_td6').height();\r
+        $('#filterTpLogicalType_select_popupcontainer').css({'left': oLeft, 'top': oTop + oHeight + 10});\r
+    });\r
+    $('div.openo-select-popup-container>div.openo-select-item>label').click(function () {\r
+        var Lvalue = $(this).html();\r
+        $('#filterTpLogicalType_select_input').attr('value', Lvalue);\r
+        $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
+        $('#filterTpLogicalType').removeClass('openo-focus');\r
+    });\r
+    $.fn.serializeObject = function () {\r
+        var o = {};\r
+        var a = this.serializeArray();\r
+        $.each(a, function () {\r
+            if (o[this.name] !== undefined) {\r
+                if (!o[this.name].push) {\r
+                    o[this.name] = [o[this.name]];\r
+                }\r
+                o[this.name].push(this.value || '');\r
+            } else {\r
+                o[this.name] = this.value || '';\r
+            }\r
+        });\r
+        return o;\r
+    };\r
+    $('#createSite').click(function () {\r
+        var formData = JSON.stringify($("#vmAppForm").serializeObject());\r
+        var jsonobj = JSON.parse(formData);\r
+        var newJson = {"site": jsonobj};\r
+        formData = JSON.stringify(newJson);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/sites";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonResp) {\r
+                    alert("Site saved successfully!!!");\r
+                    jsonobj["id"] = jsonResp.site.id;\r
+                    $('#site').bootstrapTable("append", jsonobj);\r
+                    $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createNe').click(function () {\r
+        var formData = JSON.stringify($("#neForm").serializeObject());\r
+        var jsonobj = JSON.parse(formData);\r
+        var newJson = {"managedElement": jsonobj};\r
+        formData = JSON.stringify(newJson);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/managed-elements";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonResp) {\r
+                    alert("NE saved successfully!!!");\r
+                    jsonobj["id"] = jsonResp.managedElement.id;\r
+                    $('#ne').bootstrapTable("append", jsonobj);\r
+                    $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createPort').click(function () {\r
+        var formData = JSON.stringify($("#portForm").serializeObject());\r
+        var jsonobj = JSON.parse(formData);\r
+        var newJson = {"logicalTerminationPoint": jsonobj};\r
+        formData = JSON.stringify(newJson);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonResp) {\r
+                    alert("Port saved successfully!!!");\r
+                    //TODO : hide model data window.\r
+                    jsonobj["id"] = jsonResp.logicalTerminationPoint.id;\r
+                    $('#port').bootstrapTable("append", jsonobj);\r
+                    $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createLink').click(function () {\r
+        var formData = JSON.stringify($("#linkForm").serializeObject());\r
+        var jsonobj = JSON.parse(formData);\r
+        var newJson = {"topologicalLink": jsonobj};\r
+        formData = JSON.stringify(newJson);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/topological-links";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonResp) {\r
+                    alert("Link saved successfully!!!");\r
+                    jsonobj["id"] = jsonResp.topologicalLink.id;\r
+                    $('#link').bootstrapTable("append", jsonobj);\r
+                    $('#vmAppDialog').removeClass('in').css('display', 'none');\r
 \r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createPort').click(function(){\r
-                               var formData = JSON.stringify($("#portForm").serializeObject());\r
-                               var jsonobj = JSON.parse(formData);\r
-                       var newJson = {"logicalTerminationPoint": jsonobj};\r
-                       formData = JSON.stringify(newJson);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonResp) {\r
-                                               alert("Port saved successfully!!!");\r
-                                               //TODO : hide model data window.\r
-                                               jsonobj["id"]= jsonResp.logicalTerminationPoint.id;\r
-                                               $('#port').bootstrapTable("append", jsonobj);\r
-                                               $('#vmAppDialog').removeClass('in').css('display','none');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
 \r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createLink').click(function(){\r
-                               var formData = JSON.stringify($("#linkForm").serializeObject());\r
-                               var jsonobj = JSON.parse(formData);\r
-                       var newJson = {"topologicalLink": jsonobj};\r
-                       formData = JSON.stringify(newJson);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonResp) {\r
-                                               alert("Link saved successfully!!!");\r
-                                               jsonobj["id"]= jsonResp.topologicalLink.id;\r
-                                               $('#link').bootstrapTable("append", jsonobj);\r
-                                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                                               \r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-               })
\ No newline at end of file
+})
\ No newline at end of file
index d17d9f3..f0069cd 100644 (file)
  * limitations under the License.
  */
 var templateParameters = {
-  templateName: '',
-  parameters: []
+    templateName: '',
+    parameters: []
 };
 
 var service_instance_insert_index = 0;
 
-var lcmHandler = function(){
-  this._addOwnEvents();
+var lcmHandler = function () {
+    this._addOwnEvents();
 };
 
 lcmHandler.prototype = {
-  _addOwnEvents : function () {
-    $('a[data-toggle="tab"]').on('show.bs.tab', this.beforeParameterTabShow);
-    $('#createNS').click(this.okAction);
-  },
-  beforeParameterTabShow : function (event) {
-    renderTemplateParametersTab();
-  },
-  okAction : function (event) {
-    var serviceInstance = {
-      serviceTemplateId: $('#svcTempl').val(),
-      serviceName: $('#svcName').val(),
-      serviceDescription: $('#svcDesc').val(),
-      serviceParameters: collectServiceParameters(templateParameters),
-      vimLocation: $('#vim_location').val()
-    }
-    var gatewayService = '/openoapi/servicegateway/v1/services';
-    var serviceTemplate = fetchServiceTemplateBy(serviceInstance.serviceTemplateId);
-    if(serviceTemplate === undefined) {
-      return;
-    }
-    if(serviceTemplate.csarType === 'GSAR') {
-      serviceInstance.serviceInstanceId = createGsoServiceInstance(gatewayService, serviceInstance);
-    }else if(serviceTemplate.csarType === 'NSAR' || serviceTemplate.csarType === 'NFAR') {
-      serviceInstance.serviceInstanceId = createNfvoServiceInstance(gatewayService, serviceInstance);
-    }else if(serviceTemplate.csarType === 'SSAR') {
-      serviceInstance.serviceInstanceId = createSdnoServiceInstance(gatewayService, serviceInstance);
-    }
-    if(serviceInstance.serviceInstanceId === undefined) {
-      return;
+    _addOwnEvents: function () {
+        $('a[data-toggle="tab"]').on('show.bs.tab', this.beforeParameterTabShow);
+        $('#createNS').click(this.okAction);
+    },
+    beforeParameterTabShow: function (event) {
+        renderTemplateParametersTab();
+    },
+    okAction: function (event) {
+        var serviceInstance = {
+            serviceTemplateId: $('#svcTempl').val(),
+            serviceName: $('#svcName').val(),
+            serviceDescription: $('#svcDesc').val(),
+            serviceParameters: collectServiceParameters(templateParameters),
+            vimLocation: $('#vim_location').val()
+        }
+        var gatewayService = '/openoapi/servicegateway/v1/services';
+        var serviceTemplate = fetchServiceTemplateBy(serviceInstance.serviceTemplateId);
+        if (serviceTemplate === undefined) {
+            return;
+        }
+        if (serviceTemplate.csarType === 'GSAR') {
+            serviceInstance.serviceInstanceId = createGsoServiceInstance(gatewayService, serviceInstance);
+        } else if (serviceTemplate.csarType === 'NSAR' || serviceTemplate.csarType === 'NFAR') {
+            serviceInstance.serviceInstanceId = createNfvoServiceInstance(gatewayService, serviceInstance);
+        } else if (serviceTemplate.csarType === 'SSAR') {
+            serviceInstance.serviceInstanceId = createSdnoServiceInstance(gatewayService, serviceInstance);
+        }
+        if (serviceInstance.serviceInstanceId === undefined) {
+            return;
+        }
+        updateTable(serviceInstance);
     }
-    updateTable(serviceInstance);
-  }
 };
 
 function collectServiceParameters(parameters) {
-  var serviceParameters = {};
-  var i;
-  for( i = 0; i < parameters.length; i += 1) {
-    serviceParameters[parameters.name] = $('#' + parameters[i].id).val();
-  }
-  return serviceParameters;
+    var serviceParameters = {};
+    var i;
+    for (i = 0; i < parameters.length; i += 1) {
+        serviceParameters[parameters.name] = $('#' + parameters[i].id).val();
+    }
+    return serviceParameters;
 }
 
 function fetchServiceTemplateBy(templateId) {
-  var serviceTemplateUri = '/openoapi/catalog/v1/servicetemplates/'+ templateId;
-  var template;
-  $.ajax({
-    type : "GET",
-    async: false,
-    url : serviceTemplateUri,
-    contentType : "application/json",
-    dataType : "json",
-    success : function(jsonResp) {
-      template = {
-        name: jsonResp.templateName,
-        gsarId: jsonResp.csarId
-      }
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
+    var serviceTemplateUri = '/openoapi/catalog/v1/servicetemplates/' + templateId;
+    var template;
+    $.ajax({
+        type: "GET",
+        async: false,
+        url: serviceTemplateUri,
+        contentType: "application/json",
+        dataType: "json",
+        success: function (jsonResp) {
+            template = {
+                name: jsonResp.templateName,
+                gsarId: jsonResp.csarId
+            }
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
+    if (template === undefined) {
+        return template;
     }
-  });
-  if(template === undefined) {
+    var queryCsarUri = '/openoapi/catalog/v1/csars/' + template.gsarId;
+    $.ajax({
+        type: "GET",
+        async: false,
+        url: queryCsarUri,
+        contentType: "application/json",
+        dataType: "json",
+        success: function (jsonResp) {
+            template.csarType = jsonResp.type
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
     return template;
-  }
-  var queryCsarUri = '/openoapi/catalog/v1/csars/' + template.gsarId;
-  $.ajax({
-    type : "GET",
-    async: false,
-    url : queryCsarUri,
-    contentType : "application/json",
-    dataType : "json",
-    success : function(jsonResp) {
-      template.csarType = jsonResp.type
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
-    }
-  });
-  return template;
 }
 
 function renderTemplateParametersTab() {
-  templateParameters = fetchTemplateParameterDefinitions(templateParameters);
-  var vims = fetchVimInfo();
-  var components = transfromToComponents(templateParameters.parameters, vims);
-  document.getElementById("parameterTab").innerHTML = components;
+    templateParameters = fetchTemplateParameterDefinitions(templateParameters);
+    var vims = fetchVimInfo();
+    var components = transfromToComponents(templateParameters.parameters, vims);
+    document.getElementById("parameterTab").innerHTML = components;
 }
 
 function fetchTemplateParameterDefinitions(parameters) {
-  var serviceTemplate = parameters.templateName;
-  var currentServiceTemplate = $("#svcTempl").val();
-  // Do not need to fetch template parameters if template do not change in UI.
-  if(serviceTemplate === currentServiceTemplate) {
-    return;
-  }
-  var queryParametersUri = '/openoapi/catalog/v1/servicetemplates/' + currentServiceTemplate + '/parameters';
-  var inputParameters = [];
-  $.ajax({
-    type : "GET",
-    async: false,
-    url : queryParametersUri,
-    contentType : "application/json",
-    dataType : "json",
-    success : function(jsonResp) {
-      var inputs = jsonResp.inputs;
-      var i;
-      for( i = 0; i < inputs.length; i += 1) {
-        inputParameters[i] = {
-          name: inputs[i].name,
-          type: inputs[i].type,
-          description: inputs[i].description,
-          defaultValue: inputs[i].defaultValue,
-          required: inputs[i].required,
-          id: 'parameter_' + i,
-          value: inputs[i].defaultValue
-        };
-      }
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
+    var serviceTemplate = parameters.templateName;
+    var currentServiceTemplate = $("#svcTempl").val();
+    // Do not need to fetch template parameters if template do not change in UI.
+    if (serviceTemplate === currentServiceTemplate) {
+        return;
     }
-  });
-  return { name: currentServiceTemplate, parameters: inputParameters };
+    var queryParametersUri = '/openoapi/catalog/v1/servicetemplates/' + currentServiceTemplate + '/parameters';
+    var inputParameters = [];
+    $.ajax({
+        type: "GET",
+        async: false,
+        url: queryParametersUri,
+        contentType: "application/json",
+        dataType: "json",
+        success: function (jsonResp) {
+            var inputs = jsonResp.inputs;
+            var i;
+            for (i = 0; i < inputs.length; i += 1) {
+                inputParameters[i] = {
+                    name: inputs[i].name,
+                    type: inputs[i].type,
+                    description: inputs[i].description,
+                    defaultValue: inputs[i].defaultValue,
+                    required: inputs[i].required,
+                    id: 'parameter_' + i,
+                    value: inputs[i].defaultValue
+                };
+            }
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
+    return {name: currentServiceTemplate, parameters: inputParameters};
 }
 
 function fetchVimInfo() {
-  var result = [];
-  var vimQueryUri = '/openoapi/extsys/v1/vims';
-  $.ajax({
-    type : "GET",
-    async: false,
-    url : vimQueryUri,
-    contentType : "application/json",
-    dataType : "json",
-    success : function(jsonResp) {
-      var vims = jsonResp;
-      var i;
-      for( i = 0; i < vims.length; i += 1) {
-        var option = '<option value="' + vims[i].vimId + '">'+vims[i].name+'</option>';
-        result[i] = {
-          vimId: vims[i].vimId,
-          vimName: vims[i].name
+    var result = [];
+    var vimQueryUri = '/openoapi/extsys/v1/vims';
+    $.ajax({
+        type: "GET",
+        async: false,
+        url: vimQueryUri,
+        contentType: "application/json",
+        dataType: "json",
+        success: function (jsonResp) {
+            var vims = jsonResp;
+            var i;
+            for (i = 0; i < vims.length; i += 1) {
+                var option = '<option value="' + vims[i].vimId + '">' + vims[i].name + '</option>';
+                result[i] = {
+                    vimId: vims[i].vimId,
+                    vimName: vims[i].name
+                }
+            }
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
         }
-      }
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
-    }
-  });
-  return result;
+    });
+    return result;
 }
 
 function transfromToComponents(parameters, vims) {
-  var components = '';
-  var i;
-  for( i = 0; i < parameters.length; i += 1) {
-    var component = '<div class="form-group">' +
-      '<label class="col-sm-3 control-label">' +
-        '<span>' + parameters[i].description + '</span>' + generateRequiredLabel(parameters[i]) +
-      '</label>' +
-      '<div class="col-sm-7">' +
-        '<input type="text" id="'+ parameters[i].id +'" name="parameter description" class="form-control" placeholder="' +
-              parameters[i].description + '" value="'+ parameters[i].value +'" />' +
-      '</div></div>';
-    components = components + component;
-  }
-  components = components + generateLocationComponent(vims);
-  return components;
+    var components = '';
+    var i;
+    for (i = 0; i < parameters.length; i += 1) {
+        var component = '<div class="form-group">' +
+            '<label class="col-sm-3 control-label">' +
+            '<span>' + parameters[i].description + '</span>' + generateRequiredLabel(parameters[i]) +
+            '</label>' +
+            '<div class="col-sm-7">' +
+            '<input type="text" id="' + parameters[i].id + '" name="parameter description" class="form-control" placeholder="' +
+            parameters[i].description + '" value="' + parameters[i].value + '" />' +
+            '</div></div>';
+        components = components + component;
+    }
+    components = components + generateLocationComponent(vims);
+    return components;
 }
 
 function generateRequiredLabel(parameter) {
-  var requiredLabel = '';
-  if(parameter.required === 'true') {
-    requiredLabel = '<span class="required">*</span>';
-  }
-  return requiredLabel;
+    var requiredLabel = '';
+    if (parameter.required === 'true') {
+        requiredLabel = '<span class="required">*</span>';
+    }
+    return requiredLabel;
 }
 
 function generateLocationComponent(vims) {
-  var component = '<div class="form-group">' +
-                    '<label class="col-sm-3 control-label">' +
-                      '<span>Location</span>' +
-                      '<span class="required">*</span>' +
-                    '</label>' +
-                    '<div class="col-sm-7">' +
-                      '<select class="form-control" style ="padding-top: 0px;padding-bottom: 0px;"' +
-                        ' id="vim_location" name="vim_location">' +
-                        transformToOptions(vims) +
-                        // '<option value="vimid">vim1 name</option>' +
-                      '</select></div></div>';
-  return component;
+    var component = '<div class="form-group">' +
+        '<label class="col-sm-3 control-label">' +
+        '<span>Location</span>' +
+        '<span class="required">*</span>' +
+        '</label>' +
+        '<div class="col-sm-7">' +
+        '<select class="form-control" style ="padding-top: 0px;padding-bottom: 0px;"' +
+        ' id="vim_location" name="vim_location">' +
+        transformToOptions(vims) +
+        // '<option value="vimid">vim1 name</option>' +
+        '</select></div></div>';
+    return component;
 }
 
 function transformToOptions(vims) {
-  var options = '';
-  var i;
-  for( i = 0; i < vims.length; i += 1) {
-    var option = '<option value="' + vims[i].vimId + '">'+vims[i].vimName+'</option>';
-    options = options + option; 
-  }
-  return options;
+    var options = '';
+    var i;
+    for (i = 0; i < vims.length; i += 1) {
+        var option = '<option value="' + vims[i].vimId + '">' + vims[i].vimName + '</option>';
+        options = options + option;
+    }
+    return options;
 }
 
 function createGsoServiceInstance(gatewayService, serviceInstance) {
-  serviceInstance.serviceParameters.location = serviceInstance.vimLocation;
-  var gsoLcmUri = '/openoapi/lifecyclemgr/v1/services';
-  var parameter = {
-    'name': serviceInstance.serviceName,
-    'description': serviceInstance.serviceDescription,
-    'serviceDefId': serviceTemplate.gsarId,
-    'templatedId': serviceInstance.serviceTemplateId,
-    'templateName': serviceTemplate.templateName,
-    'getewayUri': gsoLcmUrl,
-    'parameters': serviceInstance.serviceParameters
-  };
-  var serviceInstanceId;
-  $.ajax({
-    type : "POST",
-    async: false,
-    url : gatewayService,
-    contentType : "application/json",
-    dataType : "json",
-    data : JSON.stringify(parameter),
-    success : function(jsonResp) {
-      if(jsonResp.result.errorCode != '200') {
-        alert("Create service instance Error!");
-        return;
-      }
-      serviceInstanceId = jsonResp.serviceId;
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
-    }
-  });
-  return serviceInstanceId;
+    serviceInstance.serviceParameters.location = serviceInstance.vimLocation;
+    var gsoLcmUri = '/openoapi/lifecyclemgr/v1/services';
+    var parameter = {
+        'name': serviceInstance.serviceName,
+        'description': serviceInstance.serviceDescription,
+        'serviceDefId': serviceTemplate.gsarId,
+        'templatedId': serviceInstance.serviceTemplateId,
+        'templateName': serviceTemplate.templateName,
+        'getewayUri': gsoLcmUrl,
+        'parameters': serviceInstance.serviceParameters
+    };
+    var serviceInstanceId;
+    $.ajax({
+        type: "POST",
+        async: false,
+        url: gatewayService,
+        contentType: "application/json",
+        dataType: "json",
+        data: JSON.stringify(parameter),
+        success: function (jsonResp) {
+            if (jsonResp.result.errorCode != '200') {
+                alert("Create service instance Error!");
+                return;
+            }
+            serviceInstanceId = jsonResp.serviceId;
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
+    return serviceInstanceId;
 }
 
 function createNfvoServiceInstance(gatewayService, serviceInstance) {
-  var nfvoLcmNsUrl = '/openoapi/nslcm/v1.0/ns';
-  serviceInstance.serviceParameters.location = serviceInstance.vimLocation;
-  createServiceInstance(gatewayService, nfvoLcmNsUrl, serviceInstance);
+    var nfvoLcmNsUrl = '/openoapi/nslcm/v1.0/ns';
+    serviceInstance.serviceParameters.location = serviceInstance.vimLocation;
+    createServiceInstance(gatewayService, nfvoLcmNsUrl, serviceInstance);
 }
 
 function createServiceInstance(gatewayService, gatewayUri, serviceInstance) {
-  var nsInstanceId = createNetworkService(gatewayService, gatewayUri, serviceInstance);
-  if(nsInstanceId === undefined) {
-    return;
-  }
-  instantiateNetworkService(gatewayUri, nsInstanceId, serviceInstance);
+    var nsInstanceId = createNetworkService(gatewayService, gatewayUri, serviceInstance);
+    if (nsInstanceId === undefined) {
+        return;
+    }
+    instantiateNetworkService(gatewayUri, nsInstanceId, serviceInstance);
 }
 
 function createNetworkService(gatewayService, gatewayUri, serviceInstance) {
-  var parameter = {
-    'nsdId': serviceInstance.serviceTemplateId,
-    'nsName': serviceInstance.serviceName,
-    'description': serviceInstance.serviceDescription,
-    'gatewayUri': gatewayUri
-  };
-  var nsInstanceId;
-  $.ajax({
-    type : "POST",
-    async: false,
-    url : gatewayService,
-    contentType : "application/json",
-    dataType : "json",
-    data : JSON.stringify(parameter),
-    success : function(jsonResp) {
-      nsInstanceId = jsonResp.nsInstanceId;
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
-    }
-  });
-  return nsInstanceId;
+    var parameter = {
+        'nsdId': serviceInstance.serviceTemplateId,
+        'nsName': serviceInstance.serviceName,
+        'description': serviceInstance.serviceDescription,
+        'gatewayUri': gatewayUri
+    };
+    var nsInstanceId;
+    $.ajax({
+        type: "POST",
+        async: false,
+        url: gatewayService,
+        contentType: "application/json",
+        dataType: "json",
+        data: JSON.stringify(parameter),
+        success: function (jsonResp) {
+            nsInstanceId = jsonResp.nsInstanceId;
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
+    return nsInstanceId;
 }
 
 function instantiateNetworkService(gatewayUri, nsInstanceId, serviceInstance) {
-  var initNsUrl = gatewayUri + '/' + nsInstanceId + '/Instantiate'
-  var parameter = {
-    'gatewayUri': initNsUrl,
-    'nsInstanceId': nsInstanceId,
-    'additionalParamForNs': serviceInstance.serviceParameters
-  };
-  var result = false;
-  $.ajax({
-    type : "POST",
-    async: false,
-    url : gatewayService,
-    contentType : "application/json",
-    dataType : "json",
-    data : JSON.stringify(parameter),
-    success : function(jsonResp) {
-      result = true;
-    },
-    error : function(xhr, ajaxOptions, thrownError) {
-      alert("Error on page : " + xhr.responseText);
-    }
-  });
-  return result;
+    var initNsUrl = gatewayUri + '/' + nsInstanceId + '/Instantiate'
+    var parameter = {
+        'gatewayUri': initNsUrl,
+        'nsInstanceId': nsInstanceId,
+        'additionalParamForNs': serviceInstance.serviceParameters
+    };
+    var result = false;
+    $.ajax({
+        type: "POST",
+        async: false,
+        url: gatewayService,
+        contentType: "application/json",
+        dataType: "json",
+        data: JSON.stringify(parameter),
+        success: function (jsonResp) {
+            result = true;
+        },
+        error: function (xhr, ajaxOptions, thrownError) {
+            alert("Error on page : " + xhr.responseText);
+        }
+    });
+    return result;
 }
 
 function createSdnoServiceInstance(gatewayService, serviceInstance) {
-  var sdnoLcmNsUrl = '/openoapi/sdnonslcm/v1.0/ns';
-  createServiceInstance(gatewayService, sdnoLcmNsUrl, serviceInstance);
+    var sdnoLcmNsUrl = '/openoapi/sdnonslcm/v1.0/ns';
+    createServiceInstance(gatewayService, sdnoLcmNsUrl, serviceInstance);
 }
 
 function updateTable(serviceInstance) {
-  appendOenRow();
-  addDeleteEventRegistration();
+    appendOenRow();
+    addDeleteEventRegistration();
 }
 
 function appendOenRow() {
-  var index = service_instance_insert_index;
-  var creator = '';
-  $('#sai').append('<tr id="service_instance_' + index + '"></tr>');
-  $("#service_instance_" + index).html('<td><div class="DataTables_sort_wrapper openo-ellipsis "><span id="service_name" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">'+ serviceInstance.serviceName + '</span></td>' +
-    '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">'+ serviceInstance.templateName + '</span></td>' +
-    '<td class="service_template_id"><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">'+ serviceInstance.serviceTemplateId + '</span><input type="hidden" value="'+serviceInstance.serviceInstanceId+'"/></td>' +
-    '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">'+ formatDate(new Date()) + '</span></td>' +
-    '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">'+ creator + '</span></td>' +
-    '<td><button class="data_delete_action"><img id="delete_action" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element " src="images/delete.png"></img></button></td>');
-  service_instance_insert_index += 1;
+    var index = service_instance_insert_index;
+    var creator = '';
+    $('#sai').append('<tr id="service_instance_' + index + '"></tr>');
+    $("#service_instance_" + index).html('<td><div class="DataTables_sort_wrapper openo-ellipsis "><span id="service_name" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">' + serviceInstance.serviceName + '</span></td>' +
+        '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">' + serviceInstance.templateName + '</span></td>' +
+        '<td class="service_template_id"><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">' + serviceInstance.serviceTemplateId + '</span><input type="hidden" value="' + serviceInstance.serviceInstanceId + '"/></td>' +
+        '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">' + formatDate(new Date()) + '</span></td>' +
+        '<td><span class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">' + creator + '</span></td>' +
+        '<td><button class="data_delete_action"><img id="delete_action" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element " src="images/delete.png"></img></button></td>');
+    service_instance_insert_index += 1;
 }
 
 function formatDate(date) {
-  var year = date.getFullYear();
-  var month = date.getMonth() + 1;
-  var day = date.getDate();
-  var hh = date.getHours();
-  var mm = date.getMinutes();
-  var ss = date.getSeconds();
-  return year + "-" + month + "-" + day + " " + hh + ":" + mm + ":" + ss;
+    var year = date.getFullYear();
+    var month = date.getMonth() + 1;
+    var day = date.getDate();
+    var hh = date.getHours();
+    var mm = date.getMinutes();
+    var ss = date.getSeconds();
+    return year + "-" + month + "-" + day + " " + hh + ":" + mm + ":" + ss;
 }
 
 function addDeleteEventRegistration() {
-  $(".data_delete_action").click(function(event) {
-    var trElement = $(this).parents("tr")[0];
-    var tdElement = $(trElement).children("td.service_template_id")[0];
-    var spanElement = $(tdElement).children("span")[0];
-    var templateId = $(spanElement).text();
-    var inputElement = $(tdElement).children("input")[0];
-    var instanceId = $(inputElement).val();
-    var result = deleteServiceInstance(templateId, instanceId);
-    if(result) {
-      trElement.remove();
-      alert("Service instance deleted successfully!");
-    }
-  });
+    $(".data_delete_action").click(function (event) {
+        var trElement = $(this).parents("tr")[0];
+        var tdElement = $(trElement).children("td.service_template_id")[0];
+        var spanElement = $(tdElement).children("span")[0];
+        var templateId = $(spanElement).text();
+        var inputElement = $(tdElement).children("input")[0];
+        var instanceId = $(inputElement).val();
+        var result = deleteServiceInstance(templateId, instanceId);
+        if (result) {
+            trElement.remove();
+            alert("Service instance deleted successfully!");
+        }
+    });
 }
 
 function deleteServiceInstance(templateId, instanceId) {
     var serviceTemplate = fetchServiceTemplateBy(templateId);
-    if(serviceTemplate === undefined) {
+    if (serviceTemplate === undefined) {
         return;
     }
     var gatewayService = '/openoapi/servicegateway/v1/services';
     var result = false;
-    if(serviceTemplate.csarType === 'GSAR') {
+    if (serviceTemplate.csarType === 'GSAR') {
         result = deleteGsoServiceInstance(gatewayService, instanceId);
-    }else if(serviceTemplate.csarType === 'NSAR' || serviceTemplate.csarType === 'NFAR') {
+    } else if (serviceTemplate.csarType === 'NSAR' || serviceTemplate.csarType === 'NFAR') {
         result = deleteNfvoServiceInstance(gatewayService, instanceId);
-    }else if(serviceTemplate.csarType === 'SSAR') {
+    } else if (serviceTemplate.csarType === 'SSAR') {
         result = deleteSdnoServiceInstance(gatewayService, instanceId);
     }
     return result;
 }
 
 function deleteGsoServiceInstance(gatewayService, instanceId) {
-    var gsoLcmUrl = '/openoapi/lifecyclemgr/v1/services/'+ instanceId;
+    var gsoLcmUrl = '/openoapi/lifecyclemgr/v1/services/' + instanceId;
     var operation = 'DELETE';
     return sendDeleteRequest(operation, gatewayService, gsoLcmUrl);
 }
 
 function deleteNfvoServiceInstance(gatewayService, instanceId) {
     var nfvoNsUrl = '/openoapi/nslcm/v1.0/ns/' + instanceId;
-    var nfvoNsTerminateUrl = nfvoNsUrl +'/terminate';
+    var nfvoNsTerminateUrl = nfvoNsUrl + '/terminate';
     var terminateParameter = {
-      'nsInstanceId': instanceId,
-      'terminationType': "graceful",
-      'gracefulTerminationTimeout': "60",
-      'operation': "POST",
-      'gatewayUri': nfvoNsTerminateUrl
+        'nsInstanceId': instanceId,
+        'terminationType': "graceful",
+        'gracefulTerminationTimeout': "60",
+        'operation': "POST",
+        'gatewayUri': nfvoNsTerminateUrl
     };
     var result = sendRequest(gatewayService, terminateParameter);
-    if(result) {
-      var serviceParameter = {
-          'operation': "DELETE",
-          'gatewayUri': nfvoNsUrl
-      };
-      result = sendRequest(gatewayService, serviceParameter);
+    if (result) {
+        var serviceParameter = {
+            'operation': "DELETE",
+            'gatewayUri': nfvoNsUrl
+        };
+        result = sendRequest(gatewayService, serviceParameter);
     }
     return result;
 }
@@ -424,19 +424,19 @@ function deleteSdnoServiceInstance(gatewayService, instanceId) {
     var sdnoNsUrl = '/openoapi/sdnonslcm/v1.0/ns/' + instanceId;
     var sdnoNsTerminateUrl = sdnoNsUrl + '/terminate';
     var terminateParameter = {
-      'nsInstanceId': instanceId,
-      'terminationType': "graceful",
-      'gracefulTerminationTimeout': "60",
-      'operation': "POST",
-      'gatewayUri': sdnoNsTerminateUrl
+        'nsInstanceId': instanceId,
+        'terminationType': "graceful",
+        'gracefulTerminationTimeout': "60",
+        'operation': "POST",
+        'gatewayUri': sdnoNsTerminateUrl
     };
     var result = sendDeleteRequest(gatewayService, terminateParameter);
-    if(result) {
-      var serviceParameter = {
-        'operation': "DELETE",
-        'gatewayUri': sdnoNsUrl
-      };
-      result = sendDeleteRequest(gatewayService, serviceParameter);
+    if (result) {
+        var serviceParameter = {
+            'operation': "DELETE",
+            'gatewayUri': sdnoNsUrl
+        };
+        result = sendDeleteRequest(gatewayService, serviceParameter);
     }
     return result;
 }
@@ -444,16 +444,16 @@ function deleteSdnoServiceInstance(gatewayService, instanceId) {
 function sendDeleteRequest(gatewayService, parameter) {
     var result = false;
     $.ajax({
-        type : "DELETE",
+        type: "DELETE",
         async: false,
-        url : gatewayService,
-        contentType : "application/json",
-        dataType : "json",
-        data : JSON.stringify(parameter),
-        success : function(jsonResp) {
+        url: gatewayService,
+        contentType: "application/json",
+        dataType: "json",
+        data: JSON.stringify(parameter),
+        success: function (jsonResp) {
             result = true;
         },
-        error : function(xhr, ajaxOptions, thrownError) {
+        error: function (xhr, ajaxOptions, thrownError) {
             alert("Error on page : " + xhr.responseText);
         }
     });
index c27dbf0..680ad11 100644 (file)
  */\r
 \r
 \r
-$(function(){\r
-       $('.creat-btn').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                               \r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('.detail-top ul li').click(function(){\r
-                               $(this).addClass('current').siblings().removeClass('current');\r
-                       });\r
-                       $('.para').click(function(){                            \r
-                               if($('#serviceTemplateName').val() == ''){\r
-                                       alert('Please choose the service templet!');\r
-                                       $('#flavorTab').css('display','none');\r
-                               }else{\r
-                                       $('#flavorTab').css('display','block');\r
-                               }\r
-                               $('#basicTab').css('display','block');\r
-                       });\r
-                       $('.basic').click(function(){\r
-                               $('#flavorTab').css('display','none');\r
-                       });\r
-                       \r
-                       $('.table tbody tr').click(function(){\r
-                               $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
-                       });\r
-                       $('.table tr:odd').addClass('active');\r
-                       $('#false').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('#filterTpLogicalType').click(function(){\r
-                               $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
-                               $('#filterTpLogicalType').toggleClass('openo-focus');\r
-                               var oLeft = $('#open_base_tpL_td6').offset().left;\r
-                       var oTop = $('#open_base_tpL_td6').offset().top;\r
-                       var oHeight = $('#open_base_tpL_td6').height();\r
-                       $('#filterTpLogicalType_select_popupcontainer').css({'left':oLeft,'top':oTop + oHeight + 10});\r
-                       });\r
-                       $('div.openo-select-popup-container>div.openo-select-item>label').click(function(){\r
-                               var Lvalue = $(this).html();\r
-                               $('#filterTpLogicalType_select_input').attr('value',Lvalue);\r
-                               $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
-                               $('#filterTpLogicalType').removeClass('openo-focus');\r
-                       });\r
-                       $.fn.serializeObject = function() {\r
-                               var o = {};\r
-                               var a = this.serializeArray();\r
-                               $.each(a, function() {\r
-                                       if (o[this.name] !== undefined) {\r
-                                               if (!o[this.name].push) {\r
-                                                       o[this.name] = [ o[this.name] ];\r
-                                               }\r
-                                       o[this.name].push(this.value || '');\r
-                                       } else {\r
-                                               o[this.name] = this.value || '';\r
-                                       }\r
-                               });\r
-                       return o;\r
-                       };\r
-       \r
+$(function () {\r
+    $('.creat-btn').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('.detail-top ul li').click(function () {\r
+        $(this).addClass('current').siblings().removeClass('current');\r
+    });\r
+    $('.para').click(function () {\r
+        if ($('#serviceTemplateName').val() == '') {\r
+            alert('Please choose the service templet!');\r
+            $('#flavorTab').css('display', 'none');\r
+        } else {\r
+            $('#flavorTab').css('display', 'block');\r
+        }\r
+        $('#basicTab').css('display', 'block');\r
+    });\r
+    $('.basic').click(function () {\r
+        $('#flavorTab').css('display', 'none');\r
+    });\r
+\r
+    $('.table tbody tr').click(function () {\r
+        $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
+    });\r
+    $('.table tr:odd').addClass('active');\r
+    $('#false').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('#filterTpLogicalType').click(function () {\r
+        $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
+        $('#filterTpLogicalType').toggleClass('openo-focus');\r
+        var oLeft = $('#open_base_tpL_td6').offset().left;\r
+        var oTop = $('#open_base_tpL_td6').offset().top;\r
+        var oHeight = $('#open_base_tpL_td6').height();\r
+        $('#filterTpLogicalType_select_popupcontainer').css({'left': oLeft, 'top': oTop + oHeight + 10});\r
+    });\r
+    $('div.openo-select-popup-container>div.openo-select-item>label').click(function () {\r
+        var Lvalue = $(this).html();\r
+        $('#filterTpLogicalType_select_input').attr('value', Lvalue);\r
+        $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
+        $('#filterTpLogicalType').removeClass('openo-focus');\r
+    });\r
+    $.fn.serializeObject = function () {\r
+        var o = {};\r
+        var a = this.serializeArray();\r
+        $.each(a, function () {\r
+            if (o[this.name] !== undefined) {\r
+                if (!o[this.name].push) {\r
+                    o[this.name] = [o[this.name]];\r
+                }\r
+                o[this.name].push(this.value || '');\r
+            } else {\r
+                o[this.name] = this.value || '';\r
+            }\r
+        });\r
+        return o;\r
+    };\r
+\r
 })
\ No newline at end of file
index 0450f7e..78a3d4c 100644 (file)
  */
 
 var vm = avalon.define({
-    $id : "tmNodesController",
-    instanceId : "",
+    $id: "tmNodesController",
+    instanceId: "",
     $language: {
         "sProcessing": "<img src='../component/thirdparty/data-tables/images/loading-spinner-grey.gif'/><span>&nbsp;&nbsp;"
-        +$.i18n.prop("nfv-nso-iui-table-sProcess")+"</span>",
+        + $.i18n.prop("nfv-nso-iui-table-sProcess") + "</span>",
         "sLengthMenu": $.i18n.prop("nfv-nso-iui-table-sLengthMenu"),
         "sZeroRecords": $.i18n.prop("nfv-nso-iui-table-sZeroRecords"),
         "sInfo": "<span class='seperator'>  </span>" + $.i18n.prop("nfv-nso-iui-table-sInfo"),
         "sInfoEmpty": $.i18n.prop("nfv-nso-iui-table-sInfoEmpty"),
         "sGroupActions": $.i18n.prop("nfv-nso-iui-table-sGroupActions"),
-        "sAjaxRequestGeneralError":$.i18n.prop("nfv-nso-iui-table-sAjaxRequestGeneralError"),
+        "sAjaxRequestGeneralError": $.i18n.prop("nfv-nso-iui-table-sAjaxRequestGeneralError"),
         "sEmptyTable": $.i18n.prop("nfv-nso-iui-table-sEmptyTable"),
         "oPaginate": {
             "sPrevious": $.i18n.prop("nfv-nso-iui-table-sPrevious"),
@@ -34,23 +34,23 @@ var vm = avalon.define({
             "sPageOf": $.i18n.prop("nfv-nso-iui-table-sPageOf")
         }
     },
-    $restUrl : {
-        queryNodeInstanceUrl : "/openoapi/nslcm/v1.0/ns/"
+    $restUrl: {
+        queryNodeInstanceUrl: "/openoapi/nslcm/v1.0/ns/"
     },
-    $init : function() {
+    $init: function () {
         vm.$initInstanceData();
     },
-    $initInstanceData : function() {
+    $initInstanceData: function () {
         $.ajax({
-            type : "GET",
-            url : vm.$restUrl.queryNodeInstanceUrl,
-            success : function(resp) {
-                if(resp) {
+            type: "GET",
+            url: vm.$restUrl.queryNodeInstanceUrl,
+            success: function (resp) {
+                if (resp) {
                     vm.servicesInstanceData = [
-                       resp.nsName,
-                       resp.description,
-                       resp.nsdId,
-                       resp.nsState
+                        resp.nsName,
+                        resp.description,
+                        resp.nsdId,
+                        resp.nsState
                     ];
                     var tableData = [
                         [resp.vnfInfoId, 'vnf'],
@@ -62,34 +62,34 @@ var vm = avalon.define({
                     vm.nodesList.$initNodesTable();
                 }
             },
-            error : function() {
+            error: function () {
                 commonUtil.showMessage($.i18n.prop("nfv-topology-iui-message-error"), "danger");
             }
         });
     },
     servicesInstanceData: [],
-    $nodesTabId : "ict_nodes_template_table",
-    $nodesInstanceTabFields : {// table columns
+    $nodesTabId: "ict_nodes_template_table",
+    $nodesInstanceTabFields: {// table columns
         table: [
-            {"mData": "serviceInstanceId", name: "ID","bVisible": false},
-            {"mData": "", name: "","sClass": 'details-control'},
+            {"mData": "serviceInstanceId", name: "ID", "bVisible": false},
+            {"mData": "", name: "", "sClass": 'details-control'},
             {"mData": "serviceName", name: "Service Name"},
             {"mData": "serviceDescription", name: "Service Description"},
             {"mData": "nsdId", name: "NSD ID"},
-            {"mData":"status", name: "Status"}
+            {"mData": "status", name: "Status"}
         ]
     },
-    $initNfvNodesTab: function() {
+    $initNfvNodesTab: function () {
         var setting = {};
         setting.language = vm.$language;
         setting.paginate = true;
         setting.info = true;
         setting.columns = vm.$nodesInstanceTabFields.table;
         setting.tableId = vm.$nodesTabId;
-        vm.$initDataTable(setting,vm.$nodesTabId + '_div', vm.servicesInstanceData);
+        vm.$initDataTable(setting, vm.$nodesTabId + '_div', vm.servicesInstanceData);
         $('#' + vm.$nodesTabId + '>tbody').on("click", 'td.details-control', function () {
             var tr = $(this).closest('tr');
-            var table =  $('#' + vm.$nodesTabId).dataTable();
+            var table = $('#' + vm.$nodesTabId).dataTable();
             if (table.fnIsOpen(tr[0])) {
                 table.fnClose(tr[0]);
                 tr.removeClass('shown');
@@ -101,23 +101,23 @@ var vm = avalon.define({
         });
     },
 
-    $initDataTable : function( setting, divId, tableData) {
+    $initDataTable: function (setting, divId, tableData) {
         //transform colomn
         var column = setting.columns;
         //empty table
-        $('#'+ divId).children().remove();
+        $('#' + divId).children().remove();
         var tableId = setting.tableId;
-        var tableEleStr = '<table class="table table-striped table-bordered table-hover" id= '+ tableId + '>'
+        var tableEleStr = '<table class="table table-striped table-bordered table-hover" id= ' + tableId + '>'
             + '<thead>'
-            +'<tr role="row" class="heading" >'
+            + '<tr role="row" class="heading" >'
             + '</tr>'
             + '</thead>'
-            +'<tbody>'
-            +'</tbody>'
-            +'</table>';
-        $('#'+ divId).append(tableEleStr);
-        var trEle = $('#'+ tableId  + ' > thead >tr');
-        for ( var one in column){
+            + '<tbody>'
+            + '</tbody>'
+            + '</table>';
+        $('#' + divId).append(tableEleStr);
+        var trEle = $('#' + tableId + ' > thead >tr');
+        for (var one in column) {
             var th = '<th>' + column[one].name + '</th>';
             trEle.append(th);
         }
@@ -126,7 +126,7 @@ var vm = avalon.define({
             "oLanguage": setting.language,//language
             "bPaginate": setting.paginate,// page button
             "bFilter": false,// search bar
-            "bAutoWidth":true,//automatically set colum width
+            "bAutoWidth": true,//automatically set colum width
             "bLengthChange": true,// record number in each row
             "iDisplayLength": 10,// row number in each page
             "bSort": setting.sort ? true : false,// sort
@@ -140,45 +140,51 @@ var vm = avalon.define({
             "bSortCellsTop": true,
             "aoColumns": setting.columns,
             "aoColumnDefs": [
-                        {
-                            sDefaultContent: '',
-                            aTargets: [ '_all' ]
-                        }
+                {
+                    sDefaultContent: '',
+                    aTargets: ['_all']
+                }
             ],
             "aaData": tableData
         });
     };
 
-    //nodes list table
-    nodesList :{
-        nodesData: [],
-        $nodesTabDataId : "ict_nodes_table",
-        $nodesTabFields : {// table columns
-            table: [
-                {"mData": "id", name: "ID", "bVisible": false},
-                {"mData": "instanceId", name: "Instance Id"},
-                {"mData": "nodeType", name: "Node Type"}
-            ]
-        },
-        $initNodesTable: function () {
-            var setting = {};
-            setting.language = vm.$language;
-            setting.paginate = true;
-            setting.info = true;
-            setting.columns = vm.nodesList.$nodesTabFields.table;
-            setting.tableId = vm.nodesList.$nodesTabDataId;
-            vm.$initDataTable(setting,vm.nodesList.$nodesTabDataId + '_div', vm.nodesList.nodesData);
-        }
+//nodes list table
+nodesList :{
+    nodesData: [],
+        $nodesTabDataId
+:
+    "ict_nodes_table",
+        $nodesTabFields
+:
+    {// table columns
+        table: [
+            {"mData": "id", name: "ID", "bVisible": false},
+            {"mData": "instanceId", name: "Instance Id"},
+            {"mData": "nodeType", name: "Node Type"}
+        ]
+    }
+,
+    $initNodesTable: function () {
+        var setting = {};
+        setting.language = vm.$language;
+        setting.paginate = true;
+        setting.info = true;
+        setting.columns = vm.nodesList.$nodesTabFields.table;
+        setting.tableId = vm.nodesList.$nodesTabDataId;
+        vm.$initDataTable(setting, vm.nodesList.$nodesTabDataId + '_div', vm.nodesList.nodesData);
     }
-});
+}
+})
+;
 
-var initParam = function() {
+var initParam = function () {
     var paramStr = window.location.search.substring(1);
-    if(paramStr.length > 0) {
+    if (paramStr.length > 0) {
         avalon.scan();
         var params = paramStr.split("&");
         var instanceId = params[0].substring(params[0].indexOf('=') + 1);
-        
+
         vm.instanceId = instanceId;
         vm.$restUrl.queryNodeInstanceUrl = commonUtil.format(vm.$restUrl.queryNodeInstanceUrl, instanceId);
         vm.$init();
index 4d79050..80a6505 100644 (file)
  */
 
 var vm = avalon.define({
-    $id : "tmTopoController",
-    templateId : "",
+    $id: "tmTopoController",
+    templateId: "",
     nodesData: [],
     $language: {
         "sProcessing": "<img src='../component/thirdparty/data-tables/images/loading-spinner-grey.gif'/><span>&nbsp;&nbsp;"
-        +$.i18n.prop("nfv-nso-iui-table-sProcess")+"</span>",
+        + $.i18n.prop("nfv-nso-iui-table-sProcess") + "</span>",
         "sLengthMenu": $.i18n.prop("nfv-nso-iui-table-sLengthMenu"),
         "sZeroRecords": $.i18n.prop("nfv-nso-iui-table-sZeroRecords"),
         "sInfo": "<span class='seperator'>  </span>" + $.i18n.prop("nfv-nso-iui-table-sInfo"),
         "sInfoEmpty": $.i18n.prop("nfv-nso-iui-table-sInfoEmpty"),
         "sGroupActions": $.i18n.prop("nfv-nso-iui-table-sGroupActions"),
-        "sAjaxRequestGeneralError":$.i18n.prop("nfv-nso-iui-table-sAjaxRequestGeneralError"),
+        "sAjaxRequestGeneralError": $.i18n.prop("nfv-nso-iui-table-sAjaxRequestGeneralError"),
         "sEmptyTable": $.i18n.prop("nfv-nso-iui-table-sEmptyTable"),
         "oPaginate": {
             "sPrevious": $.i18n.prop("nfv-nso-iui-table-sPrevious"),
@@ -35,41 +35,41 @@ var vm = avalon.define({
             "sPageOf": $.i18n.prop("nfv-nso-iui-table-sPageOf")
         }
     },
-    $restUrl : {
-        queryNodeTemplateUrl : "/openoapi/catalog/v1/servicetemplates/{0}/nodetemplates",
-        queryTemplateInfoUrl : "/openoapi/catalog/v1/servicetemplates"
+    $restUrl: {
+        queryNodeTemplateUrl: "/openoapi/catalog/v1/servicetemplates/{0}/nodetemplates",
+        queryTemplateInfoUrl: "/openoapi/catalog/v1/servicetemplates"
     },
-    $init : function() {
+    $init: function () {
         vm.$initTemplateData();
         vm.$initTopoNodesData();
     },
-    $initTemplateData : function() {
+    $initTemplateData: function () {
         $.ajax({
-            type : "GET",
-            url : vm.$restUrl.queryTemplateInfoUrl,
-            success : function(resp) {
-                if(resp) {
+            type: "GET",
+            url: vm.$restUrl.queryTemplateInfoUrl,
+            success: function (resp) {
+                if (resp) {
                     vm.servicesTemplateData = [];
-                    for(var i=0; i<resp.length; i++) {
+                    for (var i = 0; i < resp.length; i++) {
                         //generate node table display data
                         vm.servicesTemplateData.push(resp[i]);
                     }
                     //vm.$initNfvNodesTab();
                 }
             },
-            error : function() {
+            error: function () {
                 commonUtil.showMessage($.i18n.prop("nfv-topology-iui-message-error"), "danger");
             }
         });
     },
-    $initTopoNodesData : function() {
+    $initTopoNodesData: function () {
         $.ajax({
-            type : "GET",
-            url : vm.$restUrl.queryNodeTemplateUrl,
-            success : function(resp) {
-                if(resp) {
+            type: "GET",
+            url: vm.$restUrl.queryNodeTemplateUrl,
+            success: function (resp) {
+                if (resp) {
                     vm.nodesDetail.nodesTemplateDetailData = [];
-                    for(var i=0; i<resp.length; i++) {
+                    for (var i = 0; i < resp.length; i++) {
                         //generate node table display data
                         var nodeTemplate = topoUtil.generateNodeTemplate(resp[i]);
                         vm.nodesData.push(nodeTemplate);
@@ -81,58 +81,62 @@ var vm = avalon.define({
                     topoUtil.initTopoData(vm.topologyTab.topoTemplateData.$model);
                 }
             },
-            error : function() {
+            error: function () {
                 commonUtil.showMessage($.i18n.prop("nfv-topology-iui-message-error"), "danger");
             }
         });
     },
-    topologyTab : {
-        topology : "topology.html",
-        vnfTip : $.i18n.prop("nfv-topology-iui-vnf-tip"),
-        btnTip : $.i18n.prop("nfv-topology-iui-btn-return-tip"),
-        topoTemplateData:[],
-        boxTopoDatas:[],
-        networkTopoDatas:[],
+    topologyTab: {
+        topology: "topology.html",
+        vnfTip: $.i18n.prop("nfv-topology-iui-vnf-tip"),
+        btnTip: $.i18n.prop("nfv-topology-iui-btn-return-tip"),
+        topoTemplateData: [],
+        boxTopoDatas: [],
+        networkTopoDatas: [],
         isShowNum: false,
-        returnBtnVisible : false,
-        $getColor: function(index) {
+        returnBtnVisible: false,
+        $getColor: function (index) {
             return topoUtil.getColor(index);
         },
-        $getCidr: function(properties){
+        $getCidr: function (properties) {
             return topoUtil.getCidr(properties);
         },
-        $getCpTop: function(index, parentBoxId){
+        $getCpTop: function (index, parentBoxId) {
             return topoUtil.getCpTop(index, parentBoxId);
         },
-        $initTopology : function() {
+        $initTopology: function () {
             topoUtil.initTopoData(vm.topologyTab.topoTemplateData.$model);
         },
-        $showTopo:function(id, name){
+        $showTopo: function (id, name) {
             vm.nodesDetail.$showDetails("block", id, name);
         },
-        $showVnfTopo: function(templateId) {
+        $showVnfTopo: function (templateId) {
             vm.topologyTab.returnBtnVisible = true;
             vm.$restUrl.queryNodeTemplateUrl = "/openoapi/catalog/v1/servicetemplates/" + templateId + "/nodetemplates";
             vm.$init();
         },
-        $returnNS: function() {
+        $returnNS: function () {
             vm.topologyTab.returnBtnVisible = false;
             vm.$restUrl.queryNodeTemplateUrl = "/openoapi/catalog/v1/servicetemplates/" + vm.templateId + "/nodetemplates";
             vm.$init();
         }
     },
     //Nodes Details
-    nodesDetail : {
+    nodesDetail: {
         nodesTemplateDetailData: [],
-        detailTitle : "",
-        isShow : "none",
-        detailIndex : 0,
-        detailData : [
+        detailTitle: "",
+        isShow: "none",
+        detailIndex: 0,
+        detailData: [
             {id: "general", name: $.i18n.prop("nfv-templateDetail-nodesTab-iui-tab-general"), isActive: true},
             {id: "properties", name: $.i18n.prop("nfv-templateDetail-nodesTab-iui-tab-properties"), isActive: false},
-            {id: "relationShips", name: $.i18n.prop("nfv-templateDetail-nodesTab-iui-tab-relationShips"), isActive: false}
+            {
+                id: "relationShips",
+                name: $.i18n.prop("nfv-templateDetail-nodesTab-iui-tab-relationShips"),
+                isActive: false
+            }
         ],
-        $showDetails : function(isShow, nodetypeid, nodetypename) {
+        $showDetails: function (isShow, nodetypeid, nodetypename) {
             vm.nodesDetail.isShow = isShow;
             if (isShow == "block") {
                 vm.nodesDetail.detailTitle = nodetypename + " " + $.i18n.prop("nfv-templateDetail-nodesTab-iui-title-nodeDetail"),
@@ -141,32 +145,48 @@ var vm = avalon.define({
                 vm.nodesDetail.$initNodeDetailTable(nodetypeid);
             }
         },
-        detailCondChange : function(index) {
+        detailCondChange: function (index) {
             vm.nodesDetail.detailIndex = index;
-            for(var i=0; i<vm.nodesDetail.detailData.length; i++) {
+            for (var i = 0; i < vm.nodesDetail.detailData.length; i++) {
                 vm.nodesDetail.detailData[i].isActive = false;
             }
             vm.nodesDetail.detailData[index].isActive = true;
         },
-        $tableFields : {// table columns
+        $tableFields: {// table columns
             general: [
-                {"mData": "key", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-key"), "bSortable" : false},
-                {"mData": "value", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-value"), "bSortable" : false}
+                {"mData": "key", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-key"), "bSortable": false},
+                {
+                    "mData": "value",
+                    "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-value"),
+                    "bSortable": false
+                }
             ],
             properties: [
-                {"mData": "key", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-key"), "bSortable" : false},
-                {"mData": "value", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-value"), "bSortable" : false}
+                {"mData": "key", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-key"), "bSortable": false},
+                {
+                    "mData": "value",
+                    "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-value"),
+                    "bSortable": false
+                }
             ],
             relationShips: [
-                {"mData": "sourceNodeName", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-sourceNodeName"), "bSortable" : false},
-                {"mData": "targetNodeName", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-targetNodeName"), "bSortable" : false},
-                {"mData": "type", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-type"), "bSortable" : false}
+                {
+                    "mData": "sourceNodeName",
+                    "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-sourceNodeName"),
+                    "bSortable": false
+                },
+                {
+                    "mData": "targetNodeName",
+                    "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-targetNodeName"),
+                    "bSortable": false
+                },
+                {"mData": "type", "name": $.i18n.prop("nfv-templateDetail-nodesTab-iui-field-type"), "bSortable": false}
             ]
         },
-        $initNodeDetailTable: function(nodetemplateid) {
+        $initNodeDetailTable: function (nodetemplateid) {
             var data = topoUtil.getCurrentDetailData(vm.nodesDetail.nodesTemplateDetailData.$model, nodetemplateid);
             //initialize three tables of nodedetail
-            $.each(vm.nodesDetail.$tableFields, function(key, value){
+            $.each(vm.nodesDetail.$tableFields, function (key, value) {
                 var setting = {};
                 setting.language = vm.$language;
                 setting.paginate = false;
@@ -179,22 +199,22 @@ var vm = avalon.define({
     },
 });
 
-var initParam = function() { //initialize template detail params
+var initParam = function () { //initialize template detail params
     var paramStr = window.location.search.substring(1);
-    if(paramStr.length > 0) {
+    if (paramStr.length > 0) {
         avalon.scan();
         var params = paramStr.split("&");
         var instanceId = params[0].substring(params[0].indexOf('=') + 1);
-        var templateQueryUrl = '/openoapi/nslcm/v1.0/ns/' + instanceId; 
+        var templateQueryUrl = '/openoapi/nslcm/v1.0/ns/' + instanceId;
         $.ajax({
-            type : "GET",
-            url : templateQueryUrl,
-            contentType : "application/json",
-            dataType : "json",
-            success : function(jsonResp) {
+            type: "GET",
+            url: templateQueryUrl,
+            contentType: "application/json",
+            dataType: "json",
+            success: function (jsonResp) {
                 initTopo(jsonResp.nsdId)
             },
-            error : function(xhr, ajaxOptions, thrownError) {
+            error: function (xhr, ajaxOptions, thrownError) {
                 alert("Error on page : " + xhr.responseText);
             }
         });
index fbdcbd1..615c8c0 100644 (file)
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
  */\r
\r
+\r
 var edgeColors = {\r
-       red : "#f00",\r
-       green: "#0f0",\r
-  blue: "#00f",\r
-  yellow: "#ff0",\r
-  grey: "#ddd",\r
-  black: "#000"\r
+    red: "#f00",\r
+    green: "#0f0",\r
+    blue: "#00f",\r
+    yellow: "#ff0",\r
+    grey: "#ddd",\r
+    black: "#000"\r
 }\r
 \r
 function Edge(id, label, source, target, size, color) {\r
-       this.id = id;\r
-       this.label = label;\r
-       this.source = source;\r
-       this.target = target;\r
-       this.type = 'line';\r
-  this.size = size;\r
-       this.color = edgeColors[color];\r
+    this.id = id;\r
+    this.label = label;\r
+    this.source = source;\r
+    this.target = target;\r
+    this.type = 'line';\r
+    this.size = size;\r
+    this.color = edgeColors[color];\r
 }\r
index 340947f..12d01f9 100644 (file)
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
  */\r
\r
+\r
 var icon = {\r
-       type1 : "js/topo/img/NEUP.png",\r
-       type2 : "js/topo/img/NETWORK.png",\r
-       type3 : "js/topo/img/site.png"\r
+    type1: "js/topo/img/NEUP.png",\r
+    type2: "js/topo/img/NETWORK.png",\r
+    type3: "js/topo/img/site.png"\r
 }\r
 function Node(id, label, size, type, x, y) {\r
-       this.id = id;\r
-       this.label = label;\r
-       this.type = "square";\r
-       this.x = x;\r
-       this.y = y;\r
-       this.size = size;\r
-       this.color = "white";\r
-       this.borderColor = "white";\r
-       this.image = {\r
-               url : icon[type],\r
-               scale : 1.0,\r
-               clip : 1.0\r
-       };\r
+    this.id = id;\r
+    this.label = label;\r
+    this.type = "square";\r
+    this.x = x;\r
+    this.y = y;\r
+    this.size = size;\r
+    this.color = "white";\r
+    this.borderColor = "white";\r
+    this.image = {\r
+        url: icon[type],\r
+        scale: 1.0,\r
+        clip: 1.0\r
+    };\r
 }\r
index d8d27df..0505994 100644 (file)
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
  */\r
\r
+\r
 function Topology(containerId) {\r
 \r
-       /**\r
-        * IMPORTANT: This only works with the canvas renderer. TBD in the future\r
-        * will also support the WebGL renderer.\r
-        */\r
-       sigma.utils.pkg('sigma.canvas.nodes');\r
-\r
-       this.s = new sigma({\r
-               graph : {\r
-                       nodes : [],\r
-                       edges : []\r
-               },\r
-               renderer : {\r
-                       // IMPORTANT:\r
-                       // This works only with the canvas renderer, so the\r
-                       // renderer type set as "canvas" is necessary here.\r
-                       container : document.getElementById(containerId),\r
-                       type : 'canvas'\r
-               },\r
-               settings : {\r
-                       minNodeSize : 4,\r
-                       maxNodeSize : 48,\r
-                       edgeLabelSize : 'proportional'\r
-               }\r
-       });\r
-       this.addNode = addNode;\r
-       this.addEdge = addEdge;\r
+    /**\r
+     * IMPORTANT: This only works with the canvas renderer. TBD in the future\r
+     * will also support the WebGL renderer.\r
+     */\r
+    sigma.utils.pkg('sigma.canvas.nodes');\r
+\r
+    this.s = new sigma({\r
+        graph: {\r
+            nodes: [],\r
+            edges: []\r
+        },\r
+        renderer: {\r
+            // IMPORTANT:\r
+            // This works only with the canvas renderer, so the\r
+            // renderer type set as "canvas" is necessary here.\r
+            container: document.getElementById(containerId),\r
+            type: 'canvas'\r
+        },\r
+        settings: {\r
+            minNodeSize: 4,\r
+            maxNodeSize: 48,\r
+            edgeLabelSize: 'proportional'\r
+        }\r
+    });\r
+    this.addNode = addNode;\r
+    this.addEdge = addEdge;\r
 }\r
 \r
 function addNode(node) {\r
 \r
-       this.s.graph.addNode(node);\r
+    this.s.graph.addNode(node);\r
 \r
 }\r
 \r
 function addEdge(edge) {\r
-       this.s.graph.addEdge(edge);\r
+    this.s.graph.addEdge(edge);\r
 }\r
 \r
 function init() {\r
 \r
-       var node1 = new Node("1", "ThinCPE", 8, "type1", 0.2, 0.5);\r
-  var node2 = new Node("2", "vCPE", 8, "type1", 0.5, 0.5);\r
-       var node3 = new Node("3", "VPC", 16, "type2", 0.8, 0.5);\r
-  \r
-  var node4 = new Node("4", "Site", 16, "type3", 0.2, 0.55);\r
-  var node5 = new Node("5", "POP", 24, "type3", 0.5, 0.55);\r
-       var node6 = new Node("6", "DC", 32, "type3", 0.8, 0.55);\r
-  \r
-  var node7 = new Node("7", "vFW", 6, "type1", 0.45, 0.45);\r
-  var node8 = new Node("8", "vLB", 6, "type1", 0.55, 0.45);\r
-\r
-       var edge1 = new Edge("e1", "VxLAN", "1", "2", 0.5, "blue");\r
-       var edge2 = new Edge("e2", "IPSec", "2", "3", 0.5, "green");\r
-  \r
-       var edge3 = new Edge("e3", "in", "1", "4", 0.5, "grey");\r
-  var edge4 = new Edge("e4", "in", "2", "5", 0.5, "grey");\r
-  var edge5 = new Edge("e5", "in", "3", "6", 0.5, "grey");\r
-  \r
-  var edge6 = new Edge("e6", "L2VPN", "4", "5", 0.5, "black");\r
-  var edge7 = new Edge("e7", "L3VPN", "5", "6", 0.5, "black");\r
-  \r
-  var edge8 = new Edge("e8", "", "2", "7", 0.5, "yellow");\r
-  var edge9 = new Edge("e9", "", "7", "8", 0.5, "yellow");\r
-  var edge10 = new Edge("e10", "", "8", "2", 0.5, "yellow");\r
-  \r
-       var topology = new Topology("container");\r
-  \r
-       topology.addNode(node1);\r
-       topology.addNode(node2);\r
-       topology.addNode(node3);\r
-  topology.addNode(node4);\r
-       topology.addNode(node5);\r
-       topology.addNode(node6);\r
-  topology.addNode(node7);\r
-       topology.addNode(node8);\r
-\r
-       topology.addEdge(edge1);\r
-       topology.addEdge(edge2);\r
-  topology.addEdge(edge3);\r
-  topology.addEdge(edge4);\r
-       topology.addEdge(edge5);\r
-  \r
-  \r
-  topology.addEdge(edge6);\r
-       topology.addEdge(edge7);\r
-  topology.addEdge(edge8);\r
-       topology.addEdge(edge9);\r
-  topology.addEdge(edge10);\r
-  \r
-       CustomShapes.init(topology.s);\r
-       topology.s.refresh();\r
+    var node1 = new Node("1", "ThinCPE", 8, "type1", 0.2, 0.5);\r
+    var node2 = new Node("2", "vCPE", 8, "type1", 0.5, 0.5);\r
+    var node3 = new Node("3", "VPC", 16, "type2", 0.8, 0.5);\r
+\r
+    var node4 = new Node("4", "Site", 16, "type3", 0.2, 0.55);\r
+    var node5 = new Node("5", "POP", 24, "type3", 0.5, 0.55);\r
+    var node6 = new Node("6", "DC", 32, "type3", 0.8, 0.55);\r
+\r
+    var node7 = new Node("7", "vFW", 6, "type1", 0.45, 0.45);\r
+    var node8 = new Node("8", "vLB", 6, "type1", 0.55, 0.45);\r
+\r
+    var edge1 = new Edge("e1", "VxLAN", "1", "2", 0.5, "blue");\r
+    var edge2 = new Edge("e2", "IPSec", "2", "3", 0.5, "green");\r
+\r
+    var edge3 = new Edge("e3", "in", "1", "4", 0.5, "grey");\r
+    var edge4 = new Edge("e4", "in", "2", "5", 0.5, "grey");\r
+    var edge5 = new Edge("e5", "in", "3", "6", 0.5, "grey");\r
+\r
+    var edge6 = new Edge("e6", "L2VPN", "4", "5", 0.5, "black");\r
+    var edge7 = new Edge("e7", "L3VPN", "5", "6", 0.5, "black");\r
+\r
+    var edge8 = new Edge("e8", "", "2", "7", 0.5, "yellow");\r
+    var edge9 = new Edge("e9", "", "7", "8", 0.5, "yellow");\r
+    var edge10 = new Edge("e10", "", "8", "2", 0.5, "yellow");\r
+\r
+    var topology = new Topology("container");\r
+\r
+    topology.addNode(node1);\r
+    topology.addNode(node2);\r
+    topology.addNode(node3);\r
+    topology.addNode(node4);\r
+    topology.addNode(node5);\r
+    topology.addNode(node6);\r
+    topology.addNode(node7);\r
+    topology.addNode(node8);\r
+\r
+    topology.addEdge(edge1);\r
+    topology.addEdge(edge2);\r
+    topology.addEdge(edge3);\r
+    topology.addEdge(edge4);\r
+    topology.addEdge(edge5);\r
+\r
+\r
+    topology.addEdge(edge6);\r
+    topology.addEdge(edge7);\r
+    topology.addEdge(edge8);\r
+    topology.addEdge(edge9);\r
+    topology.addEdge(edge10);\r
+\r
+    CustomShapes.init(topology.s);\r
+    topology.s.refresh();\r
 }\r
 \r
-$(document).ready(function() {\r
-       init();\r
+$(document).ready(function () {\r
+    init();\r
 });
\ No newline at end of file
index 08381e6..a4ea76e 100644 (file)
-;(function(undefined) {
-  'use strict';
-
-  var __instances = {};
-
-  /**
-   * This is the sigma instances constructor. One instance of sigma represent
-   * one graph. It is possible to represent this grapĥ with several renderers
-   * at the same time. By default, the default renderer (WebGL + Canvas
-   * polyfill) will be used as the only renderer, with the container specified
-   * in the configuration.
-   *
-   * @param  {?*}    conf The configuration of the instance. There are a lot of
-   *                      different recognized forms to instantiate sigma, check
-   *                      example files, documentation in this file and unit
-   *                      tests to know more.
-   * @return {sigma}      The fresh new sigma instance.
-   *
-   * Instanciating sigma:
-   * ********************
-   * If no parameter is given to the constructor, the instance will be created
-   * without any renderer or camera. It will just instantiate the graph, and
-   * other modules will have to be instantiated through the public methods,
-   * like "addRenderer" etc:
-   *
-   *  > s0 = new sigma();
-   *  > s0.addRenderer({
+;(function (undefined) {
+    'use strict';
+
+    var __instances = {};
+
+    /**
+     * This is the sigma instances constructor. One instance of sigma represent
+     * one graph. It is possible to represent this grapĥ with several renderers
+     * at the same time. By default, the default renderer (WebGL + Canvas
+     * polyfill) will be used as the only renderer, with the container specified
+     * in the configuration.
+     *
+     * @param  {?*}    conf The configuration of the instance. There are a lot of
+     *                      different recognized forms to instantiate sigma, check
+     *                      example files, documentation in this file and unit
+     *                      tests to know more.
+     * @return {sigma}      The fresh new sigma instance.
+     *
+     * Instanciating sigma:
+     * ********************
+     * If no parameter is given to the constructor, the instance will be created
+     * without any renderer or camera. It will just instantiate the graph, and
+     * other modules will have to be instantiated through the public methods,
+     * like "addRenderer" etc:
+     *
+     *  > s0 = new sigma();
+     *  > s0.addRenderer({
    *  >   type: 'canvas',
    *  >   container: 'my-container-id'
    *  > });
-   *
-   * In most of the cases, sigma will simply be used with the default renderer.
-   * Then, since the only required parameter is the DOM container, there are
-   * some simpler way to call the constructor. The four following calls do the
-   * exact same things:
-   *
-   *  > s1 = new sigma('my-container-id');
-   *  > s2 = new sigma(document.getElementById('my-container-id'));
-   *  > s3 = new sigma({
+     *
+     * In most of the cases, sigma will simply be used with the default renderer.
+     * Then, since the only required parameter is the DOM container, there are
+     * some simpler way to call the constructor. The four following calls do the
+     * exact same things:
+     *
+     *  > s1 = new sigma('my-container-id');
+     *  > s2 = new sigma(document.getElementById('my-container-id'));
+     *  > s3 = new sigma({
    *  >   container: document.getElementById('my-container-id')
    *  > });
-   *  > s4 = new sigma({
+     *  > s4 = new sigma({
    *  >   renderers: [{
    *  >     container: document.getElementById('my-container-id')
    *  >   }]
    *  > });
-   *
-   * Recognized parameters:
-   * **********************
-   * Here is the exhaustive list of every accepted parameters, when calling the
-   * constructor with to top level configuration object (fourth case in the
-   * previous examples):
-   *
-   *   {?string} id        The id of the instance. It will be generated
-   *                       automatically if not specified.
-   *   {?array}  renderers An array containing objects describing renderers.
-   *   {?object} graph     An object containing an array of nodes and an array
-   *                       of edges, to avoid having to add them by hand later.
-   *   {?object} settings  An object containing instance specific settings that
-   *                       will override the default ones defined in the object
-   *                       sigma.settings.
-   */
-  var sigma = function(conf) {
-    // Local variables:
-    // ****************
-    var i,
-        l,
-        a,
-        c,
-        o,
-        id;
-
-    sigma.classes.dispatcher.extend(this);
-
-    // Private attributes:
-    // *******************
-    var _self = this,
-        _conf = conf || {};
-
-    // Little shortcut:
-    // ****************
-    // The configuration is supposed to have a list of the configuration
-    // objects for each renderer.
-    //  - If there are no configuration at all, then nothing is done.
-    //  - If there are no renderer list, the given configuration object will be
-    //    considered as describing the first and only renderer.
-    //  - If there are no renderer list nor "container" object, it will be
-    //    considered as the container itself (a DOM element).
-    //  - If the argument passed to sigma() is a string, it will be considered
-    //    as the ID of the DOM container.
-    if (
-      typeof _conf === 'string' ||
-      _conf instanceof HTMLElement
-    )
-      _conf = {
-        renderers: [_conf]
-      };
-    else if (Object.prototype.toString.call(_conf) === '[object Array]')
-      _conf = {
-        renderers: _conf
-      };
-
-    // Also check "renderer" and "container" keys:
-    o = _conf.renderers || _conf.renderer || _conf.container;
-    if (!_conf.renderers || _conf.renderers.length === 0)
-      if (
-        typeof o === 'string' ||
-        o instanceof HTMLElement ||
-        (typeof o === 'object' && 'container' in o)
-      )
-        _conf.renderers = [o];
-
-    // Recense the instance:
-    if (_conf.id) {
-      if (__instances[_conf.id])
-        throw 'sigma: Instance "' + _conf.id + '" already exists.';
-      Object.defineProperty(this, 'id', {
-        value: _conf.id
-      });
-    } else {
-      id = 0;
-      while (__instances[id])
-        id++;
-      Object.defineProperty(this, 'id', {
-        value: '' + id
-      });
-    }
-    __instances[this.id] = this;
-
-    // Initialize settings function:
-    this.settings = new sigma.classes.configurable(
-      sigma.settings,
-      _conf.settings || {}
-    );
-
-    // Initialize locked attributes:
-    Object.defineProperty(this, 'graph', {
-      value: new sigma.classes.graph(this.settings),
-      configurable: true
-    });
-    Object.defineProperty(this, 'middlewares', {
-      value: [],
-      configurable: true
-    });
-    Object.defineProperty(this, 'cameras', {
-      value: {},
-      configurable: true
-    });
-    Object.defineProperty(this, 'renderers', {
-      value: {},
-      configurable: true
-    });
-    Object.defineProperty(this, 'renderersPerCamera', {
-      value: {},
-      configurable: true
-    });
-    Object.defineProperty(this, 'cameraFrames', {
-      value: {},
-      configurable: true
-    });
-    Object.defineProperty(this, 'camera', {
-      get: function() {
-        return this.cameras[0];
-      }
-    });
-    Object.defineProperty(this, 'events', {
-      value: [
-        'click',
-        'rightClick',
-        'clickStage',
-        'doubleClickStage',
-        'rightClickStage',
-        'clickNode',
-        'clickNodes',
-        'doubleClickNode',
-        'doubleClickNodes',
-        'rightClickNode',
-        'rightClickNodes',
-        'overNode',
-        'overNodes',
-        'outNode',
-        'outNodes',
-        'downNode',
-        'downNodes',
-        'upNode',
-        'upNodes'
-      ],
-      configurable: true
-    });
+     *
+     * Recognized parameters:
+     * **********************
+     * Here is the exhaustive list of every accepted parameters, when calling the
+     * constructor with to top level configuration object (fourth case in the
+     * previous examples):
+     *
+     *   {?string} id        The id of the instance. It will be generated
+     *                       automatically if not specified.
+     *   {?array}  renderers An array containing objects describing renderers.
+     *   {?object} graph     An object containing an array of nodes and an array
+     *                       of edges, to avoid having to add them by hand later.
+     *   {?object} settings  An object containing instance specific settings that
+     *                       will override the default ones defined in the object
+     *                       sigma.settings.
+     */
+    var sigma = function (conf) {
+        // Local variables:
+        // ****************
+        var i,
+            l,
+            a,
+            c,
+            o,
+            id;
+
+        sigma.classes.dispatcher.extend(this);
+
+        // Private attributes:
+        // *******************
+        var _self = this,
+            _conf = conf || {};
+
+        // Little shortcut:
+        // ****************
+        // The configuration is supposed to have a list of the configuration
+        // objects for each renderer.
+        //  - If there are no configuration at all, then nothing is done.
+        //  - If there are no renderer list, the given configuration object will be
+        //    considered as describing the first and only renderer.
+        //  - If there are no renderer list nor "container" object, it will be
+        //    considered as the container itself (a DOM element).
+        //  - If the argument passed to sigma() is a string, it will be considered
+        //    as the ID of the DOM container.
+        if (
+            typeof _conf === 'string' ||
+            _conf instanceof HTMLElement
+        )
+            _conf = {
+                renderers: [_conf]
+            };
+        else if (Object.prototype.toString.call(_conf) === '[object Array]')
+            _conf = {
+                renderers: _conf
+            };
+
+        // Also check "renderer" and "container" keys:
+        o = _conf.renderers || _conf.renderer || _conf.container;
+        if (!_conf.renderers || _conf.renderers.length === 0)
+            if (
+                typeof o === 'string' ||
+                o instanceof HTMLElement ||
+                (typeof o === 'object' && 'container' in o)
+            )
+                _conf.renderers = [o];
+
+        // Recense the instance:
+        if (_conf.id) {
+            if (__instances[_conf.id])
+                throw 'sigma: Instance "' + _conf.id + '" already exists.';
+            Object.defineProperty(this, 'id', {
+                value: _conf.id
+            });
+        } else {
+            id = 0;
+            while (__instances[id])
+                id++;
+            Object.defineProperty(this, 'id', {
+                value: '' + id
+            });
+        }
+        __instances[this.id] = this;
 
-    // Add a custom handler, to redispatch events from renderers:
-    this._handler = (function(e) {
-      var k,
-          data = {};
-
-      for (k in e.data)
-        data[k] = e.data[k];
-
-      data.renderer = e.target;
-      this.dispatchEvent(e.type, data);
-    }).bind(this);
-
-    // Initialize renderers:
-    a = _conf.renderers || [];
-    for (i = 0, l = a.length; i < l; i++)
-      this.addRenderer(a[i]);
-
-    // Initialize middlewares:
-    a = _conf.middlewares || [];
-    for (i = 0, l = a.length; i < l; i++)
-      this.middlewares.push(
-        typeof a[i] === 'string' ?
-          sigma.middlewares[a[i]] :
-          a[i]
-      );
-
-    // Check if there is already a graph to fill in:
-    if (typeof _conf.graph === 'object' && _conf.graph) {
-      this.graph.read(_conf.graph);
-
-      // If a graph is given to the to the instance, the "refresh" method is
-      // directly called:
-      this.refresh();
-    }
+        // Initialize settings function:
+        this.settings = new sigma.classes.configurable(
+            sigma.settings,
+            _conf.settings || {}
+        );
 
-    // Deal with resize:
-    window.addEventListener('resize', function() {
-      if (_self.settings)
-        _self.refresh();
-    });
-  };
+        // Initialize locked attributes:
+        Object.defineProperty(this, 'graph', {
+            value: new sigma.classes.graph(this.settings),
+            configurable: true
+        });
+        Object.defineProperty(this, 'middlewares', {
+            value: [],
+            configurable: true
+        });
+        Object.defineProperty(this, 'cameras', {
+            value: {},
+            configurable: true
+        });
+        Object.defineProperty(this, 'renderers', {
+            value: {},
+            configurable: true
+        });
+        Object.defineProperty(this, 'renderersPerCamera', {
+            value: {},
+            configurable: true
+        });
+        Object.defineProperty(this, 'cameraFrames', {
+            value: {},
+            configurable: true
+        });
+        Object.defineProperty(this, 'camera', {
+            get: function () {
+                return this.cameras[0];
+            }
+        });
+        Object.defineProperty(this, 'events', {
+            value: [
+                'click',
+                'rightClick',
+                'clickStage',
+                'doubleClickStage',
+                'rightClickStage',
+                'clickNode',
+                'clickNodes',
+                'doubleClickNode',
+                'doubleClickNodes',
+                'rightClickNode',
+                'rightClickNodes',
+                'overNode',
+                'overNodes',
+                'outNode',
+                'outNodes',
+                'downNode',
+                'downNodes',
+                'upNode',
+                'upNodes'
+            ],
+            configurable: true
+        });
 
+        // Add a custom handler, to redispatch events from renderers:
+        this._handler = (function (e) {
+            var k,
+                data = {};
 
+            for (k in e.data)
+                data[k] = e.data[k];
 
+            data.renderer = e.target;
+            this.dispatchEvent(e.type, data);
+        }).bind(this);
 
-  /**
-   * This methods will instantiate and reference a new camera. If no id is
-   * specified, then an automatic id will be generated.
-   *
-   * @param  {?string}              id Eventually the camera id.
-   * @return {sigma.classes.camera}    The fresh new camera instance.
-   */
-  sigma.prototype.addCamera = function(id) {
-    var self = this,
-        camera;
+        // Initialize renderers:
+        a = _conf.renderers || [];
+        for (i = 0, l = a.length; i < l; i++)
+            this.addRenderer(a[i]);
 
-    if (!arguments.length) {
-      id = 0;
-      while (this.cameras['' + id])
-        id++;
-      id = '' + id;
-    }
+        // Initialize middlewares:
+        a = _conf.middlewares || [];
+        for (i = 0, l = a.length; i < l; i++)
+            this.middlewares.push(
+                typeof a[i] === 'string' ?
+                    sigma.middlewares[a[i]] :
+                    a[i]
+            );
 
-    if (this.cameras[id])
-      throw 'sigma.addCamera: The camera "' + id + '" already exists.';
+        // Check if there is already a graph to fill in:
+        if (typeof _conf.graph === 'object' && _conf.graph) {
+            this.graph.read(_conf.graph);
+
+            // If a graph is given to the to the instance, the "refresh" method is
+            // directly called:
+            this.refresh();
+        }
 
-    camera = new sigma.classes.camera(id, this.graph, this.settings);
-    this.cameras[id] = camera;
+        // Deal with resize:
+        window.addEventListener('resize', function () {
+            if (_self.settings)
+                _self.refresh();
+        });
+    };
 
-    // Add a quadtree to the camera:
-    camera.quadtree = new sigma.classes.quad();
 
-    // Add an edgequadtree to the camera:
-    if (sigma.classes.edgequad !== undefined) {
-      camera.edgequadtree = new sigma.classes.edgequad();
-    }
+    /**
+     * This methods will instantiate and reference a new camera. If no id is
+     * specified, then an automatic id will be generated.
+     *
+     * @param  {?string}              id Eventually the camera id.
+     * @return {sigma.classes.camera}    The fresh new camera instance.
+     */
+    sigma.prototype.addCamera = function (id) {
+        var self = this,
+            camera;
+
+        if (!arguments.length) {
+            id = 0;
+            while (this.cameras['' + id])
+                id++;
+            id = '' + id;
+        }
 
-    camera.bind('coordinatesUpdated', function(e) {
-      self.renderCamera(camera, camera.isAnimated);
-    });
+        if (this.cameras[id])
+            throw 'sigma.addCamera: The camera "' + id + '" already exists.';
 
-    this.renderersPerCamera[id] = [];
-
-    return camera;
-  };
-
-  /**
-   * This method kills a camera, and every renderer attached to it.
-   *
-   * @param  {string|camera} v The camera to kill or its ID.
-   * @return {sigma}           Returns the instance.
-   */
-  sigma.prototype.killCamera = function(v) {
-    v = typeof v === 'string' ? this.cameras[v] : v;
-
-    if (!v)
-      throw 'sigma.killCamera: The camera is undefined.';
-
-    var i,
-        l,
-        a = this.renderersPerCamera[v.id];
-
-    for (l = a.length, i = l - 1; i >= 0; i--)
-      this.killRenderer(a[i]);
-
-    delete this.renderersPerCamera[v.id];
-    delete this.cameraFrames[v.id];
-    delete this.cameras[v.id];
-
-    if (v.kill)
-      v.kill();
-
-    return this;
-  };
-
-  /**
-   * This methods will instantiate and reference a new renderer. The "type"
-   * argument can be the constructor or its name in the "sigma.renderers"
-   * package. If no type is specified, then "sigma.renderers.def" will be used.
-   * If no id is specified, then an automatic id will be generated.
-   *
-   * @param  {?object}  options Eventually some options to give to the renderer
-   *                            constructor.
-   * @return {renderer}         The fresh new renderer instance.
-   *
-   * Recognized parameters:
-   * **********************
-   * Here is the exhaustive list of every accepted parameters in the "options"
-   * object:
-   *
-   *   {?string}            id     Eventually the renderer id.
-   *   {?(function|string)} type   Eventually the renderer constructor or its
-   *                               name in the "sigma.renderers" package.
-   *   {?(camera|string)}   camera Eventually the renderer camera or its
-   *                               id.
-   */
-  sigma.prototype.addRenderer = function(options) {
-    var id,
-        fn,
-        camera,
-        renderer,
-        o = options || {};
-
-    // Polymorphism:
-    if (typeof o === 'string')
-      o = {
-        container: document.getElementById(o)
-      };
-    else if (o instanceof HTMLElement)
-      o = {
-        container: o
-      };
-
-    // If the container still is a string, we get it by id
-    if (typeof o.container === 'string')
-      o.container = document.getElementById(o.container);
-
-    // Reference the new renderer:
-    if (!('id' in o)) {
-      id = 0;
-      while (this.renderers['' + id])
-        id++;
-      id = '' + id;
-    } else
-      id = o.id;
-
-    if (this.renderers[id])
-      throw 'sigma.addRenderer: The renderer "' + id + '" already exists.';
-
-    // Find the good constructor:
-    fn = typeof o.type === 'function' ? o.type : sigma.renderers[o.type];
-    fn = fn || sigma.renderers.def;
-
-    // Find the good camera:
-    camera = 'camera' in o ?
-      (
-        o.camera instanceof sigma.classes.camera ?
-          o.camera :
-          this.cameras[o.camera] || this.addCamera(o.camera)
-      ) :
-      this.addCamera();
-
-    if (this.cameras[camera.id] !== camera)
-      throw 'sigma.addRenderer: The camera is not properly referenced.';
-
-    // Instantiate:
-    renderer = new fn(this.graph, camera, this.settings, o);
-    this.renderers[id] = renderer;
-    Object.defineProperty(renderer, 'id', {
-      value: id
-    });
+        camera = new sigma.classes.camera(id, this.graph, this.settings);
+        this.cameras[id] = camera;
 
-    // Bind events:
-    if (renderer.bind)
-      renderer.bind(
-        [
-          'click',
-          'rightClick',
-          'clickStage',
-          'doubleClickStage',
-          'rightClickStage',
-          'clickNode',
-          'clickNodes',
-          'clickEdge',
-          'clickEdges',
-          'doubleClickNode',
-          'doubleClickNodes',
-          'doubleClickEdge',
-          'doubleClickEdges',
-          'rightClickNode',
-          'rightClickNodes',
-          'rightClickEdge',
-          'rightClickEdges',
-          'overNode',
-          'overNodes',
-          'overEdge',
-          'overEdges',
-          'outNode',
-          'outNodes',
-          'outEdge',
-          'outEdges',
-          'downNode',
-          'downNodes',
-          'downEdge',
-          'downEdges',
-          'upNode',
-          'upNodes',
-          'upEdge',
-          'upEdges'
-        ],
-        this._handler
-      );
-
-    // Reference the renderer by its camera:
-    this.renderersPerCamera[camera.id].push(renderer);
-
-    return renderer;
-  };
-
-  /**
-   * This method kills a renderer.
-   *
-   * @param  {string|renderer} v The renderer to kill or its ID.
-   * @return {sigma}             Returns the instance.
-   */
-  sigma.prototype.killRenderer = function(v) {
-    v = typeof v === 'string' ? this.renderers[v] : v;
-
-    if (!v)
-      throw 'sigma.killRenderer: The renderer is undefined.';
-
-    var a = this.renderersPerCamera[v.camera.id],
-        i = a.indexOf(v);
-
-    if (i >= 0)
-      a.splice(i, 1);
-
-    if (v.kill)
-      v.kill();
-
-    delete this.renderers[v.id];
-
-    return this;
-  };
-
-
-
-
-  /**
-   * This method calls the "render" method of each renderer, with the same
-   * arguments than the "render" method, but will also check if the renderer
-   * has a "process" method, and call it if it exists.
-   *
-   * It is useful for quadtrees or WebGL processing, for instance.
-   *
-   * @param  {?object}  options Eventually some options to give to the refresh
-   *                            method.
-   * @return {sigma}            Returns the instance itself.
-   *
-   * Recognized parameters:
-   * **********************
-   * Here is the exhaustive list of every accepted parameters in the "options"
-   * object:
-   *
-   *   {?boolean} skipIndexation A flag specifying wether or not the refresh
-   *                             function should reindex the graph in the
-   *                             quadtrees or not (default: false).
-   */
-  sigma.prototype.refresh = function(options) {
-    var i,
-        l,
-        k,
-        a,
-        c,
-        bounds,
-        prefix = 0;
-
-    options = options || {};
-
-    // Call each middleware:
-    a = this.middlewares || [];
-    for (i = 0, l = a.length; i < l; i++)
-      a[i].call(
-        this,
-        (i === 0) ? '' : 'tmp' + prefix + ':',
-        (i === l - 1) ? 'ready:' : ('tmp' + (++prefix) + ':')
-      );
-
-    // Then, for each camera, call the "rescale" middleware, unless the
-    // settings specify not to:
-    for (k in this.cameras) {
-      c = this.cameras[k];
-      if (
-        c.settings('autoRescale') &&
-        this.renderersPerCamera[c.id] &&
-        this.renderersPerCamera[c.id].length
-      )
-        sigma.middlewares.rescale.call(
-          this,
-          a.length ? 'ready:' : '',
-          c.readPrefix,
-          {
-            width: this.renderersPerCamera[c.id][0].width,
-            height: this.renderersPerCamera[c.id][0].height
-          }
-        );
-      else
-        sigma.middlewares.copy.call(
-          this,
-          a.length ? 'ready:' : '',
-          c.readPrefix
-        );
+        // Add a quadtree to the camera:
+        camera.quadtree = new sigma.classes.quad();
 
-      if (!options.skipIndexation) {
-        // Find graph boundaries:
-        bounds = sigma.utils.getBoundaries(
-          this.graph,
-          c.readPrefix
-        );
+        // Add an edgequadtree to the camera:
+        if (sigma.classes.edgequad !== undefined) {
+            camera.edgequadtree = new sigma.classes.edgequad();
+        }
 
-        // Refresh quadtree:
-        c.quadtree.index(this.graph.nodes(), {
-          prefix: c.readPrefix,
-          bounds: {
-            x: bounds.minX,
-            y: bounds.minY,
-            width: bounds.maxX - bounds.minX,
-            height: bounds.maxY - bounds.minY
-          }
+        camera.bind('coordinatesUpdated', function (e) {
+            self.renderCamera(camera, camera.isAnimated);
         });
 
-        // Refresh edgequadtree:
-        if (
-          c.edgequadtree !== undefined &&
-          c.settings('drawEdges') &&
-          c.settings('enableEdgeHovering')
-        ) {
-          c.edgequadtree.index(this.graph, {
-            prefix: c.readPrefix,
-            bounds: {
-              x: bounds.minX,
-              y: bounds.minY,
-              width: bounds.maxX - bounds.minX,
-              height: bounds.maxY - bounds.minY
-            }
-          });
-        }
-      }
-    }
+        this.renderersPerCamera[id] = [];
+
+        return camera;
+    };
+
+    /**
+     * This method kills a camera, and every renderer attached to it.
+     *
+     * @param  {string|camera} v The camera to kill or its ID.
+     * @return {sigma}           Returns the instance.
+     */
+    sigma.prototype.killCamera = function (v) {
+        v = typeof v === 'string' ? this.cameras[v] : v;
+
+        if (!v)
+            throw 'sigma.killCamera: The camera is undefined.';
+
+        var i,
+            l,
+            a = this.renderersPerCamera[v.id];
+
+        for (l = a.length, i = l - 1; i >= 0; i--)
+            this.killRenderer(a[i]);
+
+        delete this.renderersPerCamera[v.id];
+        delete this.cameraFrames[v.id];
+        delete this.cameras[v.id];
+
+        if (v.kill)
+            v.kill();
 
-    // Call each renderer:
-    a = Object.keys(this.renderers);
-    for (i = 0, l = a.length; i < l; i++)
-      if (this.renderers[a[i]].process) {
-        if (this.settings('skipErrors'))
-          try {
-            this.renderers[a[i]].process();
-          } catch (e) {
-            console.log(
-              'Warning: The renderer "' + a[i] + '" crashed on ".process()"'
+        return this;
+    };
+
+    /**
+     * This methods will instantiate and reference a new renderer. The "type"
+     * argument can be the constructor or its name in the "sigma.renderers"
+     * package. If no type is specified, then "sigma.renderers.def" will be used.
+     * If no id is specified, then an automatic id will be generated.
+     *
+     * @param  {?object}  options Eventually some options to give to the renderer
+     *                            constructor.
+     * @return {renderer}         The fresh new renderer instance.
+     *
+     * Recognized parameters:
+     * **********************
+     * Here is the exhaustive list of every accepted parameters in the "options"
+     * object:
+     *
+     *   {?string}            id     Eventually the renderer id.
+     *   {?(function|string)} type   Eventually the renderer constructor or its
+     *                               name in the "sigma.renderers" package.
+     *   {?(camera|string)}   camera Eventually the renderer camera or its
+     *                               id.
+     */
+    sigma.prototype.addRenderer = function (options) {
+        var id,
+            fn,
+            camera,
+            renderer,
+            o = options || {};
+
+        // Polymorphism:
+        if (typeof o === 'string')
+            o = {
+                container: document.getElementById(o)
+            };
+        else if (o instanceof HTMLElement)
+            o = {
+                container: o
+            };
+
+        // If the container still is a string, we get it by id
+        if (typeof o.container === 'string')
+            o.container = document.getElementById(o.container);
+
+        // Reference the new renderer:
+        if (!('id' in o)) {
+            id = 0;
+            while (this.renderers['' + id])
+                id++;
+            id = '' + id;
+        } else
+            id = o.id;
+
+        if (this.renderers[id])
+            throw 'sigma.addRenderer: The renderer "' + id + '" already exists.';
+
+        // Find the good constructor:
+        fn = typeof o.type === 'function' ? o.type : sigma.renderers[o.type];
+        fn = fn || sigma.renderers.def;
+
+        // Find the good camera:
+        camera = 'camera' in o ?
+            (
+                o.camera instanceof sigma.classes.camera ?
+                    o.camera :
+                this.cameras[o.camera] || this.addCamera(o.camera)
+            ) :
+            this.addCamera();
+
+        if (this.cameras[camera.id] !== camera)
+            throw 'sigma.addRenderer: The camera is not properly referenced.';
+
+        // Instantiate:
+        renderer = new fn(this.graph, camera, this.settings, o);
+        this.renderers[id] = renderer;
+        Object.defineProperty(renderer, 'id', {
+            value: id
+        });
+
+        // Bind events:
+        if (renderer.bind)
+            renderer.bind(
+                [
+                    'click',
+                    'rightClick',
+                    'clickStage',
+                    'doubleClickStage',
+                    'rightClickStage',
+                    'clickNode',
+                    'clickNodes',
+                    'clickEdge',
+                    'clickEdges',
+                    'doubleClickNode',
+                    'doubleClickNodes',
+                    'doubleClickEdge',
+                    'doubleClickEdges',
+                    'rightClickNode',
+                    'rightClickNodes',
+                    'rightClickEdge',
+                    'rightClickEdges',
+                    'overNode',
+                    'overNodes',
+                    'overEdge',
+                    'overEdges',
+                    'outNode',
+                    'outNodes',
+                    'outEdge',
+                    'outEdges',
+                    'downNode',
+                    'downNodes',
+                    'downEdge',
+                    'downEdges',
+                    'upNode',
+                    'upNodes',
+                    'upEdge',
+                    'upEdges'
+                ],
+                this._handler
             );
-          }
-        else
-          this.renderers[a[i]].process();
-      }
-
-    this.render();
-
-    return this;
-  };
-
-  /**
-   * This method calls the "render" method of each renderer.
-   *
-   * @return {sigma} Returns the instance itself.
-   */
-  sigma.prototype.render = function() {
-    var i,
-        l,
-        a,
-        prefix = 0;
-
-    // Call each renderer:
-    a = Object.keys(this.renderers);
-    for (i = 0, l = a.length; i < l; i++)
-      if (this.settings('skipErrors'))
-        try {
-          this.renderers[a[i]].render();
-        } catch (e) {
-          if (this.settings('verbose'))
-            console.log(
-              'Warning: The renderer "' + a[i] + '" crashed on ".render()"'
+
+        // Reference the renderer by its camera:
+        this.renderersPerCamera[camera.id].push(renderer);
+
+        return renderer;
+    };
+
+    /**
+     * This method kills a renderer.
+     *
+     * @param  {string|renderer} v The renderer to kill or its ID.
+     * @return {sigma}             Returns the instance.
+     */
+    sigma.prototype.killRenderer = function (v) {
+        v = typeof v === 'string' ? this.renderers[v] : v;
+
+        if (!v)
+            throw 'sigma.killRenderer: The renderer is undefined.';
+
+        var a = this.renderersPerCamera[v.camera.id],
+            i = a.indexOf(v);
+
+        if (i >= 0)
+            a.splice(i, 1);
+
+        if (v.kill)
+            v.kill();
+
+        delete this.renderers[v.id];
+
+        return this;
+    };
+
+
+    /**
+     * This method calls the "render" method of each renderer, with the same
+     * arguments than the "render" method, but will also check if the renderer
+     * has a "process" method, and call it if it exists.
+     *
+     * It is useful for quadtrees or WebGL processing, for instance.
+     *
+     * @param  {?object}  options Eventually some options to give to the refresh
+     *                            method.
+     * @return {sigma}            Returns the instance itself.
+     *
+     * Recognized parameters:
+     * **********************
+     * Here is the exhaustive list of every accepted parameters in the "options"
+     * object:
+     *
+     *   {?boolean} skipIndexation A flag specifying wether or not the refresh
+     *                             function should reindex the graph in the
+     *                             quadtrees or not (default: false).
+     */
+    sigma.prototype.refresh = function (options) {
+        var i,
+            l,
+            k,
+            a,
+            c,
+            bounds,
+            prefix = 0;
+
+        options = options || {};
+
+        // Call each middleware:
+        a = this.middlewares || [];
+        for (i = 0, l = a.length; i < l; i++)
+            a[i].call(
+                this,
+                (i === 0) ? '' : 'tmp' + prefix + ':',
+                (i === l - 1) ? 'ready:' : ('tmp' + (++prefix) + ':')
             );
+
+        // Then, for each camera, call the "rescale" middleware, unless the
+        // settings specify not to:
+        for (k in this.cameras) {
+            c = this.cameras[k];
+            if (
+                c.settings('autoRescale') &&
+                this.renderersPerCamera[c.id] &&
+                this.renderersPerCamera[c.id].length
+            )
+                sigma.middlewares.rescale.call(
+                    this,
+                    a.length ? 'ready:' : '',
+                    c.readPrefix,
+                    {
+                        width: this.renderersPerCamera[c.id][0].width,
+                        height: this.renderersPerCamera[c.id][0].height
+                    }
+                );
+            else
+                sigma.middlewares.copy.call(
+                    this,
+                    a.length ? 'ready:' : '',
+                    c.readPrefix
+                );
+
+            if (!options.skipIndexation) {
+                // Find graph boundaries:
+                bounds = sigma.utils.getBoundaries(
+                    this.graph,
+                    c.readPrefix
+                );
+
+                // Refresh quadtree:
+                c.quadtree.index(this.graph.nodes(), {
+                    prefix: c.readPrefix,
+                    bounds: {
+                        x: bounds.minX,
+                        y: bounds.minY,
+                        width: bounds.maxX - bounds.minX,
+                        height: bounds.maxY - bounds.minY
+                    }
+                });
+
+                // Refresh edgequadtree:
+                if (
+                    c.edgequadtree !== undefined &&
+                    c.settings('drawEdges') &&
+                    c.settings('enableEdgeHovering')
+                ) {
+                    c.edgequadtree.index(this.graph, {
+                        prefix: c.readPrefix,
+                        bounds: {
+                            x: bounds.minX,
+                            y: bounds.minY,
+                            width: bounds.maxX - bounds.minX,
+                            height: bounds.maxY - bounds.minY
+                        }
+                    });
+                }
+            }
         }
-      else
-        this.renderers[a[i]].render();
-
-    return this;
-  };
-
-  /**
-   * This method calls the "render" method of each renderer that is bound to
-   * the specified camera. To improve the performances, if this method is
-   * called too often, the number of effective renderings is limitated to one
-   * per frame, unless you are using the "force" flag.
-   *
-   * @param  {sigma.classes.camera} camera The camera to render.
-   * @param  {?boolean}             force  If true, will render the camera
-   *                                       directly.
-   * @return {sigma}                       Returns the instance itself.
-   */
-  sigma.prototype.renderCamera = function(camera, force) {
-    var i,
-        l,
-        a,
-        self = this;
-
-    if (force) {
-      a = this.renderersPerCamera[camera.id];
-      for (i = 0, l = a.length; i < l; i++)
-        if (this.settings('skipErrors'))
-          try {
-            a[i].render();
-          } catch (e) {
-            if (this.settings('verbose'))
-              console.log(
-                'Warning: The renderer "' + a[i].id + '" crashed on ".render()"'
-              );
-          }
-        else
-          a[i].render();
-    } else {
-      if (!this.cameraFrames[camera.id]) {
-        a = this.renderersPerCamera[camera.id];
+
+        // Call each renderer:
+        a = Object.keys(this.renderers);
         for (i = 0, l = a.length; i < l; i++)
-          if (this.settings('skipErrors'))
-            try {
-              a[i].render();
-            } catch (e) {
-              if (this.settings('verbose'))
-                console.log(
-                  'Warning: The renderer "' +
-                    a[i].id +
-                    '" crashed on ".render()"'
-                );
+            if (this.renderers[a[i]].process) {
+                if (this.settings('skipErrors'))
+                    try {
+                        this.renderers[a[i]].process();
+                    } catch (e) {
+                        console.log(
+                            'Warning: The renderer "' + a[i] + '" crashed on ".process()"'
+                        );
+                    }
+                else
+                    this.renderers[a[i]].process();
             }
-          else
-            a[i].render();
 
-        this.cameraFrames[camera.id] = requestAnimationFrame(function() {
-          delete self.cameraFrames[camera.id];
-        });
-      }
-    }
+        this.render();
 
-    return this;
-  };
+        return this;
+    };
 
-  /**
-   * This method calls the "kill" method of each module and destroys any
-   * reference from the instance.
-   */
-  sigma.prototype.kill = function() {
-    var k;
+    /**
+     * This method calls the "render" method of each renderer.
+     *
+     * @return {sigma} Returns the instance itself.
+     */
+    sigma.prototype.render = function () {
+        var i,
+            l,
+            a,
+            prefix = 0;
 
-    // Dispatching event
-    this.dispatchEvent('kill');
+        // Call each renderer:
+        a = Object.keys(this.renderers);
+        for (i = 0, l = a.length; i < l; i++)
+            if (this.settings('skipErrors'))
+                try {
+                    this.renderers[a[i]].render();
+                } catch (e) {
+                    if (this.settings('verbose'))
+                        console.log(
+                            'Warning: The renderer "' + a[i] + '" crashed on ".render()"'
+                        );
+                }
+            else
+                this.renderers[a[i]].render();
 
-    // Kill graph:
-    this.graph.kill();
+        return this;
+    };
 
-    // Kill middlewares:
-    delete this.middlewares;
+    /**
+     * This method calls the "render" method of each renderer that is bound to
+     * the specified camera. To improve the performances, if this method is
+     * called too often, the number of effective renderings is limitated to one
+     * per frame, unless you are using the "force" flag.
+     *
+     * @param  {sigma.classes.camera} camera The camera to render.
+     * @param  {?boolean}             force  If true, will render the camera
+     *                                       directly.
+     * @return {sigma}                       Returns the instance itself.
+     */
+    sigma.prototype.renderCamera = function (camera, force) {
+        var i,
+            l,
+            a,
+            self = this;
+
+        if (force) {
+            a = this.renderersPerCamera[camera.id];
+            for (i = 0, l = a.length; i < l; i++)
+                if (this.settings('skipErrors'))
+                    try {
+                        a[i].render();
+                    } catch (e) {
+                        if (this.settings('verbose'))
+                            console.log(
+                                'Warning: The renderer "' + a[i].id + '" crashed on ".render()"'
+                            );
+                    }
+                else
+                    a[i].render();
+        } else {
+            if (!this.cameraFrames[camera.id]) {
+                a = this.renderersPerCamera[camera.id];
+                for (i = 0, l = a.length; i < l; i++)
+                    if (this.settings('skipErrors'))
+                        try {
+                            a[i].render();
+                        } catch (e) {
+                            if (this.settings('verbose'))
+                                console.log(
+                                    'Warning: The renderer "' +
+                                    a[i].id +
+                                    '" crashed on ".render()"'
+                                );
+                        }
+                    else
+                        a[i].render();
+
+                this.cameraFrames[camera.id] = requestAnimationFrame(function () {
+                    delete self.cameraFrames[camera.id];
+                });
+            }
+        }
 
-    // Kill each renderer:
-    for (k in this.renderers)
-      this.killRenderer(this.renderers[k]);
+        return this;
+    };
 
-    // Kill each camera:
-    for (k in this.cameras)
-      this.killCamera(this.cameras[k]);
+    /**
+     * This method calls the "kill" method of each module and destroys any
+     * reference from the instance.
+     */
+    sigma.prototype.kill = function () {
+        var k;
 
-    delete this.renderers;
-    delete this.cameras;
+        // Dispatching event
+        this.dispatchEvent('kill');
 
-    // Kill everything else:
-    for (k in this)
-      if (this.hasOwnProperty(k))
-        delete this[k];
+        // Kill graph:
+        this.graph.kill();
 
-    delete __instances[this.id];
-  };
+        // Kill middlewares:
+        delete this.middlewares;
 
+        // Kill each renderer:
+        for (k in this.renderers)
+            this.killRenderer(this.renderers[k]);
 
+        // Kill each camera:
+        for (k in this.cameras)
+            this.killCamera(this.cameras[k]);
 
+        delete this.renderers;
+        delete this.cameras;
 
-  /**
-   * Returns a clone of the instances object or a specific running instance.
-   *
-   * @param  {?string} id Eventually an instance ID.
-   * @return {object}     The related instance or a clone of the instances
-   *                      object.
-   */
-  sigma.instances = function(id) {
-    return arguments.length ?
-      __instances[id] :
-      sigma.utils.extend({}, __instances);
-  };
+        // Kill everything else:
+        for (k in this)
+            if (this.hasOwnProperty(k))
+                delete this[k];
 
+        delete __instances[this.id];
+    };
 
 
-  /**
-   * The current version of sigma:
-   */
-  sigma.version = '1.1.0';
+    /**
+     * Returns a clone of the instances object or a specific running instance.
+     *
+     * @param  {?string} id Eventually an instance ID.
+     * @return {object}     The related instance or a clone of the instances
+     *                      object.
+     */
+    sigma.instances = function (id) {
+        return arguments.length ?
+            __instances[id] :
+            sigma.utils.extend({}, __instances);
+    };
 
 
+    /**
+     * The current version of sigma:
+     */
+    sigma.version = '1.1.0';
 
 
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof this.sigma !== 'undefined')
-    throw 'An object called sigma is already in the global scope.';
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof this.sigma !== 'undefined')
+        throw 'An object called sigma is already in the global scope.';
 
-  this.sigma = sigma;
+    this.sigma = sigma;
 
 }).call(this);
 
  * from, out of or in connection with the software or the use or other dealings
  * in the Software.
  */
-(function(global) {
-  'use strict';
-
-  // Check that conrad.js has not been loaded yet:
-  if (global.conrad)
-    throw new Error('conrad already exists');
-
-
-  /**
-   * PRIVATE VARIABLES:
-   * ******************
-   */
-
-  /**
-   * A flag indicating whether conrad is running or not.
-   *
-   * @type {Number}
-   */
-  var _lastFrameTime;
-
-  /**
-   * A flag indicating whether conrad is running or not.
-   *
-   * @type {Boolean}
-   */
-  var _isRunning = false;
-
-  /**
-   * The hash of registered jobs. Each job must at least have a unique ID
-   * under the key "id" and a function under the key "job". This hash
-   * contains each running job and each waiting job.
-   *
-   * @type {Object}
-   */
-  var _jobs = {};
-
-  /**
-   * The hash of currently running jobs.
-   *
-   * @type {Object}
-   */
-  var _runningJobs = {};
-
-  /**
-   * The array of currently running jobs, sorted by priority.
-   *
-   * @type {Array}
-   */
-  var _sortedByPriorityJobs = [];
-
-  /**
-   * The array of currently waiting jobs.
-   *
-   * @type {Object}
-   */
-  var _waitingJobs = {};
-
-  /**
-   * The array of finished jobs. They are stored in an array, since two jobs
-   * with the same "id" can happen at two different times.
-   *
-   * @type {Array}
-   */
-  var _doneJobs = [];
-
-  /**
-   * A dirty flag to keep conrad from starting: Indeed, when addJob() is called
-   * with several jobs, conrad must be started only at the end. This flag keeps
-   * me from duplicating the code that effectively adds a job.
-   *
-   * @type {Boolean}
-   */
-  var _noStart = false;
-
-  /**
-   * An hash containing some global settings about how conrad.js should
-   * behave.
-   *
-   * @type {Object}
-   */
-  var _parameters = {
-    frameDuration: 20,
-    history: true
-  };
-
-  /**
-   * This object contains every handlers bound to conrad events. It does not
-   * requirea any DOM implementation, since the events are all JavaScript.
-   *
-   * @type {Object}
-   */
-  var _handlers = Object.create(null);
-
-
-  /**
-   * PRIVATE FUNCTIONS:
-   * ******************
-   */
-
-  /**
-   * Will execute the handler everytime that the indicated event (or the
-   * indicated events) will be triggered.
-   *
-   * @param  {string|array|object} events  The name of the event (or the events
-   *                                       separated by spaces).
-   * @param  {function(Object)}    handler The handler to bind.
-   * @return {Object}                      Returns conrad.
-   */
-  function _bind(events, handler) {
-    var i,
-        i_end,
-        event,
-        eArray;
-
-    if (!arguments.length)
-      return;
-    else if (
-      arguments.length === 1 &&
-      Object(arguments[0]) === arguments[0]
-    )
-      for (events in arguments[0])
-        _bind(events, arguments[0][events]);
-    else if (arguments.length > 1) {
-      eArray =
-        Array.isArray(events) ?
-          events :
-          events.split(/ /);
-
-      for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
-        event = eArray[i];
-
-        if (!_handlers[event])
-          _handlers[event] = [];
-
-        // Using an object instead of directly the handler will make possible
-        // later to add flags
-        _handlers[event].push({
-          handler: handler
-        });
-      }
-    }
-  }
-
-  /**
-   * Removes the handler from a specified event (or specified events).
-   *
-   * @param  {?string}           events  The name of the event (or the events
-   *                                     separated by spaces). If undefined,
-   *                                     then all handlers are removed.
-   * @param  {?function(Object)} handler The handler to unbind. If undefined,
-   *                                     each handler bound to the event or the
-   *                                     events will be removed.
-   * @return {Object}            Returns conrad.
-   */
-  function _unbind(events, handler) {
-    var i,
-        i_end,
-        j,
-        j_end,
-        a,
-        event,
-        eArray = Array.isArray(events) ?
-                   events :
-                   events.split(/ /);
-
-    if (!arguments.length)
-      _handlers = Object.create(null);
-    else if (handler) {
-      for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
-        event = eArray[i];
-        if (_handlers[event]) {
-          a = [];
-          for (j = 0, j_end = _handlers[event].length; j !== j_end; j += 1)
-            if (_handlers[event][j].handler !== handler)
-              a.push(_handlers[event][j]);
-
-          _handlers[event] = a;
-        }
-
-        if (_handlers[event] && _handlers[event].length === 0)
-          delete _handlers[event];
-      }
-    } else
-      for (i = 0, i_end = eArray.length; i !== i_end; i += 1)
-        delete _handlers[eArray[i]];
-  }
-
-  /**
-   * Executes each handler bound to the event.
-   *
-   * @param  {string}  events The name of the event (or the events separated
-   *                          by spaces).
-   * @param  {?Object} data   The content of the event (optional).
-   * @return {Object}         Returns conrad.
-   */
-  function _dispatch(events, data) {
-    var i,
-        j,
-        i_end,
-        j_end,
-        event,
-        eventName,
-        eArray = Array.isArray(events) ?
-                   events :
-                   events.split(/ /);
-
-    data = data === undefined ? {} : data;
-
-    for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
-      eventName = eArray[i];
-
-      if (_handlers[eventName]) {
-        event = {
-          type: eventName,
-          data: data || {}
-        };
+(function (global) {
+    'use strict';
 
-        for (j = 0, j_end = _handlers[eventName].length; j !== j_end; j += 1)
-          try {
-            _handlers[eventName][j].handler(event);
-          } catch (e) {}
-      }
-    }
-  }
-
-  /**
-   * Executes the most prioritary job once, and deals with filling the stats
-   * (done, time, averageTime, currentTime, etc...).
-   *
-   * @return {?Object} Returns the job object if it has to be killed, null else.
-   */
-  function _executeFirstJob() {
-    var i,
-        l,
-        test,
-        kill,
-        pushed = false,
-        time = __dateNow(),
-        job = _sortedByPriorityJobs.shift();
-
-    // Execute the job and look at the result:
-    test = job.job();
-
-    // Deal with stats:
-    time = __dateNow() - time;
-    job.done++;
-    job.time += time;
-    job.currentTime += time;
-    job.weightTime = job.currentTime / (job.weight || 1);
-    job.averageTime = job.time / job.done;
-
-    // Check if the job has to be killed:
-    kill = job.count ? (job.count <= job.done) : !test;
-
-    // Reset priorities:
-    if (!kill) {
-      for (i = 0, l = _sortedByPriorityJobs.length; i < l; i++)
-        if (_sortedByPriorityJobs[i].weightTime > job.weightTime) {
-          _sortedByPriorityJobs.splice(i, 0, job);
-          pushed = true;
-          break;
-        }
-
-      if (!pushed)
-        _sortedByPriorityJobs.push(job);
-    }
+    // Check that conrad.js has not been loaded yet:
+    if (global.conrad)
+        throw new Error('conrad already exists');
 
-    return kill ? job : null;
-  }
-
-  /**
-   * Activates a job, by adding it to the _runningJobs object and the
-   * _sortedByPriorityJobs array. It also initializes its currentTime value.
-   *
-   * @param  {Object} job The job to activate.
-   */
-  function _activateJob(job) {
-    var l = _sortedByPriorityJobs.length;
-
-    // Add the job to the running jobs:
-    _runningJobs[job.id] = job;
-    job.status = 'running';
-
-    // Add the job to the priorities:
-    if (l) {
-      job.weightTime = _sortedByPriorityJobs[l - 1].weightTime;
-      job.currentTime = job.weightTime * (job.weight || 1);
-    }
 
-    // Initialize the job and dispatch:
-    job.startTime = __dateNow();
-    _dispatch('jobStarted', __clone(job));
-
-    _sortedByPriorityJobs.push(job);
-  }
-
-  /**
-   * The main loop of conrad.js:
-   *  . It executes job such that they all occupate the same processing time.
-   *  . It stops jobs that do not need to be executed anymore.
-   *  . It triggers callbacks when it is relevant.
-   *  . It starts waiting jobs when they need to be started.
-   *  . It injects frames to keep a constant frapes per second ratio.
-   *  . It stops itself when there are no more jobs to execute.
-   */
-  function _loop() {
-    var k,
-        o,
-        l,
-        job,
-        time,
-        deadJob;
-
-    // Deal with the newly added jobs (the _jobs object):
-    for (k in _jobs) {
-      job = _jobs[k];
-
-      if (job.after)
-        _waitingJobs[k] = job;
-      else
-        _activateJob(job);
-
-      delete _jobs[k];
-    }
+    /**
+     * PRIVATE VARIABLES:
+     * ******************
+     */
 
-    // Set the _isRunning flag to false if there are no running job:
-    _isRunning = !!_sortedByPriorityJobs.length;
-
-    // Deal with the running jobs (the _runningJobs object):
-    while (
-      _sortedByPriorityJobs.length &&
-      __dateNow() - _lastFrameTime < _parameters.frameDuration
-    ) {
-      deadJob = _executeFirstJob();
-
-      // Deal with the case where the job has ended:
-      if (deadJob) {
-        _killJob(deadJob.id);
-
-        // Check for waiting jobs:
-        for (k in _waitingJobs)
-          if (_waitingJobs[k].after === deadJob.id) {
-            _activateJob(_waitingJobs[k]);
-            delete _waitingJobs[k];
-          }
-      }
-    }
+    /**
+     * A flag indicating whether conrad is running or not.
+     *
+     * @type {Number}
+     */
+    var _lastFrameTime;
 
-    // Check if conrad still has jobs to deal with, and kill it if not:
-    if (_isRunning) {
-      // Update the _lastFrameTime:
-      _lastFrameTime = __dateNow();
+    /**
+     * A flag indicating whether conrad is running or not.
+     *
+     * @type {Boolean}
+     */
+    var _isRunning = false;
 
-      _dispatch('enterFrame');
-      setTimeout(_loop, 0);
-    } else
-      _dispatch('stop');
-  }
-
-  /**
-   * Adds one or more jobs, and starts the loop if no job was running before. A
-   * job is at least a unique string "id" and a function, and there are some
-   * parameters that you can specify for each job to modify the way conrad will
-   * execute it. If a job is added with the "id" of another job that is waiting
-   * or still running, an error will be thrown.
-   *
-   * When a job is added, it is referenced in the _jobs object, by its id.
-   * Then, if it has to be executed right now, it will be also referenced in
-   * the _runningJobs object. If it has to wait, then it will be added into the
-   * _waitingJobs object, until it can start.
-   *
-   * Keep reading this documentation to see how to call this method.
-   *
-   * @return {Object} Returns conrad.
-   *
-   * Adding one job:
-   * ***************
-   * Basically, a job is defined by its string id and a function (the job). It
-   * is also possible to add some parameters:
-   *
-   *  > conrad.addJob('myJobId', myJobFunction);
-   *  > conrad.addJob('myJobId', {
-   *  >   job: myJobFunction,
-   *  >   someParameter: someValue
-   *  > });
-   *  > conrad.addJob({
-   *  >   id: 'myJobId',
-   *  >   job: myJobFunction,
-   *  >   someParameter: someValue
-   *  > });
-   *
-   * Adding several jobs:
-   * ********************
-   * When adding several jobs at the same time, it is possible to specify
-   * parameters for each one individually or for all:
-   *
-   *  > conrad.addJob([
-   *  >   {
-   *  >     id: 'myJobId1',
-   *  >     job: myJobFunction1,
-   *  >     someParameter1: someValue1
-   *  >   },
-   *  >   {
-   *  >     id: 'myJobId2',
-   *  >     job: myJobFunction2,
-   *  >     someParameter2: someValue2
-   *  >   }
-   *  > ], {
-   *  >   someCommonParameter: someCommonValue
-   *  > });
-   *  > conrad.addJob({
-   *  >   myJobId1: {,
-   *  >     job: myJobFunction1,
-   *  >     someParameter1: someValue1
-   *  >   },
-   *  >   myJobId2: {,
-   *  >     job: myJobFunction2,
-   *  >     someParameter2: someValue2
-   *  >   }
-   *  > }, {
-   *  >   someCommonParameter: someCommonValue
-   *  > });
-   *  > conrad.addJob({
-   *  >   myJobId1: myJobFunction1,
-   *  >   myJobId2: myJobFunction2
-   *  > }, {
-   *  >   someCommonParameter: someCommonValue
-   *  > });
-   *
-   *  Recognized parameters:
-   *  **********************
-   *  Here is the exhaustive list of every accepted parameters:
-   *
-   *    {?Function} end      A callback to execute when the job is ended. It is
-   *                         not executed if the job is killed instead of ended
-   *                         "naturally".
-   *    {?Integer}  count    The number of time the job has to be executed.
-   *    {?Number}   weight   If specified, the job will be executed as it was
-   *                         added "weight" times.
-   *    {?String}   after    The id of another job (eventually not added yet).
-   *                         If specified, this job will start only when the
-   *                         specified "after" job is ended.
-   */
-  function _addJob(v1, v2) {
-    var i,
-        l,
-        o;
-
-    // Array of jobs:
-    if (Array.isArray(v1)) {
-      // Keep conrad to start until the last job is added:
-      _noStart = true;
-
-      for (i = 0, l = v1.length; i < l; i++)
-        _addJob(v1[i].id, __extend(v1[i], v2));
-
-      _noStart = false;
-      if (!_isRunning) {
-        // Update the _lastFrameTime:
-        _lastFrameTime = __dateNow();
-
-        _dispatch('start');
-        _loop();
-      }
-    } else if (typeof v1 === 'object') {
-      // One job (object):
-      if (typeof v1.id === 'string')
-        _addJob(v1.id, v1);
-
-      // Hash of jobs:
-      else {
-        // Keep conrad to start until the last job is added:
-        _noStart = true;
-
-        for (i in v1)
-          if (typeof v1[i] === 'function')
-            _addJob(i, __extend({
-              job: v1[i]
-            }, v2));
-          else
-            _addJob(i, __extend(v1[i], v2));
-
-        _noStart = false;
-        if (!_isRunning) {
-          // Update the _lastFrameTime:
-          _lastFrameTime = __dateNow();
-
-          _dispatch('start');
-          _loop();
-        }
-      }
-
-    // One job (string, *):
-    } else if (typeof v1 === 'string') {
-      if (_hasJob(v1))
-        throw new Error(
-          '[conrad.addJob] Job with id "' + v1 + '" already exists.'
-        );
+    /**
+     * The hash of registered jobs. Each job must at least have a unique ID
+     * under the key "id" and a function under the key "job". This hash
+     * contains each running job and each waiting job.
+     *
+     * @type {Object}
+     */
+    var _jobs = {};
 
-      // One job (string, function):
-      if (typeof v2 === 'function') {
-        o = {
-          id: v1,
-          done: 0,
-          time: 0,
-          status: 'waiting',
-          currentTime: 0,
-          averageTime: 0,
-          weightTime: 0,
-          job: v2
-        };
+    /**
+     * The hash of currently running jobs.
+     *
+     * @type {Object}
+     */
+    var _runningJobs = {};
 
-      // One job (string, object):
-      } else if (typeof v2 === 'object') {
-        o = __extend(
-          {
-            id: v1,
-            done: 0,
-            time: 0,
-            status: 'waiting',
-            currentTime: 0,
-            averageTime: 0,
-            weightTime: 0
-          },
-          v2
-        );
+    /**
+     * The array of currently running jobs, sorted by priority.
+     *
+     * @type {Array}
+     */
+    var _sortedByPriorityJobs = [];
 
-      // If none of those cases, throw an error:
-      } else
-        throw new Error('[conrad.addJob] Wrong arguments.');
+    /**
+     * The array of currently waiting jobs.
+     *
+     * @type {Object}
+     */
+    var _waitingJobs = {};
 
-      // Effectively add the job:
-      _jobs[v1] = o;
-      _dispatch('jobAdded', __clone(o));
+    /**
+     * The array of finished jobs. They are stored in an array, since two jobs
+     * with the same "id" can happen at two different times.
+     *
+     * @type {Array}
+     */
+    var _doneJobs = [];
 
-      // Check if the loop has to be started:
-      if (!_isRunning && !_noStart) {
-        // Update the _lastFrameTime:
-        _lastFrameTime = __dateNow();
+    /**
+     * A dirty flag to keep conrad from starting: Indeed, when addJob() is called
+     * with several jobs, conrad must be started only at the end. This flag keeps
+     * me from duplicating the code that effectively adds a job.
+     *
+     * @type {Boolean}
+     */
+    var _noStart = false;
 
-        _dispatch('start');
-        _loop();
-      }
+    /**
+     * An hash containing some global settings about how conrad.js should
+     * behave.
+     *
+     * @type {Object}
+     */
+    var _parameters = {
+        frameDuration: 20,
+        history: true
+    };
 
-    // If none of those cases, throw an error:
-    } else
-      throw new Error('[conrad.addJob] Wrong arguments.');
-
-    return this;
-  }
-
-  /**
-   * Kills one or more jobs, indicated by their ids. It is only possible to
-   * kill running jobs or waiting jobs. If you try to kill a job that does not
-   * exist or that is already killed, a warning will be thrown.
-   *
-   * @param  {Array|String} v1 A string job id or an array of job ids.
-   * @return {Object}       Returns conrad.
-   */
-  function _killJob(v1) {
-    var i,
-        l,
-        k,
-        a,
-        job,
-        found = false;
-
-    // Array of job ids:
-    if (Array.isArray(v1))
-      for (i = 0, l = v1.length; i < l; i++)
-        _killJob(v1[i]);
-
-    // One job's id:
-    else if (typeof v1 === 'string') {
-      a = [_runningJobs, _waitingJobs, _jobs];
-
-      // Remove the job from the hashes:
-      for (i = 0, l = a.length; i < l; i++)
-        if (v1 in a[i]) {
-          job = a[i][v1];
-
-          if (_parameters.history) {
-            job.status = 'done';
-            _doneJobs.push(job);
-          }
-
-          _dispatch('jobEnded', __clone(job));
-          delete a[i][v1];
-
-          if (typeof job.end === 'function')
-            job.end();
-
-          found = true;
-        }
-
-      // Remove the priorities array:
-      a = _sortedByPriorityJobs;
-      for (i = 0, l = a.length; i < l; i++)
-        if (a[i].id === v1) {
-          a.splice(i, 1);
-          break;
-        }
-
-      if (!found)
-        throw new Error('[conrad.killJob] Job "' + v1 + '" not found.');
-
-    // If none of those cases, throw an error:
-    } else
-      throw new Error('[conrad.killJob] Wrong arguments.');
-
-    return this;
-  }
-
-  /**
-   * Kills every running, waiting, and just added jobs.
-   *
-   * @return {Object} Returns conrad.
-   */
-  function _killAll() {
-    var k,
-        jobs = __extend(_jobs, _runningJobs, _waitingJobs);
-
-    // Take every jobs and push them into the _doneJobs object:
-    if (_parameters.history)
-      for (k in jobs) {
-        jobs[k].status = 'done';
-        _doneJobs.push(jobs[k]);
-
-        if (typeof jobs[k].end === 'function')
-          jobs[k].end();
-      }
-
-    // Reinitialize the different jobs lists:
-    _jobs = {};
-    _waitingJobs = {};
-    _runningJobs = {};
-    _sortedByPriorityJobs = [];
-
-    // In case some jobs are added right after the kill:
-    _isRunning = false;
-
-    return this;
-  }
-
-  /**
-   * Returns true if a job with the specified id is currently running or
-   * waiting, and false else.
-   *
-   * @param  {String}  id The id of the job.
-   * @return {?Object} Returns the job object if it exists.
-   */
-  function _hasJob(id) {
-    var job = _jobs[id] || _runningJobs[id] || _waitingJobs[id];
-    return job ? __extend(job) : null;
-  }
-
-  /**
-   * This method will set the setting specified by "v1" to the value specified
-   * by "v2" if both are given, and else return the current value of the
-   * settings "v1".
-   *
-   * @param  {String}   v1 The name of the property.
-   * @param  {?*}       v2 Eventually, a value to set to the specified
-   *                       property.
-   * @return {Object|*} Returns the specified settings value if "v2" is not
-   *                    given, and conrad else.
-   */
-  function _settings(v1, v2) {
-    var o;
-
-    if (typeof a1 === 'string' && arguments.length === 1)
-      return _parameters[a1];
-    else {
-      o = (typeof a1 === 'object' && arguments.length === 1) ?
-        a1 || {} :
-        {};
-      if (typeof a1 === 'string')
-        o[a1] = a2;
-
-      for (var k in o)
-        if (o[k] !== undefined)
-          _parameters[k] = o[k];
-        else
-          delete _parameters[k];
+    /**
+     * This object contains every handlers bound to conrad events. It does not
+     * requirea any DOM implementation, since the events are all JavaScript.
+     *
+     * @type {Object}
+     */
+    var _handlers = Object.create(null);
 
-      return this;
+
+    /**
+     * PRIVATE FUNCTIONS:
+     * ******************
+     */
+
+    /**
+     * Will execute the handler everytime that the indicated event (or the
+     * indicated events) will be triggered.
+     *
+     * @param  {string|array|object} events  The name of the event (or the events
+     *                                       separated by spaces).
+     * @param  {function(Object)}    handler The handler to bind.
+     * @return {Object}                      Returns conrad.
+     */
+    function _bind(events, handler) {
+        var i,
+            i_end,
+            event,
+            eArray;
+
+        if (!arguments.length)
+            return;
+        else if (
+            arguments.length === 1 &&
+            Object(arguments[0]) === arguments[0]
+        )
+            for (events in arguments[0])
+                _bind(events, arguments[0][events]);
+        else if (arguments.length > 1) {
+            eArray =
+                Array.isArray(events) ?
+                    events :
+                    events.split(/ /);
+
+            for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
+                event = eArray[i];
+
+                if (!_handlers[event])
+                    _handlers[event] = [];
+
+                // Using an object instead of directly the handler will make possible
+                // later to add flags
+                _handlers[event].push({
+                    handler: handler
+                });
+            }
+        }
+    }
+
+    /**
+     * Removes the handler from a specified event (or specified events).
+     *
+     * @param  {?string}           events  The name of the event (or the events
+     *                                     separated by spaces). If undefined,
+     *                                     then all handlers are removed.
+     * @param  {?function(Object)} handler The handler to unbind. If undefined,
+     *                                     each handler bound to the event or the
+     *                                     events will be removed.
+     * @return {Object}            Returns conrad.
+     */
+    function _unbind(events, handler) {
+        var i,
+            i_end,
+            j,
+            j_end,
+            a,
+            event,
+            eArray = Array.isArray(events) ?
+                events :
+                events.split(/ /);
+
+        if (!arguments.length)
+            _handlers = Object.create(null);
+        else if (handler) {
+            for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
+                event = eArray[i];
+                if (_handlers[event]) {
+                    a = [];
+                    for (j = 0, j_end = _handlers[event].length; j !== j_end; j += 1)
+                        if (_handlers[event][j].handler !== handler)
+                            a.push(_handlers[event][j]);
+
+                    _handlers[event] = a;
+                }
+
+                if (_handlers[event] && _handlers[event].length === 0)
+                    delete _handlers[event];
+            }
+        } else
+            for (i = 0, i_end = eArray.length; i !== i_end; i += 1)
+                delete _handlers[eArray[i]];
+    }
+
+    /**
+     * Executes each handler bound to the event.
+     *
+     * @param  {string}  events The name of the event (or the events separated
+     *                          by spaces).
+     * @param  {?Object} data   The content of the event (optional).
+     * @return {Object}         Returns conrad.
+     */
+    function _dispatch(events, data) {
+        var i,
+            j,
+            i_end,
+            j_end,
+            event,
+            eventName,
+            eArray = Array.isArray(events) ?
+                events :
+                events.split(/ /);
+
+        data = data === undefined ? {} : data;
+
+        for (i = 0, i_end = eArray.length; i !== i_end; i += 1) {
+            eventName = eArray[i];
+
+            if (_handlers[eventName]) {
+                event = {
+                    type: eventName,
+                    data: data || {}
+                };
+
+                for (j = 0, j_end = _handlers[eventName].length; j !== j_end; j += 1)
+                    try {
+                        _handlers[eventName][j].handler(event);
+                    } catch (e) {
+                    }
+            }
+        }
+    }
+
+    /**
+     * Executes the most prioritary job once, and deals with filling the stats
+     * (done, time, averageTime, currentTime, etc...).
+     *
+     * @return {?Object} Returns the job object if it has to be killed, null else.
+     */
+    function _executeFirstJob() {
+        var i,
+            l,
+            test,
+            kill,
+            pushed = false,
+            time = __dateNow(),
+            job = _sortedByPriorityJobs.shift();
+
+        // Execute the job and look at the result:
+        test = job.job();
+
+        // Deal with stats:
+        time = __dateNow() - time;
+        job.done++;
+        job.time += time;
+        job.currentTime += time;
+        job.weightTime = job.currentTime / (job.weight || 1);
+        job.averageTime = job.time / job.done;
+
+        // Check if the job has to be killed:
+        kill = job.count ? (job.count <= job.done) : !test;
+
+        // Reset priorities:
+        if (!kill) {
+            for (i = 0, l = _sortedByPriorityJobs.length; i < l; i++)
+                if (_sortedByPriorityJobs[i].weightTime > job.weightTime) {
+                    _sortedByPriorityJobs.splice(i, 0, job);
+                    pushed = true;
+                    break;
+                }
+
+            if (!pushed)
+                _sortedByPriorityJobs.push(job);
+        }
+
+        return kill ? job : null;
+    }
+
+    /**
+     * Activates a job, by adding it to the _runningJobs object and the
+     * _sortedByPriorityJobs array. It also initializes its currentTime value.
+     *
+     * @param  {Object} job The job to activate.
+     */
+    function _activateJob(job) {
+        var l = _sortedByPriorityJobs.length;
+
+        // Add the job to the running jobs:
+        _runningJobs[job.id] = job;
+        job.status = 'running';
+
+        // Add the job to the priorities:
+        if (l) {
+            job.weightTime = _sortedByPriorityJobs[l - 1].weightTime;
+            job.currentTime = job.weightTime * (job.weight || 1);
+        }
+
+        // Initialize the job and dispatch:
+        job.startTime = __dateNow();
+        _dispatch('jobStarted', __clone(job));
+
+        _sortedByPriorityJobs.push(job);
+    }
+
+    /**
+     * The main loop of conrad.js:
+     *  . It executes job such that they all occupate the same processing time.
+     *  . It stops jobs that do not need to be executed anymore.
+     *  . It triggers callbacks when it is relevant.
+     *  . It starts waiting jobs when they need to be started.
+     *  . It injects frames to keep a constant frapes per second ratio.
+     *  . It stops itself when there are no more jobs to execute.
+     */
+    function _loop() {
+        var k,
+            o,
+            l,
+            job,
+            time,
+            deadJob;
+
+        // Deal with the newly added jobs (the _jobs object):
+        for (k in _jobs) {
+            job = _jobs[k];
+
+            if (job.after)
+                _waitingJobs[k] = job;
+            else
+                _activateJob(job);
+
+            delete _jobs[k];
+        }
+
+        // Set the _isRunning flag to false if there are no running job:
+        _isRunning = !!_sortedByPriorityJobs.length;
+
+        // Deal with the running jobs (the _runningJobs object):
+        while (
+        _sortedByPriorityJobs.length &&
+        __dateNow() - _lastFrameTime < _parameters.frameDuration
+            ) {
+            deadJob = _executeFirstJob();
+
+            // Deal with the case where the job has ended:
+            if (deadJob) {
+                _killJob(deadJob.id);
+
+                // Check for waiting jobs:
+                for (k in _waitingJobs)
+                    if (_waitingJobs[k].after === deadJob.id) {
+                        _activateJob(_waitingJobs[k]);
+                        delete _waitingJobs[k];
+                    }
+            }
+        }
+
+        // Check if conrad still has jobs to deal with, and kill it if not:
+        if (_isRunning) {
+            // Update the _lastFrameTime:
+            _lastFrameTime = __dateNow();
+
+            _dispatch('enterFrame');
+            setTimeout(_loop, 0);
+        } else
+            _dispatch('stop');
+    }
+
+    /**
+     * Adds one or more jobs, and starts the loop if no job was running before. A
+     * job is at least a unique string "id" and a function, and there are some
+     * parameters that you can specify for each job to modify the way conrad will
+     * execute it. If a job is added with the "id" of another job that is waiting
+     * or still running, an error will be thrown.
+     *
+     * When a job is added, it is referenced in the _jobs object, by its id.
+     * Then, if it has to be executed right now, it will be also referenced in
+     * the _runningJobs object. If it has to wait, then it will be added into the
+     * _waitingJobs object, until it can start.
+     *
+     * Keep reading this documentation to see how to call this method.
+     *
+     * @return {Object} Returns conrad.
+     *
+     * Adding one job:
+     * ***************
+     * Basically, a job is defined by its string id and a function (the job). It
+     * is also possible to add some parameters:
+     *
+     *  > conrad.addJob('myJobId', myJobFunction);
+     *  > conrad.addJob('myJobId', {
+   *  >   job: myJobFunction,
+   *  >   someParameter: someValue
+   *  > });
+     *  > conrad.addJob({
+   *  >   id: 'myJobId',
+   *  >   job: myJobFunction,
+   *  >   someParameter: someValue
+   *  > });
+     *
+     * Adding several jobs:
+     * ********************
+     * When adding several jobs at the same time, it is possible to specify
+     * parameters for each one individually or for all:
+     *
+     *  > conrad.addJob([
+     *  >   {
+   *  >     id: 'myJobId1',
+   *  >     job: myJobFunction1,
+   *  >     someParameter1: someValue1
+   *  >   },
+     *  >   {
+   *  >     id: 'myJobId2',
+   *  >     job: myJobFunction2,
+   *  >     someParameter2: someValue2
+   *  >   }
+     *  > ], {
+   *  >   someCommonParameter: someCommonValue
+   *  > });
+     *  > conrad.addJob({
+   *  >   myJobId1: {,
+   *  >     job: myJobFunction1,
+   *  >     someParameter1: someValue1
+   *  >   },
+   *  >   myJobId2: {,
+   *  >     job: myJobFunction2,
+   *  >     someParameter2: someValue2
+   *  >   }
+   *  > }, {
+   *  >   someCommonParameter: someCommonValue
+   *  > });
+     *  > conrad.addJob({
+   *  >   myJobId1: myJobFunction1,
+   *  >   myJobId2: myJobFunction2
+   *  > }, {
+   *  >   someCommonParameter: someCommonValue
+   *  > });
+     *
+     *  Recognized parameters:
+     *  **********************
+     *  Here is the exhaustive list of every accepted parameters:
+     *
+     *    {?Function} end      A callback to execute when the job is ended. It is
+     *                         not executed if the job is killed instead of ended
+     *                         "naturally".
+     *    {?Integer}  count    The number of time the job has to be executed.
+     *    {?Number}   weight   If specified, the job will be executed as it was
+     *                         added "weight" times.
+     *    {?String}   after    The id of another job (eventually not added yet).
+     *                         If specified, this job will start only when the
+     *                         specified "after" job is ended.
+     */
+    function _addJob(v1, v2) {
+        var i,
+            l,
+            o;
+
+        // Array of jobs:
+        if (Array.isArray(v1)) {
+            // Keep conrad to start until the last job is added:
+            _noStart = true;
+
+            for (i = 0, l = v1.length; i < l; i++)
+                _addJob(v1[i].id, __extend(v1[i], v2));
+
+            _noStart = false;
+            if (!_isRunning) {
+                // Update the _lastFrameTime:
+                _lastFrameTime = __dateNow();
+
+                _dispatch('start');
+                _loop();
+            }
+        } else if (typeof v1 === 'object') {
+            // One job (object):
+            if (typeof v1.id === 'string')
+                _addJob(v1.id, v1);
+
+            // Hash of jobs:
+            else {
+                // Keep conrad to start until the last job is added:
+                _noStart = true;
+
+                for (i in v1)
+                    if (typeof v1[i] === 'function')
+                        _addJob(i, __extend({
+                            job: v1[i]
+                        }, v2));
+                    else
+                        _addJob(i, __extend(v1[i], v2));
+
+                _noStart = false;
+                if (!_isRunning) {
+                    // Update the _lastFrameTime:
+                    _lastFrameTime = __dateNow();
+
+                    _dispatch('start');
+                    _loop();
+                }
+            }
+
+            // One job (string, *):
+        } else if (typeof v1 === 'string') {
+            if (_hasJob(v1))
+                throw new Error(
+                    '[conrad.addJob] Job with id "' + v1 + '" already exists.'
+                );
+
+            // One job (string, function):
+            if (typeof v2 === 'function') {
+                o = {
+                    id: v1,
+                    done: 0,
+                    time: 0,
+                    status: 'waiting',
+                    currentTime: 0,
+                    averageTime: 0,
+                    weightTime: 0,
+                    job: v2
+                };
+
+                // One job (string, object):
+            } else if (typeof v2 === 'object') {
+                o = __extend(
+                    {
+                        id: v1,
+                        done: 0,
+                        time: 0,
+                        status: 'waiting',
+                        currentTime: 0,
+                        averageTime: 0,
+                        weightTime: 0
+                    },
+                    v2
+                );
+
+                // If none of those cases, throw an error:
+            } else
+                throw new Error('[conrad.addJob] Wrong arguments.');
+
+            // Effectively add the job:
+            _jobs[v1] = o;
+            _dispatch('jobAdded', __clone(o));
+
+            // Check if the loop has to be started:
+            if (!_isRunning && !_noStart) {
+                // Update the _lastFrameTime:
+                _lastFrameTime = __dateNow();
+
+                _dispatch('start');
+                _loop();
+            }
+
+            // If none of those cases, throw an error:
+        } else
+            throw new Error('[conrad.addJob] Wrong arguments.');
+
+        return this;
+    }
+
+    /**
+     * Kills one or more jobs, indicated by their ids. It is only possible to
+     * kill running jobs or waiting jobs. If you try to kill a job that does not
+     * exist or that is already killed, a warning will be thrown.
+     *
+     * @param  {Array|String} v1 A string job id or an array of job ids.
+     * @return {Object}       Returns conrad.
+     */
+    function _killJob(v1) {
+        var i,
+            l,
+            k,
+            a,
+            job,
+            found = false;
+
+        // Array of job ids:
+        if (Array.isArray(v1))
+            for (i = 0, l = v1.length; i < l; i++)
+                _killJob(v1[i]);
+
+        // One job's id:
+        else if (typeof v1 === 'string') {
+            a = [_runningJobs, _waitingJobs, _jobs];
+
+            // Remove the job from the hashes:
+            for (i = 0, l = a.length; i < l; i++)
+                if (v1 in a[i]) {
+                    job = a[i][v1];
+
+                    if (_parameters.history) {
+                        job.status = 'done';
+                        _doneJobs.push(job);
+                    }
+
+                    _dispatch('jobEnded', __clone(job));
+                    delete a[i][v1];
+
+                    if (typeof job.end === 'function')
+                        job.end();
+
+                    found = true;
+                }
+
+            // Remove the priorities array:
+            a = _sortedByPriorityJobs;
+            for (i = 0, l = a.length; i < l; i++)
+                if (a[i].id === v1) {
+                    a.splice(i, 1);
+                    break;
+                }
+
+            if (!found)
+                throw new Error('[conrad.killJob] Job "' + v1 + '" not found.');
+
+            // If none of those cases, throw an error:
+        } else
+            throw new Error('[conrad.killJob] Wrong arguments.');
+
+        return this;
+    }
+
+    /**
+     * Kills every running, waiting, and just added jobs.
+     *
+     * @return {Object} Returns conrad.
+     */
+    function _killAll() {
+        var k,
+            jobs = __extend(_jobs, _runningJobs, _waitingJobs);
+
+        // Take every jobs and push them into the _doneJobs object:
+        if (_parameters.history)
+            for (k in jobs) {
+                jobs[k].status = 'done';
+                _doneJobs.push(jobs[k]);
+
+                if (typeof jobs[k].end === 'function')
+                    jobs[k].end();
+            }
+
+        // Reinitialize the different jobs lists:
+        _jobs = {};
+        _waitingJobs = {};
+        _runningJobs = {};
+        _sortedByPriorityJobs = [];
+
+        // In case some jobs are added right after the kill:
+        _isRunning = false;
+
+        return this;
+    }
+
+    /**
+     * Returns true if a job with the specified id is currently running or
+     * waiting, and false else.
+     *
+     * @param  {String}  id The id of the job.
+     * @return {?Object} Returns the job object if it exists.
+     */
+    function _hasJob(id) {
+        var job = _jobs[id] || _runningJobs[id] || _waitingJobs[id];
+        return job ? __extend(job) : null;
+    }
+
+    /**
+     * This method will set the setting specified by "v1" to the value specified
+     * by "v2" if both are given, and else return the current value of the
+     * settings "v1".
+     *
+     * @param  {String}   v1 The name of the property.
+     * @param  {?*}       v2 Eventually, a value to set to the specified
+     *                       property.
+     * @return {Object|*} Returns the specified settings value if "v2" is not
+     *                    given, and conrad else.
+     */
+    function _settings(v1, v2) {
+        var o;
+
+        if (typeof a1 === 'string' && arguments.length === 1)
+            return _parameters[a1];
+        else {
+            o = (typeof a1 === 'object' && arguments.length === 1) ?
+            a1 || {} :
+            {};
+            if (typeof a1 === 'string')
+                o[a1] = a2;
+
+            for (var k in o)
+                if (o[k] !== undefined)
+                    _parameters[k] = o[k];
+                else
+                    delete _parameters[k];
+
+            return this;
+        }
+    }
+
+    /**
+     * Returns true if conrad is currently running, and false else.
+     *
+     * @return {Boolean} Returns _isRunning.
+     */
+    function _getIsRunning() {
+        return _isRunning;
+    }
+
+    /**
+     * Unreference every job that is stored in the _doneJobs object. It will
+     * not be possible anymore to get stats about these jobs, but it will release
+     * the memory.
+     *
+     * @return {Object} Returns conrad.
+     */
+    function _clearHistory() {
+        _doneJobs = [];
+        return this;
+    }
+
+    /**
+     * Returns a snapshot of every data about jobs that wait to be started, are
+     * currently running or are done.
+     *
+     * It is possible to get only running, waiting or done jobs by giving
+     * "running", "waiting" or "done" as fist argument.
+     *
+     * It is also possible to get every job with a specified id by giving it as
+     * first argument. Also, using a RegExp instead of an id will return every
+     * jobs whose ids match the RegExp. And these two last use cases work as well
+     * by giving before "running", "waiting" or "done".
+     *
+     * @return {Array} The array of the matching jobs.
+     *
+     * Some call examples:
+     * *******************
+     *  > conrad.getStats('running')
+     *  > conrad.getStats('waiting')
+     *  > conrad.getStats('done')
+     *  > conrad.getStats('myJob')
+     *  > conrad.getStats(/test/)
+     *  > conrad.getStats('running', 'myRunningJob')
+     *  > conrad.getStats('running', /test/)
+     */
+    function _getStats(v1, v2) {
+        var a,
+            k,
+            i,
+            l,
+            stats,
+            pattern,
+            isPatternString;
+
+        if (!arguments.length) {
+            stats = [];
+
+            for (k in _jobs)
+                stats.push(_jobs[k]);
+
+            for (k in _waitingJobs)
+                stats.push(_waitingJobs[k]);
+
+            for (k in _runningJobs)
+                stats.push(_runningJobs[k]);
+
+            stats = stats.concat(_doneJobs);
+        }
+
+        if (typeof v1 === 'string')
+            switch (v1) {
+                case 'waiting':
+                    stats = __objectValues(_waitingJobs);
+                    break;
+                case 'running':
+                    stats = __objectValues(_runningJobs);
+                    break;
+                case 'done':
+                    stats = _doneJobs;
+                    break;
+                default:
+                    pattern = v1;
+            }
+
+        if (v1 instanceof RegExp)
+            pattern = v1;
+
+        if (!pattern && (typeof v2 === 'string' || v2 instanceof RegExp))
+            pattern = v2;
+
+        // Filter jobs if a pattern is given:
+        if (pattern) {
+            isPatternString = typeof pattern === 'string';
+
+            if (stats instanceof Array) {
+                a = stats;
+            } else if (typeof stats === 'object') {
+                a = [];
+
+                for (k in stats)
+                    a = a.concat(stats[k]);
+            } else {
+                a = [];
+
+                for (k in _jobs)
+                    a.push(_jobs[k]);
+
+                for (k in _waitingJobs)
+                    a.push(_waitingJobs[k]);
+
+                for (k in _runningJobs)
+                    a.push(_runningJobs[k]);
+
+                a = a.concat(_doneJobs);
+            }
+
+            stats = [];
+            for (i = 0, l = a.length; i < l; i++)
+                if (isPatternString ? a[i].id === pattern : a[i].id.match(pattern))
+                    stats.push(a[i]);
+        }
+
+        return __clone(stats);
+    }
+
+
+    /**
+     * TOOLS FUNCTIONS:
+     * ****************
+     */
+
+    /**
+     * This function takes any number of objects as arguments, copies from each
+     * of these objects each pair key/value into a new object, and finally
+     * returns this object.
+     *
+     * The arguments are parsed from the last one to the first one, such that
+     * when two objects have keys in common, the "earliest" object wins.
+     *
+     * Example:
+     * ********
+     *  > var o1 = {
+   *  >       a: 1,
+   *  >       b: 2,
+   *  >       c: '3'
+   *  >     },
+     *  >     o2 = {
+   *  >       c: '4',
+   *  >       d: [ 5 ]
+   *  >     };
+     *  > __extend(o1, o2);
+     *  > // Returns: {
+   *  > //   a: 1,
+   *  > //   b: 2,
+   *  > //   c: '3',
+   *  > //   d: [ 5 ]
+   *  > // };
+     *
+     * @param  {Object+} Any number of objects.
+     * @return {Object}  The merged object.
+     */
+    function __extend() {
+        var i,
+            k,
+            res = {},
+            l = arguments.length;
+
+        for (i = l - 1; i >= 0; i--)
+            for (k in arguments[i])
+                res[k] = arguments[i][k];
+
+        return res;
+    }
+
+    /**
+     * This function simply clones an object. This object must contain only
+     * objects, arrays and immutable values. Since it is not public, it does not
+     * deal with cyclic references, DOM elements and instantiated objects - so
+     * use it carefully.
+     *
+     * @param  {Object} The object to clone.
+     * @return {Object} The clone.
+     */
+    function __clone(item) {
+        var result, i, k, l;
+
+        if (!item)
+            return item;
+
+        if (Array.isArray(item)) {
+            result = [];
+            for (i = 0, l = item.length; i < l; i++)
+                result.push(__clone(item[i]));
+        } else if (typeof item === 'object') {
+            result = {};
+            for (i in item)
+                result[i] = __clone(item[i]);
+        } else
+            result = item;
+
+        return result;
+    }
+
+    /**
+     * Returns an array containing the values of an object.
+     *
+     * @param  {Object} The object.
+     * @return {Array}  The array of values.
+     */
+    function __objectValues(o) {
+        var k,
+            a = [];
+
+        for (k in o)
+            a.push(o[k]);
+
+        return a;
+    }
+
+    /**
+     * A short "Date.now()" polyfill.
+     *
+     * @return {Number} The current time (in ms).
+     */
+    function __dateNow() {
+        return Date.now ? Date.now() : new Date().getTime();
+    }
+
+    /**
+     * Polyfill for the Array.isArray function:
+     */
+    if (!Array.isArray)
+        Array.isArray = function (v) {
+            return Object.prototype.toString.call(v) === '[object Array]';
+        };
+
+
+    /**
+     * EXPORT PUBLIC API:
+     * ******************
+     */
+    var conrad = {
+        hasJob: _hasJob,
+        addJob: _addJob,
+        killJob: _killJob,
+        killAll: _killAll,
+        settings: _settings,
+        getStats: _getStats,
+        isRunning: _getIsRunning,
+        clearHistory: _clearHistory,
+
+        // Events management:
+        bind: _bind,
+        unbind: _unbind,
+
+        // Version:
+        version: '0.1.0'
+    };
+
+    if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = conrad;
+        exports.conrad = conrad;
+    }
+    global.conrad = conrad;
+})(this);
+
+// Hardcoded export for the node.js version:
+var sigma = this.sigma,
+    conrad = this.conrad;
+
+sigma.conrad = conrad;
+
+// Dirty polyfills to permit sigma usage in node
+if (HTMLElement === undefined)
+    var HTMLElement = function () {
+    };
+
+if (window === undefined)
+    var window = {
+        addEventListener: function () {
+        }
+    };
+
+if (typeof exports !== 'undefined') {
+    if (typeof module !== 'undefined' && module.exports)
+        exports = module.exports = sigma;
+    exports.sigma = sigma;
+}
+
+;(function (undefined) {
+    'use strict';
+
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
+
+    var _root = this;
+
+    // Initialize packages:
+    sigma.utils = sigma.utils || {};
+
+    /**
+     * MISC UTILS:
+     */
+    /**
+     * This function takes any number of objects as arguments, copies from each
+     * of these objects each pair key/value into a new object, and finally
+     * returns this object.
+     *
+     * The arguments are parsed from the last one to the first one, such that
+     * when several objects have keys in common, the "earliest" object wins.
+     *
+     * Example:
+     * ********
+     *  > var o1 = {
+   *  >       a: 1,
+   *  >       b: 2,
+   *  >       c: '3'
+   *  >     },
+     *  >     o2 = {
+   *  >       c: '4',
+   *  >       d: [ 5 ]
+   *  >     };
+     *  > sigma.utils.extend(o1, o2);
+     *  > // Returns: {
+   *  > //   a: 1,
+   *  > //   b: 2,
+   *  > //   c: '3',
+   *  > //   d: [ 5 ]
+   *  > // };
+     *
+     * @param  {object+} Any number of objects.
+     * @return {object}  The merged object.
+     */
+    sigma.utils.extend = function () {
+        var i,
+            k,
+            res = {},
+            l = arguments.length;
+
+        for (i = l - 1; i >= 0; i--)
+            for (k in arguments[i])
+                res[k] = arguments[i][k];
+
+        return res;
+    };
+
+    /**
+     * A short "Date.now()" polyfill.
+     *
+     * @return {Number} The current time (in ms).
+     */
+    sigma.utils.dateNow = function () {
+        return Date.now ? Date.now() : new Date().getTime();
+    };
+
+    /**
+     * Takes a package name as parameter and checks at each lebel if it exists,
+     * and if it does not, creates it.
+     *
+     * Example:
+     * ********
+     *  > sigma.utils.pkg('a.b.c');
+     *  > a.b.c;
+     *  > // Object {};
+     *  >
+     *  > sigma.utils.pkg('a.b.d');
+     *  > a.b;
+     *  > // Object { c: {}, d: {} };
+     *
+     * @param  {string} pkgName The name of the package to create/find.
+     * @return {object}         The related package.
+     */
+    sigma.utils.pkg = function (pkgName) {
+        return (pkgName || '').split('.').reduce(function (context, objName) {
+            return (objName in context) ?
+                context[objName] :
+                (context[objName] = {});
+        }, _root);
+    };
+
+    /**
+     * Returns a unique incremental number ID.
+     *
+     * Example:
+     * ********
+     *  > sigma.utils.id();
+     *  > // 1;
+     *  >
+     *  > sigma.utils.id();
+     *  > // 2;
+     *  >
+     *  > sigma.utils.id();
+     *  > // 3;
+     *
+     * @param  {string} pkgName The name of the package to create/find.
+     * @return {object}         The related package.
+     */
+    sigma.utils.id = (function () {
+        var i = 0;
+        return function () {
+            return ++i;
+        };
+    })();
+
+    /**
+     * This function takes an hexa color (for instance "#ffcc00" or "#fc0") or a
+     * rgb / rgba color (like "rgb(255,255,12)" or "rgba(255,255,12,1)") and
+     * returns an integer equal to "r * 255 * 255 + g * 255 + b", to gain some
+     * memory in the data given to WebGL shaders.
+     *
+     * Note that the function actually caches its results for better performance.
+     *
+     * @param  {string} val The hexa or rgba color.
+     * @return {number}     The number value.
+     */
+    var floatColorCache = {};
+
+    sigma.utils.floatColor = function (val) {
+
+        // Is the color already computed?
+        if (floatColorCache[val])
+            return floatColorCache[val];
+
+        var original = val,
+            r = 0,
+            g = 0,
+            b = 0;
+
+        if (val[0] === '#') {
+            val = val.slice(1);
+
+            if (val.length === 3) {
+                r = parseInt(val.charAt(0) + val.charAt(0), 16);
+                g = parseInt(val.charAt(1) + val.charAt(1), 16);
+                b = parseInt(val.charAt(2) + val.charAt(2), 16);
+            }
+            else {
+                r = parseInt(val.charAt(0) + val.charAt(1), 16);
+                g = parseInt(val.charAt(2) + val.charAt(3), 16);
+                b = parseInt(val.charAt(4) + val.charAt(5), 16);
+            }
+        } else if (val.match(/^ *rgba? *\(/)) {
+            val = val.match(
+                /^ *rgba? *\( *([0-9]*) *, *([0-9]*) *, *([0-9]*) *(,.*)?\) *$/
+            );
+            r = +val[1];
+            g = +val[2];
+            b = +val[3];
+        }
+
+        var color = (
+            r * 256 * 256 +
+            g * 256 +
+            b
+        );
+
+        // Caching the color
+        floatColorCache[original] = color;
+
+        return color;
+    };
+
+    /**
+     * Perform a zoom into a camera, with or without animation, to the
+     * coordinates indicated using a specified ratio.
+     *
+     * Recognized parameters:
+     * **********************
+     * Here is the exhaustive list of every accepted parameters in the animation
+     * object:
+     *
+     *   {?number} duration     An amount of time that means the duration of the
+     *                          animation. If this parameter doesn't exist the
+     *                          zoom will be performed without animation.
+     *   {?function} onComplete A function to perform it after the animation. It
+     *                          will be performed even if there is no duration.
+     *
+     * @param {camera}     The camera where perform the zoom.
+     * @param {x}          The X coordiantion where the zoom goes.
+     * @param {y}          The Y coordiantion where the zoom goes.
+     * @param {ratio}      The ratio to apply it to the current camera ratio.
+     * @param {?animation} A dictionary with options for a possible animation.
+     */
+    sigma.utils.zoomTo = function (camera, x, y, ratio, animation) {
+        var settings = camera.settings,
+            count,
+            newRatio,
+            animationSettings,
+            coordinates;
+
+        // Create the newRatio dealing with min / max:
+        newRatio = Math.max(
+            settings('zoomMin'),
+            Math.min(
+                settings('zoomMax'),
+                camera.ratio * ratio
+            )
+        );
+
+        // Check that the new ratio is different from the initial one:
+        if (newRatio !== camera.ratio) {
+            // Create the coordinates variable:
+            ratio = newRatio / camera.ratio;
+            coordinates = {
+                x: x * (1 - ratio) + camera.x,
+                y: y * (1 - ratio) + camera.y,
+                ratio: newRatio
+            };
+
+            if (animation && animation.duration) {
+                // Complete the animation setings:
+                count = sigma.misc.animation.killAll(camera);
+                animation = sigma.utils.extend(
+                    animation,
+                    {
+                        easing: count ? 'quadraticOut' : 'quadraticInOut'
+                    }
+                );
+
+                sigma.misc.animation.camera(camera, coordinates, animation);
+            } else {
+                camera.goTo(coordinates);
+                if (animation && animation.onComplete)
+                    animation.onComplete();
+            }
+        }
+    };
+
+    /**
+     * Return the control point coordinates for a quadratic bezier curve.
+     *
+     * @param  {number} x1  The X coordinate of the start point.
+     * @param  {number} y1  The Y coordinate of the start point.
+     * @param  {number} x2  The X coordinate of the end point.
+     * @param  {number} y2  The Y coordinate of the end point.
+     * @return {x,y}        The control point coordinates.
+     */
+    sigma.utils.getQuadraticControlPoint = function (x1, y1, x2, y2) {
+        return {
+            x: (x1 + x2) / 2 + (y2 - y1) / 4,
+            y: (y1 + y2) / 2 + (x1 - x2) / 4
+        };
+    };
+
+    /**
+     * Compute the coordinates of the point positioned
+     * at length t in the quadratic bezier curve.
+     *
+     * @param  {number} t  In [0,1] the step percentage to reach
+     *                     the point in the curve from the context point.
+     * @param  {number} x1 The X coordinate of the context point.
+     * @param  {number} y1 The Y coordinate of the context point.
+     * @param  {number} x2 The X coordinate of the ending point.
+     * @param  {number} y2 The Y coordinate of the ending point.
+     * @param  {number} xi The X coordinate of the control point.
+     * @param  {number} yi The Y coordinate of the control point.
+     * @return {object}    {x,y}.
+     */
+    sigma.utils.getPointOnQuadraticCurve = function (t, x1, y1, x2, y2, xi, yi) {
+        // http://stackoverflow.com/a/5634528
+        return {
+            x: Math.pow(1 - t, 2) * x1 + 2 * (1 - t) * t * xi + Math.pow(t, 2) * x2,
+            y: Math.pow(1 - t, 2) * y1 + 2 * (1 - t) * t * yi + Math.pow(t, 2) * y2
+        };
+    };
+
+    /**
+     * Compute the coordinates of the point positioned
+     * at length t in the cubic bezier curve.
+     *
+     * @param  {number} t  In [0,1] the step percentage to reach
+     *                     the point in the curve from the context point.
+     * @param  {number} x1 The X coordinate of the context point.
+     * @param  {number} y1 The Y coordinate of the context point.
+     * @param  {number} x2 The X coordinate of the end point.
+     * @param  {number} y2 The Y coordinate of the end point.
+     * @param  {number} cx The X coordinate of the first control point.
+     * @param  {number} cy The Y coordinate of the first control point.
+     * @param  {number} dx The X coordinate of the second control point.
+     * @param  {number} dy The Y coordinate of the second control point.
+     * @return {object}    {x,y} The point at t.
+     */
+    sigma.utils.getPointOnBezierCurve =
+        function (t, x1, y1, x2, y2, cx, cy, dx, dy) {
+            // http://stackoverflow.com/a/15397596
+            // Blending functions:
+            var B0_t = Math.pow(1 - t, 3),
+                B1_t = 3 * t * Math.pow(1 - t, 2),
+                B2_t = 3 * Math.pow(t, 2) * (1 - t),
+                B3_t = Math.pow(t, 3);
+
+            return {
+                x: (B0_t * x1) + (B1_t * cx) + (B2_t * dx) + (B3_t * x2),
+                y: (B0_t * y1) + (B1_t * cy) + (B2_t * dy) + (B3_t * y2)
+            };
+        };
+
+    /**
+     * Return the coordinates of the two control points for a self loop (i.e.
+     * where the start point is also the end point) computed as a cubic bezier
+     * curve.
+     *
+     * @param  {number} x    The X coordinate of the node.
+     * @param  {number} y    The Y coordinate of the node.
+     * @param  {number} size The node size.
+     * @return {x1,y1,x2,y2} The coordinates of the two control points.
+     */
+    sigma.utils.getSelfLoopControlPoints = function (x, y, size) {
+        return {
+            x1: x - size * 7,
+            y1: y,
+            x2: x,
+            y2: y + size * 7
+        };
+    };
+
+    /**
+     * Return the euclidian distance between two points of a plane
+     * with an orthonormal basis.
+     *
+     * @param  {number} x1  The X coordinate of the first point.
+     * @param  {number} y1  The Y coordinate of the first point.
+     * @param  {number} x2  The X coordinate of the second point.
+     * @param  {number} y2  The Y coordinate of the second point.
+     * @return {number}     The euclidian distance.
+     */
+    sigma.utils.getDistance = function (x0, y0, x1, y1) {
+        return Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2));
+    };
+
+    /**
+     * Return the coordinates of the intersection points of two circles.
+     *
+     * @param  {number} x0  The X coordinate of center location of the first
+     *                      circle.
+     * @param  {number} y0  The Y coordinate of center location of the first
+     *                      circle.
+     * @param  {number} r0  The radius of the first circle.
+     * @param  {number} x1  The X coordinate of center location of the second
+     *                      circle.
+     * @param  {number} y1  The Y coordinate of center location of the second
+     *                      circle.
+     * @param  {number} r1  The radius of the second circle.
+     * @return {xi,yi}      The coordinates of the intersection points.
+     */
+    sigma.utils.getCircleIntersection = function (x0, y0, r0, x1, y1, r1) {
+        // http://stackoverflow.com/a/12219802
+        var a, dx, dy, d, h, rx, ry, x2, y2;
+
+        // dx and dy are the vertical and horizontal distances between the circle
+        // centers:
+        dx = x1 - x0;
+        dy = y1 - y0;
+
+        // Determine the straight-line distance between the centers:
+        d = Math.sqrt((dy * dy) + (dx * dx));
+
+        // Check for solvability:
+        if (d > (r0 + r1)) {
+            // No solution. circles do not intersect.
+            return false;
+        }
+        if (d < Math.abs(r0 - r1)) {
+            // No solution. one circle is contained in the other.
+            return false;
+        }
+
+        //'point 2' is the point where the line through the circle intersection
+        // points crosses the line between the circle centers.
+
+        // Determine the distance from point 0 to point 2:
+        a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d);
+
+        // Determine the coordinates of point 2:
+        x2 = x0 + (dx * a / d);
+        y2 = y0 + (dy * a / d);
+
+        // Determine the distance from point 2 to either of the intersection
+        // points:
+        h = Math.sqrt((r0 * r0) - (a * a));
+
+        // Determine the offsets of the intersection points from point 2:
+        rx = -dy * (h / d);
+        ry = dx * (h / d);
+
+        // Determine the absolute intersection points:
+        var xi = x2 + rx;
+        var xi_prime = x2 - rx;
+        var yi = y2 + ry;
+        var yi_prime = y2 - ry;
+
+        return {xi: xi, xi_prime: xi_prime, yi: yi, yi_prime: yi_prime};
+    };
+
+    /**
+     * Check if a point is on a line segment.
+     *
+     * @param  {number} x       The X coordinate of the point to check.
+     * @param  {number} y       The Y coordinate of the point to check.
+     * @param  {number} x1      The X coordinate of the line start point.
+     * @param  {number} y1      The Y coordinate of the line start point.
+     * @param  {number} x2      The X coordinate of the line end point.
+     * @param  {number} y2      The Y coordinate of the line end point.
+     * @param  {number} epsilon The precision (consider the line thickness).
+     * @return {boolean}        True if point is "close to" the line
+     *                          segment, false otherwise.
+     */
+    sigma.utils.isPointOnSegment = function (x, y, x1, y1, x2, y2, epsilon) {
+        // http://stackoverflow.com/a/328122
+        var crossProduct = Math.abs((y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)),
+            d = sigma.utils.getDistance(x1, y1, x2, y2),
+            nCrossProduct = crossProduct / d; // normalized cross product
+
+        return (nCrossProduct < epsilon &&
+        Math.min(x1, x2) <= x && x <= Math.max(x1, x2) &&
+        Math.min(y1, y2) <= y && y <= Math.max(y1, y2));
+    };
+
+    /**
+     * Check if a point is on a quadratic bezier curve segment with a thickness.
+     *
+     * @param  {number} x       The X coordinate of the point to check.
+     * @param  {number} y       The Y coordinate of the point to check.
+     * @param  {number} x1      The X coordinate of the curve start point.
+     * @param  {number} y1      The Y coordinate of the curve start point.
+     * @param  {number} x2      The X coordinate of the curve end point.
+     * @param  {number} y2      The Y coordinate of the curve end point.
+     * @param  {number} cpx     The X coordinate of the curve control point.
+     * @param  {number} cpy     The Y coordinate of the curve control point.
+     * @param  {number} epsilon The precision (consider the line thickness).
+     * @return {boolean}        True if (x,y) is on the curve segment,
+     *                          false otherwise.
+     */
+    sigma.utils.isPointOnQuadraticCurve =
+        function (x, y, x1, y1, x2, y2, cpx, cpy, epsilon) {
+            // Fails if the point is too far from the extremities of the segment,
+            // preventing for more costly computation:
+            var dP1P2 = sigma.utils.getDistance(x1, y1, x2, y2);
+            if (Math.abs(x - x1) > dP1P2 || Math.abs(y - y1) > dP1P2) {
+                return false;
+            }
+
+            var dP1 = sigma.utils.getDistance(x, y, x1, y1),
+                dP2 = sigma.utils.getDistance(x, y, x2, y2),
+                t = 0.5,
+                r = (dP1 < dP2) ? -0.01 : 0.01,
+                rThreshold = 0.001,
+                i = 100,
+                pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy),
+                dt = sigma.utils.getDistance(x, y, pt.x, pt.y),
+                old_dt;
+
+            // This algorithm minimizes the distance from the point to the curve. It
+            // find the optimal t value where t=0 is the start point and t=1 is the end
+            // point of the curve, starting from t=0.5.
+            // It terminates because it runs a maximum of i interations.
+            while (i-- > 0 &&
+            t >= 0 && t <= 1 &&
+            (dt > epsilon) &&
+            (r > rThreshold || r < -rThreshold)) {
+                old_dt = dt;
+                pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy);
+                dt = sigma.utils.getDistance(x, y, pt.x, pt.y);
+
+                if (dt > old_dt) {
+                    // not the right direction:
+                    // halfstep in the opposite direction
+                    r = -r / 2;
+                    t += r;
+                }
+                else if (t + r < 0 || t + r > 1) {
+                    // oops, we've gone too far:
+                    // revert with a halfstep
+                    r = r / 2;
+                    dt = old_dt;
+                }
+                else {
+                    // progress:
+                    t += r;
+                }
+            }
+
+            return dt < epsilon;
+        };
+
+
+    /**
+     * Check if a point is on a cubic bezier curve segment with a thickness.
+     *
+     * @param  {number} x       The X coordinate of the point to check.
+     * @param  {number} y       The Y coordinate of the point to check.
+     * @param  {number} x1      The X coordinate of the curve start point.
+     * @param  {number} y1      The Y coordinate of the curve start point.
+     * @param  {number} x2      The X coordinate of the curve end point.
+     * @param  {number} y2      The Y coordinate of the curve end point.
+     * @param  {number} cpx1    The X coordinate of the 1st curve control point.
+     * @param  {number} cpy1    The Y coordinate of the 1st curve control point.
+     * @param  {number} cpx2    The X coordinate of the 2nd curve control point.
+     * @param  {number} cpy2    The Y coordinate of the 2nd curve control point.
+     * @param  {number} epsilon The precision (consider the line thickness).
+     * @return {boolean}        True if (x,y) is on the curve segment,
+     *                          false otherwise.
+     */
+    sigma.utils.isPointOnBezierCurve =
+        function (x, y, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2, epsilon) {
+            // Fails if the point is too far from the extremities of the segment,
+            // preventing for more costly computation:
+            var dP1CP1 = sigma.utils.getDistance(x1, y1, cpx1, cpy1);
+            if (Math.abs(x - x1) > dP1CP1 || Math.abs(y - y1) > dP1CP1) {
+                return false;
+            }
+
+            var dP1 = sigma.utils.getDistance(x, y, x1, y1),
+                dP2 = sigma.utils.getDistance(x, y, x2, y2),
+                t = 0.5,
+                r = (dP1 < dP2) ? -0.01 : 0.01,
+                rThreshold = 0.001,
+                i = 100,
+                pt = sigma.utils.getPointOnBezierCurve(
+                    t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2),
+                dt = sigma.utils.getDistance(x, y, pt.x, pt.y),
+                old_dt;
+
+            // This algorithm minimizes the distance from the point to the curve. It
+            // find the optimal t value where t=0 is the start point and t=1 is the end
+            // point of the curve, starting from t=0.5.
+            // It terminates because it runs a maximum of i interations.
+            while (i-- > 0 &&
+            t >= 0 && t <= 1 &&
+            (dt > epsilon) &&
+            (r > rThreshold || r < -rThreshold)) {
+                old_dt = dt;
+                pt = sigma.utils.getPointOnBezierCurve(
+                    t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2);
+                dt = sigma.utils.getDistance(x, y, pt.x, pt.y);
+
+                if (dt > old_dt) {
+                    // not the right direction:
+                    // halfstep in the opposite direction
+                    r = -r / 2;
+                    t += r;
+                }
+                else if (t + r < 0 || t + r > 1) {
+                    // oops, we've gone too far:
+                    // revert with a halfstep
+                    r = r / 2;
+                    dt = old_dt;
+                }
+                else {
+                    // progress:
+                    t += r;
+                }
+            }
+
+            return dt < epsilon;
+        };
+
+
+    /**
+     * ************
+     * EVENTS UTILS:
+     * ************
+     */
+    /**
+     * Here are some useful functions to unify extraction of the information we
+     * need with mouse events and touch events, from different browsers:
+     */
+
+    /**
+     * Extract the local X position from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {number}   The local X value of the mouse.
+     */
+    sigma.utils.getX = function (e) {
+        return (
+            (e.offsetX !== undefined && e.offsetX) ||
+            (e.layerX !== undefined && e.layerX) ||
+            (e.clientX !== undefined && e.clientX)
+        );
+    };
+
+    /**
+     * Extract the local Y position from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {number}   The local Y value of the mouse.
+     */
+    sigma.utils.getY = function (e) {
+        return (
+            (e.offsetY !== undefined && e.offsetY) ||
+            (e.layerY !== undefined && e.layerY) ||
+            (e.clientY !== undefined && e.clientY)
+        );
+    };
+
+    /**
+     * The pixel ratio of the screen. Taking zoom into account
+     *
+     * @return {number}        Pixel ratio of the screen
+     */
+    sigma.utils.getPixelRatio = function () {
+        var ratio = 1;
+        if (window.screen.deviceXDPI !== undefined &&
+            window.screen.logicalXDPI !== undefined &&
+            window.screen.deviceXDPI > window.screen.logicalXDPI) {
+            ratio = window.screen.systemXDPI / window.screen.logicalXDPI;
+        }
+        else if (window.devicePixelRatio !== undefined) {
+            ratio = window.devicePixelRatio;
+        }
+        return ratio;
+    };
+
+    /**
+     * Extract the width from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {number}   The width of the event's target.
+     */
+    sigma.utils.getWidth = function (e) {
+        var w = (!e.target.ownerSVGElement) ?
+            e.target.width :
+            e.target.ownerSVGElement.width;
+
+        return (
+            (typeof w === 'number' && w) ||
+            (w !== undefined && w.baseVal !== undefined && w.baseVal.value)
+        );
+    };
+
+    /**
+     * Extract the center from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {object}   The center of the event's target.
+     */
+    sigma.utils.getCenter = function (e) {
+        var ratio = e.target.namespaceURI.indexOf('svg') !== -1 ? 1 :
+            sigma.utils.getPixelRatio();
+        return {
+            x: sigma.utils.getWidth(e) / (2 * ratio),
+            y: sigma.utils.getHeight(e) / (2 * ratio),
+        };
+    };
+
+    /**
+     * Convert mouse coords to sigma coords
+     *
+     * @param  {event}   e A mouse or touch event.
+     * @param  {number?} x The x coord to convert
+     * @param  {number?} x The y coord to convert
+     *
+     * @return {object}    The standardized event
+     */
+    sigma.utils.mouseCoords = function (e, x, y) {
+        x = x || sigma.utils.getX(e);
+        y = y || sigma.utils.getY(e);
+        return {
+            x: x - sigma.utils.getCenter(e).x,
+            y: y - sigma.utils.getCenter(e).y,
+            clientX: e.clientX,
+            clientY: e.clientY,
+            ctrlKey: e.ctrlKey,
+            metaKey: e.metaKey,
+            altKey: e.altKey,
+            shiftKey: e.shiftKey
+        };
+    };
+
+    /**
+     * Extract the height from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {number}   The height of the event's target.
+     */
+    sigma.utils.getHeight = function (e) {
+        var h = (!e.target.ownerSVGElement) ?
+            e.target.height :
+            e.target.ownerSVGElement.height;
+
+        return (
+            (typeof h === 'number' && h) ||
+            (h !== undefined && h.baseVal !== undefined && h.baseVal.value)
+        );
+    };
+
+    /**
+     * Extract the wheel delta from a mouse or touch event.
+     *
+     * @param  {event}  e A mouse or touch event.
+     * @return {number}   The wheel delta of the mouse.
+     */
+    sigma.utils.getDelta = function (e) {
+        return (
+            (e.wheelDelta !== undefined && e.wheelDelta) ||
+            (e.detail !== undefined && -e.detail)
+        );
+    };
+
+    /**
+     * Returns the offset of a DOM element.
+     *
+     * @param  {DOMElement} dom The element to retrieve the position.
+     * @return {object}         The offset of the DOM element (top, left).
+     */
+    sigma.utils.getOffset = function (dom) {
+        var left = 0,
+            top = 0;
+
+        while (dom) {
+            top = top + parseInt(dom.offsetTop);
+            left = left + parseInt(dom.offsetLeft);
+            dom = dom.offsetParent;
+        }
+
+        return {
+            top: top,
+            left: left
+        };
+    };
+
+    /**
+     * Simulates a "double click" event.
+     *
+     * @param  {HTMLElement} target   The event target.
+     * @param  {string}      type     The event type.
+     * @param  {function}    callback The callback to execute.
+     */
+    sigma.utils.doubleClick = function (target, type, callback) {
+        var clicks = 0,
+            self = this,
+            handlers;
+
+        target._doubleClickHandler = target._doubleClickHandler || {};
+        target._doubleClickHandler[type] = target._doubleClickHandler[type] || [];
+        handlers = target._doubleClickHandler[type];
+
+        handlers.push(function (e) {
+            clicks++;
+
+            if (clicks === 2) {
+                clicks = 0;
+                return callback(e);
+            } else if (clicks === 1) {
+                setTimeout(function () {
+                    clicks = 0;
+                }, sigma.settings.doubleClickTimeout);
+            }
+        });
+
+        target.addEventListener(type, handlers[handlers.length - 1], false);
+    };
+
+    /**
+     * Unbind simulated "double click" events.
+     *
+     * @param  {HTMLElement} target   The event target.
+     * @param  {string}      type     The event type.
+     */
+    sigma.utils.unbindDoubleClick = function (target, type) {
+        var handler,
+            handlers = (target._doubleClickHandler || {})[type] || [];
+
+        while ((handler = handlers.pop())) {
+            target.removeEventListener(type, handler);
+        }
+
+        delete (target._doubleClickHandler || {})[type];
+    };
+
+
+    /**
+     * Here are just some of the most basic easing functions, used for the
+     * animated camera "goTo" calls.
+     *
+     * If you need some more easings functions, don't hesitate to add them to
+     * sigma.utils.easings. But I will not add some more here or merge PRs
+     * containing, because I do not want sigma sources full of overkill and never
+     * used stuff...
+     */
+    sigma.utils.easings = sigma.utils.easings || {};
+    sigma.utils.easings.linearNone = function (k) {
+        return k;
+    };
+    sigma.utils.easings.quadraticIn = function (k) {
+        return k * k;
+    };
+    sigma.utils.easings.quadraticOut = function (k) {
+        return k * (2 - k);
+    };
+    sigma.utils.easings.quadraticInOut = function (k) {
+        if ((k *= 2) < 1)
+            return 0.5 * k * k;
+        return -0.5 * (--k * (k - 2) - 1);
+    };
+    sigma.utils.easings.cubicIn = function (k) {
+        return k * k * k;
+    };
+    sigma.utils.easings.cubicOut = function (k) {
+        return --k * k * k + 1;
+    };
+    sigma.utils.easings.cubicInOut = function (k) {
+        if ((k *= 2) < 1)
+            return 0.5 * k * k * k;
+        return 0.5 * ((k -= 2) * k * k + 2);
+    };
+
+
+    /**
+     * ************
+     * WEBGL UTILS:
+     * ************
+     */
+    /**
+     * Loads a WebGL shader and returns it.
+     *
+     * @param  {WebGLContext}           gl           The WebGLContext to use.
+     * @param  {string}                 shaderSource The shader source.
+     * @param  {number}                 shaderType   The type of shader.
+     * @param  {function(string): void} error        Callback for errors.
+     * @return {WebGLShader}                         The created shader.
+     */
+    sigma.utils.loadShader = function (gl, shaderSource, shaderType, error) {
+        var compiled,
+            shader = gl.createShader(shaderType);
+
+        // Load the shader source
+        gl.shaderSource(shader, shaderSource);
+
+        // Compile the shader
+        gl.compileShader(shader);
+
+        // Check the compile status
+        compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+
+        // If something went wrong:
+        if (!compiled) {
+            if (error) {
+                error(
+                    'Error compiling shader "' + shader + '":' +
+                    gl.getShaderInfoLog(shader)
+                );
+            }
+
+            gl.deleteShader(shader);
+            return null;
+        }
+
+        return shader;
+    };
+
+    /**
+     * Creates a program, attaches shaders, binds attrib locations, links the
+     * program and calls useProgram.
+     *
+     * @param  {Array.<WebGLShader>}    shaders   The shaders to attach.
+     * @param  {Array.<string>}         attribs   The attribs names.
+     * @param  {Array.<number>}         locations The locations for the attribs.
+     * @param  {function(string): void} error     Callback for errors.
+     * @return {WebGLProgram}                     The created program.
+     */
+    sigma.utils.loadProgram = function (gl, shaders, attribs, loc, error) {
+        var i,
+            linked,
+            program = gl.createProgram();
+
+        for (i = 0; i < shaders.length; ++i)
+            gl.attachShader(program, shaders[i]);
+
+        if (attribs)
+            for (i = 0; i < attribs.length; ++i)
+                gl.bindAttribLocation(
+                    program,
+                    locations ? locations[i] : i,
+                    opt_attribs[i]
+                );
+
+        gl.linkProgram(program);
+
+        // Check the link status
+        linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+        if (!linked) {
+            if (error)
+                error('Error in program linking: ' + gl.getProgramInfoLog(program));
+
+            gl.deleteProgram(program);
+            return null;
+        }
+
+        return program;
+    };
+
+
+    /**
+     * *********
+     * MATRICES:
+     * *********
+     * The following utils are just here to help generating the transformation
+     * matrices for the WebGL renderers.
+     */
+    sigma.utils.pkg('sigma.utils.matrices');
+
+    /**
+     * The returns a 3x3 translation matrix.
+     *
+     * @param  {number} dx The X translation.
+     * @param  {number} dy The Y translation.
+     * @return {array}     Returns the matrix.
+     */
+    sigma.utils.matrices.translation = function (dx, dy) {
+        return [
+            1, 0, 0,
+            0, 1, 0,
+            dx, dy, 1
+        ];
+    };
+
+    /**
+     * The returns a 3x3 or 2x2 rotation matrix.
+     *
+     * @param  {number}  angle The rotation angle.
+     * @param  {boolean} m2    If true, the function will return a 2x2 matrix.
+     * @return {array}         Returns the matrix.
+     */
+    sigma.utils.matrices.rotation = function (angle, m2) {
+        var cos = Math.cos(angle),
+            sin = Math.sin(angle);
+
+        return m2 ? [
+            cos, -sin,
+            sin, cos
+        ] : [
+            cos, -sin, 0,
+            sin, cos, 0,
+            0, 0, 1
+        ];
+    };
+
+    /**
+     * The returns a 3x3 or 2x2 homothetic transformation matrix.
+     *
+     * @param  {number}  ratio The scaling ratio.
+     * @param  {boolean} m2    If true, the function will return a 2x2 matrix.
+     * @return {array}         Returns the matrix.
+     */
+    sigma.utils.matrices.scale = function (ratio, m2) {
+        return m2 ? [
+            ratio, 0,
+            0, ratio
+        ] : [
+            ratio, 0, 0,
+            0, ratio, 0,
+            0, 0, 1
+        ];
+    };
+
+    /**
+     * The returns a 3x3 or 2x2 homothetic transformation matrix.
+     *
+     * @param  {array}   a  The first matrix.
+     * @param  {array}   b  The second matrix.
+     * @param  {boolean} m2 If true, the function will assume both matrices are
+     *                      2x2.
+     * @return {array}      Returns the matrix.
+     */
+    sigma.utils.matrices.multiply = function (a, b, m2) {
+        var l = m2 ? 2 : 3,
+            a00 = a[0 * l + 0],
+            a01 = a[0 * l + 1],
+            a02 = a[0 * l + 2],
+            a10 = a[1 * l + 0],
+            a11 = a[1 * l + 1],
+            a12 = a[1 * l + 2],
+            a20 = a[2 * l + 0],
+            a21 = a[2 * l + 1],
+            a22 = a[2 * l + 2],
+            b00 = b[0 * l + 0],
+            b01 = b[0 * l + 1],
+            b02 = b[0 * l + 2],
+            b10 = b[1 * l + 0],
+            b11 = b[1 * l + 1],
+            b12 = b[1 * l + 2],
+            b20 = b[2 * l + 0],
+            b21 = b[2 * l + 1],
+            b22 = b[2 * l + 2];
+
+        return m2 ? [
+            a00 * b00 + a01 * b10,
+            a00 * b01 + a01 * b11,
+            a10 * b00 + a11 * b10,
+            a10 * b01 + a11 * b11
+        ] : [
+            a00 * b00 + a01 * b10 + a02 * b20,
+            a00 * b01 + a01 * b11 + a02 * b21,
+            a00 * b02 + a01 * b12 + a02 * b22,
+            a10 * b00 + a11 * b10 + a12 * b20,
+            a10 * b01 + a11 * b11 + a12 * b21,
+            a10 * b02 + a11 * b12 + a12 * b22,
+            a20 * b00 + a21 * b10 + a22 * b20,
+            a20 * b01 + a21 * b11 + a22 * b21,
+            a20 * b02 + a21 * b12 + a22 * b22
+        ];
+    };
+}).call(this);
+
+;(function (global) {
+    'use strict';
+
+    /**
+     * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+     * http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
+     * requestAnimationFrame polyfill by Erik Möller.
+     * fixes from Paul Irish and Tino Zijdel
+     * MIT license
+     */
+    var x,
+        lastTime = 0,
+        vendors = ['ms', 'moz', 'webkit', 'o'];
+
+    for (x = 0; x < vendors.length && !global.requestAnimationFrame; x++) {
+        global.requestAnimationFrame =
+            global[vendors[x] + 'RequestAnimationFrame'];
+        global.cancelAnimationFrame =
+            global[vendors[x] + 'CancelAnimationFrame'] ||
+            global[vendors[x] + 'CancelRequestAnimationFrame'];
+    }
+
+    if (!global.requestAnimationFrame)
+        global.requestAnimationFrame = function (callback, element) {
+            var currTime = new Date().getTime(),
+                timeToCall = Math.max(0, 16 - (currTime - lastTime)),
+                id = global.setTimeout(
+                    function () {
+                        callback(currTime + timeToCall);
+                    },
+                    timeToCall
+                );
+
+            lastTime = currTime + timeToCall;
+            return id;
+        };
+
+    if (!global.cancelAnimationFrame)
+        global.cancelAnimationFrame = function (id) {
+            clearTimeout(id);
+        };
+
+    /**
+     * Function.prototype.bind polyfill found on MDN.
+     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
+     * Public domain
+     */
+    if (!Function.prototype.bind)
+        Function.prototype.bind = function (oThis) {
+            if (typeof this !== 'function')
+            // Closest thing possible to the ECMAScript 5 internal IsCallable
+            // function:
+                throw new TypeError(
+                    'Function.prototype.bind - what is trying to be bound is not callable'
+                );
+
+            var aArgs = Array.prototype.slice.call(arguments, 1),
+                fToBind = this,
+                fNOP,
+                fBound;
+
+            fNOP = function () {
+            };
+            fBound = function () {
+                return fToBind.apply(
+                    this instanceof fNOP && oThis ?
+                        this :
+                        oThis,
+                    aArgs.concat(Array.prototype.slice.call(arguments))
+                );
+            };
+
+            fNOP.prototype = this.prototype;
+            fBound.prototype = new fNOP();
+
+            return fBound;
+        };
+})(this);
+
+;(function (undefined) {
+    'use strict';
+
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
+
+    // Packages initialization:
+    sigma.utils.pkg('sigma.settings');
+
+    var settings = {
+        /**
+         * GRAPH SETTINGS:
+         * ***************
+         */
+        // {boolean} Indicates if the data have to be cloned in methods to add
+        //           nodes or edges.
+        clone: true,
+        // {boolean} Indicates if nodes "id" values and edges "id", "source" and
+        //           "target" values must be set as immutable.
+        immutable: true,
+        // {boolean} Indicates if sigma can log its errors and warnings.
+        verbose: false,
+
+
+        /**
+         * RENDERERS SETTINGS:
+         * *******************
+         */
+        // {string}
+        classPrefix: 'sigma',
+        // {string}
+        defaultNodeType: 'def',
+        // {string}
+        defaultEdgeType: 'def',
+        // {string}
+        defaultLabelColor: '#000',
+        // {string}
+        defaultEdgeColor: '#000',
+        // {string}
+        defaultNodeColor: '#000',
+        // {string}
+        defaultLabelSize: 14,
+        // {string} Indicates how to choose the edges color. Available values:
+        //          "source", "target", "default"
+        edgeColor: 'source',
+        // {number} Defines the minimal edge's arrow display size.
+        minArrowSize: 0,
+        // {string}
+        font: 'arial',
+        // {string} Example: 'bold'
+        fontStyle: '',
+        // {string} Indicates how to choose the labels color. Available values:
+        //          "node", "default"
+        labelColor: 'default',
+        // {string} Indicates how to choose the labels size. Available values:
+        //          "fixed", "proportional"
+        labelSize: 'fixed',
+        // {string} The ratio between the font size of the label and the node size.
+        labelSizeRatio: 1,
+        // {number} The minimum size a node must have to see its label displayed.
+        labelThreshold: 8,
+        // {number} The oversampling factor used in WebGL renderer.
+        webglOversamplingRatio: 2,
+        // {number} The size of the border of hovered nodes.
+        borderSize: 0,
+        // {number} The default hovered node border's color.
+        defaultNodeBorderColor: '#000',
+        // {number} The hovered node's label font. If not specified, will heritate
+        //          the "font" value.
+        hoverFont: '',
+        // {boolean} If true, then only one node can be hovered at a time.
+        singleHover: true,
+        // {string} Example: 'bold'
+        hoverFontStyle: '',
+        // {string} Indicates how to choose the hovered nodes shadow color.
+        //          Available values: "node", "default"
+        labelHoverShadow: 'default',
+        // {string}
+        labelHoverShadowColor: '#000',
+        // {string} Indicates how to choose the hovered nodes color.
+        //          Available values: "node", "default"
+        nodeHoverColor: 'node',
+        // {string}
+        defaultNodeHoverColor: '#000',
+        // {string} Indicates how to choose the hovered nodes background color.
+        //          Available values: "node", "default"
+        labelHoverBGColor: 'default',
+        // {string}
+        defaultHoverLabelBGColor: '#fff',
+        // {string} Indicates how to choose the hovered labels color.
+        //          Available values: "node", "default"
+        labelHoverColor: 'default',
+        // {string}
+        defaultLabelHoverColor: '#000',
+        // {string} Indicates how to choose the edges hover color. Available values:
+        //          "edge", "default"
+        edgeHoverColor: 'edge',
+        // {number} The size multiplicator of hovered edges.
+        edgeHoverSizeRatio: 1,
+        // {string}
+        defaultEdgeHoverColor: '#000',
+        // {boolean} Indicates if the edge extremities must be hovered when the
+        //           edge is hovered.
+        edgeHoverExtremities: false,
+        // {booleans} The different drawing modes:
+        //           false: Layered not displayed.
+        //           true: Layered displayed.
+        drawEdges: true,
+        drawNodes: true,
+        drawLabels: true,
+        drawEdgeLabels: false,
+        // {boolean} Indicates if the edges must be drawn in several frames or in
+        //           one frame, as the nodes and labels are drawn.
+        batchEdgesDrawing: false,
+        // {boolean} Indicates if the edges must be hidden during dragging and
+        //           animations.
+        hideEdgesOnMove: false,
+        // {numbers} The different batch sizes, when elements are displayed in
+        //           several frames.
+        canvasEdgesBatchSize: 500,
+        webglEdgesBatchSize: 1000,
+
+
+        /**
+         * RESCALE SETTINGS:
+         * *****************
+         */
+        // {string} Indicates of to scale the graph relatively to its container.
+        //          Available values: "inside", "outside"
+        scalingMode: 'inside',
+        // {number} The margin to keep around the graph.
+        sideMargin: 0,
+        // {number} Determine the size of the smallest and the biggest node / edges
+        //          on the screen. This mapping makes easier to display the graph,
+        //          avoiding too big nodes that take half of the screen, or too
+        //          small ones that are not readable. If the two parameters are
+        //          equals, then the minimal display size will be 0. And if they
+        //          are both equal to 0, then there is no mapping, and the radius
+        //          of the nodes will be their size.
+        minEdgeSize: 0.5,
+        maxEdgeSize: 1,
+        minNodeSize: 1,
+        maxNodeSize: 8,
+
+
+        /**
+         * CAPTORS SETTINGS:
+         * *****************
+         */
+        // {boolean}
+        touchEnabled: true,
+        // {boolean}
+        mouseEnabled: true,
+        // {boolean}
+        mouseWheelEnabled: true,
+        // {boolean}
+        doubleClickEnabled: true,
+        // {boolean} Defines whether the custom events such as "clickNode" can be
+        //           used.
+        eventsEnabled: true,
+        // {number} Defines by how much multiplicating the zooming level when the
+        //          user zooms with the mouse-wheel.
+        zoomingRatio: 1.7,
+        // {number} Defines by how much multiplicating the zooming level when the
+        //          user zooms by double clicking.
+        doubleClickZoomingRatio: 2.2,
+        // {number} The minimum zooming level.
+        zoomMin: 0.0625,
+        // {number} The maximum zooming level.
+        zoomMax: 2,
+        // {number} The duration of animations following a mouse scrolling.
+        mouseZoomDuration: 200,
+        // {number} The duration of animations following a mouse double click.
+        doubleClickZoomDuration: 200,
+        // {number} The duration of animations following a mouse dropping.
+        mouseInertiaDuration: 200,
+        // {number} The inertia power (mouse captor).
+        mouseInertiaRatio: 3,
+        // {number} The duration of animations following a touch dropping.
+        touchInertiaDuration: 200,
+        // {number} The inertia power (touch captor).
+        touchInertiaRatio: 3,
+        // {number} The maximum time between two clicks to make it a double click.
+        doubleClickTimeout: 300,
+        // {number} The maximum time between two taps to make it a double tap.
+        doubleTapTimeout: 300,
+        // {number} The maximum time of dragging to trigger intertia.
+        dragTimeout: 200,
+
+
+        /**
+         * GLOBAL SETTINGS:
+         * ****************
+         */
+        // {boolean} Determines whether the instance has to refresh itself
+        //           automatically when a "resize" event is dispatched from the
+        //           window object.
+        autoResize: true,
+        // {boolean} Determines whether the "rescale" middleware has to be called
+        //           automatically for each camera on refresh.
+        autoRescale: true,
+        // {boolean} If set to false, the camera method "goTo" will basically do
+        //           nothing.
+        enableCamera: true,
+        // {boolean} If set to false, the nodes cannot be hovered.
+        enableHovering: true,
+        // {boolean} If set to true, the edges can be hovered.
+        enableEdgeHovering: false,
+        // {number} The size of the area around the edges to activate hovering.
+        edgeHoverPrecision: 5,
+        // {boolean} If set to true, the rescale middleware will ignore node sizes
+        //           to determine the graphs boundings.
+        rescaleIgnoreSize: false,
+        // {boolean} Determines if the core has to try to catch errors on
+        //           rendering.
+        skipErrors: false,
+
+
+        /**
+         * CAMERA SETTINGS:
+         * ****************
+         */
+        // {number} The power degrees applied to the nodes/edges size relatively to
+        //          the zooming level. Basically:
+        //           > onScreenR = Math.pow(zoom, nodesPowRatio) * R
+        //           > onScreenT = Math.pow(zoom, edgesPowRatio) * T
+        nodesPowRatio: 0.5,
+        edgesPowRatio: 0.5,
+
+
+        /**
+         * ANIMATIONS SETTINGS:
+         * ********************
+         */
+        // {number} The default animation time.
+        animationsTime: 200
+    };
+
+    // Export the previously designed settings:
+    sigma.settings = sigma.utils.extend(sigma.settings || {}, settings);
+}).call(this);
+
+;(function () {
+    'use strict';
+
+    /**
+     * Dispatcher constructor.
+     *
+     * @return {dispatcher} The new dispatcher instance.
+     */
+    var dispatcher = function () {
+        Object.defineProperty(this, '_handlers', {
+            value: {}
+        });
+    };
+
+
+    /**
+     * Will execute the handler everytime that the indicated event (or the
+     * indicated events) will be triggered.
+     *
+     * @param  {string}           events  The name of the event (or the events
+     *                                    separated by spaces).
+     * @param  {function(Object)} handler The handler to bind.
+     * @return {dispatcher}               Returns the instance itself.
+     */
+    dispatcher.prototype.bind = function (events, handler) {
+        var i,
+            l,
+            event,
+            eArray;
+
+        if (
+            arguments.length === 1 &&
+            typeof arguments[0] === 'object'
+        )
+            for (events in arguments[0])
+                this.bind(events, arguments[0][events]);
+        else if (
+            arguments.length === 2 &&
+            typeof arguments[1] === 'function'
+        ) {
+            eArray = typeof events === 'string' ? events.split(' ') : events;
+
+            for (i = 0, l = eArray.length; i !== l; i += 1) {
+                event = eArray[i];
+
+                // Check that event is not '':
+                if (!event)
+                    continue;
+
+                if (!this._handlers[event])
+                    this._handlers[event] = [];
+
+                // Using an object instead of directly the handler will make possible
+                // later to add flags
+                this._handlers[event].push({
+                    handler: handler
+                });
+            }
+        } else
+            throw 'bind: Wrong arguments.';
+
+        return this;
+    };
+
+    /**
+     * Removes the handler from a specified event (or specified events).
+     *
+     * @param  {?string}           events  The name of the event (or the events
+     *                                     separated by spaces). If undefined,
+     *                                     then all handlers are removed.
+     * @param  {?function(object)} handler The handler to unbind. If undefined,
+     *                                     each handler bound to the event or the
+     *                                     events will be removed.
+     * @return {dispatcher}                Returns the instance itself.
+     */
+    dispatcher.prototype.unbind = function (events, handler) {
+        var i,
+            n,
+            j,
+            m,
+            k,
+            a,
+            event,
+            eArray = typeof events === 'string' ? events.split(' ') : events;
+
+        if (!arguments.length) {
+            for (k in this._handlers)
+                delete this._handlers[k];
+            return this;
+        }
+
+        if (handler) {
+            for (i = 0, n = eArray.length; i !== n; i += 1) {
+                event = eArray[i];
+                if (this._handlers[event]) {
+                    a = [];
+                    for (j = 0, m = this._handlers[event].length; j !== m; j += 1)
+                        if (this._handlers[event][j].handler !== handler)
+                            a.push(this._handlers[event][j]);
+
+                    this._handlers[event] = a;
+                }
+
+                if (this._handlers[event] && this._handlers[event].length === 0)
+                    delete this._handlers[event];
+            }
+        } else
+            for (i = 0, n = eArray.length; i !== n; i += 1)
+                delete this._handlers[eArray[i]];
+
+        return this;
+    };
+
+    /**
+     * Executes each handler bound to the event
+     *
+     * @param  {string}     events The name of the event (or the events separated
+     *                             by spaces).
+     * @param  {?object}    data   The content of the event (optional).
+     * @return {dispatcher}        Returns the instance itself.
+     */
+    dispatcher.prototype.dispatchEvent = function (events, data) {
+        var i,
+            n,
+            j,
+            m,
+            a,
+            event,
+            eventName,
+            self = this,
+            eArray = typeof events === 'string' ? events.split(' ') : events;
+
+        data = data === undefined ? {} : data;
+
+        for (i = 0, n = eArray.length; i !== n; i += 1) {
+            eventName = eArray[i];
+
+            if (this._handlers[eventName]) {
+                event = self.getEvent(eventName, data);
+                a = [];
+
+                for (j = 0, m = this._handlers[eventName].length; j !== m; j += 1) {
+                    this._handlers[eventName][j].handler(event);
+                    if (!this._handlers[eventName][j].one)
+                        a.push(this._handlers[eventName][j]);
+                }
+
+                this._handlers[eventName] = a;
+            }
+        }
+
+        return this;
+    };
+
+    /**
+     * Return an event object.
+     *
+     * @param  {string}  events The name of the event.
+     * @param  {?object} data   The content of the event (optional).
+     * @return {object}         Returns the instance itself.
+     */
+    dispatcher.prototype.getEvent = function (event, data) {
+        return {
+            type: event,
+            data: data || {},
+            target: this
+        };
+    };
+
+    /**
+     * A useful function to deal with inheritance. It will make the target
+     * inherit the prototype of the class dispatcher as well as its constructor.
+     *
+     * @param {object} target The target.
+     */
+    dispatcher.extend = function (target, args) {
+        var k;
+
+        for (k in dispatcher.prototype)
+            if (dispatcher.prototype.hasOwnProperty(k))
+                target[k] = dispatcher.prototype[k];
+
+        dispatcher.apply(target, args);
+    };
+
+
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof this.sigma !== 'undefined') {
+        this.sigma.classes = this.sigma.classes || {};
+        this.sigma.classes.dispatcher = dispatcher;
+    } else if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = dispatcher;
+        exports.dispatcher = dispatcher;
+    } else
+        this.dispatcher = dispatcher;
+}).call(this);
+
+;(function () {
+    'use strict';
+
+    /**
+     * This utils aims to facilitate the manipulation of each instance setting.
+     * Using a function instead of an object brings two main advantages: First,
+     * it will be easier in the future to catch settings updates through a
+     * function than an object. Second, giving it a full object will "merge" it
+     * to the settings object properly, keeping us to have to always add a loop.
+     *
+     * @return {configurable} The "settings" function.
+     */
+    var configurable = function () {
+        var i,
+            l,
+            data = {},
+            datas = Array.prototype.slice.call(arguments, 0);
+
+        /**
+         * The method to use to set or get any property of this instance.
+         *
+         * @param  {string|object}    a1 If it is a string and if a2 is undefined,
+         *                               then it will return the corresponding
+         *                               property. If it is a string and if a2 is
+         *                               set, then it will set a2 as the property
+         *                               corresponding to a1, and return this. If
+         *                               it is an object, then each pair string +
+         *                               object(or any other type) will be set as a
+         *                               property.
+         * @param  {*?}               a2 The new property corresponding to a1 if a1
+         *                               is a string.
+         * @return {*|configurable}      Returns itself or the corresponding
+         *                               property.
+         *
+         * Polymorphism:
+         * *************
+         * Here are some basic use examples:
+         *
+         *  > settings = new configurable();
+         *  > settings('mySetting', 42);
+         *  > settings('mySetting'); // Logs: 42
+         *  > settings('mySetting', 123);
+         *  > settings('mySetting'); // Logs: 123
+         *  > settings({mySetting: 456});
+         *  > settings('mySetting'); // Logs: 456
+         *
+         * Also, it is possible to use the function as a fallback:
+         *  > settings({mySetting: 'abc'}, 'mySetting');  // Logs: 'abc'
+         *  > settings({hisSetting: 'abc'}, 'mySetting'); // Logs: 456
+         */
+        var settings = function (a1, a2) {
+            var o,
+                i,
+                l,
+                k;
+
+            if (arguments.length === 1 && typeof a1 === 'string') {
+                if (data[a1] !== undefined)
+                    return data[a1];
+                for (i = 0, l = datas.length; i < l; i++)
+                    if (datas[i][a1] !== undefined)
+                        return datas[i][a1];
+                return undefined;
+            } else if (typeof a1 === 'object' && typeof a2 === 'string') {
+                return (a1 || {})[a2] !== undefined ? a1[a2] : settings(a2);
+            } else {
+                o = (typeof a1 === 'object' && a2 === undefined) ? a1 : {};
+
+                if (typeof a1 === 'string')
+                    o[a1] = a2;
+
+                for (i = 0, k = Object.keys(o), l = k.length; i < l; i++)
+                    data[k[i]] = o[k[i]];
+
+                return this;
+            }
+        };
+
+        /**
+         * This method returns a new configurable function, with new objects
+         *
+         * @param  {object*}  Any number of objects to search in.
+         * @return {function} Returns the function. Check its documentation to know
+         *                    more about how it works.
+         */
+        settings.embedObjects = function () {
+            var args = datas.concat(
+                data
+            ).concat(
+                Array.prototype.splice.call(arguments, 0)
+            );
+
+            return configurable.apply({}, args);
+        };
+
+        // Initialize
+        for (i = 0, l = arguments.length; i < l; i++)
+            settings(arguments[i]);
+
+        return settings;
+    };
+
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof this.sigma !== 'undefined') {
+        this.sigma.classes = this.sigma.classes || {};
+        this.sigma.classes.configurable = configurable;
+    } else if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = configurable;
+        exports.configurable = configurable;
+    } else
+        this.configurable = configurable;
+}).call(this);
+
+;(function (undefined) {
+    'use strict';
+
+    var _methods = Object.create(null),
+        _indexes = Object.create(null),
+        _initBindings = Object.create(null),
+        _methodBindings = Object.create(null),
+        _methodBeforeBindings = Object.create(null),
+        _defaultSettings = {
+            immutable: true,
+            clone: true
+        },
+        _defaultSettingsFunction = function (key) {
+            return _defaultSettings[key];
+        };
+
+    /**
+     * The graph constructor. It initializes the data and the indexes, and binds
+     * the custom indexes and methods to its own scope.
+     *
+     * Recognized parameters:
+     * **********************
+     * Here is the exhaustive list of every accepted parameters in the settings
+     * object:
+     *
+     *   {boolean} clone     Indicates if the data have to be cloned in methods
+     *                       to add nodes or edges.
+     *   {boolean} immutable Indicates if nodes "id" values and edges "id",
+     *                       "source" and "target" values must be set as
+     *                       immutable.
+     *
+     * @param  {?configurable} settings Eventually a settings function.
+     * @return {graph}                  The new graph instance.
+     */
+    var graph = function (settings) {
+        var k,
+            fn,
+            data;
+
+        /**
+         * DATA:
+         * *****
+         * Every data that is callable from graph methods are stored in this "data"
+         * object. This object will be served as context for all these methods,
+         * and it is possible to add other type of data in it.
+         */
+        data = {
+            /**
+             * SETTINGS FUNCTION:
+             * ******************
+             */
+            settings: settings || _defaultSettingsFunction,
+
+            /**
+             * MAIN DATA:
+             * **********
+             */
+            nodesArray: [],
+            edgesArray: [],
+
+            /**
+             * GLOBAL INDEXES:
+             * ***************
+             * These indexes just index data by ids.
+             */
+            nodesIndex: Object.create(null),
+            edgesIndex: Object.create(null),
+
+            /**
+             * LOCAL INDEXES:
+             * **************
+             * These indexes refer from node to nodes. Each key is an id, and each
+             * value is the array of the ids of related nodes.
+             */
+            inNeighborsIndex: Object.create(null),
+            outNeighborsIndex: Object.create(null),
+            allNeighborsIndex: Object.create(null),
+
+            inNeighborsCount: Object.create(null),
+            outNeighborsCount: Object.create(null),
+            allNeighborsCount: Object.create(null)
+        };
+
+        // Execute bindings:
+        for (k in _initBindings)
+            _initBindings[k].call(data);
+
+        // Add methods to both the scope and the data objects:
+        for (k in _methods) {
+            fn = __bindGraphMethod(k, data, _methods[k]);
+            this[k] = fn;
+            data[k] = fn;
+        }
+    };
+
+
+    /**
+     * A custom tool to bind methods such that function that are bound to it will
+     * be executed anytime the method is called.
+     *
+     * @param  {string}   methodName The name of the method to bind.
+     * @param  {object}   scope      The scope where the method must be executed.
+     * @param  {function} fn         The method itself.
+     * @return {function}            The new method.
+     */
+    function __bindGraphMethod(methodName, scope, fn) {
+        var result = function () {
+            var k,
+                res;
+
+            // Execute "before" bound functions:
+            for (k in _methodBeforeBindings[methodName])
+                _methodBeforeBindings[methodName][k].apply(scope, arguments);
+
+            // Apply the method:
+            res = fn.apply(scope, arguments);
+
+            // Execute bound functions:
+            for (k in _methodBindings[methodName])
+                _methodBindings[methodName][k].apply(scope, arguments);
+
+            // Return res:
+            return res;
+        };
+
+        return result;
+    }
+
+    /**
+     * This custom tool function removes every pair key/value from an hash. The
+     * goal is to avoid creating a new object while some other references are
+     * still hanging in some scopes...
+     *
+     * @param  {object} obj The object to empty.
+     * @return {object}     The empty object.
+     */
+    function __emptyObject(obj) {
+        var k;
+
+        for (k in obj)
+            if (!('hasOwnProperty' in obj) || obj.hasOwnProperty(k))
+                delete obj[k];
+
+        return obj;
+    }
+
+
+    /**
+     * This global method adds a method that will be bound to the futurly created
+     * graph instances.
+     *
+     * Since these methods will be bound to their scope when the instances are
+     * created, it does not use the prototype. Because of that, methods have to
+     * be added before instances are created to make them available.
+     *
+     * Here is an example:
+     *
+     *  > graph.addMethod('getNodesCount', function() {
+   *  >   return this.nodesArray.length;
+   *  > });
+     *  >
+     *  > var myGraph = new graph();
+     *  > console.log(myGraph.getNodesCount()); // outputs 0
+     *
+     * @param  {string}   methodName The name of the method.
+     * @param  {function} fn         The method itself.
+     * @return {object}              The global graph constructor.
+     */
+    graph.addMethod = function (methodName, fn) {
+        if (
+            typeof methodName !== 'string' ||
+            typeof fn !== 'function' ||
+            arguments.length !== 2
+        )
+            throw 'addMethod: Wrong arguments.';
+
+        if (_methods[methodName] || graph[methodName])
+            throw 'The method "' + methodName + '" already exists.';
+
+        _methods[methodName] = fn;
+        _methodBindings[methodName] = Object.create(null);
+        _methodBeforeBindings[methodName] = Object.create(null);
+
+        return this;
+    };
+
+    /**
+     * This global method returns true if the method has already been added, and
+     * false else.
+     *
+     * Here are some examples:
+     *
+     *  > graph.hasMethod('addNode'); // returns true
+     *  > graph.hasMethod('hasMethod'); // returns true
+     *  > graph.hasMethod('unexistingMethod'); // returns false
+     *
+     * @param  {string}  methodName The name of the method.
+     * @return {boolean}            The result.
+     */
+    graph.hasMethod = function (methodName) {
+        return !!(_methods[methodName] || graph[methodName]);
+    };
+
+    /**
+     * This global methods attaches a function to a method. Anytime the specified
+     * method is called, the attached function is called right after, with the
+     * same arguments and in the same scope. The attached function is called
+     * right before if the last argument is true, unless the method is the graph
+     * constructor.
+     *
+     * To attach a function to the graph constructor, use 'constructor' as the
+     * method name (first argument).
+     *
+     * The main idea is to have a clean way to keep custom indexes up to date,
+     * for instance:
+     *
+     *  > var timesAddNodeCalled = 0;
+     *  > graph.attach('addNode', 'timesAddNodeCalledInc', function() {
+   *  >   timesAddNodeCalled++;
+   *  > });
+     *  >
+     *  > var myGraph = new graph();
+     *  > console.log(timesAddNodeCalled); // outputs 0
+     *  >
+     *  > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
+     *  > console.log(timesAddNodeCalled); // outputs 2
+     *
+     * The idea for calling a function before is to provide pre-processors, for
+     * instance:
+     *
+     *  > var colorPalette = { Person: '#C3CBE1', Place: '#9BDEBD' };
+     *  > graph.attach('addNode', 'applyNodeColorPalette', function(n) {
+   *  >   n.color = colorPalette[n.category];
+   *  > }, true);
+     *  >
+     *  > var myGraph = new graph();
+     *  > myGraph.addNode({ id: 'n0', category: 'Person' });
+     *  > console.log(myGraph.nodes('n0').color); // outputs '#C3CBE1'
+     *
+     * @param  {string}   methodName The name of the related method or
+     *                               "constructor".
+     * @param  {string}   key        The key to identify the function to attach.
+     * @param  {function} fn         The function to bind.
+     * @param  {boolean}  before     If true the function is called right before.
+     * @return {object}              The global graph constructor.
+     */
+    graph.attach = function (methodName, key, fn, before) {
+        if (
+            typeof methodName !== 'string' ||
+            typeof key !== 'string' ||
+            typeof fn !== 'function' ||
+            arguments.length < 3 ||
+            arguments.length > 4
+        )
+            throw 'attach: Wrong arguments.';
+
+        var bindings;
+
+        if (methodName === 'constructor')
+            bindings = _initBindings;
+        else {
+            if (before) {
+                if (!_methodBeforeBindings[methodName])
+                    throw 'The method "' + methodName + '" does not exist.';
+
+                bindings = _methodBeforeBindings[methodName];
+            }
+            else {
+                if (!_methodBindings[methodName])
+                    throw 'The method "' + methodName + '" does not exist.';
+
+                bindings = _methodBindings[methodName];
+            }
+        }
+
+        if (bindings[key])
+            throw 'A function "' + key + '" is already attached ' +
+            'to the method "' + methodName + '".';
+
+        bindings[key] = fn;
+
+        return this;
+    };
+
+    /**
+     * Alias of attach(methodName, key, fn, true).
+     */
+    graph.attachBefore = function (methodName, key, fn) {
+        return this.attach(methodName, key, fn, true);
+    };
+
+    /**
+     * This methods is just an helper to deal with custom indexes. It takes as
+     * arguments the name of the index and an object containing all the different
+     * functions to bind to the methods.
+     *
+     * Here is a basic example, that creates an index to keep the number of nodes
+     * in the current graph. It also adds a method to provide a getter on that
+     * new index:
+     *
+     *  > sigma.classes.graph.addIndex('nodesCount', {
+   *  >   constructor: function() {
+   *  >     this.nodesCount = 0;
+   *  >   },
+   *  >   addNode: function() {
+   *  >     this.nodesCount++;
+   *  >   },
+   *  >   dropNode: function() {
+   *  >     this.nodesCount--;
+   *  >   }
+   *  > });
+     *  >
+     *  > sigma.classes.graph.addMethod('getNodesCount', function() {
+   *  >   return this.nodesCount;
+   *  > });
+     *  >
+     *  > var myGraph = new sigma.classes.graph();
+     *  > console.log(myGraph.getNodesCount()); // outputs 0
+     *  >
+     *  > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
+     *  > console.log(myGraph.getNodesCount()); // outputs 2
+     *
+     * @param  {string} name     The name of the index.
+     * @param  {object} bindings The object containing the functions to bind.
+     * @return {object}          The global graph constructor.
+     */
+    graph.addIndex = function (name, bindings) {
+        if (
+            typeof name !== 'string' ||
+            Object(bindings) !== bindings ||
+            arguments.length !== 2
+        )
+            throw 'addIndex: Wrong arguments.';
+
+        if (_indexes[name])
+            throw 'The index "' + name + '" already exists.';
+
+        var k;
+
+        // Store the bindings:
+        _indexes[name] = bindings;
+
+        // Attach the bindings:
+        for (k in bindings)
+            if (typeof bindings[k] !== 'function')
+                throw 'The bindings must be functions.';
+            else
+                graph.attach(k, name, bindings[k]);
+
+        return this;
+    };
+
+
+    /**
+     * This method adds a node to the graph. The node must be an object, with a
+     * string under the key "id". Except for this, it is possible to add any
+     * other attribute, that will be preserved all along the manipulations.
+     *
+     * If the graph option "clone" has a truthy value, the node will be cloned
+     * when added to the graph. Also, if the graph option "immutable" has a
+     * truthy value, its id will be defined as immutable.
+     *
+     * @param  {object} node The node to add.
+     * @return {object}      The graph instance.
+     */
+    graph.addMethod('addNode', function (node) {
+        // Check that the node is an object and has an id:
+        if (Object(node) !== node || arguments.length !== 1)
+            throw 'addNode: Wrong arguments.';
+
+        if (typeof node.id !== 'string' && typeof node.id !== 'number')
+            throw 'The node must have a string or number id.';
+
+        if (this.nodesIndex[node.id])
+            throw 'The node "' + node.id + '" already exists.';
+
+        var k,
+            id = node.id,
+            validNode = Object.create(null);
+
+        // Check the "clone" option:
+        if (this.settings('clone')) {
+            for (k in node)
+                if (k !== 'id')
+                    validNode[k] = node[k];
+        } else
+            validNode = node;
+
+        // Check the "immutable" option:
+        if (this.settings('immutable'))
+            Object.defineProperty(validNode, 'id', {
+                value: id,
+                enumerable: true
+            });
+        else
+            validNode.id = id;
+
+        // Add empty containers for edges indexes:
+        this.inNeighborsIndex[id] = Object.create(null);
+        this.outNeighborsIndex[id] = Object.create(null);
+        this.allNeighborsIndex[id] = Object.create(null);
+
+        this.inNeighborsCount[id] = 0;
+        this.outNeighborsCount[id] = 0;
+        this.allNeighborsCount[id] = 0;
+
+        // Add the node to indexes:
+        this.nodesArray.push(validNode);
+        this.nodesIndex[validNode.id] = validNode;
+
+        // Return the current instance:
+        return this;
+    });
+
+    /**
+     * This method adds an edge to the graph. The edge must be an object, with a
+     * string under the key "id", and strings under the keys "source" and
+     * "target" that design existing nodes. Except for this, it is possible to
+     * add any other attribute, that will be preserved all along the
+     * manipulations.
+     *
+     * If the graph option "clone" has a truthy value, the edge will be cloned
+     * when added to the graph. Also, if the graph option "immutable" has a
+     * truthy value, its id, source and target will be defined as immutable.
+     *
+     * @param  {object} edge The edge to add.
+     * @return {object}      The graph instance.
+     */
+    graph.addMethod('addEdge', function (edge) {
+        // Check that the edge is an object and has an id:
+        if (Object(edge) !== edge || arguments.length !== 1)
+            throw 'addEdge: Wrong arguments.';
+
+        if (typeof edge.id !== 'string' && typeof edge.id !== 'number')
+            throw 'The edge must have a string or number id.';
+
+        if ((typeof edge.source !== 'string' && typeof edge.source !== 'number') || !this.nodesIndex[edge.source])
+            throw 'The edge source must have an existing node id.';
+
+        if ((typeof edge.target !== 'string' && typeof edge.target !== 'number') || !this.nodesIndex[edge.target])
+            throw 'The edge target must have an existing node id.';
+
+        if (this.edgesIndex[edge.id])
+            throw 'The edge "' + edge.id + '" already exists.';
+
+        var k,
+            validEdge = Object.create(null);
+
+        // Check the "clone" option:
+        if (this.settings('clone')) {
+            for (k in edge)
+                if (k !== 'id' && k !== 'source' && k !== 'target')
+                    validEdge[k] = edge[k];
+        } else
+            validEdge = edge;
+
+        // Check the "immutable" option:
+        if (this.settings('immutable')) {
+            Object.defineProperty(validEdge, 'id', {
+                value: edge.id,
+                enumerable: true
+            });
+
+            Object.defineProperty(validEdge, 'source', {
+                value: edge.source,
+                enumerable: true
+            });
+
+            Object.defineProperty(validEdge, 'target', {
+                value: edge.target,
+                enumerable: true
+            });
+        } else {
+            validEdge.id = edge.id;
+            validEdge.source = edge.source;
+            validEdge.target = edge.target;
+        }
+
+        // Add the edge to indexes:
+        this.edgesArray.push(validEdge);
+        this.edgesIndex[validEdge.id] = validEdge;
+
+        if (!this.inNeighborsIndex[validEdge.target][validEdge.source])
+            this.inNeighborsIndex[validEdge.target][validEdge.source] =
+                Object.create(null);
+        this.inNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
+            validEdge;
+
+        if (!this.outNeighborsIndex[validEdge.source][validEdge.target])
+            this.outNeighborsIndex[validEdge.source][validEdge.target] =
+                Object.create(null);
+        this.outNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
+            validEdge;
+
+        if (!this.allNeighborsIndex[validEdge.source][validEdge.target])
+            this.allNeighborsIndex[validEdge.source][validEdge.target] =
+                Object.create(null);
+        this.allNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
+            validEdge;
+
+        if (validEdge.target !== validEdge.source) {
+            if (!this.allNeighborsIndex[validEdge.target][validEdge.source])
+                this.allNeighborsIndex[validEdge.target][validEdge.source] =
+                    Object.create(null);
+            this.allNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
+                validEdge;
+        }
+
+        // Keep counts up to date:
+        this.inNeighborsCount[validEdge.target]++;
+        this.outNeighborsCount[validEdge.source]++;
+        this.allNeighborsCount[validEdge.target]++;
+        this.allNeighborsCount[validEdge.source]++;
+
+        return this;
+    });
+
+    /**
+     * This method drops a node from the graph. It also removes each edge that is
+     * bound to it, through the dropEdge method. An error is thrown if the node
+     * does not exist.
+     *
+     * @param  {string} id The node id.
+     * @return {object}    The graph instance.
+     */
+    graph.addMethod('dropNode', function (id) {
+        // Check that the arguments are valid:
+        if ((typeof id !== 'string' && typeof id !== 'number') ||
+            arguments.length !== 1)
+            throw 'dropNode: Wrong arguments.';
+
+        if (!this.nodesIndex[id])
+            throw 'The node "' + id + '" does not exist.';
+
+        var i, k, l;
+
+        // Remove the node from indexes:
+        delete this.nodesIndex[id];
+        for (i = 0, l = this.nodesArray.length; i < l; i++)
+            if (this.nodesArray[i].id === id) {
+                this.nodesArray.splice(i, 1);
+                break;
+            }
+
+        // Remove related edges:
+        for (i = this.edgesArray.length - 1; i >= 0; i--)
+            if (this.edgesArray[i].source === id || this.edgesArray[i].target === id)
+                this.dropEdge(this.edgesArray[i].id);
+
+        // Remove related edge indexes:
+        delete this.inNeighborsIndex[id];
+        delete this.outNeighborsIndex[id];
+        delete this.allNeighborsIndex[id];
+
+        delete this.inNeighborsCount[id];
+        delete this.outNeighborsCount[id];
+        delete this.allNeighborsCount[id];
+
+        for (k in this.nodesIndex) {
+            delete this.inNeighborsIndex[k][id];
+            delete this.outNeighborsIndex[k][id];
+            delete this.allNeighborsIndex[k][id];
+        }
+
+        return this;
+    });
+
+    /**
+     * This method drops an edge from the graph. An error is thrown if the edge
+     * does not exist.
+     *
+     * @param  {string} id The edge id.
+     * @return {object}    The graph instance.
+     */
+    graph.addMethod('dropEdge', function (id) {
+        // Check that the arguments are valid:
+        if ((typeof id !== 'string' && typeof id !== 'number') ||
+            arguments.length !== 1)
+            throw 'dropEdge: Wrong arguments.';
+
+        if (!this.edgesIndex[id])
+            throw 'The edge "' + id + '" does not exist.';
+
+        var i, l, edge;
+
+        // Remove the edge from indexes:
+        edge = this.edgesIndex[id];
+        delete this.edgesIndex[id];
+        for (i = 0, l = this.edgesArray.length; i < l; i++)
+            if (this.edgesArray[i].id === id) {
+                this.edgesArray.splice(i, 1);
+                break;
+            }
+
+        delete this.inNeighborsIndex[edge.target][edge.source][edge.id];
+        if (!Object.keys(this.inNeighborsIndex[edge.target][edge.source]).length)
+            delete this.inNeighborsIndex[edge.target][edge.source];
+
+        delete this.outNeighborsIndex[edge.source][edge.target][edge.id];
+        if (!Object.keys(this.outNeighborsIndex[edge.source][edge.target]).length)
+            delete this.outNeighborsIndex[edge.source][edge.target];
+
+        delete this.allNeighborsIndex[edge.source][edge.target][edge.id];
+        if (!Object.keys(this.allNeighborsIndex[edge.source][edge.target]).length)
+            delete this.allNeighborsIndex[edge.source][edge.target];
+
+        if (edge.target !== edge.source) {
+            delete this.allNeighborsIndex[edge.target][edge.source][edge.id];
+            if (!Object.keys(this.allNeighborsIndex[edge.target][edge.source]).length)
+                delete this.allNeighborsIndex[edge.target][edge.source];
+        }
+
+        this.inNeighborsCount[edge.target]--;
+        this.outNeighborsCount[edge.source]--;
+        this.allNeighborsCount[edge.source]--;
+        this.allNeighborsCount[edge.target]--;
+
+        return this;
+    });
+
+    /**
+     * This method destroys the current instance. It basically empties each index
+     * and methods attached to the graph.
+     */
+    graph.addMethod('kill', function () {
+        // Delete arrays:
+        this.nodesArray.length = 0;
+        this.edgesArray.length = 0;
+        delete this.nodesArray;
+        delete this.edgesArray;
+
+        // Delete indexes:
+        delete this.nodesIndex;
+        delete this.edgesIndex;
+        delete this.inNeighborsIndex;
+        delete this.outNeighborsIndex;
+        delete this.allNeighborsIndex;
+        delete this.inNeighborsCount;
+        delete this.outNeighborsCount;
+        delete this.allNeighborsCount;
+    });
+
+    /**
+     * This method empties the nodes and edges arrays, as well as the different
+     * indexes.
+     *
+     * @return {object} The graph instance.
+     */
+    graph.addMethod('clear', function () {
+        this.nodesArray.length = 0;
+        this.edgesArray.length = 0;
+
+        // Due to GC issues, I prefer not to create new object. These objects are
+        // only available from the methods and attached functions, but still, it is
+        // better to prevent ghost references to unrelevant data...
+        __emptyObject(this.nodesIndex);
+        __emptyObject(this.edgesIndex);
+        __emptyObject(this.nodesIndex);
+        __emptyObject(this.inNeighborsIndex);
+        __emptyObject(this.outNeighborsIndex);
+        __emptyObject(this.allNeighborsIndex);
+        __emptyObject(this.inNeighborsCount);
+        __emptyObject(this.outNeighborsCount);
+        __emptyObject(this.allNeighborsCount);
+
+        return this;
+    });
+
+    /**
+     * This method reads an object and adds the nodes and edges, through the
+     * proper methods "addNode" and "addEdge".
+     *
+     * Here is an example:
+     *
+     *  > var myGraph = new graph();
+     *  > myGraph.read({
+   *  >   nodes: [
+   *  >     { id: 'n0' },
+   *  >     { id: 'n1' }
+   *  >   ],
+   *  >   edges: [
+   *  >     {
+   *  >       id: 'e0',
+   *  >       source: 'n0',
+   *  >       target: 'n1'
+   *  >     }
+   *  >   ]
+   *  > });
+     *  >
+     *  > console.log(
+     *  >   myGraph.nodes().length,
+     *  >   myGraph.edges().length
+     *  > ); // outputs 2 1
+     *
+     * @param  {object} g The graph object.
+     * @return {object}   The graph instance.
+     */
+    graph.addMethod('read', function (g) {
+        var i,
+            a,
+            l;
+
+        a = g.nodes || [];
+        for (i = 0, l = a.length; i < l; i++)
+            this.addNode(a[i]);
+
+        a = g.edges || [];
+        for (i = 0, l = a.length; i < l; i++)
+            this.addEdge(a[i]);
+
+        return this;
+    });
+
+    /**
+     * This methods returns one or several nodes, depending on how it is called.
+     *
+     * To get the array of nodes, call "nodes" without argument. To get a
+     * specific node, call it with the id of the node. The get multiple node,
+     * call it with an array of ids, and it will return the array of nodes, in
+     * the same order.
+     *
+     * @param  {?(string|array)} v Eventually one id, an array of ids.
+     * @return {object|array}      The related node or array of nodes.
+     */
+    graph.addMethod('nodes', function (v) {
+        // Clone the array of nodes and return it:
+        if (!arguments.length)
+            return this.nodesArray.slice(0);
+
+        // Return the related node:
+        if (arguments.length === 1 &&
+            (typeof v === 'string' || typeof v === 'number'))
+            return this.nodesIndex[v];
+
+        // Return an array of the related node:
+        if (
+            arguments.length === 1 &&
+            Object.prototype.toString.call(v) === '[object Array]'
+        ) {
+            var i,
+                l,
+                a = [];
+
+            for (i = 0, l = v.length; i < l; i++)
+                if (typeof v[i] === 'string' || typeof v[i] === 'number')
+                    a.push(this.nodesIndex[v[i]]);
+                else
+                    throw 'nodes: Wrong arguments.';
+
+            return a;
+        }
+
+        throw 'nodes: Wrong arguments.';
+    });
+
+    /**
+     * This methods returns the degree of one or several nodes, depending on how
+     * it is called. It is also possible to get incoming or outcoming degrees
+     * instead by specifying 'in' or 'out' as a second argument.
+     *
+     * @param  {string|array} v     One id, an array of ids.
+     * @param  {?string}      which Which degree is required. Values are 'in',
+     *                              'out', and by default the normal degree.
+     * @return {number|array}       The related degree or array of degrees.
+     */
+    graph.addMethod('degree', function (v, which) {
+        // Check which degree is required:
+        which = {
+                'in': this.inNeighborsCount,
+                'out': this.outNeighborsCount
+            }[which || ''] || this.allNeighborsCount;
+
+        // Return the related node:
+        if (typeof v === 'string' || typeof v === 'number')
+            return which[v];
+
+        // Return an array of the related node:
+        if (Object.prototype.toString.call(v) === '[object Array]') {
+            var i,
+                l,
+                a = [];
+
+            for (i = 0, l = v.length; i < l; i++)
+                if (typeof v[i] === 'string' || typeof v[i] === 'number')
+                    a.push(which[v[i]]);
+                else
+                    throw 'degree: Wrong arguments.';
+
+            return a;
+        }
+
+        throw 'degree: Wrong arguments.';
+    });
+
+    /**
+     * This methods returns one or several edges, depending on how it is called.
+     *
+     * To get the array of edges, call "edges" without argument. To get a
+     * specific edge, call it with the id of the edge. The get multiple edge,
+     * call it with an array of ids, and it will return the array of edges, in
+     * the same order.
+     *
+     * @param  {?(string|array)} v Eventually one id, an array of ids.
+     * @return {object|array}      The related edge or array of edges.
+     */
+    graph.addMethod('edges', function (v) {
+        // Clone the array of edges and return it:
+        if (!arguments.length)
+            return this.edgesArray.slice(0);
+
+        // Return the related edge:
+        if (arguments.length === 1 &&
+            (typeof v === 'string' || typeof v === 'number'))
+            return this.edgesIndex[v];
+
+        // Return an array of the related edge:
+        if (
+            arguments.length === 1 &&
+            Object.prototype.toString.call(v) === '[object Array]'
+        ) {
+            var i,
+                l,
+                a = [];
+
+            for (i = 0, l = v.length; i < l; i++)
+                if (typeof v[i] === 'string' || typeof v[i] === 'number')
+                    a.push(this.edgesIndex[v[i]]);
+                else
+                    throw 'edges: Wrong arguments.';
+
+            return a;
+        }
+
+        throw 'edges: Wrong arguments.';
+    });
+
+
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof sigma !== 'undefined') {
+        sigma.classes = sigma.classes || Object.create(null);
+        sigma.classes.graph = graph;
+    } else if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = graph;
+        exports.graph = graph;
+    } else
+        this.graph = graph;
+}).call(this);
+
+;(function (undefined) {
+    'use strict';
+
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
+
+    sigma.utils.pkg('sigma.classes');
+
+    /**
+     * The camera constructor. It just initializes its attributes and methods.
+     *
+     * @param  {string}       id       The id.
+     * @param  {sigma.classes.graph}  graph    The graph.
+     * @param  {configurable} settings The settings function.
+     * @param  {?object}      options  Eventually some overriding options.
+     * @return {camera}                Returns the fresh new camera instance.
+     */
+    sigma.classes.camera = function (id, graph, settings, options) {
+        sigma.classes.dispatcher.extend(this);
+
+        Object.defineProperty(this, 'graph', {
+            value: graph
+        });
+        Object.defineProperty(this, 'id', {
+            value: id
+        });
+        Object.defineProperty(this, 'readPrefix', {
+            value: 'read_cam' + id + ':'
+        });
+        Object.defineProperty(this, 'prefix', {
+            value: 'cam' + id + ':'
+        });
+
+        this.x = 0;
+        this.y = 0;
+        this.ratio = 1;
+        this.angle = 0;
+        this.isAnimated = false;
+        this.settings = (typeof options === 'object' && options) ?
+            settings.embedObject(options) :
+            settings;
+    };
+
+    /**
+     * Updates the camera position.
+     *
+     * @param  {object} coordinates The new coordinates object.
+     * @return {camera}             Returns the camera.
+     */
+    sigma.classes.camera.prototype.goTo = function (coordinates) {
+        if (!this.settings('enableCamera'))
+            return this;
+
+        var i,
+            l,
+            c = coordinates || {},
+            keys = ['x', 'y', 'ratio', 'angle'];
+
+        for (i = 0, l = keys.length; i < l; i++)
+            if (c[keys[i]] !== undefined) {
+                if (typeof c[keys[i]] === 'number' && !isNaN(c[keys[i]]))
+                    this[keys[i]] = c[keys[i]];
+                else
+                    throw 'Value for "' + keys[i] + '" is not a number.';
+            }
+
+        this.dispatchEvent('coordinatesUpdated');
+        return this;
+    };
+
+    /**
+     * This method takes a graph and computes for each node and edges its
+     * coordinates relatively to the center of the camera. Basically, it will
+     * compute the coordinates that will be used by the graphic renderers.
+     *
+     * Since it should be possible to use different cameras and different
+     * renderers, it is possible to specify a prefix to put before the new
+     * coordinates (to get something like "node.camera1_x")
+     *
+     * @param  {?string} read    The prefix of the coordinates to read.
+     * @param  {?string} write   The prefix of the coordinates to write.
+     * @param  {?object} options Eventually an object of options. Those can be:
+     *                           - A restricted nodes array.
+     *                           - A restricted edges array.
+     *                           - A width.
+     *                           - A height.
+     * @return {camera}        Returns the camera.
+     */
+    sigma.classes.camera.prototype.applyView = function (read, write, options) {
+        options = options || {};
+        write = write !== undefined ? write : this.prefix;
+        read = read !== undefined ? read : this.readPrefix;
+
+        var nodes = options.nodes || this.graph.nodes(),
+            edges = options.edges || this.graph.edges();
+
+        var i,
+            l,
+            node,
+            cos = Math.cos(this.angle),
+            sin = Math.sin(this.angle),
+            nodeRatio = Math.pow(this.ratio, this.settings('nodesPowRatio')),
+            edgeRatio = Math.pow(this.ratio, this.settings('edgesPowRatio')),
+            xOffset = (options.width || 0) / 2,
+            yOffset = (options.height || 0) / 2;
+
+        for (i = 0, l = nodes.length; i < l; i++) {
+            node = nodes[i];
+            node[write + 'x'] =
+                (
+                    ((node[read + 'x'] || 0) - this.x) * cos +
+                    ((node[read + 'y'] || 0) - this.y) * sin
+                ) / this.ratio + xOffset;
+            node[write + 'y'] =
+                (
+                    ((node[read + 'y'] || 0) - this.y) * cos -
+                    ((node[read + 'x'] || 0) - this.x) * sin
+                ) / this.ratio + yOffset;
+            node[write + 'size'] =
+                (node[read + 'size'] || 0) /
+                nodeRatio;
+        }
+
+        for (i = 0, l = edges.length; i < l; i++) {
+            edges[i][write + 'size'] =
+                (edges[i][read + 'size'] || 0) /
+                edgeRatio;
+        }
+
+        return this;
+    };
+
+    /**
+     * This function converts the coordinates of a point from the frame of the
+     * camera to the frame of the graph.
+     *
+     * @param  {number} x The X coordinate of the point in the frame of the
+     *                    camera.
+     * @param  {number} y The Y coordinate of the point in the frame of the
+     *                    camera.
+     * @return {object}   The point coordinates in the frame of the graph.
+     */
+    sigma.classes.camera.prototype.graphPosition = function (x, y, vector) {
+        var X = 0,
+            Y = 0,
+            cos = Math.cos(this.angle),
+            sin = Math.sin(this.angle);
+
+        // Revert the origin differential vector:
+        if (!vector) {
+            X = -(this.x * cos + this.y * sin) / this.ratio;
+            Y = -(this.y * cos - this.x * sin) / this.ratio;
+        }
+
+        return {
+            x: (x * cos + y * sin) / this.ratio + X,
+            y: (y * cos - x * sin) / this.ratio + Y
+        };
+    };
+
+    /**
+     * This function converts the coordinates of a point from the frame of the
+     * graph to the frame of the camera.
+     *
+     * @param  {number} x The X coordinate of the point in the frame of the
+     *                    graph.
+     * @param  {number} y The Y coordinate of the point in the frame of the
+     *                    graph.
+     * @return {object}   The point coordinates in the frame of the camera.
+     */
+    sigma.classes.camera.prototype.cameraPosition = function (x, y, vector) {
+        var X = 0,
+            Y = 0,
+            cos = Math.cos(this.angle),
+            sin = Math.sin(this.angle);
+
+        // Revert the origin differential vector:
+        if (!vector) {
+            X = -(this.x * cos + this.y * sin) / this.ratio;
+            Y = -(this.y * cos - this.x * sin) / this.ratio;
+        }
+
+        return {
+            x: ((x - X) * cos - (y - Y) * sin) * this.ratio,
+            y: ((y - Y) * cos + (x - X) * sin) * this.ratio
+        };
+    };
+
+    /**
+     * This method returns the transformation matrix of the camera. This is
+     * especially useful to apply the camera view directly in shaders, in case of
+     * WebGL rendering.
+     *
+     * @return {array} The transformation matrix.
+     */
+    sigma.classes.camera.prototype.getMatrix = function () {
+        var scale = sigma.utils.matrices.scale(1 / this.ratio),
+            rotation = sigma.utils.matrices.rotation(this.angle),
+            translation = sigma.utils.matrices.translation(-this.x, -this.y),
+            matrix = sigma.utils.matrices.multiply(
+                translation,
+                sigma.utils.matrices.multiply(
+                    rotation,
+                    scale
+                )
+            );
+
+        return matrix;
+    };
+
+    /**
+     * Taking a width and a height as parameters, this method returns the
+     * coordinates of the rectangle representing the camera on screen, in the
+     * graph's referentiel.
+     *
+     * To keep displaying labels of nodes going out of the screen, the method
+     * keeps a margin around the screen in the returned rectangle.
+     *
+     * @param  {number} width  The width of the screen.
+     * @param  {number} height The height of the screen.
+     * @return {object}        The rectangle as x1, y1, x2 and y2, representing
+     *                         two opposite points.
+     */
+    sigma.classes.camera.prototype.getRectangle = function (width, height) {
+        var widthVect = this.cameraPosition(width, 0, true),
+            heightVect = this.cameraPosition(0, height, true),
+            centerVect = this.cameraPosition(width / 2, height / 2, true),
+            marginX = this.cameraPosition(width / 4, 0, true).x,
+            marginY = this.cameraPosition(0, height / 4, true).y;
+
+        return {
+            x1: this.x - centerVect.x - marginX,
+            y1: this.y - centerVect.y - marginY,
+            x2: this.x - centerVect.x + marginX + widthVect.x,
+            y2: this.y - centerVect.y - marginY + widthVect.y,
+            height: Math.sqrt(
+                Math.pow(heightVect.x, 2) +
+                Math.pow(heightVect.y + 2 * marginY, 2)
+            )
+        };
+    };
+}).call(this);
+
+;(function (undefined) {
+    'use strict';
+
+    /**
+     * Sigma Quadtree Module
+     * =====================
+     *
+     * Author: Guillaume Plique (Yomguithereal)
+     * Version: 0.2
+     */
+
+
+    /**
+     * Quad Geometric Operations
+     * -------------------------
+     *
+     * A useful batch of geometric operations used by the quadtree.
+     */
+
+    var _geom = {
+
+        /**
+         * Transforms a graph node with x, y and size into an
+         * axis-aligned square.
+         *
+         * @param  {object} A graph node with at least a point (x, y) and a size.
+         * @return {object} A square: two points (x1, y1), (x2, y2) and height.
+         */
+        pointToSquare: function (n) {
+            return {
+                x1: n.x - n.size,
+                y1: n.y - n.size,
+                x2: n.x + n.size,
+                y2: n.y - n.size,
+                height: n.size * 2
+            };
+        },
+
+        /**
+         * Checks whether a rectangle is axis-aligned.
+         *
+         * @param  {object}  A rectangle defined by two points
+         *                   (x1, y1) and (x2, y2).
+         * @return {boolean} True if the rectangle is axis-aligned.
+         */
+        isAxisAligned: function (r) {
+            return r.x1 === r.x2 || r.y1 === r.y2;
+        },
+
+        /**
+         * Compute top points of an axis-aligned rectangle. This is useful in
+         * cases when the rectangle has been rotated (left, right or bottom up) and
+         * later operations need to know the top points.
+         *
+         * @param  {object} An axis-aligned rectangle defined by two points
+         *                  (x1, y1), (x2, y2) and height.
+         * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height.
+         */
+        axisAlignedTopPoints: function (r) {
+
+            // Basic
+            if (r.y1 === r.y2 && r.x1 < r.x2)
+                return r;
+
+            // Rotated to right
+            if (r.x1 === r.x2 && r.y2 > r.y1)
+                return {
+                    x1: r.x1 - r.height, y1: r.y1,
+                    x2: r.x1, y2: r.y1,
+                    height: r.height
+                };
+
+            // Rotated to left
+            if (r.x1 === r.x2 && r.y2 < r.y1)
+                return {
+                    x1: r.x1, y1: r.y2,
+                    x2: r.x2 + r.height, y2: r.y2,
+                    height: r.height
+                };
+
+            // Bottom's up
+            return {
+                x1: r.x2, y1: r.y1 - r.height,
+                x2: r.x1, y2: r.y1 - r.height,
+                height: r.height
+            };
+        },
+
+        /**
+         * Get coordinates of a rectangle's lower left corner from its top points.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @return {object} Coordinates of the corner (x, y).
+         */
+        lowerLeftCoor: function (r) {
+            var width = (
+                Math.sqrt(
+                    Math.pow(r.x2 - r.x1, 2) +
+                    Math.pow(r.y2 - r.y1, 2)
+                )
+            );
+
+            return {
+                x: r.x1 - (r.y2 - r.y1) * r.height / width,
+                y: r.y1 + (r.x2 - r.x1) * r.height / width
+            };
+        },
+
+        /**
+         * Get coordinates of a rectangle's lower right corner from its top points
+         * and its lower left corner.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @param  {object} A corner's coordinates (x, y).
+         * @return {object} Coordinates of the corner (x, y).
+         */
+        lowerRightCoor: function (r, llc) {
+            return {
+                x: llc.x - r.x1 + r.x2,
+                y: llc.y - r.y1 + r.y2
+            };
+        },
+
+        /**
+         * Get the coordinates of all the corners of a rectangle from its top point.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @return {array}  An array of the four corners' coordinates (x, y).
+         */
+        rectangleCorners: function (r) {
+            var llc = this.lowerLeftCoor(r),
+                lrc = this.lowerRightCoor(r, llc);
+
+            return [
+                {x: r.x1, y: r.y1},
+                {x: r.x2, y: r.y2},
+                {x: llc.x, y: llc.y},
+                {x: lrc.x, y: lrc.y}
+            ];
+        },
+
+        /**
+         * Split a square defined by its boundaries into four.
+         *
+         * @param  {object} Boundaries of the square (x, y, width, height).
+         * @return {array}  An array containing the four new squares, themselves
+         *                  defined by an array of their four corners (x, y).
+         */
+        splitSquare: function (b) {
+            return [
+                [
+                    {x: b.x, y: b.y},
+                    {x: b.x + b.width / 2, y: b.y},
+                    {x: b.x, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2}
+                ],
+                [
+                    {x: b.x + b.width / 2, y: b.y},
+                    {x: b.x + b.width, y: b.y},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x + b.width, y: b.y + b.height / 2}
+                ],
+                [
+                    {x: b.x, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x, y: b.y + b.height},
+                    {x: b.x + b.width / 2, y: b.y + b.height}
+                ],
+                [
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x + b.width, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height},
+                    {x: b.x + b.width, y: b.y + b.height}
+                ]
+            ];
+        },
+
+        /**
+         * Compute the four axis between corners of rectangle A and corners of
+         * rectangle B. This is needed later to check an eventual collision.
+         *
+         * @param  {array} An array of rectangle A's four corners (x, y).
+         * @param  {array} An array of rectangle B's four corners (x, y).
+         * @return {array} An array of four axis defined by their coordinates (x,y).
+         */
+        axis: function (c1, c2) {
+            return [
+                {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y},
+                {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y},
+                {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y},
+                {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y}
+            ];
+        },
+
+        /**
+         * Project a rectangle's corner on an axis.
+         *
+         * @param  {object} Coordinates of a corner (x, y).
+         * @param  {object} Coordinates of an axis (x, y).
+         * @return {object} The projection defined by coordinates (x, y).
+         */
+        projection: function (c, a) {
+            var l = (
+                (c.x * a.x + c.y * a.y) /
+                (Math.pow(a.x, 2) + Math.pow(a.y, 2))
+            );
+
+            return {
+                x: l * a.x,
+                y: l * a.y
+            };
+        },
+
+        /**
+         * Check whether two rectangles collide on one particular axis.
+         *
+         * @param  {object}   An axis' coordinates (x, y).
+         * @param  {array}    Rectangle A's corners.
+         * @param  {array}    Rectangle B's corners.
+         * @return {boolean}  True if the rectangles collide on the axis.
+         */
+        axisCollision: function (a, c1, c2) {
+            var sc1 = [],
+                sc2 = [];
+
+            for (var ci = 0; ci < 4; ci++) {
+                var p1 = this.projection(c1[ci], a),
+                    p2 = this.projection(c2[ci], a);
+
+                sc1.push(p1.x * a.x + p1.y * a.y);
+                sc2.push(p2.x * a.x + p2.y * a.y);
+            }
+
+            var maxc1 = Math.max.apply(Math, sc1),
+                maxc2 = Math.max.apply(Math, sc2),
+                minc1 = Math.min.apply(Math, sc1),
+                minc2 = Math.min.apply(Math, sc2);
+
+            return (minc2 <= maxc1 && maxc2 >= minc1);
+        },
+
+        /**
+         * Check whether two rectangles collide on each one of their four axis. If
+         * all axis collide, then the two rectangles do collide on the plane.
+         *
+         * @param  {array}    Rectangle A's corners.
+         * @param  {array}    Rectangle B's corners.
+         * @return {boolean}  True if the rectangles collide.
+         */
+        collision: function (c1, c2) {
+            var axis = this.axis(c1, c2),
+                col = true;
+
+            for (var i = 0; i < 4; i++)
+                col = col && this.axisCollision(axis[i], c1, c2);
+
+            return col;
+        }
+    };
+
+
+    /**
+     * Quad Functions
+     * ------------
+     *
+     * The Quadtree functions themselves.
+     * For each of those functions, we consider that in a splitted quad, the
+     * index of each node is the following:
+     * 0: top left
+     * 1: top right
+     * 2: bottom left
+     * 3: bottom right
+     *
+     * Moreover, the hereafter quad's philosophy is to consider that if an element
+     * collides with more than one nodes, this element belongs to each of the
+     * nodes it collides with where other would let it lie on a higher node.
+     */
+
+    /**
+     * Get the index of the node containing the point in the quad
+     *
+     * @param  {object}  point      A point defined by coordinates (x, y).
+     * @param  {object}  quadBounds Boundaries of the quad (x, y, width, heigth).
+     * @return {integer}            The index of the node containing the point.
+     */
+    function _quadIndex(point, quadBounds) {
+        var xmp = quadBounds.x + quadBounds.width / 2,
+            ymp = quadBounds.y + quadBounds.height / 2,
+            top = (point.y < ymp),
+            left = (point.x < xmp);
+
+        if (top) {
+            if (left)
+                return 0;
+            else
+                return 1;
+        }
+        else {
+            if (left)
+                return 2;
+            else
+                return 3;
+        }
+    }
+
+    /**
+     * Get a list of indexes of nodes containing an axis-aligned rectangle
+     *
+     * @param  {object}  rectangle   A rectangle defined by two points (x1, y1),
+     *                               (x2, y2) and height.
+     * @param  {array}   quadCorners An array of the quad nodes' corners.
+     * @return {array}               An array of indexes containing one to
+     *                               four integers.
+     */
+    function _quadIndexes(rectangle, quadCorners) {
+        var indexes = [];
+
+        // Iterating through quads
+        for (var i = 0; i < 4; i++)
+            if ((rectangle.x2 >= quadCorners[i][0].x) &&
+                (rectangle.x1 <= quadCorners[i][1].x) &&
+                (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) &&
+                (rectangle.y1 <= quadCorners[i][2].y))
+                indexes.push(i);
+
+        return indexes;
+    }
+
+    /**
+     * Get a list of indexes of nodes containing a non-axis-aligned rectangle
+     *
+     * @param  {array}  corners      An array containing each corner of the
+     *                               rectangle defined by its coordinates (x, y).
+     * @param  {array}  quadCorners  An array of the quad nodes' corners.
+     * @return {array}               An array of indexes containing one to
+     *                               four integers.
+     */
+    function _quadCollision(corners, quadCorners) {
+        var indexes = [];
+
+        // Iterating through quads
+        for (var i = 0; i < 4; i++)
+            if (_geom.collision(corners, quadCorners[i]))
+                indexes.push(i);
+
+        return indexes;
+    }
+
+    /**
+     * Subdivide a quad by creating a node at a precise index. The function does
+     * not generate all four nodes not to potentially create unused nodes.
+     *
+     * @param  {integer}  index The index of the node to create.
+     * @param  {object}   quad  The quad object to subdivide.
+     * @return {object}         A new quad representing the node created.
+     */
+    function _quadSubdivide(index, quad) {
+        var next = quad.level + 1,
+            subw = Math.round(quad.bounds.width / 2),
+            subh = Math.round(quad.bounds.height / 2),
+            qx = Math.round(quad.bounds.x),
+            qy = Math.round(quad.bounds.y),
+            x,
+            y;
+
+        switch (index) {
+            case 0:
+                x = qx;
+                y = qy;
+                break;
+            case 1:
+                x = qx + subw;
+                y = qy;
+                break;
+            case 2:
+                x = qx;
+                y = qy + subh;
+                break;
+            case 3:
+                x = qx + subw;
+                y = qy + subh;
+                break;
+        }
+
+        return _quadTree(
+            {x: x, y: y, width: subw, height: subh},
+            next,
+            quad.maxElements,
+            quad.maxLevel
+        );
+    }
+
+    /**
+     * Recursively insert an element into the quadtree. Only points
+     * with size, i.e. axis-aligned squares, may be inserted with this
+     * method.
+     *
+     * @param  {object}  el         The element to insert in the quadtree.
+     * @param  {object}  sizedPoint A sized point defined by two top points
+     *                              (x1, y1), (x2, y2) and height.
+     * @param  {object}  quad       The quad in which to insert the element.
+     * @return {undefined}          The function does not return anything.
+     */
+    function _quadInsert(el, sizedPoint, quad) {
+        if (quad.level < quad.maxLevel) {
+
+            // Searching appropriate quads
+            var indexes = _quadIndexes(sizedPoint, quad.corners);
+
+            // Iterating
+            for (var i = 0, l = indexes.length; i < l; i++) {
+
+                // Subdividing if necessary
+                if (quad.nodes[indexes[i]] === undefined)
+                    quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad);
+
+                // Recursion
+                _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]);
+            }
+        }
+        else {
+
+            // Pushing the element in a leaf node
+            quad.elements.push(el);
+        }
+    }
+
+    /**
+     * Recursively retrieve every elements held by the node containing the
+     * searched point.
+     *
+     * @param  {object}  point The searched point (x, y).
+     * @param  {object}  quad  The searched quad.
+     * @return {array}         An array of elements contained in the relevant
+     *                         node.
+     */
+    function _quadRetrievePoint(point, quad) {
+        if (quad.level < quad.maxLevel) {
+            var index = _quadIndex(point, quad.bounds);
+
+            // If node does not exist we return an empty list
+            if (quad.nodes[index] !== undefined) {
+                return _quadRetrievePoint(point, quad.nodes[index]);
+            }
+            else {
+                return [];
+            }
+        }
+        else {
+            return quad.elements;
+        }
+    }
+
+    /**
+     * Recursively retrieve every elements contained within an rectangular area
+     * that may or may not be axis-aligned.
+     *
+     * @param  {object|array} rectData       The searched area defined either by
+     *                                       an array of four corners (x, y) in
+     *                                       the case of a non-axis-aligned
+     *                                       rectangle or an object with two top
+     *                                       points (x1, y1), (x2, y2) and height.
+     * @param  {object}       quad           The searched quad.
+     * @param  {function}     collisionFunc  The collision function used to search
+     *                                       for node indexes.
+     * @param  {array?}       els            The retrieved elements.
+     * @return {array}                       An array of elements contained in the
+     *                                       area.
+     */
+    function _quadRetrieveArea(rectData, quad, collisionFunc, els) {
+        els = els || {};
+
+        if (quad.level < quad.maxLevel) {
+            var indexes = collisionFunc(rectData, quad.corners);
+
+            for (var i = 0, l = indexes.length; i < l; i++)
+                if (quad.nodes[indexes[i]] !== undefined)
+                    _quadRetrieveArea(
+                        rectData,
+                        quad.nodes[indexes[i]],
+                        collisionFunc,
+                        els
+                    );
+        } else
+            for (var j = 0, m = quad.elements.length; j < m; j++)
+                if (els[quad.elements[j].id] === undefined)
+                    els[quad.elements[j].id] = quad.elements[j];
+
+        return els;
     }
-  }
-
-  /**
-   * Returns true if conrad is currently running, and false else.
-   *
-   * @return {Boolean} Returns _isRunning.
-   */
-  function _getIsRunning() {
-    return _isRunning;
-  }
-
-  /**
-   * Unreference every job that is stored in the _doneJobs object. It will
-   * not be possible anymore to get stats about these jobs, but it will release
-   * the memory.
-   *
-   * @return {Object} Returns conrad.
-   */
-  function _clearHistory() {
-    _doneJobs = [];
-    return this;
-  }
-
-  /**
-   * Returns a snapshot of every data about jobs that wait to be started, are
-   * currently running or are done.
-   *
-   * It is possible to get only running, waiting or done jobs by giving
-   * "running", "waiting" or "done" as fist argument.
-   *
-   * It is also possible to get every job with a specified id by giving it as
-   * first argument. Also, using a RegExp instead of an id will return every
-   * jobs whose ids match the RegExp. And these two last use cases work as well
-   * by giving before "running", "waiting" or "done".
-   *
-   * @return {Array} The array of the matching jobs.
-   *
-   * Some call examples:
-   * *******************
-   *  > conrad.getStats('running')
-   *  > conrad.getStats('waiting')
-   *  > conrad.getStats('done')
-   *  > conrad.getStats('myJob')
-   *  > conrad.getStats(/test/)
-   *  > conrad.getStats('running', 'myRunningJob')
-   *  > conrad.getStats('running', /test/)
-   */
-  function _getStats(v1, v2) {
-    var a,
-        k,
-        i,
-        l,
-        stats,
-        pattern,
-        isPatternString;
-
-    if (!arguments.length) {
-      stats = [];
-
-      for (k in _jobs)
-        stats.push(_jobs[k]);
-
-      for (k in _waitingJobs)
-        stats.push(_waitingJobs[k]);
-
-      for (k in _runningJobs)
-        stats.push(_runningJobs[k]);
-
-      stats = stats.concat(_doneJobs);
+
+    /**
+     * Creates the quadtree object itself.
+     *
+     * @param  {object}   bounds       The boundaries of the quad defined by an
+     *                                 origin (x, y), width and heigth.
+     * @param  {integer}  level        The level of the quad in the tree.
+     * @param  {integer}  maxElements  The max number of element in a leaf node.
+     * @param  {integer}  maxLevel     The max recursion level of the tree.
+     * @return {object}                The quadtree object.
+     */
+    function _quadTree(bounds, level, maxElements, maxLevel) {
+        return {
+            level: level || 0,
+            bounds: bounds,
+            corners: _geom.splitSquare(bounds),
+            maxElements: maxElements || 20,
+            maxLevel: maxLevel || 4,
+            elements: [],
+            nodes: []
+        };
     }
 
-    if (typeof v1 === 'string')
-      switch (v1) {
-        case 'waiting':
-          stats = __objectValues(_waitingJobs);
-          break;
-        case 'running':
-          stats = __objectValues(_runningJobs);
-          break;
-        case 'done':
-          stats = _doneJobs;
-          break;
-        default:
-          pattern = v1;
-      }
-
-    if (v1 instanceof RegExp)
-      pattern = v1;
-
-    if (!pattern && (typeof v2 === 'string' || v2 instanceof RegExp))
-      pattern = v2;
-
-    // Filter jobs if a pattern is given:
-    if (pattern) {
-      isPatternString = typeof pattern === 'string';
-
-      if (stats instanceof Array) {
-        a = stats;
-      } else if (typeof stats === 'object') {
-        a = [];
-
-        for (k in stats)
-          a = a.concat(stats[k]);
-      } else {
-        a = [];
-
-        for (k in _jobs)
-          a.push(_jobs[k]);
-
-        for (k in _waitingJobs)
-          a.push(_waitingJobs[k]);
-
-        for (k in _runningJobs)
-          a.push(_runningJobs[k]);
-
-        a = a.concat(_doneJobs);
-      }
-
-      stats = [];
-      for (i = 0, l = a.length; i < l; i++)
-        if (isPatternString ? a[i].id === pattern : a[i].id.match(pattern))
-          stats.push(a[i]);
-    }
 
-    return __clone(stats);
-  }
-
-
-  /**
-   * TOOLS FUNCTIONS:
-   * ****************
-   */
-
-  /**
-   * This function takes any number of objects as arguments, copies from each
-   * of these objects each pair key/value into a new object, and finally
-   * returns this object.
-   *
-   * The arguments are parsed from the last one to the first one, such that
-   * when two objects have keys in common, the "earliest" object wins.
-   *
-   * Example:
-   * ********
-   *  > var o1 = {
-   *  >       a: 1,
-   *  >       b: 2,
-   *  >       c: '3'
-   *  >     },
-   *  >     o2 = {
-   *  >       c: '4',
-   *  >       d: [ 5 ]
-   *  >     };
-   *  > __extend(o1, o2);
-   *  > // Returns: {
-   *  > //   a: 1,
-   *  > //   b: 2,
-   *  > //   c: '3',
-   *  > //   d: [ 5 ]
-   *  > // };
-   *
-   * @param  {Object+} Any number of objects.
-   * @return {Object}  The merged object.
-   */
-  function __extend() {
-    var i,
-        k,
-        res = {},
-        l = arguments.length;
-
-    for (i = l - 1; i >= 0; i--)
-      for (k in arguments[i])
-        res[k] = arguments[i][k];
-
-    return res;
-  }
-
-  /**
-   * This function simply clones an object. This object must contain only
-   * objects, arrays and immutable values. Since it is not public, it does not
-   * deal with cyclic references, DOM elements and instantiated objects - so
-   * use it carefully.
-   *
-   * @param  {Object} The object to clone.
-   * @return {Object} The clone.
-   */
-  function __clone(item) {
-    var result, i, k, l;
-
-    if (!item)
-      return item;
-
-    if (Array.isArray(item)) {
-      result = [];
-      for (i = 0, l = item.length; i < l; i++)
-        result.push(__clone(item[i]));
-    } else if (typeof item === 'object') {
-      result = {};
-      for (i in item)
-        result[i] = __clone(item[i]);
+    /**
+     * Sigma Quad Constructor
+     * ----------------------
+     *
+     * The quad API as exposed to sigma.
+     */
+
+    /**
+     * The quad core that will become the sigma interface with the quadtree.
+     *
+     * property {object} _tree  Property holding the quadtree object.
+     * property {object} _geom  Exposition of the _geom namespace for testing.
+     * property {object} _cache Cache for the area method.
+     */
+    var quad = function () {
+        this._geom = _geom;
+        this._tree = null;
+        this._cache = {
+            query: false,
+            result: false
+        };
+    };
+
+    /**
+     * Index a graph by inserting its nodes into the quadtree.
+     *
+     * @param  {array}  nodes   An array of nodes to index.
+     * @param  {object} params  An object of parameters with at least the quad
+     *                          bounds.
+     * @return {object}         The quadtree object.
+     *
+     * Parameters:
+     * ----------
+     * bounds:      {object}   boundaries of the quad defined by its origin (x, y)
+     *                         width and heigth.
+     * prefix:      {string?}  a prefix for node geometric attributes.
+     * maxElements: {integer?} the max number of elements in a leaf node.
+     * maxLevel:    {integer?} the max recursion level of the tree.
+     */
+    quad.prototype.index = function (nodes, params) {
+
+        // Enforcing presence of boundaries
+        if (!params.bounds)
+            throw 'sigma.classes.quad.index: bounds information not given.';
+
+        // Prefix
+        var prefix = params.prefix || '';
+
+        // Building the tree
+        this._tree = _quadTree(
+            params.bounds,
+            0,
+            params.maxElements,
+            params.maxLevel
+        );
+
+        // Inserting graph nodes into the tree
+        for (var i = 0, l = nodes.length; i < l; i++) {
+
+            // Inserting node
+            _quadInsert(
+                nodes[i],
+                _geom.pointToSquare({
+                    x: nodes[i][prefix + 'x'],
+                    y: nodes[i][prefix + 'y'],
+                    size: nodes[i][prefix + 'size']
+                }),
+                this._tree
+            );
+        }
+
+        // Reset cache:
+        this._cache = {
+            query: false,
+            result: false
+        };
+
+        // remove?
+        return this._tree;
+    };
+
+    /**
+     * Retrieve every graph nodes held by the quadtree node containing the
+     * searched point.
+     *
+     * @param  {number} x of the point.
+     * @param  {number} y of the point.
+     * @return {array}  An array of nodes retrieved.
+     */
+    quad.prototype.point = function (x, y) {
+        return this._tree ?
+        _quadRetrievePoint({x: x, y: y}, this._tree) || [] :
+            [];
+    };
+
+    /**
+     * Retrieve every graph nodes within a rectangular area. The methods keep the
+     * last area queried in cache for optimization reason and will act differently
+     * for the same reason if the area is axis-aligned or not.
+     *
+     * @param  {object} A rectangle defined by two top points (x1, y1), (x2, y2)
+     *                  and height.
+     * @return {array}  An array of nodes retrieved.
+     */
+    quad.prototype.area = function (rect) {
+        var serialized = JSON.stringify(rect),
+            collisionFunc,
+            rectData;
+
+        // Returning cache?
+        if (this._cache.query === serialized)
+            return this._cache.result;
+
+        // Axis aligned ?
+        if (_geom.isAxisAligned(rect)) {
+            collisionFunc = _quadIndexes;
+            rectData = _geom.axisAlignedTopPoints(rect);
+        }
+        else {
+            collisionFunc = _quadCollision;
+            rectData = _geom.rectangleCorners(rect);
+        }
+
+        // Retrieving nodes
+        var nodes = this._tree ?
+            _quadRetrieveArea(
+                rectData,
+                this._tree,
+                collisionFunc
+            ) :
+            [];
+
+        // Object to array
+        var nodesArray = [];
+        for (var i in nodes)
+            nodesArray.push(nodes[i]);
+
+        // Caching
+        this._cache.query = serialized;
+        this._cache.result = nodesArray;
+
+        return nodesArray;
+    };
+
+
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof this.sigma !== 'undefined') {
+        this.sigma.classes = this.sigma.classes || {};
+        this.sigma.classes.quad = quad;
+    } else if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = quad;
+        exports.quad = quad;
     } else
-      result = item;
-
-    return result;
-  }
-
-  /**
-   * Returns an array containing the values of an object.
-   *
-   * @param  {Object} The object.
-   * @return {Array}  The array of values.
-   */
-  function __objectValues(o) {
-    var k,
-        a = [];
-
-    for (k in o)
-      a.push(o[k]);
-
-    return a;
-  }
-
-  /**
-   * A short "Date.now()" polyfill.
-   *
-   * @return {Number} The current time (in ms).
-   */
-  function __dateNow() {
-    return Date.now ? Date.now() : new Date().getTime();
-  }
-
-  /**
-   * Polyfill for the Array.isArray function:
-   */
-  if (!Array.isArray)
-    Array.isArray = function(v) {
-      return Object.prototype.toString.call(v) === '[object Array]';
-    };
-
-
-  /**
-   * EXPORT PUBLIC API:
-   * ******************
-   */
-  var conrad = {
-    hasJob: _hasJob,
-    addJob: _addJob,
-    killJob: _killJob,
-    killAll: _killAll,
-    settings: _settings,
-    getStats: _getStats,
-    isRunning: _getIsRunning,
-    clearHistory: _clearHistory,
-
-    // Events management:
-    bind: _bind,
-    unbind: _unbind,
-
-    // Version:
-    version: '0.1.0'
-  };
-
-  if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = conrad;
-    exports.conrad = conrad;
-  }
-  global.conrad = conrad;
-})(this);
+        this.quad = quad;
+}).call(this);
 
-// Hardcoded export for the node.js version:
-var sigma = this.sigma,
-    conrad = this.conrad;
+;(function (undefined) {
+    'use strict';
 
-sigma.conrad = conrad;
+    /**
+     * Sigma Quadtree Module for edges
+     * ===============================
+     *
+     * Author: Sébastien Heymann,
+     *   from the quad of Guillaume Plique (Yomguithereal)
+     * Version: 0.2
+     */
 
-// Dirty polyfills to permit sigma usage in node
-if (HTMLElement === undefined)
-  var HTMLElement = function() {};
 
-if (window === undefined)
-  var window = {
-    addEventListener: function() {}
-  };
+    /**
+     * Quad Geometric Operations
+     * -------------------------
+     *
+     * A useful batch of geometric operations used by the quadtree.
+     */
 
-if (typeof exports !== 'undefined') {
-  if (typeof module !== 'undefined' && module.exports)
-    exports = module.exports = sigma;
-  exports.sigma = sigma;
-}
+    var _geom = {
+
+        /**
+         * Transforms a graph node with x, y and size into an
+         * axis-aligned square.
+         *
+         * @param  {object} A graph node with at least a point (x, y) and a size.
+         * @return {object} A square: two points (x1, y1), (x2, y2) and height.
+         */
+        pointToSquare: function (n) {
+            return {
+                x1: n.x - n.size,
+                y1: n.y - n.size,
+                x2: n.x + n.size,
+                y2: n.y - n.size,
+                height: n.size * 2
+            };
+        },
+
+        /**
+         * Transforms a graph edge with x1, y1, x2, y2 and size into an
+         * axis-aligned square.
+         *
+         * @param  {object} A graph edge with at least two points
+         *                  (x1, y1), (x2, y2) and a size.
+         * @return {object} A square: two points (x1, y1), (x2, y2) and height.
+         */
+        lineToSquare: function (e) {
+            if (e.y1 < e.y2) {
+                // (e.x1, e.y1) on top
+                if (e.x1 < e.x2) {
+                    // (e.x1, e.y1) on left
+                    return {
+                        x1: e.x1 - e.size,
+                        y1: e.y1 - e.size,
+                        x2: e.x2 + e.size,
+                        y2: e.y1 - e.size,
+                        height: e.y2 - e.y1 + e.size * 2
+                    };
+                }
+                // (e.x1, e.y1) on right
+                return {
+                    x1: e.x2 - e.size,
+                    y1: e.y1 - e.size,
+                    x2: e.x1 + e.size,
+                    y2: e.y1 - e.size,
+                    height: e.y2 - e.y1 + e.size * 2
+                };
+            }
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  var _root = this;
-
-  // Initialize packages:
-  sigma.utils = sigma.utils || {};
-
-  /**
-   * MISC UTILS:
-   */
-  /**
-   * This function takes any number of objects as arguments, copies from each
-   * of these objects each pair key/value into a new object, and finally
-   * returns this object.
-   *
-   * The arguments are parsed from the last one to the first one, such that
-   * when several objects have keys in common, the "earliest" object wins.
-   *
-   * Example:
-   * ********
-   *  > var o1 = {
-   *  >       a: 1,
-   *  >       b: 2,
-   *  >       c: '3'
-   *  >     },
-   *  >     o2 = {
-   *  >       c: '4',
-   *  >       d: [ 5 ]
-   *  >     };
-   *  > sigma.utils.extend(o1, o2);
-   *  > // Returns: {
-   *  > //   a: 1,
-   *  > //   b: 2,
-   *  > //   c: '3',
-   *  > //   d: [ 5 ]
-   *  > // };
-   *
-   * @param  {object+} Any number of objects.
-   * @return {object}  The merged object.
-   */
-  sigma.utils.extend = function() {
-    var i,
-        k,
-        res = {},
-        l = arguments.length;
-
-    for (i = l - 1; i >= 0; i--)
-      for (k in arguments[i])
-        res[k] = arguments[i][k];
-
-    return res;
-  };
-
-  /**
-   * A short "Date.now()" polyfill.
-   *
-   * @return {Number} The current time (in ms).
-   */
-  sigma.utils.dateNow = function() {
-    return Date.now ? Date.now() : new Date().getTime();
-  };
-
-  /**
-   * Takes a package name as parameter and checks at each lebel if it exists,
-   * and if it does not, creates it.
-   *
-   * Example:
-   * ********
-   *  > sigma.utils.pkg('a.b.c');
-   *  > a.b.c;
-   *  > // Object {};
-   *  >
-   *  > sigma.utils.pkg('a.b.d');
-   *  > a.b;
-   *  > // Object { c: {}, d: {} };
-   *
-   * @param  {string} pkgName The name of the package to create/find.
-   * @return {object}         The related package.
-   */
-  sigma.utils.pkg = function(pkgName) {
-    return (pkgName || '').split('.').reduce(function(context, objName) {
-      return (objName in context) ?
-        context[objName] :
-        (context[objName] = {});
-    }, _root);
-  };
-
-  /**
-   * Returns a unique incremental number ID.
-   *
-   * Example:
-   * ********
-   *  > sigma.utils.id();
-   *  > // 1;
-   *  >
-   *  > sigma.utils.id();
-   *  > // 2;
-   *  >
-   *  > sigma.utils.id();
-   *  > // 3;
-   *
-   * @param  {string} pkgName The name of the package to create/find.
-   * @return {object}         The related package.
-   */
-  sigma.utils.id = (function() {
-    var i = 0;
-    return function() {
-      return ++i;
-    };
-  })();
-
-  /**
-   * This function takes an hexa color (for instance "#ffcc00" or "#fc0") or a
-   * rgb / rgba color (like "rgb(255,255,12)" or "rgba(255,255,12,1)") and
-   * returns an integer equal to "r * 255 * 255 + g * 255 + b", to gain some
-   * memory in the data given to WebGL shaders.
-   *
-   * Note that the function actually caches its results for better performance.
-   *
-   * @param  {string} val The hexa or rgba color.
-   * @return {number}     The number value.
-   */
-  var floatColorCache = {};
-
-  sigma.utils.floatColor = function(val) {
-
-    // Is the color already computed?
-    if (floatColorCache[val])
-      return floatColorCache[val];
-
-    var original = val,
-        r = 0,
-        g = 0,
-        b = 0;
-
-    if (val[0] === '#') {
-      val = val.slice(1);
-
-      if (val.length === 3) {
-        r = parseInt(val.charAt(0) + val.charAt(0), 16);
-        g = parseInt(val.charAt(1) + val.charAt(1), 16);
-        b = parseInt(val.charAt(2) + val.charAt(2), 16);
-      }
-      else {
-        r = parseInt(val.charAt(0) + val.charAt(1), 16);
-        g = parseInt(val.charAt(2) + val.charAt(3), 16);
-        b = parseInt(val.charAt(4) + val.charAt(5), 16);
-      }
-    } else if (val.match(/^ *rgba? *\(/)) {
-      val = val.match(
-        /^ *rgba? *\( *([0-9]*) *, *([0-9]*) *, *([0-9]*) *(,.*)?\) *$/
-      );
-      r = +val[1];
-      g = +val[2];
-      b = +val[3];
-    }
+            // (e.x2, e.y2) on top
+            if (e.x1 < e.x2) {
+                // (e.x1, e.y1) on left
+                return {
+                    x1: e.x1 - e.size,
+                    y1: e.y2 - e.size,
+                    x2: e.x2 + e.size,
+                    y2: e.y2 - e.size,
+                    height: e.y1 - e.y2 + e.size * 2
+                };
+            }
+            // (e.x2, e.y2) on right
+            return {
+                x1: e.x2 - e.size,
+                y1: e.y2 - e.size,
+                x2: e.x1 + e.size,
+                y2: e.y2 - e.size,
+                height: e.y1 - e.y2 + e.size * 2
+            };
+        },
+
+        /**
+         * Transforms a graph edge of type 'curve' with x1, y1, x2, y2,
+         * control point and size into an axis-aligned square.
+         *
+         * @param  {object} e  A graph edge with at least two points
+         *                     (x1, y1), (x2, y2) and a size.
+         * @param  {object} cp A control point (x,y).
+         * @return {object}    A square: two points (x1, y1), (x2, y2) and height.
+         */
+        quadraticCurveToSquare: function (e, cp) {
+            var pt = sigma.utils.getPointOnQuadraticCurve(
+                0.5,
+                e.x1,
+                e.y1,
+                e.x2,
+                e.y2,
+                cp.x,
+                cp.y
+            );
 
-    var color = (
-      r * 256 * 256 +
-      g * 256 +
-      b
-    );
-
-    // Caching the color
-    floatColorCache[original] = color;
-
-    return color;
-  };
-
-    /**
-   * Perform a zoom into a camera, with or without animation, to the
-   * coordinates indicated using a specified ratio.
-   *
-   * Recognized parameters:
-   * **********************
-   * Here is the exhaustive list of every accepted parameters in the animation
-   * object:
-   *
-   *   {?number} duration     An amount of time that means the duration of the
-   *                          animation. If this parameter doesn't exist the
-   *                          zoom will be performed without animation.
-   *   {?function} onComplete A function to perform it after the animation. It
-   *                          will be performed even if there is no duration.
-   *
-   * @param {camera}     The camera where perform the zoom.
-   * @param {x}          The X coordiantion where the zoom goes.
-   * @param {y}          The Y coordiantion where the zoom goes.
-   * @param {ratio}      The ratio to apply it to the current camera ratio.
-   * @param {?animation} A dictionary with options for a possible animation.
-   */
-  sigma.utils.zoomTo = function(camera, x, y, ratio, animation) {
-    var settings = camera.settings,
-        count,
-        newRatio,
-        animationSettings,
-        coordinates;
-
-    // Create the newRatio dealing with min / max:
-    newRatio = Math.max(
-      settings('zoomMin'),
-      Math.min(
-        settings('zoomMax'),
-        camera.ratio * ratio
-      )
-    );
-
-    // Check that the new ratio is different from the initial one:
-    if (newRatio !== camera.ratio) {
-      // Create the coordinates variable:
-      ratio = newRatio / camera.ratio;
-      coordinates = {
-        x: x * (1 - ratio) + camera.x,
-        y: y * (1 - ratio) + camera.y,
-        ratio: newRatio
-      };
-
-      if (animation && animation.duration) {
-        // Complete the animation setings:
-        count = sigma.misc.animation.killAll(camera);
-        animation = sigma.utils.extend(
-          animation,
-          {
-            easing: count ? 'quadraticOut' : 'quadraticInOut'
-          }
-        );
+            // Bounding box of the two points and the point at the middle of the
+            // curve:
+            var minX = Math.min(e.x1, e.x2, pt.x),
+                maxX = Math.max(e.x1, e.x2, pt.x),
+                minY = Math.min(e.y1, e.y2, pt.y),
+                maxY = Math.max(e.y1, e.y2, pt.y);
+
+            return {
+                x1: minX - e.size,
+                y1: minY - e.size,
+                x2: maxX + e.size,
+                y2: minY - e.size,
+                height: maxY - minY + e.size * 2
+            };
+        },
+
+        /**
+         * Transforms a graph self loop into an axis-aligned square.
+         *
+         * @param  {object} n A graph node with a point (x, y) and a size.
+         * @return {object}   A square: two points (x1, y1), (x2, y2) and height.
+         */
+        selfLoopToSquare: function (n) {
+            // Fitting to the curve is too costly, we compute a larger bounding box
+            // using the control points:
+            var cp = sigma.utils.getSelfLoopControlPoints(n.x, n.y, n.size);
+
+            // Bounding box of the point and the two control points:
+            var minX = Math.min(n.x, cp.x1, cp.x2),
+                maxX = Math.max(n.x, cp.x1, cp.x2),
+                minY = Math.min(n.y, cp.y1, cp.y2),
+                maxY = Math.max(n.y, cp.y1, cp.y2);
+
+            return {
+                x1: minX - n.size,
+                y1: minY - n.size,
+                x2: maxX + n.size,
+                y2: minY - n.size,
+                height: maxY - minY + n.size * 2
+            };
+        },
+
+        /**
+         * Checks whether a rectangle is axis-aligned.
+         *
+         * @param  {object}  A rectangle defined by two points
+         *                   (x1, y1) and (x2, y2).
+         * @return {boolean} True if the rectangle is axis-aligned.
+         */
+        isAxisAligned: function (r) {
+            return r.x1 === r.x2 || r.y1 === r.y2;
+        },
+
+        /**
+         * Compute top points of an axis-aligned rectangle. This is useful in
+         * cases when the rectangle has been rotated (left, right or bottom up) and
+         * later operations need to know the top points.
+         *
+         * @param  {object} An axis-aligned rectangle defined by two points
+         *                  (x1, y1), (x2, y2) and height.
+         * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height.
+         */
+        axisAlignedTopPoints: function (r) {
+
+            // Basic
+            if (r.y1 === r.y2 && r.x1 < r.x2)
+                return r;
+
+            // Rotated to right
+            if (r.x1 === r.x2 && r.y2 > r.y1)
+                return {
+                    x1: r.x1 - r.height, y1: r.y1,
+                    x2: r.x1, y2: r.y1,
+                    height: r.height
+                };
+
+            // Rotated to left
+            if (r.x1 === r.x2 && r.y2 < r.y1)
+                return {
+                    x1: r.x1, y1: r.y2,
+                    x2: r.x2 + r.height, y2: r.y2,
+                    height: r.height
+                };
+
+            // Bottom's up
+            return {
+                x1: r.x2, y1: r.y1 - r.height,
+                x2: r.x1, y2: r.y1 - r.height,
+                height: r.height
+            };
+        },
+
+        /**
+         * Get coordinates of a rectangle's lower left corner from its top points.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @return {object} Coordinates of the corner (x, y).
+         */
+        lowerLeftCoor: function (r) {
+            var width = (
+                Math.sqrt(
+                    Math.pow(r.x2 - r.x1, 2) +
+                    Math.pow(r.y2 - r.y1, 2)
+                )
+            );
 
-        sigma.misc.animation.camera(camera, coordinates, animation);
-      } else {
-        camera.goTo(coordinates);
-        if (animation && animation.onComplete)
-          animation.onComplete();
-      }
-    }
-  };
-
-  /**
-   * Return the control point coordinates for a quadratic bezier curve.
-   *
-   * @param  {number} x1  The X coordinate of the start point.
-   * @param  {number} y1  The Y coordinate of the start point.
-   * @param  {number} x2  The X coordinate of the end point.
-   * @param  {number} y2  The Y coordinate of the end point.
-   * @return {x,y}        The control point coordinates.
-   */
-  sigma.utils.getQuadraticControlPoint = function(x1, y1, x2, y2) {
-    return {
-      x: (x1 + x2) / 2 + (y2 - y1) / 4,
-      y: (y1 + y2) / 2 + (x1 - x2) / 4
-    };
-  };
-
-  /**
-    * Compute the coordinates of the point positioned
-    * at length t in the quadratic bezier curve.
-    *
-    * @param  {number} t  In [0,1] the step percentage to reach
-    *                     the point in the curve from the context point.
-    * @param  {number} x1 The X coordinate of the context point.
-    * @param  {number} y1 The Y coordinate of the context point.
-    * @param  {number} x2 The X coordinate of the ending point.
-    * @param  {number} y2 The Y coordinate of the ending point.
-    * @param  {number} xi The X coordinate of the control point.
-    * @param  {number} yi The Y coordinate of the control point.
-    * @return {object}    {x,y}.
-  */
-  sigma.utils.getPointOnQuadraticCurve = function(t, x1, y1, x2, y2, xi, yi) {
-    // http://stackoverflow.com/a/5634528
-    return {
-      x: Math.pow(1 - t, 2) * x1 + 2 * (1 - t) * t * xi + Math.pow(t, 2) * x2,
-      y: Math.pow(1 - t, 2) * y1 + 2 * (1 - t) * t * yi + Math.pow(t, 2) * y2
-    };
-  };
-
-  /**
-    * Compute the coordinates of the point positioned
-    * at length t in the cubic bezier curve.
-    *
-    * @param  {number} t  In [0,1] the step percentage to reach
-    *                     the point in the curve from the context point.
-    * @param  {number} x1 The X coordinate of the context point.
-    * @param  {number} y1 The Y coordinate of the context point.
-    * @param  {number} x2 The X coordinate of the end point.
-    * @param  {number} y2 The Y coordinate of the end point.
-    * @param  {number} cx The X coordinate of the first control point.
-    * @param  {number} cy The Y coordinate of the first control point.
-    * @param  {number} dx The X coordinate of the second control point.
-    * @param  {number} dy The Y coordinate of the second control point.
-    * @return {object}    {x,y} The point at t.
-  */
-  sigma.utils.getPointOnBezierCurve =
-    function(t, x1, y1, x2, y2, cx, cy, dx, dy) {
-    // http://stackoverflow.com/a/15397596
-    // Blending functions:
-    var B0_t = Math.pow(1 - t, 3),
-        B1_t = 3 * t * Math.pow(1 - t, 2),
-        B2_t = 3 * Math.pow(t, 2) * (1 - t),
-        B3_t = Math.pow(t, 3);
-
-    return {
-      x: (B0_t * x1) + (B1_t * cx) + (B2_t * dx) + (B3_t * x2),
-      y: (B0_t * y1) + (B1_t * cy) + (B2_t * dy) + (B3_t * y2)
-    };
-  };
-
-  /**
-   * Return the coordinates of the two control points for a self loop (i.e.
-   * where the start point is also the end point) computed as a cubic bezier
-   * curve.
-   *
-   * @param  {number} x    The X coordinate of the node.
-   * @param  {number} y    The Y coordinate of the node.
-   * @param  {number} size The node size.
-   * @return {x1,y1,x2,y2} The coordinates of the two control points.
-   */
-  sigma.utils.getSelfLoopControlPoints = function(x , y, size) {
-    return {
-      x1: x - size * 7,
-      y1: y,
-      x2: x,
-      y2: y + size * 7
-    };
-  };
-
-  /**
-   * Return the euclidian distance between two points of a plane
-   * with an orthonormal basis.
-   *
-   * @param  {number} x1  The X coordinate of the first point.
-   * @param  {number} y1  The Y coordinate of the first point.
-   * @param  {number} x2  The X coordinate of the second point.
-   * @param  {number} y2  The Y coordinate of the second point.
-   * @return {number}     The euclidian distance.
-   */
-  sigma.utils.getDistance = function(x0, y0, x1, y1) {
-    return Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2));
-  };
-
-  /**
-   * Return the coordinates of the intersection points of two circles.
-   *
-   * @param  {number} x0  The X coordinate of center location of the first
-   *                      circle.
-   * @param  {number} y0  The Y coordinate of center location of the first
-   *                      circle.
-   * @param  {number} r0  The radius of the first circle.
-   * @param  {number} x1  The X coordinate of center location of the second
-   *                      circle.
-   * @param  {number} y1  The Y coordinate of center location of the second
-   *                      circle.
-   * @param  {number} r1  The radius of the second circle.
-   * @return {xi,yi}      The coordinates of the intersection points.
-   */
-  sigma.utils.getCircleIntersection = function(x0, y0, r0, x1, y1, r1) {
-    // http://stackoverflow.com/a/12219802
-    var a, dx, dy, d, h, rx, ry, x2, y2;
-
-    // dx and dy are the vertical and horizontal distances between the circle
-    // centers:
-    dx = x1 - x0;
-    dy = y1 - y0;
-
-    // Determine the straight-line distance between the centers:
-    d = Math.sqrt((dy * dy) + (dx * dx));
-
-    // Check for solvability:
-    if (d > (r0 + r1)) {
-        // No solution. circles do not intersect.
-        return false;
-    }
-    if (d < Math.abs(r0 - r1)) {
-        // No solution. one circle is contained in the other.
-        return false;
-    }
+            return {
+                x: r.x1 - (r.y2 - r.y1) * r.height / width,
+                y: r.y1 + (r.x2 - r.x1) * r.height / width
+            };
+        },
+
+        /**
+         * Get coordinates of a rectangle's lower right corner from its top points
+         * and its lower left corner.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @param  {object} A corner's coordinates (x, y).
+         * @return {object} Coordinates of the corner (x, y).
+         */
+        lowerRightCoor: function (r, llc) {
+            return {
+                x: llc.x - r.x1 + r.x2,
+                y: llc.y - r.y1 + r.y2
+            };
+        },
+
+        /**
+         * Get the coordinates of all the corners of a rectangle from its top point.
+         *
+         * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
+         * @return {array}  An array of the four corners' coordinates (x, y).
+         */
+        rectangleCorners: function (r) {
+            var llc = this.lowerLeftCoor(r),
+                lrc = this.lowerRightCoor(r, llc);
+
+            return [
+                {x: r.x1, y: r.y1},
+                {x: r.x2, y: r.y2},
+                {x: llc.x, y: llc.y},
+                {x: lrc.x, y: lrc.y}
+            ];
+        },
+
+        /**
+         * Split a square defined by its boundaries into four.
+         *
+         * @param  {object} Boundaries of the square (x, y, width, height).
+         * @return {array}  An array containing the four new squares, themselves
+         *                  defined by an array of their four corners (x, y).
+         */
+        splitSquare: function (b) {
+            return [
+                [
+                    {x: b.x, y: b.y},
+                    {x: b.x + b.width / 2, y: b.y},
+                    {x: b.x, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2}
+                ],
+                [
+                    {x: b.x + b.width / 2, y: b.y},
+                    {x: b.x + b.width, y: b.y},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x + b.width, y: b.y + b.height / 2}
+                ],
+                [
+                    {x: b.x, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x, y: b.y + b.height},
+                    {x: b.x + b.width / 2, y: b.y + b.height}
+                ],
+                [
+                    {x: b.x + b.width / 2, y: b.y + b.height / 2},
+                    {x: b.x + b.width, y: b.y + b.height / 2},
+                    {x: b.x + b.width / 2, y: b.y + b.height},
+                    {x: b.x + b.width, y: b.y + b.height}
+                ]
+            ];
+        },
+
+        /**
+         * Compute the four axis between corners of rectangle A and corners of
+         * rectangle B. This is needed later to check an eventual collision.
+         *
+         * @param  {array} An array of rectangle A's four corners (x, y).
+         * @param  {array} An array of rectangle B's four corners (x, y).
+         * @return {array} An array of four axis defined by their coordinates (x,y).
+         */
+        axis: function (c1, c2) {
+            return [
+                {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y},
+                {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y},
+                {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y},
+                {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y}
+            ];
+        },
+
+        /**
+         * Project a rectangle's corner on an axis.
+         *
+         * @param  {object} Coordinates of a corner (x, y).
+         * @param  {object} Coordinates of an axis (x, y).
+         * @return {object} The projection defined by coordinates (x, y).
+         */
+        projection: function (c, a) {
+            var l = (
+                (c.x * a.x + c.y * a.y) /
+                (Math.pow(a.x, 2) + Math.pow(a.y, 2))
+            );
 
-    //'point 2' is the point where the line through the circle intersection
-    // points crosses the line between the circle centers.
-
-    // Determine the distance from point 0 to point 2:
-    a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d);
-
-    // Determine the coordinates of point 2:
-    x2 = x0 + (dx * a / d);
-    y2 = y0 + (dy * a / d);
-
-    // Determine the distance from point 2 to either of the intersection
-    // points:
-    h = Math.sqrt((r0 * r0) - (a * a));
-
-    // Determine the offsets of the intersection points from point 2:
-    rx = -dy * (h / d);
-    ry = dx * (h / d);
-
-    // Determine the absolute intersection points:
-    var xi = x2 + rx;
-    var xi_prime = x2 - rx;
-    var yi = y2 + ry;
-    var yi_prime = y2 - ry;
-
-    return {xi: xi, xi_prime: xi_prime, yi: yi, yi_prime: yi_prime};
-  };
-
-  /**
-    * Check if a point is on a line segment.
-    *
-    * @param  {number} x       The X coordinate of the point to check.
-    * @param  {number} y       The Y coordinate of the point to check.
-    * @param  {number} x1      The X coordinate of the line start point.
-    * @param  {number} y1      The Y coordinate of the line start point.
-    * @param  {number} x2      The X coordinate of the line end point.
-    * @param  {number} y2      The Y coordinate of the line end point.
-    * @param  {number} epsilon The precision (consider the line thickness).
-    * @return {boolean}        True if point is "close to" the line
-    *                          segment, false otherwise.
-  */
-  sigma.utils.isPointOnSegment = function(x, y, x1, y1, x2, y2, epsilon) {
-    // http://stackoverflow.com/a/328122
-    var crossProduct = Math.abs((y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)),
-        d = sigma.utils.getDistance(x1, y1, x2, y2),
-        nCrossProduct = crossProduct / d; // normalized cross product
-
-    return (nCrossProduct < epsilon &&
-     Math.min(x1, x2) <= x && x <= Math.max(x1, x2) &&
-     Math.min(y1, y2) <= y && y <= Math.max(y1, y2));
-  };
-
-  /**
-    * Check if a point is on a quadratic bezier curve segment with a thickness.
-    *
-    * @param  {number} x       The X coordinate of the point to check.
-    * @param  {number} y       The Y coordinate of the point to check.
-    * @param  {number} x1      The X coordinate of the curve start point.
-    * @param  {number} y1      The Y coordinate of the curve start point.
-    * @param  {number} x2      The X coordinate of the curve end point.
-    * @param  {number} y2      The Y coordinate of the curve end point.
-    * @param  {number} cpx     The X coordinate of the curve control point.
-    * @param  {number} cpy     The Y coordinate of the curve control point.
-    * @param  {number} epsilon The precision (consider the line thickness).
-    * @return {boolean}        True if (x,y) is on the curve segment,
-    *                          false otherwise.
-  */
-  sigma.utils.isPointOnQuadraticCurve =
-    function(x, y, x1, y1, x2, y2, cpx, cpy, epsilon) {
-    // Fails if the point is too far from the extremities of the segment,
-    // preventing for more costly computation:
-    var dP1P2 = sigma.utils.getDistance(x1, y1, x2, y2);
-    if (Math.abs(x - x1) > dP1P2 || Math.abs(y - y1) > dP1P2) {
-      return false;
-    }
+            return {
+                x: l * a.x,
+                y: l * a.y
+            };
+        },
+
+        /**
+         * Check whether two rectangles collide on one particular axis.
+         *
+         * @param  {object}   An axis' coordinates (x, y).
+         * @param  {array}    Rectangle A's corners.
+         * @param  {array}    Rectangle B's corners.
+         * @return {boolean}  True if the rectangles collide on the axis.
+         */
+        axisCollision: function (a, c1, c2) {
+            var sc1 = [],
+                sc2 = [];
+
+            for (var ci = 0; ci < 4; ci++) {
+                var p1 = this.projection(c1[ci], a),
+                    p2 = this.projection(c2[ci], a);
+
+                sc1.push(p1.x * a.x + p1.y * a.y);
+                sc2.push(p2.x * a.x + p2.y * a.y);
+            }
 
-    var dP1 = sigma.utils.getDistance(x, y, x1, y1),
-        dP2 = sigma.utils.getDistance(x, y, x2, y2),
-        t = 0.5,
-        r = (dP1 < dP2) ? -0.01 : 0.01,
-        rThreshold = 0.001,
-        i = 100,
-        pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy),
-        dt = sigma.utils.getDistance(x, y, pt.x, pt.y),
-        old_dt;
-
-    // This algorithm minimizes the distance from the point to the curve. It
-    // find the optimal t value where t=0 is the start point and t=1 is the end
-    // point of the curve, starting from t=0.5.
-    // It terminates because it runs a maximum of i interations.
-    while (i-- > 0 &&
-      t >= 0 && t <= 1 &&
-      (dt > epsilon) &&
-      (r > rThreshold || r < -rThreshold)) {
-      old_dt = dt;
-      pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy);
-      dt = sigma.utils.getDistance(x, y, pt.x, pt.y);
-
-      if (dt > old_dt) {
-        // not the right direction:
-        // halfstep in the opposite direction
-        r = -r / 2;
-        t += r;
-      }
-      else if (t + r < 0 || t + r > 1) {
-        // oops, we've gone too far:
-        // revert with a halfstep
-        r = r / 2;
-        dt = old_dt;
-      }
-      else {
-        // progress:
-        t += r;
-      }
-    }
+            var maxc1 = Math.max.apply(Math, sc1),
+                maxc2 = Math.max.apply(Math, sc2),
+                minc1 = Math.min.apply(Math, sc1),
+                minc2 = Math.min.apply(Math, sc2);
+
+            return (minc2 <= maxc1 && maxc2 >= minc1);
+        },
+
+        /**
+         * Check whether two rectangles collide on each one of their four axis. If
+         * all axis collide, then the two rectangles do collide on the plane.
+         *
+         * @param  {array}    Rectangle A's corners.
+         * @param  {array}    Rectangle B's corners.
+         * @return {boolean}  True if the rectangles collide.
+         */
+        collision: function (c1, c2) {
+            var axis = this.axis(c1, c2),
+                col = true;
+
+            for (var i = 0; i < 4; i++)
+                col = col && this.axisCollision(axis[i], c1, c2);
+
+            return col;
+        }
+    };
 
-    return dt < epsilon;
-  };
-
-
-  /**
-    * Check if a point is on a cubic bezier curve segment with a thickness.
-    *
-    * @param  {number} x       The X coordinate of the point to check.
-    * @param  {number} y       The Y coordinate of the point to check.
-    * @param  {number} x1      The X coordinate of the curve start point.
-    * @param  {number} y1      The Y coordinate of the curve start point.
-    * @param  {number} x2      The X coordinate of the curve end point.
-    * @param  {number} y2      The Y coordinate of the curve end point.
-    * @param  {number} cpx1    The X coordinate of the 1st curve control point.
-    * @param  {number} cpy1    The Y coordinate of the 1st curve control point.
-    * @param  {number} cpx2    The X coordinate of the 2nd curve control point.
-    * @param  {number} cpy2    The Y coordinate of the 2nd curve control point.
-    * @param  {number} epsilon The precision (consider the line thickness).
-    * @return {boolean}        True if (x,y) is on the curve segment,
-    *                          false otherwise.
-  */
-  sigma.utils.isPointOnBezierCurve =
-    function(x, y, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2, epsilon) {
-    // Fails if the point is too far from the extremities of the segment,
-    // preventing for more costly computation:
-    var dP1CP1 = sigma.utils.getDistance(x1, y1, cpx1, cpy1);
-    if (Math.abs(x - x1) > dP1CP1 || Math.abs(y - y1) > dP1CP1) {
-      return false;
-    }
 
-    var dP1 = sigma.utils.getDistance(x, y, x1, y1),
-        dP2 = sigma.utils.getDistance(x, y, x2, y2),
-        t = 0.5,
-        r = (dP1 < dP2) ? -0.01 : 0.01,
-        rThreshold = 0.001,
-        i = 100,
-        pt = sigma.utils.getPointOnBezierCurve(
-          t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2),
-        dt = sigma.utils.getDistance(x, y, pt.x, pt.y),
-        old_dt;
-
-    // This algorithm minimizes the distance from the point to the curve. It
-    // find the optimal t value where t=0 is the start point and t=1 is the end
-    // point of the curve, starting from t=0.5.
-    // It terminates because it runs a maximum of i interations.
-    while (i-- > 0 &&
-      t >= 0 && t <= 1 &&
-      (dt > epsilon) &&
-      (r > rThreshold || r < -rThreshold)) {
-      old_dt = dt;
-      pt = sigma.utils.getPointOnBezierCurve(
-        t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2);
-      dt = sigma.utils.getDistance(x, y, pt.x, pt.y);
-
-      if (dt > old_dt) {
-        // not the right direction:
-        // halfstep in the opposite direction
-        r = -r / 2;
-        t += r;
-      }
-      else if (t + r < 0 || t + r > 1) {
-        // oops, we've gone too far:
-        // revert with a halfstep
-        r = r / 2;
-        dt = old_dt;
-      }
-      else {
-        // progress:
-        t += r;
-      }
-    }
+    /**
+     * Quad Functions
+     * ------------
+     *
+     * The Quadtree functions themselves.
+     * For each of those functions, we consider that in a splitted quad, the
+     * index of each node is the following:
+     * 0: top left
+     * 1: top right
+     * 2: bottom left
+     * 3: bottom right
+     *
+     * Moreover, the hereafter quad's philosophy is to consider that if an element
+     * collides with more than one nodes, this element belongs to each of the
+     * nodes it collides with where other would let it lie on a higher node.
+     */
 
-    return dt < epsilon;
-  };
-
-
-  /**
-   * ************
-   * EVENTS UTILS:
-   * ************
-   */
-  /**
-   * Here are some useful functions to unify extraction of the information we
-   * need with mouse events and touch events, from different browsers:
-   */
-
-  /**
-   * Extract the local X position from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {number}   The local X value of the mouse.
-   */
-  sigma.utils.getX = function(e) {
-    return (
-      (e.offsetX !== undefined && e.offsetX) ||
-      (e.layerX !== undefined && e.layerX) ||
-      (e.clientX !== undefined && e.clientX)
-    );
-  };
-
-  /**
-   * Extract the local Y position from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {number}   The local Y value of the mouse.
-   */
-  sigma.utils.getY = function(e) {
-    return (
-      (e.offsetY !== undefined && e.offsetY) ||
-      (e.layerY !== undefined && e.layerY) ||
-      (e.clientY !== undefined && e.clientY)
-    );
-  };
-
-  /**
-   * The pixel ratio of the screen. Taking zoom into account
-   *
-   * @return {number}        Pixel ratio of the screen
-   */
-  sigma.utils.getPixelRatio = function() {
-    var ratio = 1;
-    if (window.screen.deviceXDPI !== undefined &&
-         window.screen.logicalXDPI !== undefined &&
-         window.screen.deviceXDPI > window.screen.logicalXDPI) {
-        ratio = window.screen.systemXDPI / window.screen.logicalXDPI;
-    }
-    else if (window.devicePixelRatio !== undefined) {
-        ratio = window.devicePixelRatio;
-    }
-    return ratio;
-  };
-
-  /**
-   * Extract the width from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {number}   The width of the event's target.
-   */
-  sigma.utils.getWidth = function(e) {
-    var w = (!e.target.ownerSVGElement) ?
-              e.target.width :
-              e.target.ownerSVGElement.width;
-
-    return (
-      (typeof w === 'number' && w) ||
-      (w !== undefined && w.baseVal !== undefined && w.baseVal.value)
-    );
-  };
-
-  /**
-   * Extract the center from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {object}   The center of the event's target.
-   */
-  sigma.utils.getCenter = function(e) {
-    var ratio = e.target.namespaceURI.indexOf('svg') !== -1 ? 1 :
-        sigma.utils.getPixelRatio();
-    return {
-      x: sigma.utils.getWidth(e) / (2 * ratio),
-      y: sigma.utils.getHeight(e) / (2 * ratio),
-    };
-  };
-
-  /**
-   * Convert mouse coords to sigma coords
-   *
-   * @param  {event}   e A mouse or touch event.
-   * @param  {number?} x The x coord to convert
-   * @param  {number?} x The y coord to convert
-   *
-   * @return {object}    The standardized event
-   */
-  sigma.utils.mouseCoords = function(e, x, y) {
-    x = x || sigma.utils.getX(e);
-    y = y || sigma.utils.getY(e);
-    return {
-        x: x - sigma.utils.getCenter(e).x,
-        y: y - sigma.utils.getCenter(e).y,
-        clientX: e.clientX,
-        clientY: e.clientY,
-        ctrlKey: e.ctrlKey,
-        metaKey: e.metaKey,
-        altKey: e.altKey,
-        shiftKey: e.shiftKey
-    };
-  };
-
-  /**
-   * Extract the height from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {number}   The height of the event's target.
-   */
-  sigma.utils.getHeight = function(e) {
-    var h = (!e.target.ownerSVGElement) ?
-              e.target.height :
-              e.target.ownerSVGElement.height;
-
-    return (
-      (typeof h === 'number' && h) ||
-      (h !== undefined && h.baseVal !== undefined && h.baseVal.value)
-    );
-  };
-
-  /**
-   * Extract the wheel delta from a mouse or touch event.
-   *
-   * @param  {event}  e A mouse or touch event.
-   * @return {number}   The wheel delta of the mouse.
-   */
-  sigma.utils.getDelta = function(e) {
-    return (
-      (e.wheelDelta !== undefined && e.wheelDelta) ||
-      (e.detail !== undefined && -e.detail)
-    );
-  };
-
-  /**
-   * Returns the offset of a DOM element.
-   *
-   * @param  {DOMElement} dom The element to retrieve the position.
-   * @return {object}         The offset of the DOM element (top, left).
-   */
-  sigma.utils.getOffset = function(dom) {
-    var left = 0,
-        top = 0;
-
-    while (dom) {
-      top = top + parseInt(dom.offsetTop);
-      left = left + parseInt(dom.offsetLeft);
-      dom = dom.offsetParent;
+    /**
+     * Get the index of the node containing the point in the quad
+     *
+     * @param  {object}  point      A point defined by coordinates (x, y).
+     * @param  {object}  quadBounds Boundaries of the quad (x, y, width, heigth).
+     * @return {integer}            The index of the node containing the point.
+     */
+    function _quadIndex(point, quadBounds) {
+        var xmp = quadBounds.x + quadBounds.width / 2,
+            ymp = quadBounds.y + quadBounds.height / 2,
+            top = (point.y < ymp),
+            left = (point.x < xmp);
+
+        if (top) {
+            if (left)
+                return 0;
+            else
+                return 1;
+        }
+        else {
+            if (left)
+                return 2;
+            else
+                return 3;
+        }
     }
 
-    return {
-      top: top,
-      left: left
-    };
-  };
-
-  /**
-   * Simulates a "double click" event.
-   *
-   * @param  {HTMLElement} target   The event target.
-   * @param  {string}      type     The event type.
-   * @param  {function}    callback The callback to execute.
-   */
-  sigma.utils.doubleClick = function(target, type, callback) {
-    var clicks = 0,
-        self = this,
-        handlers;
-
-    target._doubleClickHandler = target._doubleClickHandler || {};
-    target._doubleClickHandler[type] = target._doubleClickHandler[type] || [];
-    handlers = target._doubleClickHandler[type];
-
-    handlers.push(function(e) {
-      clicks++;
-
-      if (clicks === 2) {
-        clicks = 0;
-        return callback(e);
-      } else if (clicks === 1) {
-        setTimeout(function() {
-          clicks = 0;
-        }, sigma.settings.doubleClickTimeout);
-      }
-    });
+    /**
+     * Get a list of indexes of nodes containing an axis-aligned rectangle
+     *
+     * @param  {object}  rectangle   A rectangle defined by two points (x1, y1),
+     *                               (x2, y2) and height.
+     * @param  {array}   quadCorners An array of the quad nodes' corners.
+     * @return {array}               An array of indexes containing one to
+     *                               four integers.
+     */
+    function _quadIndexes(rectangle, quadCorners) {
+        var indexes = [];
+
+        // Iterating through quads
+        for (var i = 0; i < 4; i++)
+            if ((rectangle.x2 >= quadCorners[i][0].x) &&
+                (rectangle.x1 <= quadCorners[i][1].x) &&
+                (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) &&
+                (rectangle.y1 <= quadCorners[i][2].y))
+                indexes.push(i);
 
-    target.addEventListener(type, handlers[handlers.length - 1], false);
-  };
-
-  /**
-   * Unbind simulated "double click" events.
-   *
-   * @param  {HTMLElement} target   The event target.
-   * @param  {string}      type     The event type.
-   */
-  sigma.utils.unbindDoubleClick = function(target, type) {
-    var handler,
-        handlers = (target._doubleClickHandler || {})[type] || [];
-
-    while ((handler = handlers.pop())) {
-      target.removeEventListener(type, handler);
+        return indexes;
     }
 
-    delete (target._doubleClickHandler || {})[type];
-  };
-
-
-
-
-  /**
-   * Here are just some of the most basic easing functions, used for the
-   * animated camera "goTo" calls.
-   *
-   * If you need some more easings functions, don't hesitate to add them to
-   * sigma.utils.easings. But I will not add some more here or merge PRs
-   * containing, because I do not want sigma sources full of overkill and never
-   * used stuff...
-   */
-  sigma.utils.easings = sigma.utils.easings || {};
-  sigma.utils.easings.linearNone = function(k) {
-    return k;
-  };
-  sigma.utils.easings.quadraticIn = function(k) {
-    return k * k;
-  };
-  sigma.utils.easings.quadraticOut = function(k) {
-    return k * (2 - k);
-  };
-  sigma.utils.easings.quadraticInOut = function(k) {
-    if ((k *= 2) < 1)
-      return 0.5 * k * k;
-    return - 0.5 * (--k * (k - 2) - 1);
-  };
-  sigma.utils.easings.cubicIn = function(k) {
-    return k * k * k;
-  };
-  sigma.utils.easings.cubicOut = function(k) {
-    return --k * k * k + 1;
-  };
-  sigma.utils.easings.cubicInOut = function(k) {
-    if ((k *= 2) < 1)
-      return 0.5 * k * k * k;
-    return 0.5 * ((k -= 2) * k * k + 2);
-  };
-
-
-
-
-  /**
-   * ************
-   * WEBGL UTILS:
-   * ************
-   */
-  /**
-   * Loads a WebGL shader and returns it.
-   *
-   * @param  {WebGLContext}           gl           The WebGLContext to use.
-   * @param  {string}                 shaderSource The shader source.
-   * @param  {number}                 shaderType   The type of shader.
-   * @param  {function(string): void} error        Callback for errors.
-   * @return {WebGLShader}                         The created shader.
-   */
-  sigma.utils.loadShader = function(gl, shaderSource, shaderType, error) {
-    var compiled,
-        shader = gl.createShader(shaderType);
-
-    // Load the shader source
-    gl.shaderSource(shader, shaderSource);
-
-    // Compile the shader
-    gl.compileShader(shader);
-
-    // Check the compile status
-    compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
-
-    // If something went wrong:
-    if (!compiled) {
-      if (error) {
-        error(
-          'Error compiling shader "' + shader + '":' +
-          gl.getShaderInfoLog(shader)
-        );
-      }
+    /**
+     * Get a list of indexes of nodes containing a non-axis-aligned rectangle
+     *
+     * @param  {array}  corners      An array containing each corner of the
+     *                               rectangle defined by its coordinates (x, y).
+     * @param  {array}  quadCorners  An array of the quad nodes' corners.
+     * @return {array}               An array of indexes containing one to
+     *                               four integers.
+     */
+    function _quadCollision(corners, quadCorners) {
+        var indexes = [];
 
-      gl.deleteShader(shader);
-      return null;
+        // Iterating through quads
+        for (var i = 0; i < 4; i++)
+            if (_geom.collision(corners, quadCorners[i]))
+                indexes.push(i);
+
+        return indexes;
     }
 
-    return shader;
-  };
-
-  /**
-   * Creates a program, attaches shaders, binds attrib locations, links the
-   * program and calls useProgram.
-   *
-   * @param  {Array.<WebGLShader>}    shaders   The shaders to attach.
-   * @param  {Array.<string>}         attribs   The attribs names.
-   * @param  {Array.<number>}         locations The locations for the attribs.
-   * @param  {function(string): void} error     Callback for errors.
-   * @return {WebGLProgram}                     The created program.
-   */
-  sigma.utils.loadProgram = function(gl, shaders, attribs, loc, error) {
-    var i,
-        linked,
-        program = gl.createProgram();
-
-    for (i = 0; i < shaders.length; ++i)
-      gl.attachShader(program, shaders[i]);
-
-    if (attribs)
-      for (i = 0; i < attribs.length; ++i)
-        gl.bindAttribLocation(
-          program,
-          locations ? locations[i] : i,
-          opt_attribs[i]
-        );
+    /**
+     * Subdivide a quad by creating a node at a precise index. The function does
+     * not generate all four nodes not to potentially create unused nodes.
+     *
+     * @param  {integer}  index The index of the node to create.
+     * @param  {object}   quad  The quad object to subdivide.
+     * @return {object}         A new quad representing the node created.
+     */
+    function _quadSubdivide(index, quad) {
+        var next = quad.level + 1,
+            subw = Math.round(quad.bounds.width / 2),
+            subh = Math.round(quad.bounds.height / 2),
+            qx = Math.round(quad.bounds.x),
+            qy = Math.round(quad.bounds.y),
+            x,
+            y;
+
+        switch (index) {
+            case 0:
+                x = qx;
+                y = qy;
+                break;
+            case 1:
+                x = qx + subw;
+                y = qy;
+                break;
+            case 2:
+                x = qx;
+                y = qy + subh;
+                break;
+            case 3:
+                x = qx + subw;
+                y = qy + subh;
+                break;
+        }
 
-    gl.linkProgram(program);
+        return _quadTree(
+            {x: x, y: y, width: subw, height: subh},
+            next,
+            quad.maxElements,
+            quad.maxLevel
+        );
+    }
 
-    // Check the link status
-    linked = gl.getProgramParameter(program, gl.LINK_STATUS);
-    if (!linked) {
-      if (error)
-        error('Error in program linking: ' + gl.getProgramInfoLog(program));
+    /**
+     * Recursively insert an element into the quadtree. Only points
+     * with size, i.e. axis-aligned squares, may be inserted with this
+     * method.
+     *
+     * @param  {object}  el         The element to insert in the quadtree.
+     * @param  {object}  sizedPoint A sized point defined by two top points
+     *                              (x1, y1), (x2, y2) and height.
+     * @param  {object}  quad       The quad in which to insert the element.
+     * @return {undefined}          The function does not return anything.
+     */
+    function _quadInsert(el, sizedPoint, quad) {
+        if (quad.level < quad.maxLevel) {
 
-      gl.deleteProgram(program);
-      return null;
-    }
+            // Searching appropriate quads
+            var indexes = _quadIndexes(sizedPoint, quad.corners);
 
-    return program;
-  };
-
-
-
-
-  /**
-   * *********
-   * MATRICES:
-   * *********
-   * The following utils are just here to help generating the transformation
-   * matrices for the WebGL renderers.
-   */
-  sigma.utils.pkg('sigma.utils.matrices');
-
-  /**
-   * The returns a 3x3 translation matrix.
-   *
-   * @param  {number} dx The X translation.
-   * @param  {number} dy The Y translation.
-   * @return {array}     Returns the matrix.
-   */
-  sigma.utils.matrices.translation = function(dx, dy) {
-    return [
-      1, 0, 0,
-      0, 1, 0,
-      dx, dy, 1
-    ];
-  };
-
-  /**
-   * The returns a 3x3 or 2x2 rotation matrix.
-   *
-   * @param  {number}  angle The rotation angle.
-   * @param  {boolean} m2    If true, the function will return a 2x2 matrix.
-   * @return {array}         Returns the matrix.
-   */
-  sigma.utils.matrices.rotation = function(angle, m2) {
-    var cos = Math.cos(angle),
-        sin = Math.sin(angle);
-
-    return m2 ? [
-      cos, -sin,
-      sin, cos
-    ] : [
-      cos, -sin, 0,
-      sin, cos, 0,
-      0, 0, 1
-    ];
-  };
-
-  /**
-   * The returns a 3x3 or 2x2 homothetic transformation matrix.
-   *
-   * @param  {number}  ratio The scaling ratio.
-   * @param  {boolean} m2    If true, the function will return a 2x2 matrix.
-   * @return {array}         Returns the matrix.
-   */
-  sigma.utils.matrices.scale = function(ratio, m2) {
-    return m2 ? [
-      ratio, 0,
-      0, ratio
-    ] : [
-      ratio, 0, 0,
-      0, ratio, 0,
-      0, 0, 1
-    ];
-  };
-
-  /**
-   * The returns a 3x3 or 2x2 homothetic transformation matrix.
-   *
-   * @param  {array}   a  The first matrix.
-   * @param  {array}   b  The second matrix.
-   * @param  {boolean} m2 If true, the function will assume both matrices are
-   *                      2x2.
-   * @return {array}      Returns the matrix.
-   */
-  sigma.utils.matrices.multiply = function(a, b, m2) {
-    var l = m2 ? 2 : 3,
-        a00 = a[0 * l + 0],
-        a01 = a[0 * l + 1],
-        a02 = a[0 * l + 2],
-        a10 = a[1 * l + 0],
-        a11 = a[1 * l + 1],
-        a12 = a[1 * l + 2],
-        a20 = a[2 * l + 0],
-        a21 = a[2 * l + 1],
-        a22 = a[2 * l + 2],
-        b00 = b[0 * l + 0],
-        b01 = b[0 * l + 1],
-        b02 = b[0 * l + 2],
-        b10 = b[1 * l + 0],
-        b11 = b[1 * l + 1],
-        b12 = b[1 * l + 2],
-        b20 = b[2 * l + 0],
-        b21 = b[2 * l + 1],
-        b22 = b[2 * l + 2];
-
-    return m2 ? [
-      a00 * b00 + a01 * b10,
-      a00 * b01 + a01 * b11,
-      a10 * b00 + a11 * b10,
-      a10 * b01 + a11 * b11
-    ] : [
-      a00 * b00 + a01 * b10 + a02 * b20,
-      a00 * b01 + a01 * b11 + a02 * b21,
-      a00 * b02 + a01 * b12 + a02 * b22,
-      a10 * b00 + a11 * b10 + a12 * b20,
-      a10 * b01 + a11 * b11 + a12 * b21,
-      a10 * b02 + a11 * b12 + a12 * b22,
-      a20 * b00 + a21 * b10 + a22 * b20,
-      a20 * b01 + a21 * b11 + a22 * b21,
-      a20 * b02 + a21 * b12 + a22 * b22
-    ];
-  };
-}).call(this);
+            // Iterating
+            for (var i = 0, l = indexes.length; i < l; i++) {
 
-;(function(global) {
-  'use strict';
-
-  /**
-   * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
-   * http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
-   * requestAnimationFrame polyfill by Erik Möller.
-   * fixes from Paul Irish and Tino Zijdel
-   * MIT license
-   */
-  var x,
-      lastTime = 0,
-      vendors = ['ms', 'moz', 'webkit', 'o'];
-
-  for (x = 0; x < vendors.length && !global.requestAnimationFrame; x++) {
-    global.requestAnimationFrame =
-      global[vendors[x] + 'RequestAnimationFrame'];
-    global.cancelAnimationFrame =
-      global[vendors[x] + 'CancelAnimationFrame'] ||
-      global[vendors[x] + 'CancelRequestAnimationFrame'];
-  }
-
-  if (!global.requestAnimationFrame)
-    global.requestAnimationFrame = function(callback, element) {
-      var currTime = new Date().getTime(),
-          timeToCall = Math.max(0, 16 - (currTime - lastTime)),
-          id = global.setTimeout(
-            function() {
-              callback(currTime + timeToCall);
-            },
-            timeToCall
-          );
-
-      lastTime = currTime + timeToCall;
-      return id;
-    };
-
-  if (!global.cancelAnimationFrame)
-    global.cancelAnimationFrame = function(id) {
-      clearTimeout(id);
-    };
-
-  /**
-   * Function.prototype.bind polyfill found on MDN.
-   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
-   * Public domain
-   */
-  if (!Function.prototype.bind)
-    Function.prototype.bind = function(oThis) {
-      if (typeof this !== 'function')
-        // Closest thing possible to the ECMAScript 5 internal IsCallable
-        // function:
-        throw new TypeError(
-          'Function.prototype.bind - what is trying to be bound is not callable'
-        );
+                // Subdividing if necessary
+                if (quad.nodes[indexes[i]] === undefined)
+                    quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad);
 
-      var aArgs = Array.prototype.slice.call(arguments, 1),
-          fToBind = this,
-          fNOP,
-          fBound;
-
-      fNOP = function() {};
-      fBound = function() {
-        return fToBind.apply(
-          this instanceof fNOP && oThis ?
-            this :
-            oThis,
-          aArgs.concat(Array.prototype.slice.call(arguments))
-        );
-      };
+                // Recursion
+                _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]);
+            }
+        }
+        else {
 
-      fNOP.prototype = this.prototype;
-      fBound.prototype = new fNOP();
+            // Pushing the element in a leaf node
+            quad.elements.push(el);
+        }
+    }
 
-      return fBound;
-    };
-})(this);
+    /**
+     * Recursively retrieve every elements held by the node containing the
+     * searched point.
+     *
+     * @param  {object}  point The searched point (x, y).
+     * @param  {object}  quad  The searched quad.
+     * @return {array}         An array of elements contained in the relevant
+     *                         node.
+     */
+    function _quadRetrievePoint(point, quad) {
+        if (quad.level < quad.maxLevel) {
+            var index = _quadIndex(point, quad.bounds);
 
-;(function(undefined) {
-  'use strict';
+            // If node does not exist we return an empty list
+            if (quad.nodes[index] !== undefined) {
+                return _quadRetrievePoint(point, quad.nodes[index]);
+            }
+            else {
+                return [];
+            }
+        }
+        else {
+            return quad.elements;
+        }
+    }
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
+    /**
+     * Recursively retrieve every elements contained within an rectangular area
+     * that may or may not be axis-aligned.
+     *
+     * @param  {object|array} rectData       The searched area defined either by
+     *                                       an array of four corners (x, y) in
+     *                                       the case of a non-axis-aligned
+     *                                       rectangle or an object with two top
+     *                                       points (x1, y1), (x2, y2) and height.
+     * @param  {object}       quad           The searched quad.
+     * @param  {function}     collisionFunc  The collision function used to search
+     *                                       for node indexes.
+     * @param  {array?}       els            The retrieved elements.
+     * @return {array}                       An array of elements contained in the
+     *                                       area.
+     */
+    function _quadRetrieveArea(rectData, quad, collisionFunc, els) {
+        els = els || {};
+
+        if (quad.level < quad.maxLevel) {
+            var indexes = collisionFunc(rectData, quad.corners);
+
+            for (var i = 0, l = indexes.length; i < l; i++)
+                if (quad.nodes[indexes[i]] !== undefined)
+                    _quadRetrieveArea(
+                        rectData,
+                        quad.nodes[indexes[i]],
+                        collisionFunc,
+                        els
+                    );
+        } else
+            for (var j = 0, m = quad.elements.length; j < m; j++)
+                if (els[quad.elements[j].id] === undefined)
+                    els[quad.elements[j].id] = quad.elements[j];
 
-  // Packages initialization:
-  sigma.utils.pkg('sigma.settings');
+        return els;
+    }
 
-  var settings = {
     /**
-     * GRAPH SETTINGS:
-     * ***************
+     * Creates the quadtree object itself.
+     *
+     * @param  {object}   bounds       The boundaries of the quad defined by an
+     *                                 origin (x, y), width and heigth.
+     * @param  {integer}  level        The level of the quad in the tree.
+     * @param  {integer}  maxElements  The max number of element in a leaf node.
+     * @param  {integer}  maxLevel     The max recursion level of the tree.
+     * @return {object}                The quadtree object.
      */
-    // {boolean} Indicates if the data have to be cloned in methods to add
-    //           nodes or edges.
-    clone: true,
-    // {boolean} Indicates if nodes "id" values and edges "id", "source" and
-    //           "target" values must be set as immutable.
-    immutable: true,
-    // {boolean} Indicates if sigma can log its errors and warnings.
-    verbose: false,
+    function _quadTree(bounds, level, maxElements, maxLevel) {
+        return {
+            level: level || 0,
+            bounds: bounds,
+            corners: _geom.splitSquare(bounds),
+            maxElements: maxElements || 40,
+            maxLevel: maxLevel || 8,
+            elements: [],
+            nodes: []
+        };
+    }
 
 
     /**
-     * RENDERERS SETTINGS:
-     * *******************
+     * Sigma Quad Constructor
+     * ----------------------
+     *
+     * The edgequad API as exposed to sigma.
      */
-    // {string}
-    classPrefix: 'sigma',
-    // {string}
-    defaultNodeType: 'def',
-    // {string}
-    defaultEdgeType: 'def',
-    // {string}
-    defaultLabelColor: '#000',
-    // {string}
-    defaultEdgeColor: '#000',
-    // {string}
-    defaultNodeColor: '#000',
-    // {string}
-    defaultLabelSize: 14,
-    // {string} Indicates how to choose the edges color. Available values:
-    //          "source", "target", "default"
-    edgeColor: 'source',
-    // {number} Defines the minimal edge's arrow display size.
-    minArrowSize: 0,
-    // {string}
-    font: 'arial',
-    // {string} Example: 'bold'
-    fontStyle: '',
-    // {string} Indicates how to choose the labels color. Available values:
-    //          "node", "default"
-    labelColor: 'default',
-    // {string} Indicates how to choose the labels size. Available values:
-    //          "fixed", "proportional"
-    labelSize: 'fixed',
-    // {string} The ratio between the font size of the label and the node size.
-    labelSizeRatio: 1,
-    // {number} The minimum size a node must have to see its label displayed.
-    labelThreshold: 8,
-    // {number} The oversampling factor used in WebGL renderer.
-    webglOversamplingRatio: 2,
-    // {number} The size of the border of hovered nodes.
-    borderSize: 0,
-    // {number} The default hovered node border's color.
-    defaultNodeBorderColor: '#000',
-    // {number} The hovered node's label font. If not specified, will heritate
-    //          the "font" value.
-    hoverFont: '',
-    // {boolean} If true, then only one node can be hovered at a time.
-    singleHover: true,
-    // {string} Example: 'bold'
-    hoverFontStyle: '',
-    // {string} Indicates how to choose the hovered nodes shadow color.
-    //          Available values: "node", "default"
-    labelHoverShadow: 'default',
-    // {string}
-    labelHoverShadowColor: '#000',
-    // {string} Indicates how to choose the hovered nodes color.
-    //          Available values: "node", "default"
-    nodeHoverColor: 'node',
-    // {string}
-    defaultNodeHoverColor: '#000',
-    // {string} Indicates how to choose the hovered nodes background color.
-    //          Available values: "node", "default"
-    labelHoverBGColor: 'default',
-    // {string}
-    defaultHoverLabelBGColor: '#fff',
-    // {string} Indicates how to choose the hovered labels color.
-    //          Available values: "node", "default"
-    labelHoverColor: 'default',
-    // {string}
-    defaultLabelHoverColor: '#000',
-    // {string} Indicates how to choose the edges hover color. Available values:
-    //          "edge", "default"
-    edgeHoverColor: 'edge',
-    // {number} The size multiplicator of hovered edges.
-    edgeHoverSizeRatio: 1,
-    // {string}
-    defaultEdgeHoverColor: '#000',
-    // {boolean} Indicates if the edge extremities must be hovered when the
-    //           edge is hovered.
-    edgeHoverExtremities: false,
-    // {booleans} The different drawing modes:
-    //           false: Layered not displayed.
-    //           true: Layered displayed.
-    drawEdges: true,
-    drawNodes: true,
-    drawLabels: true,
-    drawEdgeLabels: false,
-    // {boolean} Indicates if the edges must be drawn in several frames or in
-    //           one frame, as the nodes and labels are drawn.
-    batchEdgesDrawing: false,
-    // {boolean} Indicates if the edges must be hidden during dragging and
-    //           animations.
-    hideEdgesOnMove: false,
-    // {numbers} The different batch sizes, when elements are displayed in
-    //           several frames.
-    canvasEdgesBatchSize: 500,
-    webglEdgesBatchSize: 1000,
-
-
-
-
-    /**
-     * RESCALE SETTINGS:
-     * *****************
-     */
-    // {string} Indicates of to scale the graph relatively to its container.
-    //          Available values: "inside", "outside"
-    scalingMode: 'inside',
-    // {number} The margin to keep around the graph.
-    sideMargin: 0,
-    // {number} Determine the size of the smallest and the biggest node / edges
-    //          on the screen. This mapping makes easier to display the graph,
-    //          avoiding too big nodes that take half of the screen, or too
-    //          small ones that are not readable. If the two parameters are
-    //          equals, then the minimal display size will be 0. And if they
-    //          are both equal to 0, then there is no mapping, and the radius
-    //          of the nodes will be their size.
-    minEdgeSize: 0.5,
-    maxEdgeSize: 1,
-    minNodeSize: 1,
-    maxNodeSize: 8,
-
-
-
-
-    /**
-     * CAPTORS SETTINGS:
-     * *****************
-     */
-    // {boolean}
-    touchEnabled: true,
-    // {boolean}
-    mouseEnabled: true,
-    // {boolean}
-    mouseWheelEnabled: true,
-    // {boolean}
-    doubleClickEnabled: true,
-    // {boolean} Defines whether the custom events such as "clickNode" can be
-    //           used.
-    eventsEnabled: true,
-    // {number} Defines by how much multiplicating the zooming level when the
-    //          user zooms with the mouse-wheel.
-    zoomingRatio: 1.7,
-    // {number} Defines by how much multiplicating the zooming level when the
-    //          user zooms by double clicking.
-    doubleClickZoomingRatio: 2.2,
-    // {number} The minimum zooming level.
-    zoomMin: 0.0625,
-    // {number} The maximum zooming level.
-    zoomMax: 2,
-    // {number} The duration of animations following a mouse scrolling.
-    mouseZoomDuration: 200,
-    // {number} The duration of animations following a mouse double click.
-    doubleClickZoomDuration: 200,
-    // {number} The duration of animations following a mouse dropping.
-    mouseInertiaDuration: 200,
-    // {number} The inertia power (mouse captor).
-    mouseInertiaRatio: 3,
-    // {number} The duration of animations following a touch dropping.
-    touchInertiaDuration: 200,
-    // {number} The inertia power (touch captor).
-    touchInertiaRatio: 3,
-    // {number} The maximum time between two clicks to make it a double click.
-    doubleClickTimeout: 300,
-    // {number} The maximum time between two taps to make it a double tap.
-    doubleTapTimeout: 300,
-    // {number} The maximum time of dragging to trigger intertia.
-    dragTimeout: 200,
-
-
-
-
-    /**
-     * GLOBAL SETTINGS:
-     * ****************
+
+    /**
+     * The edgequad core that will become the sigma interface with the quadtree.
+     *
+     * property {object} _tree     Property holding the quadtree object.
+     * property {object} _geom     Exposition of the _geom namespace for testing.
+     * property {object} _cache    Cache for the area method.
+     * property {boolean} _enabled Can index and retreive elements.
      */
-    // {boolean} Determines whether the instance has to refresh itself
-    //           automatically when a "resize" event is dispatched from the
-    //           window object.
-    autoResize: true,
-    // {boolean} Determines whether the "rescale" middleware has to be called
-    //           automatically for each camera on refresh.
-    autoRescale: true,
-    // {boolean} If set to false, the camera method "goTo" will basically do
-    //           nothing.
-    enableCamera: true,
-    // {boolean} If set to false, the nodes cannot be hovered.
-    enableHovering: true,
-    // {boolean} If set to true, the edges can be hovered.
-    enableEdgeHovering: false,
-    // {number} The size of the area around the edges to activate hovering.
-    edgeHoverPrecision: 5,
-    // {boolean} If set to true, the rescale middleware will ignore node sizes
-    //           to determine the graphs boundings.
-    rescaleIgnoreSize: false,
-    // {boolean} Determines if the core has to try to catch errors on
-    //           rendering.
-    skipErrors: false,
-
-
-
-
-    /**
-     * CAMERA SETTINGS:
-     * ****************
+    var edgequad = function () {
+        this._geom = _geom;
+        this._tree = null;
+        this._cache = {
+            query: false,
+            result: false
+        };
+        this._enabled = true;
+    };
+
+    /**
+     * Index a graph by inserting its edges into the quadtree.
+     *
+     * @param  {object} graph   A graph instance.
+     * @param  {object} params  An object of parameters with at least the quad
+     *                          bounds.
+     * @return {object}         The quadtree object.
+     *
+     * Parameters:
+     * ----------
+     * bounds:      {object}   boundaries of the quad defined by its origin (x, y)
+     *                         width and heigth.
+     * prefix:      {string?}  a prefix for edge geometric attributes.
+     * maxElements: {integer?} the max number of elements in a leaf node.
+     * maxLevel:    {integer?} the max recursion level of the tree.
      */
-    // {number} The power degrees applied to the nodes/edges size relatively to
-    //          the zooming level. Basically:
-    //           > onScreenR = Math.pow(zoom, nodesPowRatio) * R
-    //           > onScreenT = Math.pow(zoom, edgesPowRatio) * T
-    nodesPowRatio: 0.5,
-    edgesPowRatio: 0.5,
+    edgequad.prototype.index = function (graph, params) {
+        if (!this._enabled)
+            return this._tree;
+
+        // Enforcing presence of boundaries
+        if (!params.bounds)
+            throw 'sigma.classes.edgequad.index: bounds information not given.';
+
+        // Prefix
+        var prefix = params.prefix || '',
+            cp,
+            source,
+            target,
+            n,
+            e;
+
+        // Building the tree
+        this._tree = _quadTree(
+            params.bounds,
+            0,
+            params.maxElements,
+            params.maxLevel
+        );
 
+        var edges = graph.edges();
+
+        // Inserting graph edges into the tree
+        for (var i = 0, l = edges.length; i < l; i++) {
+            source = graph.nodes(edges[i].source);
+            target = graph.nodes(edges[i].target);
+            e = {
+                x1: source[prefix + 'x'],
+                y1: source[prefix + 'y'],
+                x2: target[prefix + 'x'],
+                y2: target[prefix + 'y'],
+                size: edges[i][prefix + 'size'] || 0
+            };
+
+            // Inserting edge
+            if (edges[i].type === 'curve' || edges[i].type === 'curvedArrow') {
+                if (source.id === target.id) {
+                    n = {
+                        x: source[prefix + 'x'],
+                        y: source[prefix + 'y'],
+                        size: source[prefix + 'size'] || 0
+                    };
+                    _quadInsert(
+                        edges[i],
+                        _geom.selfLoopToSquare(n),
+                        this._tree);
+                }
+                else {
+                    cp = sigma.utils.getQuadraticControlPoint(e.x1, e.y1, e.x2, e.y2);
+                    _quadInsert(
+                        edges[i],
+                        _geom.quadraticCurveToSquare(e, cp),
+                        this._tree);
+                }
+            }
+            else {
+                _quadInsert(
+                    edges[i],
+                    _geom.lineToSquare(e),
+                    this._tree);
+            }
+        }
 
+        // Reset cache:
+        this._cache = {
+            query: false,
+            result: false
+        };
 
+        // remove?
+        return this._tree;
+    };
 
     /**
-     * ANIMATIONS SETTINGS:
-     * ********************
+     * Retrieve every graph edges held by the quadtree node containing the
+     * searched point.
+     *
+     * @param  {number} x of the point.
+     * @param  {number} y of the point.
+     * @return {array}  An array of edges retrieved.
      */
-    // {number} The default animation time.
-    animationsTime: 200
-  };
+    edgequad.prototype.point = function (x, y) {
+        if (!this._enabled)
+            return [];
 
-  // Export the previously designed settings:
-  sigma.settings = sigma.utils.extend(sigma.settings || {}, settings);
-}).call(this);
+        return this._tree ?
+        _quadRetrievePoint({x: x, y: y}, this._tree) || [] :
+            [];
+    };
 
-;(function() {
-  'use strict';
-
-  /**
-   * Dispatcher constructor.
-   *
-   * @return {dispatcher} The new dispatcher instance.
-   */
-  var dispatcher = function() {
-    Object.defineProperty(this, '_handlers', {
-      value: {}
-    });
-  };
-
-
-
-
-  /**
-   * Will execute the handler everytime that the indicated event (or the
-   * indicated events) will be triggered.
-   *
-   * @param  {string}           events  The name of the event (or the events
-   *                                    separated by spaces).
-   * @param  {function(Object)} handler The handler to bind.
-   * @return {dispatcher}               Returns the instance itself.
-   */
-  dispatcher.prototype.bind = function(events, handler) {
-    var i,
-        l,
-        event,
-        eArray;
-
-    if (
-      arguments.length === 1 &&
-      typeof arguments[0] === 'object'
-    )
-      for (events in arguments[0])
-        this.bind(events, arguments[0][events]);
-    else if (
-      arguments.length === 2 &&
-      typeof arguments[1] === 'function'
-    ) {
-      eArray = typeof events === 'string' ? events.split(' ') : events;
-
-      for (i = 0, l = eArray.length; i !== l; i += 1) {
-        event = eArray[i];
-
-        // Check that event is not '':
-        if (!event)
-          continue;
-
-        if (!this._handlers[event])
-          this._handlers[event] = [];
-
-        // Using an object instead of directly the handler will make possible
-        // later to add flags
-        this._handlers[event].push({
-          handler: handler
-        });
-      }
-    } else
-      throw 'bind: Wrong arguments.';
-
-    return this;
-  };
-
-  /**
-   * Removes the handler from a specified event (or specified events).
-   *
-   * @param  {?string}           events  The name of the event (or the events
-   *                                     separated by spaces). If undefined,
-   *                                     then all handlers are removed.
-   * @param  {?function(object)} handler The handler to unbind. If undefined,
-   *                                     each handler bound to the event or the
-   *                                     events will be removed.
-   * @return {dispatcher}                Returns the instance itself.
-   */
-  dispatcher.prototype.unbind = function(events, handler) {
-    var i,
-        n,
-        j,
-        m,
-        k,
-        a,
-        event,
-        eArray = typeof events === 'string' ? events.split(' ') : events;
-
-    if (!arguments.length) {
-      for (k in this._handlers)
-        delete this._handlers[k];
-      return this;
-    }
+    /**
+     * Retrieve every graph edges within a rectangular area. The methods keep the
+     * last area queried in cache for optimization reason and will act differently
+     * for the same reason if the area is axis-aligned or not.
+     *
+     * @param  {object} A rectangle defined by two top points (x1, y1), (x2, y2)
+     *                  and height.
+     * @return {array}  An array of edges retrieved.
+     */
+    edgequad.prototype.area = function (rect) {
+        if (!this._enabled)
+            return [];
+
+        var serialized = JSON.stringify(rect),
+            collisionFunc,
+            rectData;
 
-    if (handler) {
-      for (i = 0, n = eArray.length; i !== n; i += 1) {
-        event = eArray[i];
-        if (this._handlers[event]) {
-          a = [];
-          for (j = 0, m = this._handlers[event].length; j !== m; j += 1)
-            if (this._handlers[event][j].handler !== handler)
-              a.push(this._handlers[event][j]);
+        // Returning cache?
+        if (this._cache.query === serialized)
+            return this._cache.result;
 
-          this._handlers[event] = a;
+        // Axis aligned ?
+        if (_geom.isAxisAligned(rect)) {
+            collisionFunc = _quadIndexes;
+            rectData = _geom.axisAlignedTopPoints(rect);
+        }
+        else {
+            collisionFunc = _quadCollision;
+            rectData = _geom.rectangleCorners(rect);
         }
 
-        if (this._handlers[event] && this._handlers[event].length === 0)
-          delete this._handlers[event];
-      }
-    } else
-      for (i = 0, n = eArray.length; i !== n; i += 1)
-        delete this._handlers[eArray[i]];
-
-    return this;
-  };
-
-  /**
-   * Executes each handler bound to the event
-   *
-   * @param  {string}     events The name of the event (or the events separated
-   *                             by spaces).
-   * @param  {?object}    data   The content of the event (optional).
-   * @return {dispatcher}        Returns the instance itself.
-   */
-  dispatcher.prototype.dispatchEvent = function(events, data) {
-    var i,
-        n,
-        j,
-        m,
-        a,
-        event,
-        eventName,
-        self = this,
-        eArray = typeof events === 'string' ? events.split(' ') : events;
-
-    data = data === undefined ? {} : data;
-
-    for (i = 0, n = eArray.length; i !== n; i += 1) {
-      eventName = eArray[i];
-
-      if (this._handlers[eventName]) {
-        event = self.getEvent(eventName, data);
-        a = [];
-
-        for (j = 0, m = this._handlers[eventName].length; j !== m; j += 1) {
-          this._handlers[eventName][j].handler(event);
-          if (!this._handlers[eventName][j].one)
-            a.push(this._handlers[eventName][j]);
-        }
-
-        this._handlers[eventName] = a;
-      }
-    }
+        // Retrieving edges
+        var edges = this._tree ?
+            _quadRetrieveArea(
+                rectData,
+                this._tree,
+                collisionFunc
+            ) :
+            [];
+
+        // Object to array
+        var edgesArray = [];
+        for (var i in edges)
+            edgesArray.push(edges[i]);
+
+        // Caching
+        this._cache.query = serialized;
+        this._cache.result = edgesArray;
+
+        return edgesArray;
+    };
 
-    return this;
-  };
-
-  /**
-   * Return an event object.
-   *
-   * @param  {string}  events The name of the event.
-   * @param  {?object} data   The content of the event (optional).
-   * @return {object}         Returns the instance itself.
-   */
-  dispatcher.prototype.getEvent = function(event, data) {
-    return {
-      type: event,
-      data: data || {},
-      target: this
-    };
-  };
-
-  /**
-   * A useful function to deal with inheritance. It will make the target
-   * inherit the prototype of the class dispatcher as well as its constructor.
-   *
-   * @param {object} target The target.
-   */
-  dispatcher.extend = function(target, args) {
-    var k;
-
-    for (k in dispatcher.prototype)
-      if (dispatcher.prototype.hasOwnProperty(k))
-        target[k] = dispatcher.prototype[k];
-
-    dispatcher.apply(target, args);
-  };
-
-
-
-
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof this.sigma !== 'undefined') {
-    this.sigma.classes = this.sigma.classes || {};
-    this.sigma.classes.dispatcher = dispatcher;
-  } else if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = dispatcher;
-    exports.dispatcher = dispatcher;
-  } else
-    this.dispatcher = dispatcher;
+
+    /**
+     * EXPORT:
+     * *******
+     */
+    if (typeof this.sigma !== 'undefined') {
+        this.sigma.classes = this.sigma.classes || {};
+        this.sigma.classes.edgequad = edgequad;
+    } else if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports)
+            exports = module.exports = edgequad;
+        exports.edgequad = edgequad;
+    } else
+        this.edgequad = edgequad;
 }).call(this);
 
-;(function() {
-  'use strict';
-
-  /**
-   * This utils aims to facilitate the manipulation of each instance setting.
-   * Using a function instead of an object brings two main advantages: First,
-   * it will be easier in the future to catch settings updates through a
-   * function than an object. Second, giving it a full object will "merge" it
-   * to the settings object properly, keeping us to have to always add a loop.
-   *
-   * @return {configurable} The "settings" function.
-   */
-  var configurable = function() {
-    var i,
-        l,
-        data = {},
-        datas = Array.prototype.slice.call(arguments, 0);
-
-    /**
-     * The method to use to set or get any property of this instance.
-     *
-     * @param  {string|object}    a1 If it is a string and if a2 is undefined,
-     *                               then it will return the corresponding
-     *                               property. If it is a string and if a2 is
-     *                               set, then it will set a2 as the property
-     *                               corresponding to a1, and return this. If
-     *                               it is an object, then each pair string +
-     *                               object(or any other type) will be set as a
-     *                               property.
-     * @param  {*?}               a2 The new property corresponding to a1 if a1
-     *                               is a string.
-     * @return {*|configurable}      Returns itself or the corresponding
-     *                               property.
-     *
-     * Polymorphism:
-     * *************
-     * Here are some basic use examples:
-     *
-     *  > settings = new configurable();
-     *  > settings('mySetting', 42);
-     *  > settings('mySetting'); // Logs: 42
-     *  > settings('mySetting', 123);
-     *  > settings('mySetting'); // Logs: 123
-     *  > settings({mySetting: 456});
-     *  > settings('mySetting'); // Logs: 456
-     *
-     * Also, it is possible to use the function as a fallback:
-     *  > settings({mySetting: 'abc'}, 'mySetting');  // Logs: 'abc'
-     *  > settings({hisSetting: 'abc'}, 'mySetting'); // Logs: 456
-     */
-    var settings = function(a1, a2) {
-      var o,
-          i,
-          l,
-          k;
-
-      if (arguments.length === 1 && typeof a1 === 'string') {
-        if (data[a1] !== undefined)
-          return data[a1];
-        for (i = 0, l = datas.length; i < l; i++)
-          if (datas[i][a1] !== undefined)
-            return datas[i][a1];
-        return undefined;
-      } else if (typeof a1 === 'object' && typeof a2 === 'string') {
-        return (a1 || {})[a2] !== undefined ? a1[a2] : settings(a2);
-      } else {
-        o = (typeof a1 === 'object' && a2 === undefined) ? a1 : {};
-
-        if (typeof a1 === 'string')
-          o[a1] = a2;
-
-        for (i = 0, k = Object.keys(o), l = k.length; i < l; i++)
-          data[k[i]] = o[k[i]];
+;(function (undefined) {
+    'use strict';
 
-        return this;
-      }
-    };
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
+
+    // Initialize packages:
+    sigma.utils.pkg('sigma.captors');
 
     /**
-     * This method returns a new configurable function, with new objects
+     * The user inputs default captor. It deals with mouse events, keyboards
+     * events and touch events.
      *
-     * @param  {object*}  Any number of objects to search in.
-     * @return {function} Returns the function. Check its documentation to know
-     *                    more about how it works.
+     * @param  {DOMElement}   target   The DOM element where the listeners will be
+     *                                 bound.
+     * @param  {camera}       camera   The camera related to the target.
+     * @param  {configurable} settings The settings function.
+     * @return {sigma.captor}          The fresh new captor instance.
      */
-    settings.embedObjects = function() {
-      var args = datas.concat(
-        data
-      ).concat(
-        Array.prototype.splice.call(arguments, 0)
-      );
+    sigma.captors.mouse = function (target, camera, settings) {
+        var _self = this,
+            _target = target,
+            _camera = camera,
+            _settings = settings,
+
+            // CAMERA MANAGEMENT:
+            // ******************
+            // The camera position when the user starts dragging:
+            _startCameraX,
+            _startCameraY,
+            _startCameraAngle,
+
+            // The latest stage position:
+            _lastCameraX,
+            _lastCameraY,
+            _lastCameraAngle,
+            _lastCameraRatio,
+
+            // MOUSE MANAGEMENT:
+            // *****************
+            // The mouse position when the user starts dragging:
+            _startMouseX,
+            _startMouseY,
+
+            _isMouseDown,
+            _isMoving,
+            _hasDragged,
+            _downStartTime,
+            _movingTimeoutId;
+
+        sigma.classes.dispatcher.extend(this);
+
+        sigma.utils.doubleClick(_target, 'click', _doubleClickHandler);
+        _target.addEventListener('DOMMouseScroll', _wheelHandler, false);
+        _target.addEventListener('mousewheel', _wheelHandler, false);
+        _target.addEventListener('mousemove', _moveHandler, false);
+        _target.addEventListener('mousedown', _downHandler, false);
+        _target.addEventListener('click', _clickHandler, false);
+        _target.addEventListener('mouseout', _outHandler, false);
+        document.addEventListener('mouseup', _upHandler, false);
+
+
+        /**
+         * This method unbinds every handlers that makes the captor work.
+         */
+        this.kill = function () {
+            sigma.utils.unbindDoubleClick(_target, 'click');
+            _target.removeEventListener('DOMMouseScroll', _wheelHandler);
+            _target.removeEventListener('mousewheel', _wheelHandler);
+            _target.removeEventListener('mousemove', _moveHandler);
+            _target.removeEventListener('mousedown', _downHandler);
+            _target.removeEventListener('click', _clickHandler);
+            _target.removeEventListener('mouseout', _outHandler);
+            document.removeEventListener('mouseup', _upHandler);
+        };
 
-      return configurable.apply({}, args);
-    };
 
-    // Initialize
-    for (i = 0, l = arguments.length; i < l; i++)
-      settings(arguments[i]);
+        // MOUSE EVENTS:
+        // *************
+
+        /**
+         * The handler listening to the 'move' mouse event. It will effectively
+         * drag the graph.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _moveHandler(e) {
+            var x,
+                y,
+                pos;
+
+            // Dispatch event:
+            if (_settings('mouseEnabled')) {
+                _self.dispatchEvent('mousemove',
+                    sigma.utils.mouseCoords(e));
+
+                if (_isMouseDown) {
+                    _isMoving = true;
+                    _hasDragged = true;
+
+                    if (_movingTimeoutId)
+                        clearTimeout(_movingTimeoutId);
+
+                    _movingTimeoutId = setTimeout(function () {
+                        _isMoving = false;
+                    }, _settings('dragTimeout'));
+
+                    sigma.misc.animation.killAll(_camera);
+
+                    _camera.isMoving = true;
+                    pos = _camera.cameraPosition(
+                        sigma.utils.getX(e) - _startMouseX,
+                        sigma.utils.getY(e) - _startMouseY,
+                        true
+                    );
+
+                    x = _startCameraX - pos.x;
+                    y = _startCameraY - pos.y;
+
+                    if (x !== _camera.x || y !== _camera.y) {
+                        _lastCameraX = _camera.x;
+                        _lastCameraY = _camera.y;
+
+                        _camera.goTo({
+                            x: x,
+                            y: y
+                        });
+                    }
+
+                    if (e.preventDefault)
+                        e.preventDefault();
+                    else
+                        e.returnValue = false;
+
+                    e.stopPropagation();
+                    return false;
+                }
+            }
+        }
 
-    return settings;
-  };
+        /**
+         * The handler listening to the 'up' mouse event. It will stop dragging the
+         * graph.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _upHandler(e) {
+            if (_settings('mouseEnabled') && _isMouseDown) {
+                _isMouseDown = false;
+                if (_movingTimeoutId)
+                    clearTimeout(_movingTimeoutId);
+
+                _camera.isMoving = false;
+
+                var x = sigma.utils.getX(e),
+                    y = sigma.utils.getY(e);
+
+                if (_isMoving) {
+                    sigma.misc.animation.killAll(_camera);
+                    sigma.misc.animation.camera(
+                        _camera,
+                        {
+                            x: _camera.x +
+                            _settings('mouseInertiaRatio') * (_camera.x - _lastCameraX),
+                            y: _camera.y +
+                            _settings('mouseInertiaRatio') * (_camera.y - _lastCameraY)
+                        },
+                        {
+                            easing: 'quadraticOut',
+                            duration: _settings('mouseInertiaDuration')
+                        }
+                    );
+                } else if (
+                    _startMouseX !== x ||
+                    _startMouseY !== y
+                )
+                    _camera.goTo({
+                        x: _camera.x,
+                        y: _camera.y
+                    });
+
+                _self.dispatchEvent('mouseup',
+                    sigma.utils.mouseCoords(e));
+
+                // Update _isMoving flag:
+                _isMoving = false;
+            }
+        }
 
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof this.sigma !== 'undefined') {
-    this.sigma.classes = this.sigma.classes || {};
-    this.sigma.classes.configurable = configurable;
-  } else if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = configurable;
-    exports.configurable = configurable;
-  } else
-    this.configurable = configurable;
-}).call(this);
+        /**
+         * The handler listening to the 'down' mouse event. It will start observing
+         * the mouse position for dragging the graph.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _downHandler(e) {
+            if (_settings('mouseEnabled')) {
+                _startCameraX = _camera.x;
+                _startCameraY = _camera.y;
+
+                _lastCameraX = _camera.x;
+                _lastCameraY = _camera.y;
+
+                _startMouseX = sigma.utils.getX(e);
+                _startMouseY = sigma.utils.getY(e);
+
+                _hasDragged = false;
+                _downStartTime = (new Date()).getTime();
+
+                switch (e.which) {
+                    case 2:
+                        // Middle mouse button pressed
+                        // Do nothing.
+                        break;
+                    case 3:
+                        // Right mouse button pressed
+                        _self.dispatchEvent('rightclick',
+                            sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
+                        break;
+                    // case 1:
+                    default:
+                        // Left mouse button pressed
+                        _isMouseDown = true;
+
+                        _self.dispatchEvent('mousedown',
+                            sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
+                }
+            }
+        }
 
-;(function(undefined) {
-  'use strict';
+        /**
+         * The handler listening to the 'out' mouse event. It will just redispatch
+         * the event.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _outHandler(e) {
+            if (_settings('mouseEnabled'))
+                _self.dispatchEvent('mouseout');
+        }
 
-  var _methods = Object.create(null),
-      _indexes = Object.create(null),
-      _initBindings = Object.create(null),
-      _methodBindings = Object.create(null),
-      _methodBeforeBindings = Object.create(null),
-      _defaultSettings = {
-        immutable: true,
-        clone: true
-      },
-      _defaultSettingsFunction = function(key) {
-        return _defaultSettings[key];
-      };
-
-  /**
-   * The graph constructor. It initializes the data and the indexes, and binds
-   * the custom indexes and methods to its own scope.
-   *
-   * Recognized parameters:
-   * **********************
-   * Here is the exhaustive list of every accepted parameters in the settings
-   * object:
-   *
-   *   {boolean} clone     Indicates if the data have to be cloned in methods
-   *                       to add nodes or edges.
-   *   {boolean} immutable Indicates if nodes "id" values and edges "id",
-   *                       "source" and "target" values must be set as
-   *                       immutable.
-   *
-   * @param  {?configurable} settings Eventually a settings function.
-   * @return {graph}                  The new graph instance.
-   */
-  var graph = function(settings) {
-    var k,
-        fn,
-        data;
-
-    /**
-     * DATA:
-     * *****
-     * Every data that is callable from graph methods are stored in this "data"
-     * object. This object will be served as context for all these methods,
-     * and it is possible to add other type of data in it.
-     */
-    data = {
-      /**
-       * SETTINGS FUNCTION:
-       * ******************
-       */
-      settings: settings || _defaultSettingsFunction,
-
-      /**
-       * MAIN DATA:
-       * **********
-       */
-      nodesArray: [],
-      edgesArray: [],
-
-      /**
-       * GLOBAL INDEXES:
-       * ***************
-       * These indexes just index data by ids.
-       */
-      nodesIndex: Object.create(null),
-      edgesIndex: Object.create(null),
-
-      /**
-       * LOCAL INDEXES:
-       * **************
-       * These indexes refer from node to nodes. Each key is an id, and each
-       * value is the array of the ids of related nodes.
-       */
-      inNeighborsIndex: Object.create(null),
-      outNeighborsIndex: Object.create(null),
-      allNeighborsIndex: Object.create(null),
-
-      inNeighborsCount: Object.create(null),
-      outNeighborsCount: Object.create(null),
-      allNeighborsCount: Object.create(null)
-    };
-
-    // Execute bindings:
-    for (k in _initBindings)
-      _initBindings[k].call(data);
-
-    // Add methods to both the scope and the data objects:
-    for (k in _methods) {
-      fn = __bindGraphMethod(k, data, _methods[k]);
-      this[k] = fn;
-      data[k] = fn;
-    }
-  };
+        /**
+         * The handler listening to the 'click' mouse event. It will redispatch the
+         * click event, but with normalized X and Y coordinates.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _clickHandler(e) {
+            if (_settings('mouseEnabled')) {
+                var event = sigma.utils.mouseCoords(e);
+                event.isDragging =
+                    (((new Date()).getTime() - _downStartTime) > 100) && _hasDragged;
+                _self.dispatchEvent('click', event);
+            }
+
+            if (e.preventDefault)
+                e.preventDefault();
+            else
+                e.returnValue = false;
+
+            e.stopPropagation();
+            return false;
+        }
 
+        /**
+         * The handler listening to the double click custom event. It will
+         * basically zoom into the graph.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _doubleClickHandler(e) {
+            var pos,
+                ratio,
+                animation;
+
+            if (_settings('mouseEnabled')) {
+                ratio = 1 / _settings('doubleClickZoomingRatio');
+
+                _self.dispatchEvent('doubleclick',
+                    sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
+
+                if (_settings('doubleClickEnabled')) {
+                    pos = _camera.cameraPosition(
+                        sigma.utils.getX(e) - sigma.utils.getCenter(e).x,
+                        sigma.utils.getY(e) - sigma.utils.getCenter(e).y,
+                        true
+                    );
+
+                    animation = {
+                        duration: _settings('doubleClickZoomDuration')
+                    };
+
+                    sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
+                }
+
+                if (e.preventDefault)
+                    e.preventDefault();
+                else
+                    e.returnValue = false;
+
+                e.stopPropagation();
+                return false;
+            }
+        }
 
+        /**
+         * The handler listening to the 'wheel' mouse event. It will basically zoom
+         * in or not into the graph.
+         *
+         * @param {event} e A mouse event.
+         */
+        function _wheelHandler(e) {
+            var pos,
+                ratio,
+                animation;
+
+            if (_settings('mouseEnabled') && _settings('mouseWheelEnabled')) {
+                ratio = sigma.utils.getDelta(e) > 0 ?
+                1 / _settings('zoomingRatio') :
+                    _settings('zoomingRatio');
+
+                pos = _camera.cameraPosition(
+                    sigma.utils.getX(e) - sigma.utils.getCenter(e).x,
+                    sigma.utils.getY(e) - sigma.utils.getCenter(e).y,
+                    true
+                );
 
+                animation = {
+                    duration: _settings('mouseZoomDuration')
+                };
 
-  /**
-   * A custom tool to bind methods such that function that are bound to it will
-   * be executed anytime the method is called.
-   *
-   * @param  {string}   methodName The name of the method to bind.
-   * @param  {object}   scope      The scope where the method must be executed.
-   * @param  {function} fn         The method itself.
-   * @return {function}            The new method.
-   */
-  function __bindGraphMethod(methodName, scope, fn) {
-    var result = function() {
-      var k,
-          res;
+                sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
 
-      // Execute "before" bound functions:
-      for (k in _methodBeforeBindings[methodName])
-        _methodBeforeBindings[methodName][k].apply(scope, arguments);
+                if (e.preventDefault)
+                    e.preventDefault();
+                else
+                    e.returnValue = false;
 
-      // Apply the method:
-      res = fn.apply(scope, arguments);
+                e.stopPropagation();
+                return false;
+            }
+        }
+    };
+}).call(this);
 
-      // Execute bound functions:
-      for (k in _methodBindings[methodName])
-        _methodBindings[methodName][k].apply(scope, arguments);
+;(function (undefined) {
+    'use strict';
 
-      // Return res:
-      return res;
-    };
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-    return result;
-  }
+    // Initialize packages:
+    sigma.utils.pkg('sigma.captors');
 
-  /**
-   * This custom tool function removes every pair key/value from an hash. The
-   * goal is to avoid creating a new object while some other references are
-   * still hanging in some scopes...
-   *
-   * @param  {object} obj The object to empty.
-   * @return {object}     The empty object.
-   */
-  function __emptyObject(obj) {
-    var k;
+    /**
+     * The user inputs default captor. It deals with mouse events, keyboards
+     * events and touch events.
+     *
+     * @param  {DOMElement}   target   The DOM element where the listeners will be
+     *                                 bound.
+     * @param  {camera}       camera   The camera related to the target.
+     * @param  {configurable} settings The settings function.
+     * @return {sigma.captor}          The fresh new captor instance.
+     */
+    sigma.captors.touch = function (target, camera, settings) {
+        var _self = this,
+            _target = target,
+            _camera = camera,
+            _settings = settings,
+
+            // CAMERA MANAGEMENT:
+            // ******************
+            // The camera position when the user starts dragging:
+            _startCameraX,
+            _startCameraY,
+            _startCameraAngle,
+            _startCameraRatio,
+
+            // The latest stage position:
+            _lastCameraX,
+            _lastCameraY,
+            _lastCameraAngle,
+            _lastCameraRatio,
+
+            // TOUCH MANAGEMENT:
+            // *****************
+            // Touches that are down:
+            _downTouches = [],
+
+            _startTouchX0,
+            _startTouchY0,
+            _startTouchX1,
+            _startTouchY1,
+            _startTouchAngle,
+            _startTouchDistance,
+
+            _touchMode,
+
+            _isMoving,
+            _doubleTap,
+            _movingTimeoutId;
+
+        sigma.classes.dispatcher.extend(this);
+
+        sigma.utils.doubleClick(_target, 'touchstart', _doubleTapHandler);
+        _target.addEventListener('touchstart', _handleStart, false);
+        _target.addEventListener('touchend', _handleLeave, false);
+        _target.addEventListener('touchcancel', _handleLeave, false);
+        _target.addEventListener('touchleave', _handleLeave, false);
+        _target.addEventListener('touchmove', _handleMove, false);
+
+        function position(e) {
+            var offset = sigma.utils.getOffset(_target);
+
+            return {
+                x: e.pageX - offset.left,
+                y: e.pageY - offset.top
+            };
+        }
 
-    for (k in obj)
-      if (!('hasOwnProperty' in obj) || obj.hasOwnProperty(k))
-        delete obj[k];
+        /**
+         * This method unbinds every handlers that makes the captor work.
+         */
+        this.kill = function () {
+            sigma.utils.unbindDoubleClick(_target, 'touchstart');
+            _target.addEventListener('touchstart', _handleStart);
+            _target.addEventListener('touchend', _handleLeave);
+            _target.addEventListener('touchcancel', _handleLeave);
+            _target.addEventListener('touchleave', _handleLeave);
+            _target.addEventListener('touchmove', _handleMove);
+        };
 
-    return obj;
-  }
+        // TOUCH EVENTS:
+        // *************
+        /**
+         * The handler listening to the 'touchstart' event. It will set the touch
+         * mode ("_touchMode") and start observing the user touch moves.
+         *
+         * @param {event} e A touch event.
+         */
+        function _handleStart(e) {
+            if (_settings('touchEnabled')) {
+                var x0,
+                    x1,
+                    y0,
+                    y1,
+                    pos0,
+                    pos1;
+
+                _downTouches = e.touches;
+
+                switch (_downTouches.length) {
+                    case 1:
+                        _camera.isMoving = true;
+                        _touchMode = 1;
+
+                        _startCameraX = _camera.x;
+                        _startCameraY = _camera.y;
+
+                        _lastCameraX = _camera.x;
+                        _lastCameraY = _camera.y;
+
+                        pos0 = position(_downTouches[0]);
+                        _startTouchX0 = pos0.x;
+                        _startTouchY0 = pos0.y;
+
+                        break;
+                    case 2:
+                        _camera.isMoving = true;
+                        _touchMode = 2;
+
+                        pos0 = position(_downTouches[0]);
+                        pos1 = position(_downTouches[1]);
+                        x0 = pos0.x;
+                        y0 = pos0.y;
+                        x1 = pos1.x;
+                        y1 = pos1.y;
+
+                        _lastCameraX = _camera.x;
+                        _lastCameraY = _camera.y;
+
+                        _startCameraAngle = _camera.angle;
+                        _startCameraRatio = _camera.ratio;
+
+                        _startCameraX = _camera.x;
+                        _startCameraY = _camera.y;
+
+                        _startTouchX0 = x0;
+                        _startTouchY0 = y0;
+                        _startTouchX1 = x1;
+                        _startTouchY1 = y1;
+
+                        _startTouchAngle = Math.atan2(
+                            _startTouchY1 - _startTouchY0,
+                            _startTouchX1 - _startTouchX0
+                        );
+                        _startTouchDistance = Math.sqrt(
+                            (_startTouchY1 - _startTouchY0) *
+                            (_startTouchY1 - _startTouchY0) +
+                            (_startTouchX1 - _startTouchX0) *
+                            (_startTouchX1 - _startTouchX0)
+                        );
+
+                        e.preventDefault();
+                        return false;
+                }
+            }
+        }
 
+        /**
+         * The handler listening to the 'touchend', 'touchcancel' and 'touchleave'
+         * event. It will update the touch mode if there are still at least one
+         * finger, and stop dragging else.
+         *
+         * @param {event} e A touch event.
+         */
+        function _handleLeave(e) {
+            if (_settings('touchEnabled')) {
+                _downTouches = e.touches;
+                var inertiaRatio = _settings('touchInertiaRatio');
+
+                if (_movingTimeoutId) {
+                    _isMoving = false;
+                    clearTimeout(_movingTimeoutId);
+                }
 
+                switch (_touchMode) {
+                    case 2:
+                        if (e.touches.length === 1) {
+                            _handleStart(e);
+
+                            e.preventDefault();
+                            break;
+                        }
+                    /* falls through */
+                    case 1:
+                        _camera.isMoving = false;
+                        _self.dispatchEvent('stopDrag');
+
+                        if (_isMoving) {
+                            _doubleTap = false;
+                            sigma.misc.animation.camera(
+                                _camera,
+                                {
+                                    x: _camera.x +
+                                    inertiaRatio * (_camera.x - _lastCameraX),
+                                    y: _camera.y +
+                                    inertiaRatio * (_camera.y - _lastCameraY)
+                                },
+                                {
+                                    easing: 'quadraticOut',
+                                    duration: _settings('touchInertiaDuration')
+                                }
+                            );
+                        }
+
+                        _isMoving = false;
+                        _touchMode = 0;
+                        break;
+                }
+            }
+        }
 
+        /**
+         * The handler listening to the 'touchmove' event. It will effectively drag
+         * the graph, and eventually zooms and turn it if the user is using two
+         * fingers.
+         *
+         * @param {event} e A touch event.
+         */
+        function _handleMove(e) {
+            if (!_doubleTap && _settings('touchEnabled')) {
+                var x0,
+                    x1,
+                    y0,
+                    y1,
+                    cos,
+                    sin,
+                    end,
+                    pos0,
+                    pos1,
+                    diff,
+                    start,
+                    dAngle,
+                    dRatio,
+                    newStageX,
+                    newStageY,
+                    newStageRatio,
+                    newStageAngle;
+
+                _downTouches = e.touches;
+                _isMoving = true;
+
+                if (_movingTimeoutId)
+                    clearTimeout(_movingTimeoutId);
+
+                _movingTimeoutId = setTimeout(function () {
+                    _isMoving = false;
+                }, _settings('dragTimeout'));
+
+                switch (_touchMode) {
+                    case 1:
+                        pos0 = position(_downTouches[0]);
+                        x0 = pos0.x;
+                        y0 = pos0.y;
+
+                        diff = _camera.cameraPosition(
+                            x0 - _startTouchX0,
+                            y0 - _startTouchY0,
+                            true
+                        );
+
+                        newStageX = _startCameraX - diff.x;
+                        newStageY = _startCameraY - diff.y;
+
+                        if (newStageX !== _camera.x || newStageY !== _camera.y) {
+                            _lastCameraX = _camera.x;
+                            _lastCameraY = _camera.y;
+
+                            _camera.goTo({
+                                x: newStageX,
+                                y: newStageY
+                            });
+
+                            _self.dispatchEvent('mousemove',
+                                sigma.utils.mouseCoords(e, pos0.x, pos0.y));
+
+                            _self.dispatchEvent('drag');
+                        }
+                        break;
+                    case 2:
+                        pos0 = position(_downTouches[0]);
+                        pos1 = position(_downTouches[1]);
+                        x0 = pos0.x;
+                        y0 = pos0.y;
+                        x1 = pos1.x;
+                        y1 = pos1.y;
+
+                        start = _camera.cameraPosition(
+                            (_startTouchX0 + _startTouchX1) / 2 -
+                            sigma.utils.getCenter(e).x,
+                            (_startTouchY0 + _startTouchY1) / 2 -
+                            sigma.utils.getCenter(e).y,
+                            true
+                        );
+                        end = _camera.cameraPosition(
+                            (x0 + x1) / 2 - sigma.utils.getCenter(e).x,
+                            (y0 + y1) / 2 - sigma.utils.getCenter(e).y,
+                            true
+                        );
+
+                        dAngle = Math.atan2(y1 - y0, x1 - x0) - _startTouchAngle;
+                        dRatio = Math.sqrt(
+                                (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0)
+                            ) / _startTouchDistance;
+
+                        // Translation:
+                        x0 = start.x;
+                        y0 = start.y;
+
+                        // Homothetic transformation:
+                        newStageRatio = _startCameraRatio / dRatio;
+                        x0 = x0 * dRatio;
+                        y0 = y0 * dRatio;
+
+                        // Rotation:
+                        newStageAngle = _startCameraAngle - dAngle;
+                        cos = Math.cos(-dAngle);
+                        sin = Math.sin(-dAngle);
+                        x1 = x0 * cos + y0 * sin;
+                        y1 = y0 * cos - x0 * sin;
+                        x0 = x1;
+                        y0 = y1;
+
+                        // Finalize:
+                        newStageX = x0 - end.x + _startCameraX;
+                        newStageY = y0 - end.y + _startCameraY;
+
+                        if (
+                            newStageRatio !== _camera.ratio ||
+                            newStageAngle !== _camera.angle ||
+                            newStageX !== _camera.x ||
+                            newStageY !== _camera.y
+                        ) {
+                            _lastCameraX = _camera.x;
+                            _lastCameraY = _camera.y;
+                            _lastCameraAngle = _camera.angle;
+                            _lastCameraRatio = _camera.ratio;
+
+                            _camera.goTo({
+                                x: newStageX,
+                                y: newStageY,
+                                angle: newStageAngle,
+                                ratio: newStageRatio
+                            });
+
+                            _self.dispatchEvent('drag');
+                        }
+
+                        break;
+                }
 
-  /**
-   * This global method adds a method that will be bound to the futurly created
-   * graph instances.
-   *
-   * Since these methods will be bound to their scope when the instances are
-   * created, it does not use the prototype. Because of that, methods have to
-   * be added before instances are created to make them available.
-   *
-   * Here is an example:
-   *
-   *  > graph.addMethod('getNodesCount', function() {
-   *  >   return this.nodesArray.length;
-   *  > });
-   *  >
-   *  > var myGraph = new graph();
-   *  > console.log(myGraph.getNodesCount()); // outputs 0
-   *
-   * @param  {string}   methodName The name of the method.
-   * @param  {function} fn         The method itself.
-   * @return {object}              The global graph constructor.
-   */
-  graph.addMethod = function(methodName, fn) {
-    if (
-      typeof methodName !== 'string' ||
-      typeof fn !== 'function' ||
-      arguments.length !== 2
-    )
-      throw 'addMethod: Wrong arguments.';
-
-    if (_methods[methodName] || graph[methodName])
-      throw 'The method "' + methodName + '" already exists.';
-
-    _methods[methodName] = fn;
-    _methodBindings[methodName] = Object.create(null);
-    _methodBeforeBindings[methodName] = Object.create(null);
-
-    return this;
-  };
-
-  /**
-   * This global method returns true if the method has already been added, and
-   * false else.
-   *
-   * Here are some examples:
-   *
-   *  > graph.hasMethod('addNode'); // returns true
-   *  > graph.hasMethod('hasMethod'); // returns true
-   *  > graph.hasMethod('unexistingMethod'); // returns false
-   *
-   * @param  {string}  methodName The name of the method.
-   * @return {boolean}            The result.
-   */
-  graph.hasMethod = function(methodName) {
-    return !!(_methods[methodName] || graph[methodName]);
-  };
-
-  /**
-   * This global methods attaches a function to a method. Anytime the specified
-   * method is called, the attached function is called right after, with the
-   * same arguments and in the same scope. The attached function is called
-   * right before if the last argument is true, unless the method is the graph
-   * constructor.
-   *
-   * To attach a function to the graph constructor, use 'constructor' as the
-   * method name (first argument).
-   *
-   * The main idea is to have a clean way to keep custom indexes up to date,
-   * for instance:
-   *
-   *  > var timesAddNodeCalled = 0;
-   *  > graph.attach('addNode', 'timesAddNodeCalledInc', function() {
-   *  >   timesAddNodeCalled++;
-   *  > });
-   *  >
-   *  > var myGraph = new graph();
-   *  > console.log(timesAddNodeCalled); // outputs 0
-   *  >
-   *  > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
-   *  > console.log(timesAddNodeCalled); // outputs 2
-   *
-   * The idea for calling a function before is to provide pre-processors, for
-   * instance:
-   *
-   *  > var colorPalette = { Person: '#C3CBE1', Place: '#9BDEBD' };
-   *  > graph.attach('addNode', 'applyNodeColorPalette', function(n) {
-   *  >   n.color = colorPalette[n.category];
-   *  > }, true);
-   *  >
-   *  > var myGraph = new graph();
-   *  > myGraph.addNode({ id: 'n0', category: 'Person' });
-   *  > console.log(myGraph.nodes('n0').color); // outputs '#C3CBE1'
-   *
-   * @param  {string}   methodName The name of the related method or
-   *                               "constructor".
-   * @param  {string}   key        The key to identify the function to attach.
-   * @param  {function} fn         The function to bind.
-   * @param  {boolean}  before     If true the function is called right before.
-   * @return {object}              The global graph constructor.
-   */
-  graph.attach = function(methodName, key, fn, before) {
-    if (
-      typeof methodName !== 'string' ||
-      typeof key !== 'string' ||
-      typeof fn !== 'function' ||
-      arguments.length < 3 ||
-      arguments.length > 4
-    )
-      throw 'attach: Wrong arguments.';
-
-    var bindings;
-
-    if (methodName === 'constructor')
-      bindings = _initBindings;
-    else {
-      if (before) {
-        if (!_methodBeforeBindings[methodName])
-        throw 'The method "' + methodName + '" does not exist.';
-
-        bindings = _methodBeforeBindings[methodName];
-      }
-      else {
-        if (!_methodBindings[methodName])
-          throw 'The method "' + methodName + '" does not exist.';
-
-        bindings = _methodBindings[methodName];
-      }
-    }
+                e.preventDefault();
+                return false;
+            }
+        }
 
-    if (bindings[key])
-      throw 'A function "' + key + '" is already attached ' +
-            'to the method "' + methodName + '".';
+        /**
+         * The handler listening to the double tap custom event. It will
+         * basically zoom into the graph.
+         *
+         * @param {event} e A touch event.
+         */
+        function _doubleTapHandler(e) {
+            var pos,
+                ratio,
+                animation;
+
+            if (e.touches && e.touches.length === 1 && _settings('touchEnabled')) {
+                _doubleTap = true;
+
+                ratio = 1 / _settings('doubleClickZoomingRatio');
+
+                pos = position(e.touches[0]);
+                _self.dispatchEvent('doubleclick',
+                    sigma.utils.mouseCoords(e, pos.x, pos.y));
+
+                if (_settings('doubleClickEnabled')) {
+                    pos = _camera.cameraPosition(
+                        pos.x - sigma.utils.getCenter(e).x,
+                        pos.y - sigma.utils.getCenter(e).y,
+                        true
+                    );
+
+                    animation = {
+                        duration: _settings('doubleClickZoomDuration'),
+                        onComplete: function () {
+                            _doubleTap = false;
+                        }
+                    };
+
+                    sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
+                }
 
-    bindings[key] = fn;
-
-    return this;
-  };
-
-  /**
-   * Alias of attach(methodName, key, fn, true).
-   */
-  graph.attachBefore = function(methodName, key, fn) {
-    return this.attach(methodName, key, fn, true);
-  };
-
-  /**
-   * This methods is just an helper to deal with custom indexes. It takes as
-   * arguments the name of the index and an object containing all the different
-   * functions to bind to the methods.
-   *
-   * Here is a basic example, that creates an index to keep the number of nodes
-   * in the current graph. It also adds a method to provide a getter on that
-   * new index:
-   *
-   *  > sigma.classes.graph.addIndex('nodesCount', {
-   *  >   constructor: function() {
-   *  >     this.nodesCount = 0;
-   *  >   },
-   *  >   addNode: function() {
-   *  >     this.nodesCount++;
-   *  >   },
-   *  >   dropNode: function() {
-   *  >     this.nodesCount--;
-   *  >   }
-   *  > });
-   *  >
-   *  > sigma.classes.graph.addMethod('getNodesCount', function() {
-   *  >   return this.nodesCount;
-   *  > });
-   *  >
-   *  > var myGraph = new sigma.classes.graph();
-   *  > console.log(myGraph.getNodesCount()); // outputs 0
-   *  >
-   *  > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
-   *  > console.log(myGraph.getNodesCount()); // outputs 2
-   *
-   * @param  {string} name     The name of the index.
-   * @param  {object} bindings The object containing the functions to bind.
-   * @return {object}          The global graph constructor.
-   */
-  graph.addIndex = function(name, bindings) {
-    if (
-      typeof name !== 'string' ||
-      Object(bindings) !== bindings ||
-      arguments.length !== 2
-    )
-      throw 'addIndex: Wrong arguments.';
-
-    if (_indexes[name])
-      throw 'The index "' + name + '" already exists.';
-
-    var k;
-
-    // Store the bindings:
-    _indexes[name] = bindings;
-
-    // Attach the bindings:
-    for (k in bindings)
-      if (typeof bindings[k] !== 'function')
-        throw 'The bindings must be functions.';
-      else
-        graph.attach(k, name, bindings[k]);
-
-    return this;
-  };
-
-
-
-
-  /**
-   * This method adds a node to the graph. The node must be an object, with a
-   * string under the key "id". Except for this, it is possible to add any
-   * other attribute, that will be preserved all along the manipulations.
-   *
-   * If the graph option "clone" has a truthy value, the node will be cloned
-   * when added to the graph. Also, if the graph option "immutable" has a
-   * truthy value, its id will be defined as immutable.
-   *
-   * @param  {object} node The node to add.
-   * @return {object}      The graph instance.
-   */
-  graph.addMethod('addNode', function(node) {
-    // Check that the node is an object and has an id:
-    if (Object(node) !== node || arguments.length !== 1)
-      throw 'addNode: Wrong arguments.';
-
-    if (typeof node.id !== 'string' && typeof node.id !== 'number')
-      throw 'The node must have a string or number id.';
-
-    if (this.nodesIndex[node.id])
-      throw 'The node "' + node.id + '" already exists.';
-
-    var k,
-        id = node.id,
-        validNode = Object.create(null);
-
-    // Check the "clone" option:
-    if (this.settings('clone')) {
-      for (k in node)
-        if (k !== 'id')
-          validNode[k] = node[k];
-    } else
-      validNode = node;
-
-    // Check the "immutable" option:
-    if (this.settings('immutable'))
-      Object.defineProperty(validNode, 'id', {
-        value: id,
-        enumerable: true
-      });
-    else
-      validNode.id = id;
-
-    // Add empty containers for edges indexes:
-    this.inNeighborsIndex[id] = Object.create(null);
-    this.outNeighborsIndex[id] = Object.create(null);
-    this.allNeighborsIndex[id] = Object.create(null);
-
-    this.inNeighborsCount[id] = 0;
-    this.outNeighborsCount[id] = 0;
-    this.allNeighborsCount[id] = 0;
-
-    // Add the node to indexes:
-    this.nodesArray.push(validNode);
-    this.nodesIndex[validNode.id] = validNode;
-
-    // Return the current instance:
-    return this;
-  });
-
-  /**
-   * This method adds an edge to the graph. The edge must be an object, with a
-   * string under the key "id", and strings under the keys "source" and
-   * "target" that design existing nodes. Except for this, it is possible to
-   * add any other attribute, that will be preserved all along the
-   * manipulations.
-   *
-   * If the graph option "clone" has a truthy value, the edge will be cloned
-   * when added to the graph. Also, if the graph option "immutable" has a
-   * truthy value, its id, source and target will be defined as immutable.
-   *
-   * @param  {object} edge The edge to add.
-   * @return {object}      The graph instance.
-   */
-  graph.addMethod('addEdge', function(edge) {
-    // Check that the edge is an object and has an id:
-    if (Object(edge) !== edge || arguments.length !== 1)
-      throw 'addEdge: Wrong arguments.';
-
-    if (typeof edge.id !== 'string' && typeof edge.id !== 'number')
-      throw 'The edge must have a string or number id.';
-
-    if ((typeof edge.source !== 'string' && typeof edge.source !== 'number') ||
-        !this.nodesIndex[edge.source])
-      throw 'The edge source must have an existing node id.';
-
-    if ((typeof edge.target !== 'string' && typeof edge.target !== 'number') ||
-        !this.nodesIndex[edge.target])
-      throw 'The edge target must have an existing node id.';
-
-    if (this.edgesIndex[edge.id])
-      throw 'The edge "' + edge.id + '" already exists.';
-
-    var k,
-        validEdge = Object.create(null);
-
-    // Check the "clone" option:
-    if (this.settings('clone')) {
-      for (k in edge)
-        if (k !== 'id' && k !== 'source' && k !== 'target')
-          validEdge[k] = edge[k];
-    } else
-      validEdge = edge;
-
-    // Check the "immutable" option:
-    if (this.settings('immutable')) {
-      Object.defineProperty(validEdge, 'id', {
-        value: edge.id,
-        enumerable: true
-      });
-
-      Object.defineProperty(validEdge, 'source', {
-        value: edge.source,
-        enumerable: true
-      });
-
-      Object.defineProperty(validEdge, 'target', {
-        value: edge.target,
-        enumerable: true
-      });
-    } else {
-      validEdge.id = edge.id;
-      validEdge.source = edge.source;
-      validEdge.target = edge.target;
-    }
+                if (e.preventDefault)
+                    e.preventDefault();
+                else
+                    e.returnValue = false;
 
-    // Add the edge to indexes:
-    this.edgesArray.push(validEdge);
-    this.edgesIndex[validEdge.id] = validEdge;
-
-    if (!this.inNeighborsIndex[validEdge.target][validEdge.source])
-      this.inNeighborsIndex[validEdge.target][validEdge.source] =
-        Object.create(null);
-    this.inNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
-      validEdge;
-
-    if (!this.outNeighborsIndex[validEdge.source][validEdge.target])
-      this.outNeighborsIndex[validEdge.source][validEdge.target] =
-        Object.create(null);
-    this.outNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
-      validEdge;
-
-    if (!this.allNeighborsIndex[validEdge.source][validEdge.target])
-      this.allNeighborsIndex[validEdge.source][validEdge.target] =
-        Object.create(null);
-    this.allNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
-      validEdge;
-
-    if (validEdge.target !== validEdge.source) {
-      if (!this.allNeighborsIndex[validEdge.target][validEdge.source])
-        this.allNeighborsIndex[validEdge.target][validEdge.source] =
-          Object.create(null);
-      this.allNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
-        validEdge;
-    }
+                e.stopPropagation();
+                return false;
+            }
+        }
+    };
+}).call(this);
 
-    // Keep counts up to date:
-    this.inNeighborsCount[validEdge.target]++;
-    this.outNeighborsCount[validEdge.source]++;
-    this.allNeighborsCount[validEdge.target]++;
-    this.allNeighborsCount[validEdge.source]++;
-
-    return this;
-  });
-
-  /**
-   * This method drops a node from the graph. It also removes each edge that is
-   * bound to it, through the dropEdge method. An error is thrown if the node
-   * does not exist.
-   *
-   * @param  {string} id The node id.
-   * @return {object}    The graph instance.
-   */
-  graph.addMethod('dropNode', function(id) {
-    // Check that the arguments are valid:
-    if ((typeof id !== 'string' && typeof id !== 'number') ||
-        arguments.length !== 1)
-      throw 'dropNode: Wrong arguments.';
-
-    if (!this.nodesIndex[id])
-      throw 'The node "' + id + '" does not exist.';
-
-    var i, k, l;
-
-    // Remove the node from indexes:
-    delete this.nodesIndex[id];
-    for (i = 0, l = this.nodesArray.length; i < l; i++)
-      if (this.nodesArray[i].id === id) {
-        this.nodesArray.splice(i, 1);
-        break;
-      }
-
-    // Remove related edges:
-    for (i = this.edgesArray.length - 1; i >= 0; i--)
-      if (this.edgesArray[i].source === id || this.edgesArray[i].target === id)
-        this.dropEdge(this.edgesArray[i].id);
-
-    // Remove related edge indexes:
-    delete this.inNeighborsIndex[id];
-    delete this.outNeighborsIndex[id];
-    delete this.allNeighborsIndex[id];
-
-    delete this.inNeighborsCount[id];
-    delete this.outNeighborsCount[id];
-    delete this.allNeighborsCount[id];
-
-    for (k in this.nodesIndex) {
-      delete this.inNeighborsIndex[k][id];
-      delete this.outNeighborsIndex[k][id];
-      delete this.allNeighborsIndex[k][id];
-    }
+;(function (undefined) {
+    'use strict';
 
-    return this;
-  });
-
-  /**
-   * This method drops an edge from the graph. An error is thrown if the edge
-   * does not exist.
-   *
-   * @param  {string} id The edge id.
-   * @return {object}    The graph instance.
-   */
-  graph.addMethod('dropEdge', function(id) {
-    // Check that the arguments are valid:
-    if ((typeof id !== 'string' && typeof id !== 'number') ||
-        arguments.length !== 1)
-      throw 'dropEdge: Wrong arguments.';
-
-    if (!this.edgesIndex[id])
-      throw 'The edge "' + id + '" does not exist.';
-
-    var i, l, edge;
-
-    // Remove the edge from indexes:
-    edge = this.edgesIndex[id];
-    delete this.edgesIndex[id];
-    for (i = 0, l = this.edgesArray.length; i < l; i++)
-      if (this.edgesArray[i].id === id) {
-        this.edgesArray.splice(i, 1);
-        break;
-      }
-
-    delete this.inNeighborsIndex[edge.target][edge.source][edge.id];
-    if (!Object.keys(this.inNeighborsIndex[edge.target][edge.source]).length)
-      delete this.inNeighborsIndex[edge.target][edge.source];
-
-    delete this.outNeighborsIndex[edge.source][edge.target][edge.id];
-    if (!Object.keys(this.outNeighborsIndex[edge.source][edge.target]).length)
-      delete this.outNeighborsIndex[edge.source][edge.target];
-
-    delete this.allNeighborsIndex[edge.source][edge.target][edge.id];
-    if (!Object.keys(this.allNeighborsIndex[edge.source][edge.target]).length)
-      delete this.allNeighborsIndex[edge.source][edge.target];
-
-    if (edge.target !== edge.source) {
-      delete this.allNeighborsIndex[edge.target][edge.source][edge.id];
-      if (!Object.keys(this.allNeighborsIndex[edge.target][edge.source]).length)
-        delete this.allNeighborsIndex[edge.target][edge.source];
-    }
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-    this.inNeighborsCount[edge.target]--;
-    this.outNeighborsCount[edge.source]--;
-    this.allNeighborsCount[edge.source]--;
-    this.allNeighborsCount[edge.target]--;
-
-    return this;
-  });
-
-  /**
-   * This method destroys the current instance. It basically empties each index
-   * and methods attached to the graph.
-   */
-  graph.addMethod('kill', function() {
-    // Delete arrays:
-    this.nodesArray.length = 0;
-    this.edgesArray.length = 0;
-    delete this.nodesArray;
-    delete this.edgesArray;
-
-    // Delete indexes:
-    delete this.nodesIndex;
-    delete this.edgesIndex;
-    delete this.inNeighborsIndex;
-    delete this.outNeighborsIndex;
-    delete this.allNeighborsIndex;
-    delete this.inNeighborsCount;
-    delete this.outNeighborsCount;
-    delete this.allNeighborsCount;
-  });
-
-  /**
-   * This method empties the nodes and edges arrays, as well as the different
-   * indexes.
-   *
-   * @return {object} The graph instance.
-   */
-  graph.addMethod('clear', function() {
-    this.nodesArray.length = 0;
-    this.edgesArray.length = 0;
-
-    // Due to GC issues, I prefer not to create new object. These objects are
-    // only available from the methods and attached functions, but still, it is
-    // better to prevent ghost references to unrelevant data...
-    __emptyObject(this.nodesIndex);
-    __emptyObject(this.edgesIndex);
-    __emptyObject(this.nodesIndex);
-    __emptyObject(this.inNeighborsIndex);
-    __emptyObject(this.outNeighborsIndex);
-    __emptyObject(this.allNeighborsIndex);
-    __emptyObject(this.inNeighborsCount);
-    __emptyObject(this.outNeighborsCount);
-    __emptyObject(this.allNeighborsCount);
-
-    return this;
-  });
-
-  /**
-   * This method reads an object and adds the nodes and edges, through the
-   * proper methods "addNode" and "addEdge".
-   *
-   * Here is an example:
-   *
-   *  > var myGraph = new graph();
-   *  > myGraph.read({
-   *  >   nodes: [
-   *  >     { id: 'n0' },
-   *  >     { id: 'n1' }
-   *  >   ],
-   *  >   edges: [
-   *  >     {
-   *  >       id: 'e0',
-   *  >       source: 'n0',
-   *  >       target: 'n1'
-   *  >     }
-   *  >   ]
-   *  > });
-   *  >
-   *  > console.log(
-   *  >   myGraph.nodes().length,
-   *  >   myGraph.edges().length
-   *  > ); // outputs 2 1
-   *
-   * @param  {object} g The graph object.
-   * @return {object}   The graph instance.
-   */
-  graph.addMethod('read', function(g) {
-    var i,
-        a,
-        l;
-
-    a = g.nodes || [];
-    for (i = 0, l = a.length; i < l; i++)
-      this.addNode(a[i]);
-
-    a = g.edges || [];
-    for (i = 0, l = a.length; i < l; i++)
-      this.addEdge(a[i]);
-
-    return this;
-  });
-
-  /**
-   * This methods returns one or several nodes, depending on how it is called.
-   *
-   * To get the array of nodes, call "nodes" without argument. To get a
-   * specific node, call it with the id of the node. The get multiple node,
-   * call it with an array of ids, and it will return the array of nodes, in
-   * the same order.
-   *
-   * @param  {?(string|array)} v Eventually one id, an array of ids.
-   * @return {object|array}      The related node or array of nodes.
-   */
-  graph.addMethod('nodes', function(v) {
-    // Clone the array of nodes and return it:
-    if (!arguments.length)
-      return this.nodesArray.slice(0);
-
-    // Return the related node:
-    if (arguments.length === 1 &&
-        (typeof v === 'string' || typeof v === 'number'))
-      return this.nodesIndex[v];
-
-    // Return an array of the related node:
-    if (
-      arguments.length === 1 &&
-      Object.prototype.toString.call(v) === '[object Array]'
-    ) {
-      var i,
-          l,
-          a = [];
-
-      for (i = 0, l = v.length; i < l; i++)
-        if (typeof v[i] === 'string' || typeof v[i] === 'number')
-          a.push(this.nodesIndex[v[i]]);
-        else
-          throw 'nodes: Wrong arguments.';
+    if (typeof conrad === 'undefined')
+        throw 'conrad is not declared';
 
-      return a;
-    }
+    // Initialize packages:
+    sigma.utils.pkg('sigma.renderers');
 
-    throw 'nodes: Wrong arguments.';
-  });
-
-  /**
-   * This methods returns the degree of one or several nodes, depending on how
-   * it is called. It is also possible to get incoming or outcoming degrees
-   * instead by specifying 'in' or 'out' as a second argument.
-   *
-   * @param  {string|array} v     One id, an array of ids.
-   * @param  {?string}      which Which degree is required. Values are 'in',
-   *                              'out', and by default the normal degree.
-   * @return {number|array}       The related degree or array of degrees.
-   */
-  graph.addMethod('degree', function(v, which) {
-    // Check which degree is required:
-    which = {
-      'in': this.inNeighborsCount,
-      'out': this.outNeighborsCount
-    }[which || ''] || this.allNeighborsCount;
-
-    // Return the related node:
-    if (typeof v === 'string' || typeof v === 'number')
-      return which[v];
-
-    // Return an array of the related node:
-    if (Object.prototype.toString.call(v) === '[object Array]') {
-      var i,
-          l,
-          a = [];
-
-      for (i = 0, l = v.length; i < l; i++)
-        if (typeof v[i] === 'string' || typeof v[i] === 'number')
-          a.push(which[v[i]]);
-        else
-          throw 'degree: Wrong arguments.';
+    /**
+     * This function is the constructor of the canvas sigma's renderer.
+     *
+     * @param  {sigma.classes.graph}            graph    The graph to render.
+     * @param  {sigma.classes.camera}           camera   The camera.
+     * @param  {configurable}           settings The sigma instance settings
+     *                                           function.
+     * @param  {object}                 object   The options object.
+     * @return {sigma.renderers.canvas}          The renderer instance.
+     */
+    sigma.renderers.canvas = function (graph, camera, settings, options) {
+        if (typeof options !== 'object')
+            throw 'sigma.renderers.canvas: Wrong arguments.';
 
-      return a;
-    }
+        if (!(options.container instanceof HTMLElement))
+            throw 'Container not found.';
 
-    throw 'degree: Wrong arguments.';
-  });
-
-  /**
-   * This methods returns one or several edges, depending on how it is called.
-   *
-   * To get the array of edges, call "edges" without argument. To get a
-   * specific edge, call it with the id of the edge. The get multiple edge,
-   * call it with an array of ids, and it will return the array of edges, in
-   * the same order.
-   *
-   * @param  {?(string|array)} v Eventually one id, an array of ids.
-   * @return {object|array}      The related edge or array of edges.
-   */
-  graph.addMethod('edges', function(v) {
-    // Clone the array of edges and return it:
-    if (!arguments.length)
-      return this.edgesArray.slice(0);
-
-    // Return the related edge:
-    if (arguments.length === 1 &&
-        (typeof v === 'string' || typeof v === 'number'))
-      return this.edgesIndex[v];
-
-    // Return an array of the related edge:
-    if (
-      arguments.length === 1 &&
-      Object.prototype.toString.call(v) === '[object Array]'
-    ) {
-      var i,
-          l,
-          a = [];
-
-      for (i = 0, l = v.length; i < l; i++)
-        if (typeof v[i] === 'string' || typeof v[i] === 'number')
-          a.push(this.edgesIndex[v[i]]);
-        else
-          throw 'edges: Wrong arguments.';
+        var k,
+            i,
+            l,
+            a,
+            fn,
+            self = this;
 
-      return a;
-    }
+        sigma.classes.dispatcher.extend(this);
 
-    throw 'edges: Wrong arguments.';
-  });
+        // Initialize main attributes:
+        Object.defineProperty(this, 'conradId', {
+            value: sigma.utils.id()
+        });
+        this.graph = graph;
+        this.camera = camera;
+        this.contexts = {};
+        this.domElements = {};
+        this.options = options;
+        this.container = this.options.container;
+        this.settings = (
+            typeof options.settings === 'object' &&
+            options.settings
+        ) ?
+            settings.embedObjects(options.settings) :
+            settings;
+
+        // Node indexes:
+        this.nodesOnScreen = [];
+        this.edgesOnScreen = [];
+
+        // Conrad related attributes:
+        this.jobs = {};
+
+        // Find the prefix:
+        this.options.prefix = 'renderer' + this.conradId + ':';
+
+        // Initialize the DOM elements:
+        if (
+            !this.settings('batchEdgesDrawing')
+        ) {
+            this.initDOM('canvas', 'scene');
+            this.contexts.edges = this.contexts.scene;
+            this.contexts.nodes = this.contexts.scene;
+            this.contexts.labels = this.contexts.scene;
+        } else {
+            this.initDOM('canvas', 'edges');
+            this.initDOM('canvas', 'scene');
+            this.contexts.nodes = this.contexts.scene;
+            this.contexts.labels = this.contexts.scene;
+        }
 
+        this.initDOM('canvas', 'mouse');
+        this.contexts.hover = this.contexts.mouse;
+
+        // Initialize captors:
+        this.captors = [];
+        a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
+        for (i = 0, l = a.length; i < l; i++) {
+            fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
+            this.captors.push(
+                new fn(
+                    this.domElements.mouse,
+                    this.camera,
+                    this.settings
+                )
+            );
+        }
 
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof sigma !== 'undefined') {
-    sigma.classes = sigma.classes || Object.create(null);
-    sigma.classes.graph = graph;
-  } else if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = graph;
-    exports.graph = graph;
-  } else
-    this.graph = graph;
-}).call(this);
+        // Deal with sigma events:
+        sigma.misc.bindEvents.call(this, this.options.prefix);
+        sigma.misc.drawHovers.call(this, this.options.prefix);
 
-;(function(undefined) {
-  'use strict';
+        this.resize(false);
+    };
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
 
-  sigma.utils.pkg('sigma.classes');
+    /**
+     * This method renders the graph on the canvases.
+     *
+     * @param  {?object}                options Eventually an object of options.
+     * @return {sigma.renderers.canvas}         Returns the instance itself.
+     */
+    sigma.renderers.canvas.prototype.render = function (options) {
+        options = options || {};
 
-  /**
-   * The camera constructor. It just initializes its attributes and methods.
-   *
-   * @param  {string}       id       The id.
-   * @param  {sigma.classes.graph}  graph    The graph.
-   * @param  {configurable} settings The settings function.
-   * @param  {?object}      options  Eventually some overriding options.
-   * @return {camera}                Returns the fresh new camera instance.
-   */
-  sigma.classes.camera = function(id, graph, settings, options) {
-    sigma.classes.dispatcher.extend(this);
+        var a,
+            i,
+            k,
+            l,
+            o,
+            id,
+            end,
+            job,
+            start,
+            edges,
+            renderers,
+            rendererType,
+            batchSize,
+            tempGCO,
+            index = {},
+            graph = this.graph,
+            nodes = this.graph.nodes,
+            prefix = this.options.prefix || '',
+            drawEdges = this.settings(options, 'drawEdges'),
+            drawNodes = this.settings(options, 'drawNodes'),
+            drawLabels = this.settings(options, 'drawLabels'),
+            drawEdgeLabels = this.settings(options, 'drawEdgeLabels'),
+            embedSettings = this.settings.embedObjects(options, {
+                prefix: this.options.prefix
+            });
 
-    Object.defineProperty(this, 'graph', {
-      value: graph
-    });
-    Object.defineProperty(this, 'id', {
-      value: id
-    });
-    Object.defineProperty(this, 'readPrefix', {
-      value: 'read_cam' + id + ':'
-    });
-    Object.defineProperty(this, 'prefix', {
-      value: 'cam' + id + ':'
-    });
+        // Call the resize function:
+        this.resize(false);
 
-    this.x = 0;
-    this.y = 0;
-    this.ratio = 1;
-    this.angle = 0;
-    this.isAnimated = false;
-    this.settings = (typeof options === 'object' && options) ?
-      settings.embedObject(options) :
-      settings;
-  };
-
-  /**
-   * Updates the camera position.
-   *
-   * @param  {object} coordinates The new coordinates object.
-   * @return {camera}             Returns the camera.
-   */
-  sigma.classes.camera.prototype.goTo = function(coordinates) {
-    if (!this.settings('enableCamera'))
-      return this;
-
-    var i,
-        l,
-        c = coordinates || {},
-        keys = ['x', 'y', 'ratio', 'angle'];
-
-    for (i = 0, l = keys.length; i < l; i++)
-      if (c[keys[i]] !== undefined) {
-        if (typeof c[keys[i]] === 'number' && !isNaN(c[keys[i]]))
-          this[keys[i]] = c[keys[i]];
-        else
-          throw 'Value for "' + keys[i] + '" is not a number.';
-      }
-
-    this.dispatchEvent('coordinatesUpdated');
-    return this;
-  };
-
-  /**
-   * This method takes a graph and computes for each node and edges its
-   * coordinates relatively to the center of the camera. Basically, it will
-   * compute the coordinates that will be used by the graphic renderers.
-   *
-   * Since it should be possible to use different cameras and different
-   * renderers, it is possible to specify a prefix to put before the new
-   * coordinates (to get something like "node.camera1_x")
-   *
-   * @param  {?string} read    The prefix of the coordinates to read.
-   * @param  {?string} write   The prefix of the coordinates to write.
-   * @param  {?object} options Eventually an object of options. Those can be:
-   *                           - A restricted nodes array.
-   *                           - A restricted edges array.
-   *                           - A width.
-   *                           - A height.
-   * @return {camera}        Returns the camera.
-   */
-  sigma.classes.camera.prototype.applyView = function(read, write, options) {
-    options = options || {};
-    write = write !== undefined ? write : this.prefix;
-    read = read !== undefined ? read : this.readPrefix;
-
-    var nodes = options.nodes || this.graph.nodes(),
-        edges = options.edges || this.graph.edges();
-
-    var i,
-        l,
-        node,
-        cos = Math.cos(this.angle),
-        sin = Math.sin(this.angle),
-        nodeRatio = Math.pow(this.ratio, this.settings('nodesPowRatio')),
-        edgeRatio = Math.pow(this.ratio, this.settings('edgesPowRatio')),
-        xOffset = (options.width || 0) / 2,
-        yOffset = (options.height || 0) / 2;
-
-    for (i = 0, l = nodes.length; i < l; i++) {
-      node = nodes[i];
-      node[write + 'x'] =
-        (
-          ((node[read + 'x'] || 0) - this.x) * cos +
-          ((node[read + 'y'] || 0) - this.y) * sin
-        ) / this.ratio + xOffset;
-      node[write + 'y'] =
-        (
-          ((node[read + 'y'] || 0) - this.y) * cos -
-          ((node[read + 'x'] || 0) - this.x) * sin
-        ) / this.ratio + yOffset;
-      node[write + 'size'] =
-        (node[read + 'size'] || 0) /
-        nodeRatio;
-    }
+        // Check the 'hideEdgesOnMove' setting:
+        if (this.settings(options, 'hideEdgesOnMove'))
+            if (this.camera.isAnimated || this.camera.isMoving)
+                drawEdges = false;
 
-    for (i = 0, l = edges.length; i < l; i++) {
-      edges[i][write + 'size'] =
-        (edges[i][read + 'size'] || 0) /
-        edgeRatio;
-    }
+        // Apply the camera's view:
+        this.camera.applyView(
+            undefined,
+            this.options.prefix,
+            {
+                width: this.width,
+                height: this.height
+            }
+        );
 
-    return this;
-  };
-
-  /**
-   * This function converts the coordinates of a point from the frame of the
-   * camera to the frame of the graph.
-   *
-   * @param  {number} x The X coordinate of the point in the frame of the
-   *                    camera.
-   * @param  {number} y The Y coordinate of the point in the frame of the
-   *                    camera.
-   * @return {object}   The point coordinates in the frame of the graph.
-   */
-  sigma.classes.camera.prototype.graphPosition = function(x, y, vector) {
-    var X = 0,
-        Y = 0,
-        cos = Math.cos(this.angle),
-        sin = Math.sin(this.angle);
-
-    // Revert the origin differential vector:
-    if (!vector) {
-      X = - (this.x * cos + this.y * sin) / this.ratio;
-      Y = - (this.y * cos - this.x * sin) / this.ratio;
-    }
+        // Clear canvases:
+        this.clear();
 
-    return {
-      x: (x * cos + y * sin) / this.ratio + X,
-      y: (y * cos - x * sin) / this.ratio + Y
-    };
-  };
-
-  /**
-   * This function converts the coordinates of a point from the frame of the
-   * graph to the frame of the camera.
-   *
-   * @param  {number} x The X coordinate of the point in the frame of the
-   *                    graph.
-   * @param  {number} y The Y coordinate of the point in the frame of the
-   *                    graph.
-   * @return {object}   The point coordinates in the frame of the camera.
-   */
-  sigma.classes.camera.prototype.cameraPosition = function(x, y, vector) {
-    var X = 0,
-        Y = 0,
-        cos = Math.cos(this.angle),
-        sin = Math.sin(this.angle);
-
-    // Revert the origin differential vector:
-    if (!vector) {
-      X = - (this.x * cos + this.y * sin) / this.ratio;
-      Y = - (this.y * cos - this.x * sin) / this.ratio;
-    }
+        // Kill running jobs:
+        for (k in this.jobs)
+            if (conrad.hasJob(k))
+                conrad.killJob(k);
 
-    return {
-      x: ((x - X) * cos - (y - Y) * sin) * this.ratio,
-      y: ((y - Y) * cos + (x - X) * sin) * this.ratio
-    };
-  };
-
-  /**
-   * This method returns the transformation matrix of the camera. This is
-   * especially useful to apply the camera view directly in shaders, in case of
-   * WebGL rendering.
-   *
-   * @return {array} The transformation matrix.
-   */
-  sigma.classes.camera.prototype.getMatrix = function() {
-    var scale = sigma.utils.matrices.scale(1 / this.ratio),
-        rotation = sigma.utils.matrices.rotation(this.angle),
-        translation = sigma.utils.matrices.translation(-this.x, -this.y),
-        matrix = sigma.utils.matrices.multiply(
-          translation,
-          sigma.utils.matrices.multiply(
-            rotation,
-            scale
-          )
+        // Find which nodes are on screen:
+        this.edgesOnScreen = [];
+        this.nodesOnScreen = this.camera.quadtree.area(
+            this.camera.getRectangle(this.width, this.height)
         );
 
-    return matrix;
-  };
-
-  /**
-   * Taking a width and a height as parameters, this method returns the
-   * coordinates of the rectangle representing the camera on screen, in the
-   * graph's referentiel.
-   *
-   * To keep displaying labels of nodes going out of the screen, the method
-   * keeps a margin around the screen in the returned rectangle.
-   *
-   * @param  {number} width  The width of the screen.
-   * @param  {number} height The height of the screen.
-   * @return {object}        The rectangle as x1, y1, x2 and y2, representing
-   *                         two opposite points.
-   */
-  sigma.classes.camera.prototype.getRectangle = function(width, height) {
-    var widthVect = this.cameraPosition(width, 0, true),
-        heightVect = this.cameraPosition(0, height, true),
-        centerVect = this.cameraPosition(width / 2, height / 2, true),
-        marginX = this.cameraPosition(width / 4, 0, true).x,
-        marginY = this.cameraPosition(0, height / 4, true).y;
-
-    return {
-      x1: this.x - centerVect.x - marginX,
-      y1: this.y - centerVect.y - marginY,
-      x2: this.x - centerVect.x + marginX + widthVect.x,
-      y2: this.y - centerVect.y - marginY + widthVect.y,
-      height: Math.sqrt(
-        Math.pow(heightVect.x, 2) +
-        Math.pow(heightVect.y + 2 * marginY, 2)
-      )
-    };
-  };
-}).call(this);
+        for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
+            index[a[i].id] = a[i];
+
+        // Draw edges:
+        // - If settings('batchEdgesDrawing') is true, the edges are displayed per
+        //   batches. If not, they are drawn in one frame.
+        if (drawEdges) {
+            // First, let's identify which edges to draw. To do this, we just keep
+            // every edges that have at least one extremity displayed according to
+            // the quadtree and the "hidden" attribute. We also do not keep hidden
+            // edges.
+            for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
+                o = a[i];
+                if (
+                    (index[o.source] || index[o.target]) &&
+                    (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden)
+                )
+                    this.edgesOnScreen.push(o);
+            }
 
-;(function(undefined) {
-  'use strict';
+            // If the "batchEdgesDrawing" settings is true, edges are batched:
+            if (this.settings(options, 'batchEdgesDrawing')) {
+                id = 'edges_' + this.conradId;
+                batchSize = embedSettings('canvasEdgesBatchSize');
+
+                edges = this.edgesOnScreen;
+                l = edges.length;
+
+                start = 0;
+                end = Math.min(edges.length, start + batchSize);
+
+                job = function () {
+                    tempGCO = this.contexts.edges.globalCompositeOperation;
+                    this.contexts.edges.globalCompositeOperation = 'destination-over';
+
+                    renderers = sigma.canvas.edges;
+                    for (i = start; i < end; i++) {
+                        o = edges[i];
+                        (renderers[
+                        o.type || this.settings(options, 'defaultEdgeType')
+                            ] || renderers.def)(
+                            o,
+                            graph.nodes(o.source),
+                            graph.nodes(o.target),
+                            this.contexts.edges,
+                            embedSettings
+                        );
+                    }
+
+                    // Draw edge labels:
+                    if (drawEdgeLabels) {
+                        renderers = sigma.canvas.edges.labels;
+                        for (i = start; i < end; i++) {
+                            o = edges[i];
+                            if (!o.hidden)
+                                (renderers[
+                                o.type || this.settings(options, 'defaultEdgeType')
+                                    ] || renderers.def)(
+                                    o,
+                                    graph.nodes(o.source),
+                                    graph.nodes(o.target),
+                                    this.contexts.labels,
+                                    embedSettings
+                                );
+                        }
+                    }
+
+                    // Restore original globalCompositeOperation:
+                    this.contexts.edges.globalCompositeOperation = tempGCO;
+
+                    // Catch job's end:
+                    if (end === edges.length) {
+                        delete this.jobs[id];
+                        return false;
+                    }
+
+                    start = end + 1;
+                    end = Math.min(edges.length, start + batchSize);
+                    return true;
+                };
+
+                this.jobs[id] = job;
+                conrad.addJob(id, job.bind(this));
+
+                // If not, they are drawn in one frame:
+            } else {
+                renderers = sigma.canvas.edges;
+                for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
+                    o = a[i];
+                    (renderers[
+                    o.type || this.settings(options, 'defaultEdgeType')
+                        ] || renderers.def)(
+                        o,
+                        graph.nodes(o.source),
+                        graph.nodes(o.target),
+                        this.contexts.edges,
+                        embedSettings
+                    );
+                }
 
-  /**
-   * Sigma Quadtree Module
-   * =====================
-   *
-   * Author: Guillaume Plique (Yomguithereal)
-   * Version: 0.2
-   */
+                // Draw edge labels:
+                // - No batching
+                if (drawEdgeLabels) {
+                    renderers = sigma.canvas.edges.labels;
+                    for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++)
+                        if (!a[i].hidden)
+                            (renderers[
+                            a[i].type || this.settings(options, 'defaultEdgeType')
+                                ] || renderers.def)(
+                                a[i],
+                                graph.nodes(a[i].source),
+                                graph.nodes(a[i].target),
+                                this.contexts.labels,
+                                embedSettings
+                            );
+                }
+            }
+        }
 
+        // Draw nodes:
+        // - No batching
+        if (drawNodes) {
+            renderers = sigma.canvas.nodes;
+            for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
+                if (!a[i].hidden)
+                    (renderers[
+                    a[i].type || this.settings(options, 'defaultNodeType')
+                        ] || renderers.def)(
+                        a[i],
+                        this.contexts.nodes,
+                        embedSettings
+                    );
+        }
 
+        // Draw labels:
+        // - No batching
+        if (drawLabels) {
+            renderers = sigma.canvas.labels;
+            for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
+                if (!a[i].hidden)
+                    (renderers[
+                    a[i].type || this.settings(options, 'defaultNodeType')
+                        ] || renderers.def)(
+                        a[i],
+                        this.contexts.labels,
+                        embedSettings
+                    );
+        }
 
-  /**
-   * Quad Geometric Operations
-   * -------------------------
-   *
-   * A useful batch of geometric operations used by the quadtree.
-   */
+        this.dispatchEvent('render');
 
-  var _geom = {
+        return this;
+    };
 
     /**
-     * Transforms a graph node with x, y and size into an
-     * axis-aligned square.
+     * This method creates a DOM element of the specified type, switches its
+     * position to "absolute", references it to the domElements attribute, and
+     * finally appends it to the container.
      *
-     * @param  {object} A graph node with at least a point (x, y) and a size.
-     * @return {object} A square: two points (x1, y1), (x2, y2) and height.
+     * @param  {string} tag The label tag.
+     * @param  {string} id  The id of the element (to store it in "domElements").
      */
-    pointToSquare: function(n) {
-      return {
-        x1: n.x - n.size,
-        y1: n.y - n.size,
-        x2: n.x + n.size,
-        y2: n.y - n.size,
-        height: n.size * 2
-      };
-    },
+    sigma.renderers.canvas.prototype.initDOM = function (tag, id) {
+        var dom = document.createElement(tag);
 
-    /**
-     * Checks whether a rectangle is axis-aligned.
-     *
-     * @param  {object}  A rectangle defined by two points
-     *                   (x1, y1) and (x2, y2).
-     * @return {boolean} True if the rectangle is axis-aligned.
-     */
-    isAxisAligned: function(r) {
-      return r.x1 === r.x2 || r.y1 === r.y2;
-    },
+        dom.style.position = 'absolute';
+        dom.setAttribute('class', 'sigma-' + id);
+
+        this.domElements[id] = dom;
+        this.container.appendChild(dom);
+
+        if (tag.toLowerCase() === 'canvas')
+            this.contexts[id] = dom.getContext('2d');
+    };
 
     /**
-     * Compute top points of an axis-aligned rectangle. This is useful in
-     * cases when the rectangle has been rotated (left, right or bottom up) and
-     * later operations need to know the top points.
+     * This method resizes each DOM elements in the container and stores the new
+     * dimensions. Then, it renders the graph.
      *
-     * @param  {object} An axis-aligned rectangle defined by two points
-     *                  (x1, y1), (x2, y2) and height.
-     * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height.
+     * @param  {?number}                width  The new width of the container.
+     * @param  {?number}                height The new height of the container.
+     * @return {sigma.renderers.canvas}        Returns the instance itself.
      */
-    axisAlignedTopPoints: function(r) {
+    sigma.renderers.canvas.prototype.resize = function (w, h) {
+        var k,
+            oldWidth = this.width,
+            oldHeight = this.height,
+            pixelRatio = sigma.utils.getPixelRatio();
+
+        if (w !== undefined && h !== undefined) {
+            this.width = w;
+            this.height = h;
+        } else {
+            this.width = this.container.offsetWidth;
+            this.height = this.container.offsetHeight;
+
+            w = this.width;
+            h = this.height;
+        }
 
-      // Basic
-      if (r.y1 === r.y2 && r.x1 < r.x2)
-        return r;
+        if (oldWidth !== this.width || oldHeight !== this.height) {
+            for (k in this.domElements) {
+                this.domElements[k].style.width = w + 'px';
+                this.domElements[k].style.height = h + 'px';
 
-      // Rotated to right
-      if (r.x1 === r.x2 && r.y2 > r.y1)
-        return {
-          x1: r.x1 - r.height, y1: r.y1,
-          x2: r.x1, y2: r.y1,
-          height: r.height
-        };
+                if (this.domElements[k].tagName.toLowerCase() === 'canvas') {
+                    this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px');
+                    this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px');
 
-      // Rotated to left
-      if (r.x1 === r.x2 && r.y2 < r.y1)
-        return {
-          x1: r.x1, y1: r.y2,
-          x2: r.x2 + r.height, y2: r.y2,
-          height: r.height
-        };
+                    if (pixelRatio !== 1)
+                        this.contexts[k].scale(pixelRatio, pixelRatio);
+                }
+            }
+        }
 
-      // Bottom's up
-      return {
-        x1: r.x2, y1: r.y1 - r.height,
-        x2: r.x1, y2: r.y1 - r.height,
-        height: r.height
-      };
-    },
+        return this;
+    };
 
     /**
-     * Get coordinates of a rectangle's lower left corner from its top points.
+     * This method clears each canvas.
      *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @return {object} Coordinates of the corner (x, y).
+     * @return {sigma.renderers.canvas} Returns the instance itself.
      */
-    lowerLeftCoor: function(r) {
-      var width = (
-        Math.sqrt(
-          Math.pow(r.x2 - r.x1, 2) +
-          Math.pow(r.y2 - r.y1, 2)
-        )
-      );
-
-      return {
-        x: r.x1 - (r.y2 - r.y1) * r.height / width,
-        y: r.y1 + (r.x2 - r.x1) * r.height / width
-      };
-    },
-
-    /**
-     * Get coordinates of a rectangle's lower right corner from its top points
-     * and its lower left corner.
-     *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @param  {object} A corner's coordinates (x, y).
-     * @return {object} Coordinates of the corner (x, y).
-     */
-    lowerRightCoor: function(r, llc) {
-      return {
-        x: llc.x - r.x1 + r.x2,
-        y: llc.y - r.y1 + r.y2
-      };
-    },
-
-    /**
-     * Get the coordinates of all the corners of a rectangle from its top point.
-     *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @return {array}  An array of the four corners' coordinates (x, y).
-     */
-    rectangleCorners: function(r) {
-      var llc = this.lowerLeftCoor(r),
-          lrc = this.lowerRightCoor(r, llc);
-
-      return [
-        {x: r.x1, y: r.y1},
-        {x: r.x2, y: r.y2},
-        {x: llc.x, y: llc.y},
-        {x: lrc.x, y: lrc.y}
-      ];
-    },
-
-    /**
-     * Split a square defined by its boundaries into four.
-     *
-     * @param  {object} Boundaries of the square (x, y, width, height).
-     * @return {array}  An array containing the four new squares, themselves
-     *                  defined by an array of their four corners (x, y).
-     */
-    splitSquare: function(b) {
-      return [
-        [
-          {x: b.x, y: b.y},
-          {x: b.x + b.width / 2, y: b.y},
-          {x: b.x, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2}
-        ],
-        [
-          {x: b.x + b.width / 2, y: b.y},
-          {x: b.x + b.width, y: b.y},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x + b.width, y: b.y + b.height / 2}
-        ],
-        [
-          {x: b.x, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x, y: b.y + b.height},
-          {x: b.x + b.width / 2, y: b.y + b.height}
-        ],
-        [
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x + b.width, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height},
-          {x: b.x + b.width, y: b.y + b.height}
-        ]
-      ];
-    },
-
-    /**
-     * Compute the four axis between corners of rectangle A and corners of
-     * rectangle B. This is needed later to check an eventual collision.
-     *
-     * @param  {array} An array of rectangle A's four corners (x, y).
-     * @param  {array} An array of rectangle B's four corners (x, y).
-     * @return {array} An array of four axis defined by their coordinates (x,y).
-     */
-    axis: function(c1, c2) {
-      return [
-        {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y},
-        {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y},
-        {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y},
-        {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y}
-      ];
-    },
-
-    /**
-     * Project a rectangle's corner on an axis.
-     *
-     * @param  {object} Coordinates of a corner (x, y).
-     * @param  {object} Coordinates of an axis (x, y).
-     * @return {object} The projection defined by coordinates (x, y).
-     */
-    projection: function(c, a) {
-      var l = (
-        (c.x * a.x + c.y * a.y) /
-        (Math.pow(a.x, 2) + Math.pow(a.y, 2))
-      );
-
-      return {
-        x: l * a.x,
-        y: l * a.y
-      };
-    },
-
-    /**
-     * Check whether two rectangles collide on one particular axis.
-     *
-     * @param  {object}   An axis' coordinates (x, y).
-     * @param  {array}    Rectangle A's corners.
-     * @param  {array}    Rectangle B's corners.
-     * @return {boolean}  True if the rectangles collide on the axis.
-     */
-    axisCollision: function(a, c1, c2) {
-      var sc1 = [],
-          sc2 = [];
-
-      for (var ci = 0; ci < 4; ci++) {
-        var p1 = this.projection(c1[ci], a),
-            p2 = this.projection(c2[ci], a);
-
-        sc1.push(p1.x * a.x + p1.y * a.y);
-        sc2.push(p2.x * a.x + p2.y * a.y);
-      }
-
-      var maxc1 = Math.max.apply(Math, sc1),
-          maxc2 = Math.max.apply(Math, sc2),
-          minc1 = Math.min.apply(Math, sc1),
-          minc2 = Math.min.apply(Math, sc2);
-
-      return (minc2 <= maxc1 && maxc2 >= minc1);
-    },
-
-    /**
-     * Check whether two rectangles collide on each one of their four axis. If
-     * all axis collide, then the two rectangles do collide on the plane.
-     *
-     * @param  {array}    Rectangle A's corners.
-     * @param  {array}    Rectangle B's corners.
-     * @return {boolean}  True if the rectangles collide.
-     */
-    collision: function(c1, c2) {
-      var axis = this.axis(c1, c2),
-          col = true;
-
-      for (var i = 0; i < 4; i++)
-        col = col && this.axisCollision(axis[i], c1, c2);
-
-      return col;
-    }
-  };
-
-
-  /**
-   * Quad Functions
-   * ------------
-   *
-   * The Quadtree functions themselves.
-   * For each of those functions, we consider that in a splitted quad, the
-   * index of each node is the following:
-   * 0: top left
-   * 1: top right
-   * 2: bottom left
-   * 3: bottom right
-   *
-   * Moreover, the hereafter quad's philosophy is to consider that if an element
-   * collides with more than one nodes, this element belongs to each of the
-   * nodes it collides with where other would let it lie on a higher node.
-   */
-
-  /**
-   * Get the index of the node containing the point in the quad
-   *
-   * @param  {object}  point      A point defined by coordinates (x, y).
-   * @param  {object}  quadBounds Boundaries of the quad (x, y, width, heigth).
-   * @return {integer}            The index of the node containing the point.
-   */
-  function _quadIndex(point, quadBounds) {
-    var xmp = quadBounds.x + quadBounds.width / 2,
-        ymp = quadBounds.y + quadBounds.height / 2,
-        top = (point.y < ymp),
-        left = (point.x < xmp);
-
-    if (top) {
-      if (left)
-        return 0;
-      else
-        return 1;
-    }
-    else {
-      if (left)
-        return 2;
-      else
-        return 3;
-    }
-  }
-
-  /**
-   * Get a list of indexes of nodes containing an axis-aligned rectangle
-   *
-   * @param  {object}  rectangle   A rectangle defined by two points (x1, y1),
-   *                               (x2, y2) and height.
-   * @param  {array}   quadCorners An array of the quad nodes' corners.
-   * @return {array}               An array of indexes containing one to
-   *                               four integers.
-   */
-  function _quadIndexes(rectangle, quadCorners) {
-    var indexes = [];
-
-    // Iterating through quads
-    for (var i = 0; i < 4; i++)
-      if ((rectangle.x2 >= quadCorners[i][0].x) &&
-          (rectangle.x1 <= quadCorners[i][1].x) &&
-          (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) &&
-          (rectangle.y1 <= quadCorners[i][2].y))
-        indexes.push(i);
-
-    return indexes;
-  }
-
-  /**
-   * Get a list of indexes of nodes containing a non-axis-aligned rectangle
-   *
-   * @param  {array}  corners      An array containing each corner of the
-   *                               rectangle defined by its coordinates (x, y).
-   * @param  {array}  quadCorners  An array of the quad nodes' corners.
-   * @return {array}               An array of indexes containing one to
-   *                               four integers.
-   */
-  function _quadCollision(corners, quadCorners) {
-    var indexes = [];
-
-    // Iterating through quads
-    for (var i = 0; i < 4; i++)
-      if (_geom.collision(corners, quadCorners[i]))
-        indexes.push(i);
-
-    return indexes;
-  }
-
-  /**
-   * Subdivide a quad by creating a node at a precise index. The function does
-   * not generate all four nodes not to potentially create unused nodes.
-   *
-   * @param  {integer}  index The index of the node to create.
-   * @param  {object}   quad  The quad object to subdivide.
-   * @return {object}         A new quad representing the node created.
-   */
-  function _quadSubdivide(index, quad) {
-    var next = quad.level + 1,
-        subw = Math.round(quad.bounds.width / 2),
-        subh = Math.round(quad.bounds.height / 2),
-        qx = Math.round(quad.bounds.x),
-        qy = Math.round(quad.bounds.y),
-        x,
-        y;
-
-    switch (index) {
-      case 0:
-        x = qx;
-        y = qy;
-        break;
-      case 1:
-        x = qx + subw;
-        y = qy;
-        break;
-      case 2:
-        x = qx;
-        y = qy + subh;
-        break;
-      case 3:
-        x = qx + subw;
-        y = qy + subh;
-        break;
-    }
+    sigma.renderers.canvas.prototype.clear = function () {
+        for (var k in this.contexts) {
+            this.contexts[k].clearRect(0, 0, this.width, this.height);
+        }
 
-    return _quadTree(
-      {x: x, y: y, width: subw, height: subh},
-      next,
-      quad.maxElements,
-      quad.maxLevel
-    );
-  }
-
-  /**
-   * Recursively insert an element into the quadtree. Only points
-   * with size, i.e. axis-aligned squares, may be inserted with this
-   * method.
-   *
-   * @param  {object}  el         The element to insert in the quadtree.
-   * @param  {object}  sizedPoint A sized point defined by two top points
-   *                              (x1, y1), (x2, y2) and height.
-   * @param  {object}  quad       The quad in which to insert the element.
-   * @return {undefined}          The function does not return anything.
-   */
-  function _quadInsert(el, sizedPoint, quad) {
-    if (quad.level < quad.maxLevel) {
-
-      // Searching appropriate quads
-      var indexes = _quadIndexes(sizedPoint, quad.corners);
-
-      // Iterating
-      for (var i = 0, l = indexes.length; i < l; i++) {
-
-        // Subdividing if necessary
-        if (quad.nodes[indexes[i]] === undefined)
-          quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad);
-
-        // Recursion
-        _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]);
-      }
-    }
-    else {
+        return this;
+    };
 
-      // Pushing the element in a leaf node
-      quad.elements.push(el);
-    }
-  }
-
-  /**
-   * Recursively retrieve every elements held by the node containing the
-   * searched point.
-   *
-   * @param  {object}  point The searched point (x, y).
-   * @param  {object}  quad  The searched quad.
-   * @return {array}         An array of elements contained in the relevant
-   *                         node.
-   */
-  function _quadRetrievePoint(point, quad) {
-    if (quad.level < quad.maxLevel) {
-      var index = _quadIndex(point, quad.bounds);
-
-      // If node does not exist we return an empty list
-      if (quad.nodes[index] !== undefined) {
-        return _quadRetrievePoint(point, quad.nodes[index]);
-      }
-      else {
-        return [];
-      }
-    }
-    else {
-      return quad.elements;
-    }
-  }
-
-  /**
-   * Recursively retrieve every elements contained within an rectangular area
-   * that may or may not be axis-aligned.
-   *
-   * @param  {object|array} rectData       The searched area defined either by
-   *                                       an array of four corners (x, y) in
-   *                                       the case of a non-axis-aligned
-   *                                       rectangle or an object with two top
-   *                                       points (x1, y1), (x2, y2) and height.
-   * @param  {object}       quad           The searched quad.
-   * @param  {function}     collisionFunc  The collision function used to search
-   *                                       for node indexes.
-   * @param  {array?}       els            The retrieved elements.
-   * @return {array}                       An array of elements contained in the
-   *                                       area.
-   */
-  function _quadRetrieveArea(rectData, quad, collisionFunc, els) {
-    els = els || {};
-
-    if (quad.level < quad.maxLevel) {
-      var indexes = collisionFunc(rectData, quad.corners);
-
-      for (var i = 0, l = indexes.length; i < l; i++)
-        if (quad.nodes[indexes[i]] !== undefined)
-          _quadRetrieveArea(
-            rectData,
-            quad.nodes[indexes[i]],
-            collisionFunc,
-            els
-          );
-    } else
-      for (var j = 0, m = quad.elements.length; j < m; j++)
-        if (els[quad.elements[j].id] === undefined)
-          els[quad.elements[j].id] = quad.elements[j];
-
-    return els;
-  }
-
-  /**
-   * Creates the quadtree object itself.
-   *
-   * @param  {object}   bounds       The boundaries of the quad defined by an
-   *                                 origin (x, y), width and heigth.
-   * @param  {integer}  level        The level of the quad in the tree.
-   * @param  {integer}  maxElements  The max number of element in a leaf node.
-   * @param  {integer}  maxLevel     The max recursion level of the tree.
-   * @return {object}                The quadtree object.
-   */
-  function _quadTree(bounds, level, maxElements, maxLevel) {
-    return {
-      level: level || 0,
-      bounds: bounds,
-      corners: _geom.splitSquare(bounds),
-      maxElements: maxElements || 20,
-      maxLevel: maxLevel || 4,
-      elements: [],
-      nodes: []
-    };
-  }
-
-
-  /**
-   * Sigma Quad Constructor
-   * ----------------------
-   *
-   * The quad API as exposed to sigma.
-   */
-
-  /**
-   * The quad core that will become the sigma interface with the quadtree.
-   *
-   * property {object} _tree  Property holding the quadtree object.
-   * property {object} _geom  Exposition of the _geom namespace for testing.
-   * property {object} _cache Cache for the area method.
-   */
-  var quad = function() {
-    this._geom = _geom;
-    this._tree = null;
-    this._cache = {
-      query: false,
-      result: false
-    };
-  };
-
-  /**
-   * Index a graph by inserting its nodes into the quadtree.
-   *
-   * @param  {array}  nodes   An array of nodes to index.
-   * @param  {object} params  An object of parameters with at least the quad
-   *                          bounds.
-   * @return {object}         The quadtree object.
-   *
-   * Parameters:
-   * ----------
-   * bounds:      {object}   boundaries of the quad defined by its origin (x, y)
-   *                         width and heigth.
-   * prefix:      {string?}  a prefix for node geometric attributes.
-   * maxElements: {integer?} the max number of elements in a leaf node.
-   * maxLevel:    {integer?} the max recursion level of the tree.
-   */
-  quad.prototype.index = function(nodes, params) {
-
-    // Enforcing presence of boundaries
-    if (!params.bounds)
-      throw 'sigma.classes.quad.index: bounds information not given.';
-
-    // Prefix
-    var prefix = params.prefix || '';
-
-    // Building the tree
-    this._tree = _quadTree(
-      params.bounds,
-      0,
-      params.maxElements,
-      params.maxLevel
-    );
-
-    // Inserting graph nodes into the tree
-    for (var i = 0, l = nodes.length; i < l; i++) {
-
-      // Inserting node
-      _quadInsert(
-        nodes[i],
-        _geom.pointToSquare({
-          x: nodes[i][prefix + 'x'],
-          y: nodes[i][prefix + 'y'],
-          size: nodes[i][prefix + 'size']
-        }),
-        this._tree
-      );
-    }
+    /**
+     * This method kills contexts and other attributes.
+     */
+    sigma.renderers.canvas.prototype.kill = function () {
+        var k,
+            captor;
+
+        // Kill captors:
+        while ((captor = this.captors.pop()))
+            captor.kill();
+        delete this.captors;
+
+        // Kill contexts:
+        for (k in this.domElements) {
+            this.domElements[k].parentNode.removeChild(this.domElements[k]);
+            delete this.domElements[k];
+            delete this.contexts[k];
+        }
+        delete this.domElements;
+        delete this.contexts;
+    };
 
-    // Reset cache:
-    this._cache = {
-      query: false,
-      result: false
-    };
-
-    // remove?
-    return this._tree;
-  };
-
-  /**
-   * Retrieve every graph nodes held by the quadtree node containing the
-   * searched point.
-   *
-   * @param  {number} x of the point.
-   * @param  {number} y of the point.
-   * @return {array}  An array of nodes retrieved.
-   */
-  quad.prototype.point = function(x, y) {
-    return this._tree ?
-      _quadRetrievePoint({x: x, y: y}, this._tree) || [] :
-      [];
-  };
-
-  /**
-   * Retrieve every graph nodes within a rectangular area. The methods keep the
-   * last area queried in cache for optimization reason and will act differently
-   * for the same reason if the area is axis-aligned or not.
-   *
-   * @param  {object} A rectangle defined by two top points (x1, y1), (x2, y2)
-   *                  and height.
-   * @return {array}  An array of nodes retrieved.
-   */
-  quad.prototype.area = function(rect) {
-    var serialized = JSON.stringify(rect),
-        collisionFunc,
-        rectData;
-
-    // Returning cache?
-    if (this._cache.query === serialized)
-      return this._cache.result;
-
-    // Axis aligned ?
-    if (_geom.isAxisAligned(rect)) {
-      collisionFunc = _quadIndexes;
-      rectData = _geom.axisAlignedTopPoints(rect);
-    }
-    else {
-      collisionFunc = _quadCollision;
-      rectData = _geom.rectangleCorners(rect);
-    }
 
-    // Retrieving nodes
-    var nodes = this._tree ?
-      _quadRetrieveArea(
-        rectData,
-        this._tree,
-        collisionFunc
-      ) :
-      [];
-
-    // Object to array
-    var nodesArray = [];
-    for (var i in nodes)
-      nodesArray.push(nodes[i]);
-
-    // Caching
-    this._cache.query = serialized;
-    this._cache.result = nodesArray;
-
-    return nodesArray;
-  };
-
-
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof this.sigma !== 'undefined') {
-    this.sigma.classes = this.sigma.classes || {};
-    this.sigma.classes.quad = quad;
-  } else if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = quad;
-    exports.quad = quad;
-  } else
-    this.quad = quad;
+    /**
+     * The labels, nodes and edges renderers are stored in the three following
+     * objects. When an element is drawn, its type will be checked and if a
+     * renderer with the same name exists, it will be used. If not found, the
+     * default renderer will be used instead.
+     *
+     * They are stored in different files, in the "./canvas" folder.
+     */
+    sigma.utils.pkg('sigma.canvas.nodes');
+    sigma.utils.pkg('sigma.canvas.edges');
+    sigma.utils.pkg('sigma.canvas.labels');
 }).call(this);
 
-;(function(undefined) {
-  'use strict';
-
-  /**
-   * Sigma Quadtree Module for edges
-   * ===============================
-   *
-   * Author: Sébastien Heymann,
-   *   from the quad of Guillaume Plique (Yomguithereal)
-   * Version: 0.2
-   */
+;(function (undefined) {
+    'use strict';
 
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-
-  /**
-   * Quad Geometric Operations
-   * -------------------------
-   *
-   * A useful batch of geometric operations used by the quadtree.
-   */
-
-  var _geom = {
+    // Initialize packages:
+    sigma.utils.pkg('sigma.renderers');
 
     /**
-     * Transforms a graph node with x, y and size into an
-     * axis-aligned square.
+     * This function is the constructor of the canvas sigma's renderer.
      *
-     * @param  {object} A graph node with at least a point (x, y) and a size.
-     * @return {object} A square: two points (x1, y1), (x2, y2) and height.
+     * @param  {sigma.classes.graph}            graph    The graph to render.
+     * @param  {sigma.classes.camera}           camera   The camera.
+     * @param  {configurable}           settings The sigma instance settings
+     *                                           function.
+     * @param  {object}                 object   The options object.
+     * @return {sigma.renderers.canvas}          The renderer instance.
      */
-    pointToSquare: function(n) {
-      return {
-        x1: n.x - n.size,
-        y1: n.y - n.size,
-        x2: n.x + n.size,
-        y2: n.y - n.size,
-        height: n.size * 2
-      };
-    },
+    sigma.renderers.webgl = function (graph, camera, settings, options) {
+        if (typeof options !== 'object')
+            throw 'sigma.renderers.webgl: Wrong arguments.';
 
-    /**
-     * Transforms a graph edge with x1, y1, x2, y2 and size into an
-     * axis-aligned square.
-     *
-     * @param  {object} A graph edge with at least two points
-     *                  (x1, y1), (x2, y2) and a size.
-     * @return {object} A square: two points (x1, y1), (x2, y2) and height.
-     */
-    lineToSquare: function(e) {
-      if (e.y1 < e.y2) {
-        // (e.x1, e.y1) on top
-        if (e.x1 < e.x2) {
-          // (e.x1, e.y1) on left
-          return {
-            x1: e.x1 - e.size,
-            y1: e.y1 - e.size,
-            x2: e.x2 + e.size,
-            y2: e.y1 - e.size,
-            height: e.y2 - e.y1 + e.size * 2
-          };
-        }
-        // (e.x1, e.y1) on right
-        return {
-          x1: e.x2 - e.size,
-          y1: e.y1 - e.size,
-          x2: e.x1 + e.size,
-          y2: e.y1 - e.size,
-          height: e.y2 - e.y1 + e.size * 2
-        };
-      }
+        if (!(options.container instanceof HTMLElement))
+            throw 'Container not found.';
 
-      // (e.x2, e.y2) on top
-      if (e.x1 < e.x2) {
-        // (e.x1, e.y1) on left
-        return {
-          x1: e.x1 - e.size,
-          y1: e.y2 - e.size,
-          x2: e.x2 + e.size,
-          y2: e.y2 - e.size,
-          height: e.y1 - e.y2 + e.size * 2
-        };
-      }
-      // (e.x2, e.y2) on right
-      return {
-        x1: e.x2 - e.size,
-        y1: e.y2 - e.size,
-        x2: e.x1 + e.size,
-        y2: e.y2 - e.size,
-        height: e.y1 - e.y2 + e.size * 2
-      };
-    },
-
-    /**
-     * Transforms a graph edge of type 'curve' with x1, y1, x2, y2,
-     * control point and size into an axis-aligned square.
-     *
-     * @param  {object} e  A graph edge with at least two points
-     *                     (x1, y1), (x2, y2) and a size.
-     * @param  {object} cp A control point (x,y).
-     * @return {object}    A square: two points (x1, y1), (x2, y2) and height.
-     */
-    quadraticCurveToSquare: function(e, cp) {
-      var pt = sigma.utils.getPointOnQuadraticCurve(
-        0.5,
-        e.x1,
-        e.y1,
-        e.x2,
-        e.y2,
-        cp.x,
-        cp.y
-      );
-
-      // Bounding box of the two points and the point at the middle of the
-      // curve:
-      var minX = Math.min(e.x1, e.x2, pt.x),
-          maxX = Math.max(e.x1, e.x2, pt.x),
-          minY = Math.min(e.y1, e.y2, pt.y),
-          maxY = Math.max(e.y1, e.y2, pt.y);
-
-      return {
-        x1: minX - e.size,
-        y1: minY - e.size,
-        x2: maxX + e.size,
-        y2: minY - e.size,
-        height: maxY - minY + e.size * 2
-      };
-    },
-
-    /**
-     * Transforms a graph self loop into an axis-aligned square.
-     *
-     * @param  {object} n A graph node with a point (x, y) and a size.
-     * @return {object}   A square: two points (x1, y1), (x2, y2) and height.
-     */
-    selfLoopToSquare: function(n) {
-      // Fitting to the curve is too costly, we compute a larger bounding box
-      // using the control points:
-      var cp = sigma.utils.getSelfLoopControlPoints(n.x, n.y, n.size);
-
-      // Bounding box of the point and the two control points:
-      var minX = Math.min(n.x, cp.x1, cp.x2),
-          maxX = Math.max(n.x, cp.x1, cp.x2),
-          minY = Math.min(n.y, cp.y1, cp.y2),
-          maxY = Math.max(n.y, cp.y1, cp.y2);
-
-      return {
-        x1: minX - n.size,
-        y1: minY - n.size,
-        x2: maxX + n.size,
-        y2: minY - n.size,
-        height: maxY - minY + n.size * 2
-      };
-    },
-
-    /**
-     * Checks whether a rectangle is axis-aligned.
-     *
-     * @param  {object}  A rectangle defined by two points
-     *                   (x1, y1) and (x2, y2).
-     * @return {boolean} True if the rectangle is axis-aligned.
-     */
-    isAxisAligned: function(r) {
-      return r.x1 === r.x2 || r.y1 === r.y2;
-    },
-
-    /**
-     * Compute top points of an axis-aligned rectangle. This is useful in
-     * cases when the rectangle has been rotated (left, right or bottom up) and
-     * later operations need to know the top points.
-     *
-     * @param  {object} An axis-aligned rectangle defined by two points
-     *                  (x1, y1), (x2, y2) and height.
-     * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height.
-     */
-    axisAlignedTopPoints: function(r) {
-
-      // Basic
-      if (r.y1 === r.y2 && r.x1 < r.x2)
-        return r;
-
-      // Rotated to right
-      if (r.x1 === r.x2 && r.y2 > r.y1)
-        return {
-          x1: r.x1 - r.height, y1: r.y1,
-          x2: r.x1, y2: r.y1,
-          height: r.height
-        };
+        var k,
+            i,
+            l,
+            a,
+            fn,
+            _self = this;
 
-      // Rotated to left
-      if (r.x1 === r.x2 && r.y2 < r.y1)
-        return {
-          x1: r.x1, y1: r.y2,
-          x2: r.x2 + r.height, y2: r.y2,
-          height: r.height
-        };
+        sigma.classes.dispatcher.extend(this);
 
-      // Bottom's up
-      return {
-        x1: r.x2, y1: r.y1 - r.height,
-        x2: r.x1, y2: r.y1 - r.height,
-        height: r.height
-      };
-    },
+        // Conrad related attributes:
+        this.jobs = {};
 
-    /**
-     * Get coordinates of a rectangle's lower left corner from its top points.
-     *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @return {object} Coordinates of the corner (x, y).
-     */
-    lowerLeftCoor: function(r) {
-      var width = (
-        Math.sqrt(
-          Math.pow(r.x2 - r.x1, 2) +
-          Math.pow(r.y2 - r.y1, 2)
-        )
-      );
-
-      return {
-        x: r.x1 - (r.y2 - r.y1) * r.height / width,
-        y: r.y1 + (r.x2 - r.x1) * r.height / width
-      };
-    },
-
-    /**
-     * Get coordinates of a rectangle's lower right corner from its top points
-     * and its lower left corner.
-     *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @param  {object} A corner's coordinates (x, y).
-     * @return {object} Coordinates of the corner (x, y).
-     */
-    lowerRightCoor: function(r, llc) {
-      return {
-        x: llc.x - r.x1 + r.x2,
-        y: llc.y - r.y1 + r.y2
-      };
-    },
-
-    /**
-     * Get the coordinates of all the corners of a rectangle from its top point.
-     *
-     * @param  {object} A rectangle defined by two points (x1, y1) and (x2, y2).
-     * @return {array}  An array of the four corners' coordinates (x, y).
-     */
-    rectangleCorners: function(r) {
-      var llc = this.lowerLeftCoor(r),
-          lrc = this.lowerRightCoor(r, llc);
-
-      return [
-        {x: r.x1, y: r.y1},
-        {x: r.x2, y: r.y2},
-        {x: llc.x, y: llc.y},
-        {x: lrc.x, y: lrc.y}
-      ];
-    },
-
-    /**
-     * Split a square defined by its boundaries into four.
-     *
-     * @param  {object} Boundaries of the square (x, y, width, height).
-     * @return {array}  An array containing the four new squares, themselves
-     *                  defined by an array of their four corners (x, y).
-     */
-    splitSquare: function(b) {
-      return [
-        [
-          {x: b.x, y: b.y},
-          {x: b.x + b.width / 2, y: b.y},
-          {x: b.x, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2}
-        ],
-        [
-          {x: b.x + b.width / 2, y: b.y},
-          {x: b.x + b.width, y: b.y},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x + b.width, y: b.y + b.height / 2}
-        ],
-        [
-          {x: b.x, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x, y: b.y + b.height},
-          {x: b.x + b.width / 2, y: b.y + b.height}
-        ],
-        [
-          {x: b.x + b.width / 2, y: b.y + b.height / 2},
-          {x: b.x + b.width, y: b.y + b.height / 2},
-          {x: b.x + b.width / 2, y: b.y + b.height},
-          {x: b.x + b.width, y: b.y + b.height}
-        ]
-      ];
-    },
-
-    /**
-     * Compute the four axis between corners of rectangle A and corners of
-     * rectangle B. This is needed later to check an eventual collision.
-     *
-     * @param  {array} An array of rectangle A's four corners (x, y).
-     * @param  {array} An array of rectangle B's four corners (x, y).
-     * @return {array} An array of four axis defined by their coordinates (x,y).
-     */
-    axis: function(c1, c2) {
-      return [
-        {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y},
-        {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y},
-        {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y},
-        {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y}
-      ];
-    },
-
-    /**
-     * Project a rectangle's corner on an axis.
-     *
-     * @param  {object} Coordinates of a corner (x, y).
-     * @param  {object} Coordinates of an axis (x, y).
-     * @return {object} The projection defined by coordinates (x, y).
-     */
-    projection: function(c, a) {
-      var l = (
-        (c.x * a.x + c.y * a.y) /
-        (Math.pow(a.x, 2) + Math.pow(a.y, 2))
-      );
-
-      return {
-        x: l * a.x,
-        y: l * a.y
-      };
-    },
-
-    /**
-     * Check whether two rectangles collide on one particular axis.
-     *
-     * @param  {object}   An axis' coordinates (x, y).
-     * @param  {array}    Rectangle A's corners.
-     * @param  {array}    Rectangle B's corners.
-     * @return {boolean}  True if the rectangles collide on the axis.
-     */
-    axisCollision: function(a, c1, c2) {
-      var sc1 = [],
-          sc2 = [];
-
-      for (var ci = 0; ci < 4; ci++) {
-        var p1 = this.projection(c1[ci], a),
-            p2 = this.projection(c2[ci], a);
-
-        sc1.push(p1.x * a.x + p1.y * a.y);
-        sc2.push(p2.x * a.x + p2.y * a.y);
-      }
-
-      var maxc1 = Math.max.apply(Math, sc1),
-          maxc2 = Math.max.apply(Math, sc2),
-          minc1 = Math.min.apply(Math, sc1),
-          minc2 = Math.min.apply(Math, sc2);
-
-      return (minc2 <= maxc1 && maxc2 >= minc1);
-    },
-
-    /**
-     * Check whether two rectangles collide on each one of their four axis. If
-     * all axis collide, then the two rectangles do collide on the plane.
-     *
-     * @param  {array}    Rectangle A's corners.
-     * @param  {array}    Rectangle B's corners.
-     * @return {boolean}  True if the rectangles collide.
-     */
-    collision: function(c1, c2) {
-      var axis = this.axis(c1, c2),
-          col = true;
-
-      for (var i = 0; i < 4; i++)
-        col = col && this.axisCollision(axis[i], c1, c2);
-
-      return col;
-    }
-  };
-
-
-  /**
-   * Quad Functions
-   * ------------
-   *
-   * The Quadtree functions themselves.
-   * For each of those functions, we consider that in a splitted quad, the
-   * index of each node is the following:
-   * 0: top left
-   * 1: top right
-   * 2: bottom left
-   * 3: bottom right
-   *
-   * Moreover, the hereafter quad's philosophy is to consider that if an element
-   * collides with more than one nodes, this element belongs to each of the
-   * nodes it collides with where other would let it lie on a higher node.
-   */
-
-  /**
-   * Get the index of the node containing the point in the quad
-   *
-   * @param  {object}  point      A point defined by coordinates (x, y).
-   * @param  {object}  quadBounds Boundaries of the quad (x, y, width, heigth).
-   * @return {integer}            The index of the node containing the point.
-   */
-  function _quadIndex(point, quadBounds) {
-    var xmp = quadBounds.x + quadBounds.width / 2,
-        ymp = quadBounds.y + quadBounds.height / 2,
-        top = (point.y < ymp),
-        left = (point.x < xmp);
-
-    if (top) {
-      if (left)
-        return 0;
-      else
-        return 1;
-    }
-    else {
-      if (left)
-        return 2;
-      else
-        return 3;
-    }
-  }
-
-  /**
-   * Get a list of indexes of nodes containing an axis-aligned rectangle
-   *
-   * @param  {object}  rectangle   A rectangle defined by two points (x1, y1),
-   *                               (x2, y2) and height.
-   * @param  {array}   quadCorners An array of the quad nodes' corners.
-   * @return {array}               An array of indexes containing one to
-   *                               four integers.
-   */
-  function _quadIndexes(rectangle, quadCorners) {
-    var indexes = [];
-
-    // Iterating through quads
-    for (var i = 0; i < 4; i++)
-      if ((rectangle.x2 >= quadCorners[i][0].x) &&
-          (rectangle.x1 <= quadCorners[i][1].x) &&
-          (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) &&
-          (rectangle.y1 <= quadCorners[i][2].y))
-        indexes.push(i);
-
-    return indexes;
-  }
-
-  /**
-   * Get a list of indexes of nodes containing a non-axis-aligned rectangle
-   *
-   * @param  {array}  corners      An array containing each corner of the
-   *                               rectangle defined by its coordinates (x, y).
-   * @param  {array}  quadCorners  An array of the quad nodes' corners.
-   * @return {array}               An array of indexes containing one to
-   *                               four integers.
-   */
-  function _quadCollision(corners, quadCorners) {
-    var indexes = [];
-
-    // Iterating through quads
-    for (var i = 0; i < 4; i++)
-      if (_geom.collision(corners, quadCorners[i]))
-        indexes.push(i);
-
-    return indexes;
-  }
-
-  /**
-   * Subdivide a quad by creating a node at a precise index. The function does
-   * not generate all four nodes not to potentially create unused nodes.
-   *
-   * @param  {integer}  index The index of the node to create.
-   * @param  {object}   quad  The quad object to subdivide.
-   * @return {object}         A new quad representing the node created.
-   */
-  function _quadSubdivide(index, quad) {
-    var next = quad.level + 1,
-        subw = Math.round(quad.bounds.width / 2),
-        subh = Math.round(quad.bounds.height / 2),
-        qx = Math.round(quad.bounds.x),
-        qy = Math.round(quad.bounds.y),
-        x,
-        y;
-
-    switch (index) {
-      case 0:
-        x = qx;
-        y = qy;
-        break;
-      case 1:
-        x = qx + subw;
-        y = qy;
-        break;
-      case 2:
-        x = qx;
-        y = qy + subh;
-        break;
-      case 3:
-        x = qx + subw;
-        y = qy + subh;
-        break;
-    }
+        Object.defineProperty(this, 'conradId', {
+            value: sigma.utils.id()
+        });
 
-    return _quadTree(
-      {x: x, y: y, width: subw, height: subh},
-      next,
-      quad.maxElements,
-      quad.maxLevel
-    );
-  }
-
-  /**
-   * Recursively insert an element into the quadtree. Only points
-   * with size, i.e. axis-aligned squares, may be inserted with this
-   * method.
-   *
-   * @param  {object}  el         The element to insert in the quadtree.
-   * @param  {object}  sizedPoint A sized point defined by two top points
-   *                              (x1, y1), (x2, y2) and height.
-   * @param  {object}  quad       The quad in which to insert the element.
-   * @return {undefined}          The function does not return anything.
-   */
-  function _quadInsert(el, sizedPoint, quad) {
-    if (quad.level < quad.maxLevel) {
-
-      // Searching appropriate quads
-      var indexes = _quadIndexes(sizedPoint, quad.corners);
-
-      // Iterating
-      for (var i = 0, l = indexes.length; i < l; i++) {
-
-        // Subdividing if necessary
-        if (quad.nodes[indexes[i]] === undefined)
-          quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad);
-
-        // Recursion
-        _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]);
-      }
-    }
-    else {
+        // Initialize main attributes:
+        this.graph = graph;
+        this.camera = camera;
+        this.contexts = {};
+        this.domElements = {};
+        this.options = options;
+        this.container = this.options.container;
+        this.settings = (
+            typeof options.settings === 'object' &&
+            options.settings
+        ) ?
+            settings.embedObjects(options.settings) :
+            settings;
+
+        // Find the prefix:
+        this.options.prefix = this.camera.readPrefix;
+
+        // Initialize programs hash
+        Object.defineProperty(this, 'nodePrograms', {
+            value: {}
+        });
+        Object.defineProperty(this, 'edgePrograms', {
+            value: {}
+        });
+        Object.defineProperty(this, 'nodeFloatArrays', {
+            value: {}
+        });
+        Object.defineProperty(this, 'edgeFloatArrays', {
+            value: {}
+        });
+        Object.defineProperty(this, 'edgeIndicesArrays', {
+            value: {}
+        });
 
-      // Pushing the element in a leaf node
-      quad.elements.push(el);
-    }
-  }
-
-  /**
-   * Recursively retrieve every elements held by the node containing the
-   * searched point.
-   *
-   * @param  {object}  point The searched point (x, y).
-   * @param  {object}  quad  The searched quad.
-   * @return {array}         An array of elements contained in the relevant
-   *                         node.
-   */
-  function _quadRetrievePoint(point, quad) {
-    if (quad.level < quad.maxLevel) {
-      var index = _quadIndex(point, quad.bounds);
-
-      // If node does not exist we return an empty list
-      if (quad.nodes[index] !== undefined) {
-        return _quadRetrievePoint(point, quad.nodes[index]);
-      }
-      else {
-        return [];
-      }
-    }
-    else {
-      return quad.elements;
-    }
-  }
-
-  /**
-   * Recursively retrieve every elements contained within an rectangular area
-   * that may or may not be axis-aligned.
-   *
-   * @param  {object|array} rectData       The searched area defined either by
-   *                                       an array of four corners (x, y) in
-   *                                       the case of a non-axis-aligned
-   *                                       rectangle or an object with two top
-   *                                       points (x1, y1), (x2, y2) and height.
-   * @param  {object}       quad           The searched quad.
-   * @param  {function}     collisionFunc  The collision function used to search
-   *                                       for node indexes.
-   * @param  {array?}       els            The retrieved elements.
-   * @return {array}                       An array of elements contained in the
-   *                                       area.
-   */
-  function _quadRetrieveArea(rectData, quad, collisionFunc, els) {
-    els = els || {};
-
-    if (quad.level < quad.maxLevel) {
-      var indexes = collisionFunc(rectData, quad.corners);
-
-      for (var i = 0, l = indexes.length; i < l; i++)
-        if (quad.nodes[indexes[i]] !== undefined)
-          _quadRetrieveArea(
-            rectData,
-            quad.nodes[indexes[i]],
-            collisionFunc,
-            els
-          );
-    } else
-      for (var j = 0, m = quad.elements.length; j < m; j++)
-        if (els[quad.elements[j].id] === undefined)
-          els[quad.elements[j].id] = quad.elements[j];
-
-    return els;
-  }
-
-  /**
-   * Creates the quadtree object itself.
-   *
-   * @param  {object}   bounds       The boundaries of the quad defined by an
-   *                                 origin (x, y), width and heigth.
-   * @param  {integer}  level        The level of the quad in the tree.
-   * @param  {integer}  maxElements  The max number of element in a leaf node.
-   * @param  {integer}  maxLevel     The max recursion level of the tree.
-   * @return {object}                The quadtree object.
-   */
-  function _quadTree(bounds, level, maxElements, maxLevel) {
-    return {
-      level: level || 0,
-      bounds: bounds,
-      corners: _geom.splitSquare(bounds),
-      maxElements: maxElements || 40,
-      maxLevel: maxLevel || 8,
-      elements: [],
-      nodes: []
-    };
-  }
-
-
-  /**
-   * Sigma Quad Constructor
-   * ----------------------
-   *
-   * The edgequad API as exposed to sigma.
-   */
-
-  /**
-   * The edgequad core that will become the sigma interface with the quadtree.
-   *
-   * property {object} _tree     Property holding the quadtree object.
-   * property {object} _geom     Exposition of the _geom namespace for testing.
-   * property {object} _cache    Cache for the area method.
-   * property {boolean} _enabled Can index and retreive elements.
-   */
-  var edgequad = function() {
-    this._geom = _geom;
-    this._tree = null;
-    this._cache = {
-      query: false,
-      result: false
-    };
-    this._enabled = true;
-  };
-
-  /**
-   * Index a graph by inserting its edges into the quadtree.
-   *
-   * @param  {object} graph   A graph instance.
-   * @param  {object} params  An object of parameters with at least the quad
-   *                          bounds.
-   * @return {object}         The quadtree object.
-   *
-   * Parameters:
-   * ----------
-   * bounds:      {object}   boundaries of the quad defined by its origin (x, y)
-   *                         width and heigth.
-   * prefix:      {string?}  a prefix for edge geometric attributes.
-   * maxElements: {integer?} the max number of elements in a leaf node.
-   * maxLevel:    {integer?} the max recursion level of the tree.
-   */
-  edgequad.prototype.index = function(graph, params) {
-    if (!this._enabled)
-      return this._tree;
-
-    // Enforcing presence of boundaries
-    if (!params.bounds)
-      throw 'sigma.classes.edgequad.index: bounds information not given.';
-
-    // Prefix
-    var prefix = params.prefix || '',
-        cp,
-        source,
-        target,
-        n,
-        e;
-
-    // Building the tree
-    this._tree = _quadTree(
-      params.bounds,
-      0,
-      params.maxElements,
-      params.maxLevel
-    );
-
-    var edges = graph.edges();
-
-    // Inserting graph edges into the tree
-    for (var i = 0, l = edges.length; i < l; i++) {
-      source = graph.nodes(edges[i].source);
-      target = graph.nodes(edges[i].target);
-      e = {
-        x1: source[prefix + 'x'],
-        y1: source[prefix + 'y'],
-        x2: target[prefix + 'x'],
-        y2: target[prefix + 'y'],
-        size: edges[i][prefix + 'size'] || 0
-      };
-
-      // Inserting edge
-      if (edges[i].type === 'curve' || edges[i].type === 'curvedArrow') {
-        if (source.id === target.id) {
-          n = {
-            x: source[prefix + 'x'],
-            y: source[prefix + 'y'],
-            size: source[prefix + 'size'] || 0
-          };
-          _quadInsert(
-            edges[i],
-            _geom.selfLoopToSquare(n),
-            this._tree);
+        // Initialize the DOM elements:
+        if (this.settings(options, 'batchEdgesDrawing')) {
+            this.initDOM('canvas', 'edges', true);
+            this.initDOM('canvas', 'nodes', true);
+        } else {
+            this.initDOM('canvas', 'scene', true);
+            this.contexts.nodes = this.contexts.scene;
+            this.contexts.edges = this.contexts.scene;
         }
-        else {
-          cp = sigma.utils.getQuadraticControlPoint(e.x1, e.y1, e.x2, e.y2);
-          _quadInsert(
-            edges[i],
-            _geom.quadraticCurveToSquare(e, cp),
-            this._tree);
-        }
-      }
-      else {
-        _quadInsert(
-          edges[i],
-          _geom.lineToSquare(e),
-          this._tree);
-      }
-    }
 
-    // Reset cache:
-    this._cache = {
-      query: false,
-      result: false
-    };
-
-    // remove?
-    return this._tree;
-  };
-
-  /**
-   * Retrieve every graph edges held by the quadtree node containing the
-   * searched point.
-   *
-   * @param  {number} x of the point.
-   * @param  {number} y of the point.
-   * @return {array}  An array of edges retrieved.
-   */
-  edgequad.prototype.point = function(x, y) {
-    if (!this._enabled)
-      return [];
-
-    return this._tree ?
-      _quadRetrievePoint({x: x, y: y}, this._tree) || [] :
-      [];
-  };
-
-  /**
-   * Retrieve every graph edges within a rectangular area. The methods keep the
-   * last area queried in cache for optimization reason and will act differently
-   * for the same reason if the area is axis-aligned or not.
-   *
-   * @param  {object} A rectangle defined by two top points (x1, y1), (x2, y2)
-   *                  and height.
-   * @return {array}  An array of edges retrieved.
-   */
-  edgequad.prototype.area = function(rect) {
-    if (!this._enabled)
-      return [];
-
-    var serialized = JSON.stringify(rect),
-        collisionFunc,
-        rectData;
-
-    // Returning cache?
-    if (this._cache.query === serialized)
-      return this._cache.result;
-
-    // Axis aligned ?
-    if (_geom.isAxisAligned(rect)) {
-      collisionFunc = _quadIndexes;
-      rectData = _geom.axisAlignedTopPoints(rect);
-    }
-    else {
-      collisionFunc = _quadCollision;
-      rectData = _geom.rectangleCorners(rect);
-    }
-
-    // Retrieving edges
-    var edges = this._tree ?
-      _quadRetrieveArea(
-        rectData,
-        this._tree,
-        collisionFunc
-      ) :
-      [];
-
-    // Object to array
-    var edgesArray = [];
-    for (var i in edges)
-      edgesArray.push(edges[i]);
-
-    // Caching
-    this._cache.query = serialized;
-    this._cache.result = edgesArray;
-
-    return edgesArray;
-  };
-
-
-  /**
-   * EXPORT:
-   * *******
-   */
-  if (typeof this.sigma !== 'undefined') {
-    this.sigma.classes = this.sigma.classes || {};
-    this.sigma.classes.edgequad = edgequad;
-  } else if (typeof exports !== 'undefined') {
-    if (typeof module !== 'undefined' && module.exports)
-      exports = module.exports = edgequad;
-    exports.edgequad = edgequad;
-  } else
-    this.edgequad = edgequad;
-}).call(this);
+        this.initDOM('canvas', 'labels');
+        this.initDOM('canvas', 'mouse');
+        this.contexts.hover = this.contexts.mouse;
+
+        // Initialize captors:
+        this.captors = [];
+        a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
+        for (i = 0, l = a.length; i < l; i++) {
+            fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
+            this.captors.push(
+                new fn(
+                    this.domElements.mouse,
+                    this.camera,
+                    this.settings
+                )
+            );
+        }
 
-;(function(undefined) {
-  'use strict';
+        // Deal with sigma events:
+        sigma.misc.bindEvents.call(this, this.camera.prefix);
+        sigma.misc.drawHovers.call(this, this.camera.prefix);
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
+        this.resize();
+    };
 
-  // Initialize packages:
-  sigma.utils.pkg('sigma.captors');
 
-  /**
-   * The user inputs default captor. It deals with mouse events, keyboards
-   * events and touch events.
-   *
-   * @param  {DOMElement}   target   The DOM element where the listeners will be
-   *                                 bound.
-   * @param  {camera}       camera   The camera related to the target.
-   * @param  {configurable} settings The settings function.
-   * @return {sigma.captor}          The fresh new captor instance.
-   */
-  sigma.captors.mouse = function(target, camera, settings) {
-    var _self = this,
-        _target = target,
-        _camera = camera,
-        _settings = settings,
+    /**
+     * This method will generate the nodes and edges float arrays. This step is
+     * separated from the "render" method, because to keep WebGL efficient, since
+     * all the camera and middlewares are modelised as matrices and they do not
+     * require the float arrays to be regenerated.
+     *
+     * Basically, when the user moves the camera or applies some specific linear
+     * transformations, this process step will be skipped, and the "render"
+     * method will efficiently refresh the rendering.
+     *
+     * And when the user modifies the graph colors or positions (applying a new
+     * layout or filtering the colors, for instance), this "process" step will be
+     * required to regenerate the float arrays.
+     *
+     * @return {sigma.renderers.webgl} Returns the instance itself.
+     */
+    sigma.renderers.webgl.prototype.process = function () {
+        var a,
+            i,
+            l,
+            k,
+            type,
+            renderer,
+            graph = this.graph,
+            options = sigma.utils.extend(options, this.options),
+            defaultEdgeType = this.settings(options, 'defaultEdgeType'),
+            defaultNodeType = this.settings(options, 'defaultNodeType');
+
+        // Empty float arrays:
+        for (k in this.nodeFloatArrays)
+            delete this.nodeFloatArrays[k];
+
+        for (k in this.edgeFloatArrays)
+            delete this.edgeFloatArrays[k];
+
+        for (k in this.edgeIndicesArrays)
+            delete this.edgeIndicesArrays[k];
+
+        // Sort edges and nodes per types:
+        for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
+            type = a[i].type || defaultEdgeType;
+            k = (type && sigma.webgl.edges[type]) ? type : 'def';
+
+            if (!this.edgeFloatArrays[k])
+                this.edgeFloatArrays[k] = {
+                    edges: []
+                };
+
+            this.edgeFloatArrays[k].edges.push(a[i]);
+        }
 
-        // CAMERA MANAGEMENT:
-        // ******************
-        // The camera position when the user starts dragging:
-        _startCameraX,
-        _startCameraY,
-        _startCameraAngle,
+        for (a = graph.nodes(), i = 0, l = a.length; i < l; i++) {
+            type = a[i].type || defaultNodeType;
+            k = (type && sigma.webgl.nodes[type]) ? type : 'def';
 
-        // The latest stage position:
-        _lastCameraX,
-        _lastCameraY,
-        _lastCameraAngle,
-        _lastCameraRatio,
+            if (!this.nodeFloatArrays[k])
+                this.nodeFloatArrays[k] = {
+                    nodes: []
+                };
 
-        // MOUSE MANAGEMENT:
-        // *****************
-        // The mouse position when the user starts dragging:
-        _startMouseX,
-        _startMouseY,
+            this.nodeFloatArrays[k].nodes.push(a[i]);
+        }
 
-        _isMouseDown,
-        _isMoving,
-        _hasDragged,
-        _downStartTime,
-        _movingTimeoutId;
+        // Push edges:
+        for (k in this.edgeFloatArrays) {
+            renderer = sigma.webgl.edges[k];
+            a = this.edgeFloatArrays[k].edges;
 
-    sigma.classes.dispatcher.extend(this);
+            // Creating the necessary arrays
+            this.edgeFloatArrays[k].array = new Float32Array(
+                a.length * renderer.POINTS * renderer.ATTRIBUTES
+            );
 
-    sigma.utils.doubleClick(_target, 'click', _doubleClickHandler);
-    _target.addEventListener('DOMMouseScroll', _wheelHandler, false);
-    _target.addEventListener('mousewheel', _wheelHandler, false);
-    _target.addEventListener('mousemove', _moveHandler, false);
-    _target.addEventListener('mousedown', _downHandler, false);
-    _target.addEventListener('click', _clickHandler, false);
-    _target.addEventListener('mouseout', _outHandler, false);
-    document.addEventListener('mouseup', _upHandler, false);
+            for (i = 0, l = a.length; i < l; i++) {
 
+                // Just check that the edge and both its extremities are visible:
+                if (
+                    !a[i].hidden && !graph.nodes(a[i].source).hidden && !graph.nodes(a[i].target).hidden
+                )
+                    renderer.addEdge(
+                        a[i],
+                        graph.nodes(a[i].source),
+                        graph.nodes(a[i].target),
+                        this.edgeFloatArrays[k].array,
+                        i * renderer.POINTS * renderer.ATTRIBUTES,
+                        options.prefix,
+                        this.settings
+                    );
+            }
 
+            if (typeof renderer.computeIndices === 'function')
+                this.edgeIndicesArrays[k] = renderer.computeIndices(
+                    this.edgeFloatArrays[k].array
+                );
+        }
 
+        // Push nodes:
+        for (k in this.nodeFloatArrays) {
+            renderer = sigma.webgl.nodes[k];
+            a = this.nodeFloatArrays[k].nodes;
 
-    /**
-     * This method unbinds every handlers that makes the captor work.
-     */
-    this.kill = function() {
-      sigma.utils.unbindDoubleClick(_target, 'click');
-      _target.removeEventListener('DOMMouseScroll', _wheelHandler);
-      _target.removeEventListener('mousewheel', _wheelHandler);
-      _target.removeEventListener('mousemove', _moveHandler);
-      _target.removeEventListener('mousedown', _downHandler);
-      _target.removeEventListener('click', _clickHandler);
-      _target.removeEventListener('mouseout', _outHandler);
-      document.removeEventListener('mouseup', _upHandler);
-    };
+            // Creating the necessary arrays
+            this.nodeFloatArrays[k].array = new Float32Array(
+                a.length * renderer.POINTS * renderer.ATTRIBUTES
+            );
 
+            for (i = 0, l = a.length; i < l; i++) {
+                if (!this.nodeFloatArrays[k].array)
+                    this.nodeFloatArrays[k].array = new Float32Array(
+                        a.length * renderer.POINTS * renderer.ATTRIBUTES
+                    );
 
+                // Just check that the edge and both its extremities are visible:
+                if (
+                    !a[i].hidden
+                )
+                    renderer.addNode(
+                        a[i],
+                        this.nodeFloatArrays[k].array,
+                        i * renderer.POINTS * renderer.ATTRIBUTES,
+                        options.prefix,
+                        this.settings
+                    );
+            }
+        }
 
+        return this;
+    };
 
-    // MOUSE EVENTS:
-    // *************
 
     /**
-     * The handler listening to the 'move' mouse event. It will effectively
-     * drag the graph.
+     * This method renders the graph. It basically calls each program (and
+     * generate them if they do not exist yet) to render nodes and edges, batched
+     * per renderer.
+     *
+     * As in the canvas renderer, it is possible to display edges, nodes and / or
+     * labels in batches, to make the whole thing way more scalable.
      *
-     * @param {event} e A mouse event.
+     * @param  {?object}               params Eventually an object of options.
+     * @return {sigma.renderers.webgl}        Returns the instance itself.
      */
-    function _moveHandler(e) {
-      var x,
-          y,
-          pos;
+    sigma.renderers.webgl.prototype.render = function (params) {
+        var a,
+            i,
+            l,
+            k,
+            o,
+            program,
+            renderer,
+            self = this,
+            graph = this.graph,
+            nodesGl = this.contexts.nodes,
+            edgesGl = this.contexts.edges,
+            matrix = this.camera.getMatrix(),
+            options = sigma.utils.extend(params, this.options),
+            drawLabels = this.settings(options, 'drawLabels'),
+            drawEdges = this.settings(options, 'drawEdges'),
+            drawNodes = this.settings(options, 'drawNodes');
+
+        // Call the resize function:
+        this.resize(false);
+
+        // Check the 'hideEdgesOnMove' setting:
+        if (this.settings(options, 'hideEdgesOnMove'))
+            if (this.camera.isAnimated || this.camera.isMoving)
+                drawEdges = false;
+
+        // Clear canvases:
+        this.clear();
+
+        // Translate matrix to [width/2, height/2]:
+        matrix = sigma.utils.matrices.multiply(
+            matrix,
+            sigma.utils.matrices.translation(this.width / 2, this.height / 2)
+        );
+
+        // Kill running jobs:
+        for (k in this.jobs)
+            if (conrad.hasJob(k))
+                conrad.killJob(k);
+
+        if (drawEdges) {
+            if (this.settings(options, 'batchEdgesDrawing'))
+                (function () {
+                    var a,
+                        k,
+                        i,
+                        id,
+                        job,
+                        arr,
+                        end,
+                        start,
+                        indices,
+                        renderer,
+                        batchSize,
+                        currentProgram;
+
+                    id = 'edges_' + this.conradId;
+                    batchSize = this.settings(options, 'webglEdgesBatchSize');
+                    a = Object.keys(this.edgeFloatArrays);
+
+                    if (!a.length)
+                        return;
+                    i = 0;
+                    renderer = sigma.webgl.edges[a[i]];
+                    arr = this.edgeFloatArrays[a[i]].array;
+                    indices = this.edgeIndicesArrays[a[i]];
+                    start = 0;
+                    end = Math.min(
+                        start + batchSize * renderer.POINTS,
+                        arr.length / renderer.ATTRIBUTES
+                    );
+
+                    job = function () {
+                        // Check program:
+                        if (!this.edgePrograms[a[i]])
+                            this.edgePrograms[a[i]] = renderer.initProgram(edgesGl);
+
+                        if (start < end) {
+                            edgesGl.useProgram(this.edgePrograms[a[i]]);
+                            renderer.render(
+                                edgesGl,
+                                this.edgePrograms[a[i]],
+                                arr,
+                                {
+                                    settings: this.settings,
+                                    matrix: matrix,
+                                    width: this.width,
+                                    height: this.height,
+                                    ratio: this.camera.ratio,
+                                    scalingRatio: this.settings(
+                                        options,
+                                        'webglOversamplingRatio'
+                                    ),
+                                    start: start,
+                                    count: end - start,
+                                    indicesData: indices
+                                }
+                            );
+                        }
+
+                        // Catch job's end:
+                        if (
+                            end >= arr.length / renderer.ATTRIBUTES &&
+                            i === a.length - 1
+                        ) {
+                            delete this.jobs[id];
+                            return false;
+                        }
+
+                        if (end >= arr.length / renderer.ATTRIBUTES) {
+                            i++;
+                            arr = this.edgeFloatArrays[a[i]].array;
+                            renderer = sigma.webgl.edges[a[i]];
+                            start = 0;
+                            end = Math.min(
+                                start + batchSize * renderer.POINTS,
+                                arr.length / renderer.ATTRIBUTES
+                            );
+                        } else {
+                            start = end;
+                            end = Math.min(
+                                start + batchSize * renderer.POINTS,
+                                arr.length / renderer.ATTRIBUTES
+                            );
+                        }
+
+                        return true;
+                    };
+
+                    this.jobs[id] = job;
+                    conrad.addJob(id, job.bind(this));
+                }).call(this);
+            else {
+                for (k in this.edgeFloatArrays) {
+                    renderer = sigma.webgl.edges[k];
+
+                    // Check program:
+                    if (!this.edgePrograms[k])
+                        this.edgePrograms[k] = renderer.initProgram(edgesGl);
+
+                    // Render
+                    if (this.edgeFloatArrays[k]) {
+                        edgesGl.useProgram(this.edgePrograms[k]);
+                        renderer.render(
+                            edgesGl,
+                            this.edgePrograms[k],
+                            this.edgeFloatArrays[k].array,
+                            {
+                                settings: this.settings,
+                                matrix: matrix,
+                                width: this.width,
+                                height: this.height,
+                                ratio: this.camera.ratio,
+                                scalingRatio: this.settings(options, 'webglOversamplingRatio'),
+                                indicesData: this.edgeIndicesArrays[k]
+                            }
+                        );
+                    }
+                }
+            }
+        }
 
-      // Dispatch event:
-      if (_settings('mouseEnabled')) {
-        _self.dispatchEvent('mousemove',
-          sigma.utils.mouseCoords(e));
+        if (drawNodes) {
+            // Enable blending:
+            nodesGl.blendFunc(nodesGl.SRC_ALPHA, nodesGl.ONE_MINUS_SRC_ALPHA);
+            nodesGl.enable(nodesGl.BLEND);
+
+            for (k in this.nodeFloatArrays) {
+                renderer = sigma.webgl.nodes[k];
+
+                // Check program:
+                if (!this.nodePrograms[k])
+                    this.nodePrograms[k] = renderer.initProgram(nodesGl);
+
+                // Render
+                if (this.nodeFloatArrays[k]) {
+                    nodesGl.useProgram(this.nodePrograms[k]);
+                    renderer.render(
+                        nodesGl,
+                        this.nodePrograms[k],
+                        this.nodeFloatArrays[k].array,
+                        {
+                            settings: this.settings,
+                            matrix: matrix,
+                            width: this.width,
+                            height: this.height,
+                            ratio: this.camera.ratio,
+                            scalingRatio: this.settings(options, 'webglOversamplingRatio')
+                        }
+                    );
+                }
+            }
+        }
+
+        if (drawLabels) {
+            a = this.camera.quadtree.area(
+                this.camera.getRectangle(this.width, this.height)
+            );
+
+            // Apply camera view to these nodes:
+            this.camera.applyView(
+                undefined,
+                undefined,
+                {
+                    nodes: a,
+                    edges: [],
+                    width: this.width,
+                    height: this.height
+                }
+            );
 
-        if (_isMouseDown) {
-          _isMoving = true;
-          _hasDragged = true;
+            o = function (key) {
+                return self.settings({
+                    prefix: self.camera.prefix
+                }, key);
+            };
+
+            for (i = 0, l = a.length; i < l; i++)
+                if (!a[i].hidden)
+                    (
+                        sigma.canvas.labels[
+                        a[i].type ||
+                        this.settings(options, 'defaultNodeType')
+                            ] || sigma.canvas.labels.def
+                    )(a[i], this.contexts.labels, o);
+        }
 
-          if (_movingTimeoutId)
-            clearTimeout(_movingTimeoutId);
+        this.dispatchEvent('render');
 
-          _movingTimeoutId = setTimeout(function() {
-            _isMoving = false;
-          }, _settings('dragTimeout'));
+        return this;
+    };
 
-          sigma.misc.animation.killAll(_camera);
 
-          _camera.isMoving = true;
-          pos = _camera.cameraPosition(
-            sigma.utils.getX(e) - _startMouseX,
-            sigma.utils.getY(e) - _startMouseY,
-            true
-          );
+    /**
+     * This method creates a DOM element of the specified type, switches its
+     * position to "absolute", references it to the domElements attribute, and
+     * finally appends it to the container.
+     *
+     * @param  {string}   tag   The label tag.
+     * @param  {string}   id    The id of the element (to store it in
+     *                          "domElements").
+     * @param  {?boolean} webgl Will init the WebGL context if true.
+     */
+    sigma.renderers.webgl.prototype.initDOM = function (tag, id, webgl) {
+        var gl,
+            dom = document.createElement(tag),
+            self = this;
 
-          x = _startCameraX - pos.x;
-          y = _startCameraY - pos.y;
+        dom.style.position = 'absolute';
+        dom.setAttribute('class', 'sigma-' + id);
 
-          if (x !== _camera.x || y !== _camera.y) {
-            _lastCameraX = _camera.x;
-            _lastCameraY = _camera.y;
+        this.domElements[id] = dom;
+        this.container.appendChild(dom);
 
-            _camera.goTo({
-              x: x,
-              y: y
+        if (tag.toLowerCase() === 'canvas') {
+            this.contexts[id] = dom.getContext(webgl ? 'experimental-webgl' : '2d', {
+                preserveDrawingBuffer: true
             });
-          }
 
-          if (e.preventDefault)
-            e.preventDefault();
-          else
-            e.returnValue = false;
+            // Adding webgl context loss listeners
+            if (webgl) {
+                dom.addEventListener('webglcontextlost', function (e) {
+                    e.preventDefault();
+                }, false);
 
-          e.stopPropagation();
-          return false;
+                dom.addEventListener('webglcontextrestored', function (e) {
+                    self.render();
+                }, false);
+            }
         }
-      }
-    }
+    };
 
     /**
-     * The handler listening to the 'up' mouse event. It will stop dragging the
-     * graph.
+     * This method resizes each DOM elements in the container and stores the new
+     * dimensions. Then, it renders the graph.
      *
-     * @param {event} e A mouse event.
+     * @param  {?number}               width  The new width of the container.
+     * @param  {?number}               height The new height of the container.
+     * @return {sigma.renderers.webgl}        Returns the instance itself.
      */
-    function _upHandler(e) {
-      if (_settings('mouseEnabled') && _isMouseDown) {
-        _isMouseDown = false;
-        if (_movingTimeoutId)
-          clearTimeout(_movingTimeoutId);
-
-        _camera.isMoving = false;
-
-        var x = sigma.utils.getX(e),
-            y = sigma.utils.getY(e);
+    sigma.renderers.webgl.prototype.resize = function (w, h) {
+        var k,
+            oldWidth = this.width,
+            oldHeight = this.height,
+            pixelRatio = sigma.utils.getPixelRatio();
+
+        if (w !== undefined && h !== undefined) {
+            this.width = w;
+            this.height = h;
+        } else {
+            this.width = this.container.offsetWidth;
+            this.height = this.container.offsetHeight;
+
+            w = this.width;
+            h = this.height;
+        }
 
-        if (_isMoving) {
-          sigma.misc.animation.killAll(_camera);
-          sigma.misc.animation.camera(
-            _camera,
-            {
-              x: _camera.x +
-                _settings('mouseInertiaRatio') * (_camera.x - _lastCameraX),
-              y: _camera.y +
-                _settings('mouseInertiaRatio') * (_camera.y - _lastCameraY)
-            },
-            {
-              easing: 'quadraticOut',
-              duration: _settings('mouseInertiaDuration')
+        if (oldWidth !== this.width || oldHeight !== this.height) {
+            for (k in this.domElements) {
+                this.domElements[k].style.width = w + 'px';
+                this.domElements[k].style.height = h + 'px';
+
+                if (this.domElements[k].tagName.toLowerCase() === 'canvas') {
+                    // If simple 2D canvas:
+                    if (this.contexts[k] && this.contexts[k].scale) {
+                        this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px');
+                        this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px');
+
+                        if (pixelRatio !== 1)
+                            this.contexts[k].scale(pixelRatio, pixelRatio);
+                    } else {
+                        this.domElements[k].setAttribute(
+                            'width',
+                            (w * this.settings('webglOversamplingRatio')) + 'px'
+                        );
+                        this.domElements[k].setAttribute(
+                            'height',
+                            (h * this.settings('webglOversamplingRatio')) + 'px'
+                        );
+                    }
+                }
             }
-          );
-        } else if (
-          _startMouseX !== x ||
-          _startMouseY !== y
-        )
-          _camera.goTo({
-            x: _camera.x,
-            y: _camera.y
-          });
+        }
 
-        _self.dispatchEvent('mouseup',
-          sigma.utils.mouseCoords(e));
+        // Scale:
+        for (k in this.contexts)
+            if (this.contexts[k] && this.contexts[k].viewport)
+                this.contexts[k].viewport(
+                    0,
+                    0,
+                    this.width * this.settings('webglOversamplingRatio'),
+                    this.height * this.settings('webglOversamplingRatio')
+                );
 
-        // Update _isMoving flag:
-        _isMoving = false;
-      }
-    }
+        return this;
+    };
 
     /**
-     * The handler listening to the 'down' mouse event. It will start observing
-     * the mouse position for dragging the graph.
+     * This method clears each canvas.
      *
-     * @param {event} e A mouse event.
+     * @return {sigma.renderers.webgl} Returns the instance itself.
      */
-    function _downHandler(e) {
-      if (_settings('mouseEnabled')) {
-        _startCameraX = _camera.x;
-        _startCameraY = _camera.y;
-
-        _lastCameraX = _camera.x;
-        _lastCameraY = _camera.y;
-
-        _startMouseX = sigma.utils.getX(e);
-        _startMouseY = sigma.utils.getY(e);
-
-        _hasDragged = false;
-        _downStartTime = (new Date()).getTime();
+    sigma.renderers.webgl.prototype.clear = function () {
+        this.contexts.labels.clearRect(0, 0, this.width, this.height);
+        this.contexts.nodes.clear(this.contexts.nodes.COLOR_BUFFER_BIT);
+        this.contexts.edges.clear(this.contexts.edges.COLOR_BUFFER_BIT);
 
-        switch (e.which) {
-          case 2:
-            // Middle mouse button pressed
-            // Do nothing.
-            break;
-          case 3:
-            // Right mouse button pressed
-            _self.dispatchEvent('rightclick',
-              sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
-            break;
-          // case 1:
-          default:
-            // Left mouse button pressed
-            _isMouseDown = true;
+        return this;
+    };
 
-            _self.dispatchEvent('mousedown',
-              sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
+    /**
+     * This method kills contexts and other attributes.
+     */
+    sigma.renderers.webgl.prototype.kill = function () {
+        var k,
+            captor;
+
+        // Kill captors:
+        while ((captor = this.captors.pop()))
+            captor.kill();
+        delete this.captors;
+
+        // Kill contexts:
+        for (k in this.domElements) {
+            this.domElements[k].parentNode.removeChild(this.domElements[k]);
+            delete this.domElements[k];
+            delete this.contexts[k];
         }
-      }
-    }
+        delete this.domElements;
+        delete this.contexts;
+    };
+
 
     /**
-     * The handler listening to the 'out' mouse event. It will just redispatch
-     * the event.
+     * The object "sigma.webgl.nodes" contains the different WebGL node
+     * renderers. The default one draw nodes as discs. Here are the attributes
+     * any node renderer must have:
      *
-     * @param {event} e A mouse event.
+     * {number}   POINTS      The number of points required to draw a node.
+     * {number}   ATTRIBUTES  The number of attributes needed to draw one point.
+     * {function} addNode     A function that adds a node to the data stack that
+     *                        will be given to the buffer. Here is the arguments:
+     *                        > {object}       node
+     *                        > {number}       index   The node index in the
+     *                                                 nodes array.
+     *                        > {Float32Array} data    The stack.
+     *                        > {object}       options Some options.
+     * {function} render      The function that will effectively render the nodes
+     *                        into the buffer.
+     *                        > {WebGLRenderingContext} gl
+     *                        > {WebGLProgram}          program
+     *                        > {Float32Array} data    The stack to give to the
+     *                                                 buffer.
+     *                        > {object}       params  An object containing some
+     *                                                 options, like width,
+     *                                                 height, the camera ratio.
+     * {function} initProgram The function that will initiate the program, with
+     *                        the relevant shaders and parameters. It must return
+     *                        the newly created program.
+     *
+     * Check sigma.webgl.nodes.def or sigma.webgl.nodes.fast to see how it
+     * works more precisely.
      */
-    function _outHandler(e) {
-      if (_settings('mouseEnabled'))
-        _self.dispatchEvent('mouseout');
-    }
+    sigma.utils.pkg('sigma.webgl.nodes');
+
 
     /**
-     * The handler listening to the 'click' mouse event. It will redispatch the
-     * click event, but with normalized X and Y coordinates.
+     * The object "sigma.webgl.edges" contains the different WebGL edge
+     * renderers. The default one draw edges as direct lines. Here are the
+     * attributes any edge renderer must have:
+     *
+     * {number}   POINTS      The number of points required to draw an edge.
+     * {number}   ATTRIBUTES  The number of attributes needed to draw one point.
+     * {function} addEdge     A function that adds an edge to the data stack that
+     *                        will be given to the buffer. Here is the arguments:
+     *                        > {object}       edge
+     *                        > {object}       source
+     *                        > {object}       target
+     *                        > {Float32Array} data    The stack.
+     *                        > {object}       options Some options.
+     * {function} render      The function that will effectively render the edges
+     *                        into the buffer.
+     *                        > {WebGLRenderingContext} gl
+     *                        > {WebGLProgram}          program
+     *                        > {Float32Array} data    The stack to give to the
+     *                                                 buffer.
+     *                        > {object}       params  An object containing some
+     *                                                 options, like width,
+     *                                                 height, the camera ratio.
+     * {function} initProgram The function that will initiate the program, with
+     *                        the relevant shaders and parameters. It must return
+     *                        the newly created program.
      *
-     * @param {event} e A mouse event.
+     * Check sigma.webgl.edges.def or sigma.webgl.edges.fast to see how it
+     * works more precisely.
      */
-    function _clickHandler(e) {
-      if (_settings('mouseEnabled')) {
-        var event = sigma.utils.mouseCoords(e);
-        event.isDragging =
-          (((new Date()).getTime() - _downStartTime) > 100) && _hasDragged;
-        _self.dispatchEvent('click', event);
-      }
+    sigma.utils.pkg('sigma.webgl.edges');
 
-      if (e.preventDefault)
-        e.preventDefault();
-      else
-        e.returnValue = false;
-
-      e.stopPropagation();
-      return false;
-    }
 
     /**
-     * The handler listening to the double click custom event. It will
-     * basically zoom into the graph.
+     * The object "sigma.canvas.labels" contains the different
+     * label renderers for the WebGL renderer. Since displaying texts in WebGL is
+     * definitely painful and since there a way less labels to display than nodes
+     * or edges, the default renderer simply renders them in a canvas.
      *
-     * @param {event} e A mouse event.
+     * A labels renderer is a simple function, taking as arguments the related
+     * node, the renderer and a settings function.
      */
-    function _doubleClickHandler(e) {
-      var pos,
-          ratio,
-          animation;
-
-      if (_settings('mouseEnabled')) {
-        ratio = 1 / _settings('doubleClickZoomingRatio');
-
-        _self.dispatchEvent('doubleclick',
-            sigma.utils.mouseCoords(e, _startMouseX, _startMouseY));
-
-        if (_settings('doubleClickEnabled')) {
-          pos = _camera.cameraPosition(
-            sigma.utils.getX(e) - sigma.utils.getCenter(e).x,
-            sigma.utils.getY(e) - sigma.utils.getCenter(e).y,
-            true
-          );
+    sigma.utils.pkg('sigma.canvas.labels');
+}).call(this);
 
-          animation = {
-            duration: _settings('doubleClickZoomDuration')
-          };
+;(function (undefined) {
+    'use strict';
 
-          sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
-        }
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-        if (e.preventDefault)
-          e.preventDefault();
-        else
-          e.returnValue = false;
+    if (typeof conrad === 'undefined')
+        throw 'conrad is not declared';
 
-        e.stopPropagation();
-        return false;
-      }
-    }
+    // Initialize packages:
+    sigma.utils.pkg('sigma.renderers');
 
     /**
-     * The handler listening to the 'wheel' mouse event. It will basically zoom
-     * in or not into the graph.
+     * This function is the constructor of the svg sigma's renderer.
      *
-     * @param {event} e A mouse event.
+     * @param  {sigma.classes.graph}            graph    The graph to render.
+     * @param  {sigma.classes.camera}           camera   The camera.
+     * @param  {configurable}           settings The sigma instance settings
+     *                                           function.
+     * @param  {object}                 object   The options object.
+     * @return {sigma.renderers.svg}             The renderer instance.
      */
-    function _wheelHandler(e) {
-      var pos,
-          ratio,
-          animation;
-
-      if (_settings('mouseEnabled') && _settings('mouseWheelEnabled')) {
-        ratio = sigma.utils.getDelta(e) > 0 ?
-          1 / _settings('zoomingRatio') :
-          _settings('zoomingRatio');
+    sigma.renderers.svg = function (graph, camera, settings, options) {
+        if (typeof options !== 'object')
+            throw 'sigma.renderers.svg: Wrong arguments.';
 
-        pos = _camera.cameraPosition(
-          sigma.utils.getX(e) - sigma.utils.getCenter(e).x,
-          sigma.utils.getY(e) - sigma.utils.getCenter(e).y,
-          true
-        );
+        if (!(options.container instanceof HTMLElement))
+            throw 'Container not found.';
 
-        animation = {
-          duration: _settings('mouseZoomDuration')
+        var i,
+            l,
+            a,
+            fn,
+            self = this;
+
+        sigma.classes.dispatcher.extend(this);
+
+        // Initialize main attributes:
+        this.graph = graph;
+        this.camera = camera;
+        this.domElements = {
+            graph: null,
+            groups: {},
+            nodes: {},
+            edges: {},
+            labels: {},
+            hovers: {}
         };
+        this.measurementCanvas = null;
+        this.options = options;
+        this.container = this.options.container;
+        this.settings = (
+            typeof options.settings === 'object' &&
+            options.settings
+        ) ?
+            settings.embedObjects(options.settings) :
+            settings;
+
+        // Is the renderer meant to be freestyle?
+        this.settings('freeStyle', !!this.options.freeStyle);
+
+        // SVG xmlns
+        this.settings('xmlns', 'http://www.w3.org/2000/svg');
+
+        // Indexes:
+        this.nodesOnScreen = [];
+        this.edgesOnScreen = [];
+
+        // Find the prefix:
+        this.options.prefix = 'renderer' + sigma.utils.id() + ':';
+
+        // Initialize the DOM elements
+        this.initDOM('svg');
+
+        // Initialize captors:
+        this.captors = [];
+        a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
+        for (i = 0, l = a.length; i < l; i++) {
+            fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
+            this.captors.push(
+                new fn(
+                    this.domElements.graph,
+                    this.camera,
+                    this.settings
+                )
+            );
+        }
 
-        sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
-
-        if (e.preventDefault)
-          e.preventDefault();
-        else
-          e.returnValue = false;
-
-        e.stopPropagation();
-        return false;
-      }
-    }
-  };
-}).call(this);
+        // Bind resize:
+        window.addEventListener('resize', function () {
+            self.resize();
+        });
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.captors');
-
-  /**
-   * The user inputs default captor. It deals with mouse events, keyboards
-   * events and touch events.
-   *
-   * @param  {DOMElement}   target   The DOM element where the listeners will be
-   *                                 bound.
-   * @param  {camera}       camera   The camera related to the target.
-   * @param  {configurable} settings The settings function.
-   * @return {sigma.captor}          The fresh new captor instance.
-   */
-  sigma.captors.touch = function(target, camera, settings) {
-    var _self = this,
-        _target = target,
-        _camera = camera,
-        _settings = settings,
-
-        // CAMERA MANAGEMENT:
-        // ******************
-        // The camera position when the user starts dragging:
-        _startCameraX,
-        _startCameraY,
-        _startCameraAngle,
-        _startCameraRatio,
-
-        // The latest stage position:
-        _lastCameraX,
-        _lastCameraY,
-        _lastCameraAngle,
-        _lastCameraRatio,
-
-        // TOUCH MANAGEMENT:
-        // *****************
-        // Touches that are down:
-        _downTouches = [],
-
-        _startTouchX0,
-        _startTouchY0,
-        _startTouchX1,
-        _startTouchY1,
-        _startTouchAngle,
-        _startTouchDistance,
-
-        _touchMode,
-
-        _isMoving,
-        _doubleTap,
-        _movingTimeoutId;
-
-    sigma.classes.dispatcher.extend(this);
-
-    sigma.utils.doubleClick(_target, 'touchstart', _doubleTapHandler);
-    _target.addEventListener('touchstart', _handleStart, false);
-    _target.addEventListener('touchend', _handleLeave, false);
-    _target.addEventListener('touchcancel', _handleLeave, false);
-    _target.addEventListener('touchleave', _handleLeave, false);
-    _target.addEventListener('touchmove', _handleMove, false);
-
-    function position(e) {
-      var offset = sigma.utils.getOffset(_target);
-
-      return {
-        x: e.pageX - offset.left,
-        y: e.pageY - offset.top
-      };
-    }
+        // Deal with sigma events:
+        // TODO: keep an option to override the DOM events?
+        sigma.misc.bindDOMEvents.call(this, this.domElements.graph);
+        this.bindHovers(this.options.prefix);
 
-    /**
-     * This method unbinds every handlers that makes the captor work.
-     */
-    this.kill = function() {
-      sigma.utils.unbindDoubleClick(_target, 'touchstart');
-      _target.addEventListener('touchstart', _handleStart);
-      _target.addEventListener('touchend', _handleLeave);
-      _target.addEventListener('touchcancel', _handleLeave);
-      _target.addEventListener('touchleave', _handleLeave);
-      _target.addEventListener('touchmove', _handleMove);
+        // Resize
+        this.resize(false);
     };
 
-    // TOUCH EVENTS:
-    // *************
     /**
-     * The handler listening to the 'touchstart' event. It will set the touch
-     * mode ("_touchMode") and start observing the user touch moves.
+     * This method renders the graph on the svg scene.
      *
-     * @param {event} e A touch event.
+     * @param  {?object}                options Eventually an object of options.
+     * @return {sigma.renderers.svg}            Returns the instance itself.
      */
-    function _handleStart(e) {
-      if (_settings('touchEnabled')) {
-        var x0,
-            x1,
-            y0,
-            y1,
-            pos0,
-            pos1;
-
-        _downTouches = e.touches;
-
-        switch (_downTouches.length) {
-          case 1:
-            _camera.isMoving = true;
-            _touchMode = 1;
-
-            _startCameraX = _camera.x;
-            _startCameraY = _camera.y;
-
-            _lastCameraX = _camera.x;
-            _lastCameraY = _camera.y;
-
-            pos0 = position(_downTouches[0]);
-            _startTouchX0 = pos0.x;
-            _startTouchY0 = pos0.y;
+    sigma.renderers.svg.prototype.render = function (options) {
+        options = options || {};
 
-            break;
-          case 2:
-            _camera.isMoving = true;
-            _touchMode = 2;
-
-            pos0 = position(_downTouches[0]);
-            pos1 = position(_downTouches[1]);
-            x0 = pos0.x;
-            y0 = pos0.y;
-            x1 = pos1.x;
-            y1 = pos1.y;
+        var a,
+            i,
+            k,
+            e,
+            l,
+            o,
+            source,
+            target,
+            start,
+            edges,
+            renderers,
+            subrenderers,
+            index = {},
+            graph = this.graph,
+            nodes = this.graph.nodes,
+            prefix = this.options.prefix || '',
+            drawEdges = this.settings(options, 'drawEdges'),
+            drawNodes = this.settings(options, 'drawNodes'),
+            drawLabels = this.settings(options, 'drawLabels'),
+            embedSettings = this.settings.embedObjects(options, {
+                prefix: this.options.prefix,
+                forceLabels: this.options.forceLabels
+            });
 
-            _lastCameraX = _camera.x;
-            _lastCameraY = _camera.y;
+        // Check the 'hideEdgesOnMove' setting:
+        if (this.settings(options, 'hideEdgesOnMove'))
+            if (this.camera.isAnimated || this.camera.isMoving)
+                drawEdges = false;
 
-            _startCameraAngle = _camera.angle;
-            _startCameraRatio = _camera.ratio;
+        // Apply the camera's view:
+        this.camera.applyView(
+            undefined,
+            this.options.prefix,
+            {
+                width: this.width,
+                height: this.height
+            }
+        );
 
-            _startCameraX = _camera.x;
-            _startCameraY = _camera.y;
+        // Hiding everything
+        // TODO: find a more sensible way to perform this operation
+        this.hideDOMElements(this.domElements.nodes);
+        this.hideDOMElements(this.domElements.edges);
+        this.hideDOMElements(this.domElements.labels);
 
-            _startTouchX0 = x0;
-            _startTouchY0 = y0;
-            _startTouchX1 = x1;
-            _startTouchY1 = y1;
+        // Find which nodes are on screen
+        this.edgesOnScreen = [];
+        this.nodesOnScreen = this.camera.quadtree.area(
+            this.camera.getRectangle(this.width, this.height)
+        );
 
-            _startTouchAngle = Math.atan2(
-              _startTouchY1 - _startTouchY0,
-              _startTouchX1 - _startTouchX0
-            );
-            _startTouchDistance = Math.sqrt(
-              (_startTouchY1 - _startTouchY0) *
-                (_startTouchY1 - _startTouchY0) +
-              (_startTouchX1 - _startTouchX0) *
-                (_startTouchX1 - _startTouchX0)
-            );
+        // Node index
+        for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
+            index[a[i].id] = a[i];
 
-            e.preventDefault();
-            return false;
+        // Find which edges are on screen
+        for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
+            o = a[i];
+            if (
+                (index[o.source] || index[o.target]) &&
+                (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden)
+            )
+                this.edgesOnScreen.push(o);
         }
-      }
-    }
 
-    /**
-     * The handler listening to the 'touchend', 'touchcancel' and 'touchleave'
-     * event. It will update the touch mode if there are still at least one
-     * finger, and stop dragging else.
-     *
-     * @param {event} e A touch event.
-     */
-    function _handleLeave(e) {
-      if (_settings('touchEnabled')) {
-        _downTouches = e.touches;
-        var inertiaRatio = _settings('touchInertiaRatio');
+        // Display nodes
+        //---------------
+        renderers = sigma.svg.nodes;
+        subrenderers = sigma.svg.labels;
+
+        //-- First we create the nodes which are not already created
+        if (drawNodes)
+            for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) {
+                if (!a[i].hidden && !this.domElements.nodes[a[i].id]) {
+
+                    // Node
+                    e = (renderers[a[i].type] || renderers.def).create(
+                        a[i],
+                        embedSettings
+                    );
+
+                    this.domElements.nodes[a[i].id] = e;
+                    this.domElements.groups.nodes.appendChild(e);
+
+                    // Label
+                    e = (subrenderers[a[i].type] || subrenderers.def).create(
+                        a[i],
+                        embedSettings
+                    );
+
+                    this.domElements.labels[a[i].id] = e;
+                    this.domElements.groups.labels.appendChild(e);
+                }
+            }
 
-        if (_movingTimeoutId) {
-          _isMoving = false;
-          clearTimeout(_movingTimeoutId);
-        }
+        //-- Second we update the nodes
+        if (drawNodes)
+            for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) {
 
-        switch (_touchMode) {
-          case 2:
-            if (e.touches.length === 1) {
-              _handleStart(e);
+                if (a[i].hidden)
+                    continue;
+
+                // Node
+                (renderers[a[i].type] || renderers.def).update(
+                    a[i],
+                    this.domElements.nodes[a[i].id],
+                    embedSettings
+                );
 
-              e.preventDefault();
-              break;
+                // Label
+                (subrenderers[a[i].type] || subrenderers.def).update(
+                    a[i],
+                    this.domElements.labels[a[i].id],
+                    embedSettings
+                );
             }
-            /* falls through */
-          case 1:
-            _camera.isMoving = false;
-            _self.dispatchEvent('stopDrag');
-
-            if (_isMoving) {
-              _doubleTap = false;
-              sigma.misc.animation.camera(
-                _camera,
-                {
-                  x: _camera.x +
-                    inertiaRatio * (_camera.x - _lastCameraX),
-                  y: _camera.y +
-                    inertiaRatio * (_camera.y - _lastCameraY)
-                },
-                {
-                  easing: 'quadraticOut',
-                  duration: _settings('touchInertiaDuration')
+
+        // Display edges
+        //---------------
+        renderers = sigma.svg.edges;
+
+        //-- First we create the edges which are not already created
+        if (drawEdges)
+            for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
+                if (!this.domElements.edges[a[i].id]) {
+                    source = nodes(a[i].source);
+                    target = nodes(a[i].target);
+
+                    e = (renderers[a[i].type] || renderers.def).create(
+                        a[i],
+                        source,
+                        target,
+                        embedSettings
+                    );
+
+                    this.domElements.edges[a[i].id] = e;
+                    this.domElements.groups.edges.appendChild(e);
                 }
-              );
             }
 
-            _isMoving = false;
-            _touchMode = 0;
-            break;
-        }
-      }
-    }
+        //-- Second we update the edges
+        if (drawEdges)
+            for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
+                source = nodes(a[i].source);
+                target = nodes(a[i].target);
+
+                (renderers[a[i].type] || renderers.def).update(
+                    a[i],
+                    this.domElements.edges[a[i].id],
+                    source,
+                    target,
+                    embedSettings
+                );
+            }
+
+        this.dispatchEvent('render');
+
+        return this;
+    };
 
     /**
-     * The handler listening to the 'touchmove' event. It will effectively drag
-     * the graph, and eventually zooms and turn it if the user is using two
-     * fingers.
+     * This method creates a DOM element of the specified type, switches its
+     * position to "absolute", references it to the domElements attribute, and
+     * finally appends it to the container.
      *
-     * @param {event} e A touch event.
+     * @param  {string} tag The label tag.
+     * @param  {string} id  The id of the element (to store it in "domElements").
      */
-    function _handleMove(e) {
-      if (!_doubleTap && _settings('touchEnabled')) {
-        var x0,
-            x1,
-            y0,
-            y1,
-            cos,
-            sin,
-            end,
-            pos0,
-            pos1,
-            diff,
-            start,
-            dAngle,
-            dRatio,
-            newStageX,
-            newStageY,
-            newStageRatio,
-            newStageAngle;
-
-        _downTouches = e.touches;
-        _isMoving = true;
-
-        if (_movingTimeoutId)
-          clearTimeout(_movingTimeoutId);
-
-        _movingTimeoutId = setTimeout(function() {
-          _isMoving = false;
-        }, _settings('dragTimeout'));
-
-        switch (_touchMode) {
-          case 1:
-            pos0 = position(_downTouches[0]);
-            x0 = pos0.x;
-            y0 = pos0.y;
-
-            diff = _camera.cameraPosition(
-              x0 - _startTouchX0,
-              y0 - _startTouchY0,
-              true
-            );
-
-            newStageX = _startCameraX - diff.x;
-            newStageY = _startCameraY - diff.y;
+    sigma.renderers.svg.prototype.initDOM = function (tag) {
+        var dom = document.createElementNS(this.settings('xmlns'), tag),
+            c = this.settings('classPrefix'),
+            g,
+            l,
+            i;
 
-            if (newStageX !== _camera.x || newStageY !== _camera.y) {
-              _lastCameraX = _camera.x;
-              _lastCameraY = _camera.y;
+        dom.style.position = 'absolute';
+        dom.setAttribute('class', c + '-svg');
 
-              _camera.goTo({
-                x: newStageX,
-                y: newStageY
-              });
+        // Setting SVG namespace
+        dom.setAttribute('xmlns', this.settings('xmlns'));
+        dom.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
+        dom.setAttribute('version', '1.1');
 
-              _self.dispatchEvent('mousemove',
-                sigma.utils.mouseCoords(e, pos0.x, pos0.y));
+        // Creating the measurement canvas
+        var canvas = document.createElement('canvas');
+        canvas.setAttribute('class', c + '-measurement-canvas');
 
-              _self.dispatchEvent('drag');
-            }
-            break;
-          case 2:
-            pos0 = position(_downTouches[0]);
-            pos1 = position(_downTouches[1]);
-            x0 = pos0.x;
-            y0 = pos0.y;
-            x1 = pos1.x;
-            y1 = pos1.y;
-
-            start = _camera.cameraPosition(
-              (_startTouchX0 + _startTouchX1) / 2 -
-                sigma.utils.getCenter(e).x,
-              (_startTouchY0 + _startTouchY1) / 2 -
-                sigma.utils.getCenter(e).y,
-              true
-            );
-            end = _camera.cameraPosition(
-              (x0 + x1) / 2 - sigma.utils.getCenter(e).x,
-              (y0 + y1) / 2 - sigma.utils.getCenter(e).y,
-              true
-            );
+        // Appending elements
+        this.domElements.graph = this.container.appendChild(dom);
 
-            dAngle = Math.atan2(y1 - y0, x1 - x0) - _startTouchAngle;
-            dRatio = Math.sqrt(
-              (y1 - y0) * (y1 - y0) + (x1 - x0) * (x1 - x0)
-            ) / _startTouchDistance;
-
-            // Translation:
-            x0 = start.x;
-            y0 = start.y;
-
-            // Homothetic transformation:
-            newStageRatio = _startCameraRatio / dRatio;
-            x0 = x0 * dRatio;
-            y0 = y0 * dRatio;
-
-            // Rotation:
-            newStageAngle = _startCameraAngle - dAngle;
-            cos = Math.cos(-dAngle);
-            sin = Math.sin(-dAngle);
-            x1 = x0 * cos + y0 * sin;
-            y1 = y0 * cos - x0 * sin;
-            x0 = x1;
-            y0 = y1;
-
-            // Finalize:
-            newStageX = x0 - end.x + _startCameraX;
-            newStageY = y0 - end.y + _startCameraY;
+        // Creating groups
+        var groups = ['edges', 'nodes', 'labels', 'hovers'];
+        for (i = 0, l = groups.length; i < l; i++) {
+            g = document.createElementNS(this.settings('xmlns'), 'g');
 
-            if (
-              newStageRatio !== _camera.ratio ||
-              newStageAngle !== _camera.angle ||
-              newStageX !== _camera.x ||
-              newStageY !== _camera.y
-            ) {
-              _lastCameraX = _camera.x;
-              _lastCameraY = _camera.y;
-              _lastCameraAngle = _camera.angle;
-              _lastCameraRatio = _camera.ratio;
-
-              _camera.goTo({
-                x: newStageX,
-                y: newStageY,
-                angle: newStageAngle,
-                ratio: newStageRatio
-              });
-
-              _self.dispatchEvent('drag');
-            }
+            g.setAttributeNS(null, 'id', c + '-group-' + groups[i]);
+            g.setAttributeNS(null, 'class', c + '-group');
 
-            break;
+            this.domElements.groups[groups[i]] =
+                this.domElements.graph.appendChild(g);
         }
 
-        e.preventDefault();
-        return false;
-      }
-    }
+        // Appending measurement canvas
+        this.container.appendChild(canvas);
+        this.measurementCanvas = canvas.getContext('2d');
+    };
 
     /**
-     * The handler listening to the double tap custom event. It will
-     * basically zoom into the graph.
+     * This method hides a batch of SVG DOM elements.
      *
-     * @param {event} e A touch event.
+     * @param  {array}                  elements  An array of elements to hide.
+     * @param  {object}                 renderer  The renderer to use.
+     * @return {sigma.renderers.svg}              Returns the instance itself.
      */
-    function _doubleTapHandler(e) {
-      var pos,
-          ratio,
-          animation;
+    sigma.renderers.svg.prototype.hideDOMElements = function (elements) {
+        var o,
+            i;
 
-      if (e.touches && e.touches.length === 1 && _settings('touchEnabled')) {
-        _doubleTap = true;
-
-        ratio = 1 / _settings('doubleClickZoomingRatio');
+        for (i in elements) {
+            o = elements[i];
+            sigma.svg.utils.hide(o);
+        }
 
-        pos = position(e.touches[0]);
-        _self.dispatchEvent('doubleclick',
-          sigma.utils.mouseCoords(e, pos.x, pos.y));
+        return this;
+    };
 
-        if (_settings('doubleClickEnabled')) {
-          pos = _camera.cameraPosition(
-            pos.x - sigma.utils.getCenter(e).x,
-            pos.y - sigma.utils.getCenter(e).y,
-            true
-          );
+    /**
+     * This method binds the hover events to the renderer.
+     *
+     * @param  {string} prefix The renderer prefix.
+     */
+    // TODO: add option about whether to display hovers or not
+    sigma.renderers.svg.prototype.bindHovers = function (prefix) {
+        var renderers = sigma.svg.hovers,
+            self = this,
+            hoveredNode;
+
+        function overNode(e) {
+            var node = e.data.node,
+                embedSettings = self.settings.embedObjects({
+                    prefix: prefix
+                });
+
+            if (!embedSettings('enableHovering'))
+                return;
+
+            var hover = (renderers[node.type] || renderers.def).create(
+                node,
+                self.domElements.nodes[node.id],
+                self.measurementCanvas,
+                embedSettings
+            );
 
-          animation = {
-            duration: _settings('doubleClickZoomDuration'),
-            onComplete: function() {
-              _doubleTap = false;
-            }
-          };
+            self.domElements.hovers[node.id] = hover;
 
-          sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation);
+            // Inserting the hover in the dom
+            self.domElements.groups.hovers.appendChild(hover);
+            hoveredNode = node;
         }
 
-        if (e.preventDefault)
-          e.preventDefault();
-        else
-          e.returnValue = false;
-
-        e.stopPropagation();
-        return false;
-      }
-    }
-  };
-}).call(this);
-
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  if (typeof conrad === 'undefined')
-    throw 'conrad is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.renderers');
-
-  /**
-   * This function is the constructor of the canvas sigma's renderer.
-   *
-   * @param  {sigma.classes.graph}            graph    The graph to render.
-   * @param  {sigma.classes.camera}           camera   The camera.
-   * @param  {configurable}           settings The sigma instance settings
-   *                                           function.
-   * @param  {object}                 object   The options object.
-   * @return {sigma.renderers.canvas}          The renderer instance.
-   */
-  sigma.renderers.canvas = function(graph, camera, settings, options) {
-    if (typeof options !== 'object')
-      throw 'sigma.renderers.canvas: Wrong arguments.';
-
-    if (!(options.container instanceof HTMLElement))
-      throw 'Container not found.';
-
-    var k,
-        i,
-        l,
-        a,
-        fn,
-        self = this;
-
-    sigma.classes.dispatcher.extend(this);
-
-    // Initialize main attributes:
-    Object.defineProperty(this, 'conradId', {
-      value: sigma.utils.id()
-    });
-    this.graph = graph;
-    this.camera = camera;
-    this.contexts = {};
-    this.domElements = {};
-    this.options = options;
-    this.container = this.options.container;
-    this.settings = (
-        typeof options.settings === 'object' &&
-        options.settings
-      ) ?
-        settings.embedObjects(options.settings) :
-        settings;
-
-    // Node indexes:
-    this.nodesOnScreen = [];
-    this.edgesOnScreen = [];
-
-    // Conrad related attributes:
-    this.jobs = {};
-
-    // Find the prefix:
-    this.options.prefix = 'renderer' + this.conradId + ':';
-
-    // Initialize the DOM elements:
-    if (
-      !this.settings('batchEdgesDrawing')
-    ) {
-      this.initDOM('canvas', 'scene');
-      this.contexts.edges = this.contexts.scene;
-      this.contexts.nodes = this.contexts.scene;
-      this.contexts.labels = this.contexts.scene;
-    } else {
-      this.initDOM('canvas', 'edges');
-      this.initDOM('canvas', 'scene');
-      this.contexts.nodes = this.contexts.scene;
-      this.contexts.labels = this.contexts.scene;
-    }
-
-    this.initDOM('canvas', 'mouse');
-    this.contexts.hover = this.contexts.mouse;
-
-    // Initialize captors:
-    this.captors = [];
-    a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
-    for (i = 0, l = a.length; i < l; i++) {
-      fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
-      this.captors.push(
-        new fn(
-          this.domElements.mouse,
-          this.camera,
-          this.settings
-        )
-      );
-    }
+        function outNode(e) {
+            var node = e.data.node,
+                embedSettings = self.settings.embedObjects({
+                    prefix: prefix
+                });
 
-    // Deal with sigma events:
-    sigma.misc.bindEvents.call(this, this.options.prefix);
-    sigma.misc.drawHovers.call(this, this.options.prefix);
-
-    this.resize(false);
-  };
-
-
-
-
-  /**
-   * This method renders the graph on the canvases.
-   *
-   * @param  {?object}                options Eventually an object of options.
-   * @return {sigma.renderers.canvas}         Returns the instance itself.
-   */
-  sigma.renderers.canvas.prototype.render = function(options) {
-    options = options || {};
-
-    var a,
-        i,
-        k,
-        l,
-        o,
-        id,
-        end,
-        job,
-        start,
-        edges,
-        renderers,
-        rendererType,
-        batchSize,
-        tempGCO,
-        index = {},
-        graph = this.graph,
-        nodes = this.graph.nodes,
-        prefix = this.options.prefix || '',
-        drawEdges = this.settings(options, 'drawEdges'),
-        drawNodes = this.settings(options, 'drawNodes'),
-        drawLabels = this.settings(options, 'drawLabels'),
-        drawEdgeLabels = this.settings(options, 'drawEdgeLabels'),
-        embedSettings = this.settings.embedObjects(options, {
-          prefix: this.options.prefix
-        });
+            if (!embedSettings('enableHovering'))
+                return;
 
-    // Call the resize function:
-    this.resize(false);
-
-    // Check the 'hideEdgesOnMove' setting:
-    if (this.settings(options, 'hideEdgesOnMove'))
-      if (this.camera.isAnimated || this.camera.isMoving)
-        drawEdges = false;
-
-    // Apply the camera's view:
-    this.camera.applyView(
-      undefined,
-      this.options.prefix,
-      {
-        width: this.width,
-        height: this.height
-      }
-    );
-
-    // Clear canvases:
-    this.clear();
-
-    // Kill running jobs:
-    for (k in this.jobs)
-      if (conrad.hasJob(k))
-        conrad.killJob(k);
-
-    // Find which nodes are on screen:
-    this.edgesOnScreen = [];
-    this.nodesOnScreen = this.camera.quadtree.area(
-      this.camera.getRectangle(this.width, this.height)
-    );
-
-    for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
-      index[a[i].id] = a[i];
-
-    // Draw edges:
-    // - If settings('batchEdgesDrawing') is true, the edges are displayed per
-    //   batches. If not, they are drawn in one frame.
-    if (drawEdges) {
-      // First, let's identify which edges to draw. To do this, we just keep
-      // every edges that have at least one extremity displayed according to
-      // the quadtree and the "hidden" attribute. We also do not keep hidden
-      // edges.
-      for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
-        o = a[i];
-        if (
-          (index[o.source] || index[o.target]) &&
-          (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden)
-        )
-          this.edgesOnScreen.push(o);
-      }
-
-      // If the "batchEdgesDrawing" settings is true, edges are batched:
-      if (this.settings(options, 'batchEdgesDrawing')) {
-        id = 'edges_' + this.conradId;
-        batchSize = embedSettings('canvasEdgesBatchSize');
-
-        edges = this.edgesOnScreen;
-        l = edges.length;
-
-        start = 0;
-        end = Math.min(edges.length, start + batchSize);
-
-        job = function() {
-          tempGCO = this.contexts.edges.globalCompositeOperation;
-          this.contexts.edges.globalCompositeOperation = 'destination-over';
-
-          renderers = sigma.canvas.edges;
-          for (i = start; i < end; i++) {
-            o = edges[i];
-            (renderers[
-              o.type || this.settings(options, 'defaultEdgeType')
-            ] || renderers.def)(
-              o,
-              graph.nodes(o.source),
-              graph.nodes(o.target),
-              this.contexts.edges,
-              embedSettings
+            // Deleting element
+            self.domElements.groups.hovers.removeChild(
+                self.domElements.hovers[node.id]
             );
-          }
-
-          // Draw edge labels:
-          if (drawEdgeLabels) {
-            renderers = sigma.canvas.edges.labels;
-            for (i = start; i < end; i++) {
-              o = edges[i];
-              if (!o.hidden)
-                (renderers[
-                  o.type || this.settings(options, 'defaultEdgeType')
-                ] || renderers.def)(
-                  o,
-                  graph.nodes(o.source),
-                  graph.nodes(o.target),
-                  this.contexts.labels,
-                  embedSettings
-                );
-            }
-          }
+            hoveredNode = null;
+            delete self.domElements.hovers[node.id];
 
-          // Restore original globalCompositeOperation:
-          this.contexts.edges.globalCompositeOperation = tempGCO;
+            // Reinstate
+            self.domElements.groups.nodes.appendChild(
+                self.domElements.nodes[node.id]
+            );
+        }
 
-          // Catch job's end:
-          if (end === edges.length) {
-            delete this.jobs[id];
-            return false;
-          }
+        // OPTIMIZE: perform a real update rather than a deletion
+        function update() {
+            if (!hoveredNode)
+                return;
 
-          start = end + 1;
-          end = Math.min(edges.length, start + batchSize);
-          return true;
-        };
+            var embedSettings = self.settings.embedObjects({
+                prefix: prefix
+            });
 
-        this.jobs[id] = job;
-        conrad.addJob(id, job.bind(this));
-
-      // If not, they are drawn in one frame:
-      } else {
-        renderers = sigma.canvas.edges;
-        for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
-          o = a[i];
-          (renderers[
-            o.type || this.settings(options, 'defaultEdgeType')
-          ] || renderers.def)(
-            o,
-            graph.nodes(o.source),
-            graph.nodes(o.target),
-            this.contexts.edges,
-            embedSettings
-          );
-        }
+            // Deleting element before update
+            self.domElements.groups.hovers.removeChild(
+                self.domElements.hovers[hoveredNode.id]
+            );
+            delete self.domElements.hovers[hoveredNode.id];
 
-        // Draw edge labels:
-        // - No batching
-        if (drawEdgeLabels) {
-          renderers = sigma.canvas.edges.labels;
-          for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++)
-            if (!a[i].hidden)
-              (renderers[
-                a[i].type || this.settings(options, 'defaultEdgeType')
-              ] || renderers.def)(
-                a[i],
-                graph.nodes(a[i].source),
-                graph.nodes(a[i].target),
-                this.contexts.labels,
+            var hover = (renderers[hoveredNode.type] || renderers.def).create(
+                hoveredNode,
+                self.domElements.nodes[hoveredNode.id],
+                self.measurementCanvas,
                 embedSettings
-              );
-        }
-      }
-    }
-
-    // Draw nodes:
-    // - No batching
-    if (drawNodes) {
-      renderers = sigma.canvas.nodes;
-      for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
-        if (!a[i].hidden)
-          (renderers[
-            a[i].type || this.settings(options, 'defaultNodeType')
-          ] || renderers.def)(
-            a[i],
-            this.contexts.nodes,
-            embedSettings
-          );
-    }
+            );
 
-    // Draw labels:
-    // - No batching
-    if (drawLabels) {
-      renderers = sigma.canvas.labels;
-      for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
-        if (!a[i].hidden)
-          (renderers[
-            a[i].type || this.settings(options, 'defaultNodeType')
-          ] || renderers.def)(
-            a[i],
-            this.contexts.labels,
-            embedSettings
-          );
-    }
+            self.domElements.hovers[hoveredNode.id] = hover;
 
-    this.dispatchEvent('render');
-
-    return this;
-  };
-
-  /**
-   * This method creates a DOM element of the specified type, switches its
-   * position to "absolute", references it to the domElements attribute, and
-   * finally appends it to the container.
-   *
-   * @param  {string} tag The label tag.
-   * @param  {string} id  The id of the element (to store it in "domElements").
-   */
-  sigma.renderers.canvas.prototype.initDOM = function(tag, id) {
-    var dom = document.createElement(tag);
-
-    dom.style.position = 'absolute';
-    dom.setAttribute('class', 'sigma-' + id);
-
-    this.domElements[id] = dom;
-    this.container.appendChild(dom);
-
-    if (tag.toLowerCase() === 'canvas')
-      this.contexts[id] = dom.getContext('2d');
-  };
-
-  /**
-   * This method resizes each DOM elements in the container and stores the new
-   * dimensions. Then, it renders the graph.
-   *
-   * @param  {?number}                width  The new width of the container.
-   * @param  {?number}                height The new height of the container.
-   * @return {sigma.renderers.canvas}        Returns the instance itself.
-   */
-  sigma.renderers.canvas.prototype.resize = function(w, h) {
-    var k,
-        oldWidth = this.width,
-        oldHeight = this.height,
-        pixelRatio = sigma.utils.getPixelRatio();
-
-    if (w !== undefined && h !== undefined) {
-      this.width = w;
-      this.height = h;
-    } else {
-      this.width = this.container.offsetWidth;
-      this.height = this.container.offsetHeight;
-
-      w = this.width;
-      h = this.height;
-    }
+            // Inserting the hover in the dom
+            self.domElements.groups.hovers.appendChild(hover);
+        }
 
-    if (oldWidth !== this.width || oldHeight !== this.height) {
-      for (k in this.domElements) {
-        this.domElements[k].style.width = w + 'px';
-        this.domElements[k].style.height = h + 'px';
+        // Binding events
+        this.bind('overNode', overNode);
+        this.bind('outNode', outNode);
 
-        if (this.domElements[k].tagName.toLowerCase() === 'canvas') {
-          this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px');
-          this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px');
+        // Update on render
+        this.bind('render', update);
+    };
 
-          if (pixelRatio !== 1)
-            this.contexts[k].scale(pixelRatio, pixelRatio);
+    /**
+     * This method resizes each DOM elements in the container and stores the new
+     * dimensions. Then, it renders the graph.
+     *
+     * @param  {?number}                width  The new width of the container.
+     * @param  {?number}                height The new height of the container.
+     * @return {sigma.renderers.svg}           Returns the instance itself.
+     */
+    sigma.renderers.svg.prototype.resize = function (w, h) {
+        var oldWidth = this.width,
+            oldHeight = this.height,
+            pixelRatio = 1;
+
+        if (w !== undefined && h !== undefined) {
+            this.width = w;
+            this.height = h;
+        } else {
+            this.width = this.container.offsetWidth;
+            this.height = this.container.offsetHeight;
+
+            w = this.width;
+            h = this.height;
         }
-      }
-    }
-
-    return this;
-  };
-
-  /**
-   * This method clears each canvas.
-   *
-   * @return {sigma.renderers.canvas} Returns the instance itself.
-   */
-  sigma.renderers.canvas.prototype.clear = function() {
-    for (var k in this.contexts) {
-      this.contexts[k].clearRect(0, 0, this.width, this.height);
-    }
 
-    return this;
-  };
-
-  /**
-   * This method kills contexts and other attributes.
-   */
-  sigma.renderers.canvas.prototype.kill = function() {
-    var k,
-        captor;
-
-    // Kill captors:
-    while ((captor = this.captors.pop()))
-      captor.kill();
-    delete this.captors;
-
-    // Kill contexts:
-    for (k in this.domElements) {
-      this.domElements[k].parentNode.removeChild(this.domElements[k]);
-      delete this.domElements[k];
-      delete this.contexts[k];
-    }
-    delete this.domElements;
-    delete this.contexts;
-  };
+        if (oldWidth !== this.width || oldHeight !== this.height) {
+            this.domElements.graph.style.width = w + 'px';
+            this.domElements.graph.style.height = h + 'px';
 
+            if (this.domElements.graph.tagName.toLowerCase() === 'svg') {
+                this.domElements.graph.setAttribute('width', (w * pixelRatio));
+                this.domElements.graph.setAttribute('height', (h * pixelRatio));
+            }
+        }
 
+        return this;
+    };
 
 
-  /**
-   * The labels, nodes and edges renderers are stored in the three following
-   * objects. When an element is drawn, its type will be checked and if a
-   * renderer with the same name exists, it will be used. If not found, the
-   * default renderer will be used instead.
-   *
-   * They are stored in different files, in the "./canvas" folder.
-   */
-  sigma.utils.pkg('sigma.canvas.nodes');
-  sigma.utils.pkg('sigma.canvas.edges');
-  sigma.utils.pkg('sigma.canvas.labels');
+    /**
+     * The labels, nodes and edges renderers are stored in the three following
+     * objects. When an element is drawn, its type will be checked and if a
+     * renderer with the same name exists, it will be used. If not found, the
+     * default renderer will be used instead.
+     *
+     * They are stored in different files, in the "./svg" folder.
+     */
+    sigma.utils.pkg('sigma.svg.nodes');
+    sigma.utils.pkg('sigma.svg.edges');
+    sigma.utils.pkg('sigma.svg.labels');
 }).call(this);
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.renderers');
-
-  /**
-   * This function is the constructor of the canvas sigma's renderer.
-   *
-   * @param  {sigma.classes.graph}            graph    The graph to render.
-   * @param  {sigma.classes.camera}           camera   The camera.
-   * @param  {configurable}           settings The sigma instance settings
-   *                                           function.
-   * @param  {object}                 object   The options object.
-   * @return {sigma.renderers.canvas}          The renderer instance.
-   */
-  sigma.renderers.webgl = function(graph, camera, settings, options) {
-    if (typeof options !== 'object')
-      throw 'sigma.renderers.webgl: Wrong arguments.';
-
-    if (!(options.container instanceof HTMLElement))
-      throw 'Container not found.';
-
-    var k,
-        i,
-        l,
-        a,
-        fn,
-        _self = this;
-
-    sigma.classes.dispatcher.extend(this);
-
-    // Conrad related attributes:
-    this.jobs = {};
-
-    Object.defineProperty(this, 'conradId', {
-      value: sigma.utils.id()
-    });
-
-    // Initialize main attributes:
-    this.graph = graph;
-    this.camera = camera;
-    this.contexts = {};
-    this.domElements = {};
-    this.options = options;
-    this.container = this.options.container;
-    this.settings = (
-        typeof options.settings === 'object' &&
-        options.settings
-      ) ?
-        settings.embedObjects(options.settings) :
-        settings;
-
-    // Find the prefix:
-    this.options.prefix = this.camera.readPrefix;
-
-    // Initialize programs hash
-    Object.defineProperty(this, 'nodePrograms', {
-      value: {}
-    });
-    Object.defineProperty(this, 'edgePrograms', {
-      value: {}
-    });
-    Object.defineProperty(this, 'nodeFloatArrays', {
-      value: {}
-    });
-    Object.defineProperty(this, 'edgeFloatArrays', {
-      value: {}
-    });
-    Object.defineProperty(this, 'edgeIndicesArrays', {
-      value: {}
-    });
-
-    // Initialize the DOM elements:
-    if (this.settings(options, 'batchEdgesDrawing')) {
-      this.initDOM('canvas', 'edges', true);
-      this.initDOM('canvas', 'nodes', true);
-    } else {
-      this.initDOM('canvas', 'scene', true);
-      this.contexts.nodes = this.contexts.scene;
-      this.contexts.edges = this.contexts.scene;
-    }
-
-    this.initDOM('canvas', 'labels');
-    this.initDOM('canvas', 'mouse');
-    this.contexts.hover = this.contexts.mouse;
-
-    // Initialize captors:
-    this.captors = [];
-    a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
-    for (i = 0, l = a.length; i < l; i++) {
-      fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
-      this.captors.push(
-        new fn(
-          this.domElements.mouse,
-          this.camera,
-          this.settings
-        )
-      );
-    }
-
-    // Deal with sigma events:
-    sigma.misc.bindEvents.call(this, this.camera.prefix);
-    sigma.misc.drawHovers.call(this, this.camera.prefix);
-
-    this.resize();
-  };
-
-
-
-
-  /**
-   * This method will generate the nodes and edges float arrays. This step is
-   * separated from the "render" method, because to keep WebGL efficient, since
-   * all the camera and middlewares are modelised as matrices and they do not
-   * require the float arrays to be regenerated.
-   *
-   * Basically, when the user moves the camera or applies some specific linear
-   * transformations, this process step will be skipped, and the "render"
-   * method will efficiently refresh the rendering.
-   *
-   * And when the user modifies the graph colors or positions (applying a new
-   * layout or filtering the colors, for instance), this "process" step will be
-   * required to regenerate the float arrays.
-   *
-   * @return {sigma.renderers.webgl} Returns the instance itself.
-   */
-  sigma.renderers.webgl.prototype.process = function() {
-    var a,
-        i,
-        l,
-        k,
-        type,
-        renderer,
-        graph = this.graph,
-        options = sigma.utils.extend(options, this.options),
-        defaultEdgeType = this.settings(options, 'defaultEdgeType'),
-        defaultNodeType = this.settings(options, 'defaultNodeType');
-
-    // Empty float arrays:
-    for (k in this.nodeFloatArrays)
-      delete this.nodeFloatArrays[k];
-
-    for (k in this.edgeFloatArrays)
-      delete this.edgeFloatArrays[k];
-
-    for (k in this.edgeIndicesArrays)
-      delete this.edgeIndicesArrays[k];
-
-    // Sort edges and nodes per types:
-    for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
-      type = a[i].type || defaultEdgeType;
-      k = (type && sigma.webgl.edges[type]) ? type : 'def';
-
-      if (!this.edgeFloatArrays[k])
-        this.edgeFloatArrays[k] = {
-          edges: []
-        };
-
-      this.edgeFloatArrays[k].edges.push(a[i]);
-    }
+;(function (global) {
+    'use strict';
 
-    for (a = graph.nodes(), i = 0, l = a.length; i < l; i++) {
-      type = a[i].type || defaultNodeType;
-      k = (type && sigma.webgl.nodes[type]) ? type : 'def';
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      if (!this.nodeFloatArrays[k])
-        this.nodeFloatArrays[k] = {
-          nodes: []
-        };
+    // Initialize packages:
+    sigma.utils.pkg('sigma.renderers');
 
-      this.nodeFloatArrays[k].nodes.push(a[i]);
+    // Check if WebGL is enabled:
+    var canvas,
+        webgl = !!global.WebGLRenderingContext;
+    if (webgl) {
+        canvas = document.createElement('canvas');
+        try {
+            webgl = !!(
+                canvas.getContext('webgl') ||
+                canvas.getContext('experimental-webgl')
+            );
+        } catch (e) {
+            webgl = false;
+        }
     }
 
-    // Push edges:
-    for (k in this.edgeFloatArrays) {
-      renderer = sigma.webgl.edges[k];
-      a = this.edgeFloatArrays[k].edges;
-
-      // Creating the necessary arrays
-      this.edgeFloatArrays[k].array = new Float32Array(
-        a.length * renderer.POINTS * renderer.ATTRIBUTES
-      );
+    // Copy the good renderer:
+    sigma.renderers.def = webgl ?
+        sigma.renderers.webgl :
+        sigma.renderers.canvas;
+})(this);
 
-      for (i = 0, l = a.length; i < l; i++) {
+;(function () {
+    'use strict';
 
-        // Just check that the edge and both its extremities are visible:
-        if (
-          !a[i].hidden &&
-          !graph.nodes(a[i].source).hidden &&
-          !graph.nodes(a[i].target).hidden
-        )
-          renderer.addEdge(
-            a[i],
-            graph.nodes(a[i].source),
-            graph.nodes(a[i].target),
-            this.edgeFloatArrays[k].array,
-            i * renderer.POINTS * renderer.ATTRIBUTES,
-            options.prefix,
-            this.settings
-          );
-      }
-
-      if (typeof renderer.computeIndices === 'function')
-        this.edgeIndicesArrays[k] = renderer.computeIndices(
-          this.edgeFloatArrays[k].array
-        );
-    }
+    sigma.utils.pkg('sigma.webgl.nodes');
 
-    // Push nodes:
-    for (k in this.nodeFloatArrays) {
-      renderer = sigma.webgl.nodes[k];
-      a = this.nodeFloatArrays[k].nodes;
+    /**
+     * This node renderer will display nodes as discs, shaped in triangles with
+     * the gl.TRIANGLES display mode. So, to be more precise, to draw one node,
+     * it will store three times the center of node, with the color and the size,
+     * and an angle indicating which "corner" of the triangle to draw.
+     *
+     * The fragment shader does not deal with anti-aliasing, so make sure that
+     * you deal with it somewhere else in the code (by default, the WebGL
+     * renderer will oversample the rendering through the webglOversamplingRatio
+     * value).
+     */
+    sigma.webgl.nodes.def = {
+        POINTS: 3,
+        ATTRIBUTES: 5,
+        addNode: function (node, data, i, prefix, settings) {
+            var color = sigma.utils.floatColor(
+                node.color || settings('defaultNodeColor')
+            );
 
-      // Creating the necessary arrays
-      this.nodeFloatArrays[k].array = new Float32Array(
-        a.length * renderer.POINTS * renderer.ATTRIBUTES
-      );
+            data[i++] = node[prefix + 'x'];
+            data[i++] = node[prefix + 'y'];
+            data[i++] = node[prefix + 'size'];
+            data[i++] = color;
+            data[i++] = 0;
+
+            data[i++] = node[prefix + 'x'];
+            data[i++] = node[prefix + 'y'];
+            data[i++] = node[prefix + 'size'];
+            data[i++] = color;
+            data[i++] = 2 * Math.PI / 3;
+
+            data[i++] = node[prefix + 'x'];
+            data[i++] = node[prefix + 'y'];
+            data[i++] = node[prefix + 'size'];
+            data[i++] = color;
+            data[i++] = 4 * Math.PI / 3;
+        },
+        render: function (gl, program, data, params) {
+            var buffer;
+
+            // Define attributes:
+            var positionLocation =
+                    gl.getAttribLocation(program, 'a_position'),
+                sizeLocation =
+                    gl.getAttribLocation(program, 'a_size'),
+                colorLocation =
+                    gl.getAttribLocation(program, 'a_color'),
+                angleLocation =
+                    gl.getAttribLocation(program, 'a_angle'),
+                resolutionLocation =
+                    gl.getUniformLocation(program, 'u_resolution'),
+                matrixLocation =
+                    gl.getUniformLocation(program, 'u_matrix'),
+                ratioLocation =
+                    gl.getUniformLocation(program, 'u_ratio'),
+                scaleLocation =
+                    gl.getUniformLocation(program, 'u_scale');
+
+            buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
+
+            gl.uniform2f(resolutionLocation, params.width, params.height);
+            gl.uniform1f(
+                ratioLocation,
+                1 / Math.pow(params.ratio, params.settings('nodesPowRatio'))
+            );
+            gl.uniform1f(scaleLocation, params.scalingRatio);
+            gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
+
+            gl.enableVertexAttribArray(positionLocation);
+            gl.enableVertexAttribArray(sizeLocation);
+            gl.enableVertexAttribArray(colorLocation);
+            gl.enableVertexAttribArray(angleLocation);
+
+            gl.vertexAttribPointer(
+                positionLocation,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                0
+            );
+            gl.vertexAttribPointer(
+                sizeLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                8
+            );
+            gl.vertexAttribPointer(
+                colorLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                12
+            );
+            gl.vertexAttribPointer(
+                angleLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                16
+            );
 
-      for (i = 0, l = a.length; i < l; i++) {
-        if (!this.nodeFloatArrays[k].array)
-          this.nodeFloatArrays[k].array = new Float32Array(
-            a.length * renderer.POINTS * renderer.ATTRIBUTES
-          );
+            gl.drawArrays(
+                gl.TRIANGLES,
+                params.start || 0,
+                params.count || (data.length / this.ATTRIBUTES)
+            );
+        },
+        initProgram: function (gl) {
+            var vertexShader,
+                fragmentShader,
+                program;
+
+            vertexShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'attribute vec2 a_position;',
+                    'attribute float a_size;',
+                    'attribute float a_color;',
+                    'attribute float a_angle;',
+
+                    'uniform vec2 u_resolution;',
+                    'uniform float u_ratio;',
+                    'uniform float u_scale;',
+                    'uniform mat3 u_matrix;',
+
+                    'varying vec4 color;',
+                    'varying vec2 center;',
+                    'varying float radius;',
+
+                    'void main() {',
+                    // Multiply the point size twice:
+                    'radius = a_size * u_ratio;',
+
+                    // Scale from [[-1 1] [-1 1]] to the container:
+                    'vec2 position = (u_matrix * vec3(a_position, 1)).xy;',
+                    // 'center = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);',
+                    'center = position * u_scale;',
+                    'center = vec2(center.x, u_scale * u_resolution.y - center.y);',
+
+                    'position = position +',
+                    '2.0 * radius * vec2(cos(a_angle), sin(a_angle));',
+                    'position = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);',
+
+                    'radius = radius * u_scale;',
+
+                    'gl_Position = vec4(position, 0, 1);',
+
+                    // Extract the color:
+                    'float c = a_color;',
+                    'color.b = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.g = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
+                    'color.a = 1.0;',
+                    '}'
+                ].join('\n'),
+                gl.VERTEX_SHADER
+            );
 
-        // Just check that the edge and both its extremities are visible:
-        if (
-          !a[i].hidden
-        )
-          renderer.addNode(
-            a[i],
-            this.nodeFloatArrays[k].array,
-            i * renderer.POINTS * renderer.ATTRIBUTES,
-            options.prefix,
-            this.settings
-          );
-      }
-    }
+            fragmentShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'precision mediump float;',
+
+                    'varying vec4 color;',
+                    'varying vec2 center;',
+                    'varying float radius;',
+
+                    'void main(void) {',
+                    'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);',
+
+                    'vec2 m = gl_FragCoord.xy - center;',
+                    'float diff = radius - sqrt(m.x * m.x + m.y * m.y);',
+
+                    // Here is how we draw a disc instead of a square:
+                    'if (diff > 0.0)',
+                    'gl_FragColor = color;',
+                    'else',
+                    'gl_FragColor = color0;',
+                    '}'
+                ].join('\n'),
+                gl.FRAGMENT_SHADER
+            );
 
-    return this;
-  };
-
-
-
-
-  /**
-   * This method renders the graph. It basically calls each program (and
-   * generate them if they do not exist yet) to render nodes and edges, batched
-   * per renderer.
-   *
-   * As in the canvas renderer, it is possible to display edges, nodes and / or
-   * labels in batches, to make the whole thing way more scalable.
-   *
-   * @param  {?object}               params Eventually an object of options.
-   * @return {sigma.renderers.webgl}        Returns the instance itself.
-   */
-  sigma.renderers.webgl.prototype.render = function(params) {
-    var a,
-        i,
-        l,
-        k,
-        o,
-        program,
-        renderer,
-        self = this,
-        graph = this.graph,
-        nodesGl = this.contexts.nodes,
-        edgesGl = this.contexts.edges,
-        matrix = this.camera.getMatrix(),
-        options = sigma.utils.extend(params, this.options),
-        drawLabels = this.settings(options, 'drawLabels'),
-        drawEdges = this.settings(options, 'drawEdges'),
-        drawNodes = this.settings(options, 'drawNodes');
-
-    // Call the resize function:
-    this.resize(false);
-
-    // Check the 'hideEdgesOnMove' setting:
-    if (this.settings(options, 'hideEdgesOnMove'))
-      if (this.camera.isAnimated || this.camera.isMoving)
-        drawEdges = false;
-
-    // Clear canvases:
-    this.clear();
-
-    // Translate matrix to [width/2, height/2]:
-    matrix = sigma.utils.matrices.multiply(
-      matrix,
-      sigma.utils.matrices.translation(this.width / 2, this.height / 2)
-    );
-
-    // Kill running jobs:
-    for (k in this.jobs)
-      if (conrad.hasJob(k))
-        conrad.killJob(k);
-
-    if (drawEdges) {
-      if (this.settings(options, 'batchEdgesDrawing'))
-        (function() {
-          var a,
-              k,
-              i,
-              id,
-              job,
-              arr,
-              end,
-              start,
-              indices,
-              renderer,
-              batchSize,
-              currentProgram;
-
-          id = 'edges_' + this.conradId;
-          batchSize = this.settings(options, 'webglEdgesBatchSize');
-          a = Object.keys(this.edgeFloatArrays);
-
-          if (!a.length)
-            return;
-          i = 0;
-          renderer = sigma.webgl.edges[a[i]];
-          arr = this.edgeFloatArrays[a[i]].array;
-          indices = this.edgeIndicesArrays[a[i]];
-          start = 0;
-          end = Math.min(
-            start + batchSize * renderer.POINTS,
-            arr.length / renderer.ATTRIBUTES
-          );
-
-          job = function() {
-            // Check program:
-            if (!this.edgePrograms[a[i]])
-              this.edgePrograms[a[i]] = renderer.initProgram(edgesGl);
-
-            if (start < end) {
-              edgesGl.useProgram(this.edgePrograms[a[i]]);
-              renderer.render(
-                edgesGl,
-                this.edgePrograms[a[i]],
-                arr,
-                {
-                  settings: this.settings,
-                  matrix: matrix,
-                  width: this.width,
-                  height: this.height,
-                  ratio: this.camera.ratio,
-                  scalingRatio: this.settings(
-                    options,
-                    'webglOversamplingRatio'
-                  ),
-                  start: start,
-                  count: end - start,
-                  indicesData: indices
-                }
-              );
-            }
+            program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
 
-            // Catch job's end:
-            if (
-              end >= arr.length / renderer.ATTRIBUTES &&
-              i === a.length - 1
-            ) {
-              delete this.jobs[id];
-              return false;
-            }
+            return program;
+        }
+    };
+})();
 
-            if (end >= arr.length / renderer.ATTRIBUTES) {
-              i++;
-              arr = this.edgeFloatArrays[a[i]].array;
-              renderer = sigma.webgl.edges[a[i]];
-              start = 0;
-              end = Math.min(
-                start + batchSize * renderer.POINTS,
-                arr.length / renderer.ATTRIBUTES
-              );
-            } else {
-              start = end;
-              end = Math.min(
-                start + batchSize * renderer.POINTS,
-                arr.length / renderer.ATTRIBUTES
-              );
-            }
+;(function () {
+    'use strict';
 
-            return true;
-          };
+    sigma.utils.pkg('sigma.webgl.nodes');
 
-          this.jobs[id] = job;
-          conrad.addJob(id, job.bind(this));
-        }).call(this);
-      else {
-        for (k in this.edgeFloatArrays) {
-          renderer = sigma.webgl.edges[k];
-
-          // Check program:
-          if (!this.edgePrograms[k])
-            this.edgePrograms[k] = renderer.initProgram(edgesGl);
-
-          // Render
-          if (this.edgeFloatArrays[k]) {
-            edgesGl.useProgram(this.edgePrograms[k]);
-            renderer.render(
-              edgesGl,
-              this.edgePrograms[k],
-              this.edgeFloatArrays[k].array,
-              {
-                settings: this.settings,
-                matrix: matrix,
-                width: this.width,
-                height: this.height,
-                ratio: this.camera.ratio,
-                scalingRatio: this.settings(options, 'webglOversamplingRatio'),
-                indicesData: this.edgeIndicesArrays[k]
-              }
+    /**
+     * This node renderer will display nodes in the fastest way: Nodes are basic
+     * squares, drawn through the gl.POINTS drawing method. The size of the nodes
+     * are represented with the "gl_PointSize" value in the vertex shader.
+     *
+     * It is the fastest node renderer here since the buffer just takes one line
+     * to draw each node (with attributes "x", "y", "size" and "color").
+     *
+     * Nevertheless, this method has some problems, especially due to some issues
+     * with the gl.POINTS:
+     *  - First, if the center of a node is outside the scene, the point will not
+     *    be drawn, even if it should be partly on screen.
+     *  - I tried applying a fragment shader similar to the one in the default
+     *    node renderer to display them as discs, but it did not work fine on
+     *    some computers settings, filling the discs with weird gradients not
+     *    depending on the actual color.
+     */
+    sigma.webgl.nodes.fast = {
+        POINTS: 1,
+        ATTRIBUTES: 4,
+        addNode: function (node, data, i, prefix, settings) {
+            data[i++] = node[prefix + 'x'];
+            data[i++] = node[prefix + 'y'];
+            data[i++] = node[prefix + 'size'];
+            data[i++] = sigma.utils.floatColor(
+                node.color || settings('defaultNodeColor')
+            );
+        },
+        render: function (gl, program, data, params) {
+            var buffer;
+
+            // Define attributes:
+            var positionLocation =
+                    gl.getAttribLocation(program, 'a_position'),
+                sizeLocation =
+                    gl.getAttribLocation(program, 'a_size'),
+                colorLocation =
+                    gl.getAttribLocation(program, 'a_color'),
+                resolutionLocation =
+                    gl.getUniformLocation(program, 'u_resolution'),
+                matrixLocation =
+                    gl.getUniformLocation(program, 'u_matrix'),
+                ratioLocation =
+                    gl.getUniformLocation(program, 'u_ratio'),
+                scaleLocation =
+                    gl.getUniformLocation(program, 'u_scale');
+
+            buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
+
+            gl.uniform2f(resolutionLocation, params.width, params.height);
+            gl.uniform1f(
+                ratioLocation,
+                1 / Math.pow(params.ratio, params.settings('nodesPowRatio'))
+            );
+            gl.uniform1f(scaleLocation, params.scalingRatio);
+            gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
+
+            gl.enableVertexAttribArray(positionLocation);
+            gl.enableVertexAttribArray(sizeLocation);
+            gl.enableVertexAttribArray(colorLocation);
+
+            gl.vertexAttribPointer(
+                positionLocation,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                0
+            );
+            gl.vertexAttribPointer(
+                sizeLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                8
+            );
+            gl.vertexAttribPointer(
+                colorLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                12
             );
-          }
-        }
-      }
-    }
 
-    if (drawNodes) {
-      // Enable blending:
-      nodesGl.blendFunc(nodesGl.SRC_ALPHA, nodesGl.ONE_MINUS_SRC_ALPHA);
-      nodesGl.enable(nodesGl.BLEND);
-
-      for (k in this.nodeFloatArrays) {
-        renderer = sigma.webgl.nodes[k];
-
-        // Check program:
-        if (!this.nodePrograms[k])
-          this.nodePrograms[k] = renderer.initProgram(nodesGl);
-
-        // Render
-        if (this.nodeFloatArrays[k]) {
-          nodesGl.useProgram(this.nodePrograms[k]);
-          renderer.render(
-            nodesGl,
-            this.nodePrograms[k],
-            this.nodeFloatArrays[k].array,
-            {
-              settings: this.settings,
-              matrix: matrix,
-              width: this.width,
-              height: this.height,
-              ratio: this.camera.ratio,
-              scalingRatio: this.settings(options, 'webglOversamplingRatio')
-            }
-          );
-        }
-      }
-    }
+            gl.drawArrays(
+                gl.POINTS,
+                params.start || 0,
+                params.count || (data.length / this.ATTRIBUTES)
+            );
+        },
+        initProgram: function (gl) {
+            var vertexShader,
+                fragmentShader,
+                program;
+
+            vertexShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'attribute vec2 a_position;',
+                    'attribute float a_size;',
+                    'attribute float a_color;',
+
+                    'uniform vec2 u_resolution;',
+                    'uniform float u_ratio;',
+                    'uniform float u_scale;',
+                    'uniform mat3 u_matrix;',
+
+                    'varying vec4 color;',
+
+                    'void main() {',
+                    // Scale from [[-1 1] [-1 1]] to the container:
+                    'gl_Position = vec4(',
+                    '((u_matrix * vec3(a_position, 1)).xy /',
+                    'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
+                    '0,',
+                    '1',
+                    ');',
+
+                    // Multiply the point size twice:
+                    //  - x SCALING_RATIO to correct the canvas scaling
+                    //  - x 2 to correct the formulae
+                    'gl_PointSize = a_size * u_ratio * u_scale * 2.0;',
+
+                    // Extract the color:
+                    'float c = a_color;',
+                    'color.b = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.g = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
+                    'color.a = 1.0;',
+                    '}'
+                ].join('\n'),
+                gl.VERTEX_SHADER
+            );
 
-    if (drawLabels) {
-      a = this.camera.quadtree.area(
-        this.camera.getRectangle(this.width, this.height)
-      );
-
-      // Apply camera view to these nodes:
-      this.camera.applyView(
-        undefined,
-        undefined,
-        {
-          nodes: a,
-          edges: [],
-          width: this.width,
-          height: this.height
-        }
-      );
-
-      o = function(key) {
-        return self.settings({
-          prefix: self.camera.prefix
-        }, key);
-      };
-
-      for (i = 0, l = a.length; i < l; i++)
-        if (!a[i].hidden)
-          (
-            sigma.canvas.labels[
-              a[i].type ||
-              this.settings(options, 'defaultNodeType')
-            ] || sigma.canvas.labels.def
-          )(a[i], this.contexts.labels, o);
-    }
+            fragmentShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'precision mediump float;',
 
-    this.dispatchEvent('render');
+                    'varying vec4 color;',
 
-    return this;
-  };
+                    'void main(void) {',
+                    'float border = 0.01;',
+                    'float radius = 0.5;',
 
+                    'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);',
+                    'vec2 m = gl_PointCoord - vec2(0.5, 0.5);',
+                    'float dist = radius - sqrt(m.x * m.x + m.y * m.y);',
 
+                    'float t = 0.0;',
+                    'if (dist > border)',
+                    't = 1.0;',
+                    'else if (dist > 0.0)',
+                    't = dist / border;',
 
+                    'gl_FragColor = mix(color0, color, t);',
+                    '}'
+                ].join('\n'),
+                gl.FRAGMENT_SHADER
+            );
 
-  /**
-   * This method creates a DOM element of the specified type, switches its
-   * position to "absolute", references it to the domElements attribute, and
-   * finally appends it to the container.
-   *
-   * @param  {string}   tag   The label tag.
-   * @param  {string}   id    The id of the element (to store it in
-   *                          "domElements").
-   * @param  {?boolean} webgl Will init the WebGL context if true.
-   */
-  sigma.renderers.webgl.prototype.initDOM = function(tag, id, webgl) {
-    var gl,
-        dom = document.createElement(tag),
-        self = this;
+            program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
 
-    dom.style.position = 'absolute';
-    dom.setAttribute('class', 'sigma-' + id);
+            return program;
+        }
+    };
+})();
 
-    this.domElements[id] = dom;
-    this.container.appendChild(dom);
+;(function () {
+    'use strict';
 
-    if (tag.toLowerCase() === 'canvas') {
-      this.contexts[id] = dom.getContext(webgl ? 'experimental-webgl' : '2d', {
-        preserveDrawingBuffer: true
-      });
+    sigma.utils.pkg('sigma.webgl.edges');
 
-      // Adding webgl context loss listeners
-      if (webgl) {
-        dom.addEventListener('webglcontextlost', function(e) {
-          e.preventDefault();
-        }, false);
+    /**
+     * This edge renderer will display edges as lines going from the source node
+     * to the target node. To deal with edge thicknesses, the lines are made of
+     * two triangles forming rectangles, with the gl.TRIANGLES drawing mode.
+     *
+     * It is expensive, since drawing a single edge requires 6 points, each
+     * having 7 attributes (source position, target position, thickness, color
+     * and a flag indicating which vertice of the rectangle it is).
+     */
+    sigma.webgl.edges.def = {
+        POINTS: 6,
+        ATTRIBUTES: 7,
+        addEdge: function (edge, source, target, data, i, prefix, settings) {
+            var w = (edge[prefix + 'size'] || 1) / 2,
+                x1 = source[prefix + 'x'],
+                y1 = source[prefix + 'y'],
+                x2 = target[prefix + 'x'],
+                y2 = target[prefix + 'y'],
+                color = edge.color;
+
+            if (!color)
+                switch (settings('edgeColor')) {
+                    case 'source':
+                        color = source.color || settings('defaultNodeColor');
+                        break;
+                    case 'target':
+                        color = target.color || settings('defaultNodeColor');
+                        break;
+                    default:
+                        color = settings('defaultEdgeColor');
+                        break;
+                }
 
-        dom.addEventListener('webglcontextrestored', function(e) {
-          self.render();
-        }, false);
-      }
-    }
-  };
-
-  /**
-   * This method resizes each DOM elements in the container and stores the new
-   * dimensions. Then, it renders the graph.
-   *
-   * @param  {?number}               width  The new width of the container.
-   * @param  {?number}               height The new height of the container.
-   * @return {sigma.renderers.webgl}        Returns the instance itself.
-   */
-  sigma.renderers.webgl.prototype.resize = function(w, h) {
-    var k,
-        oldWidth = this.width,
-        oldHeight = this.height,
-        pixelRatio = sigma.utils.getPixelRatio();
-
-    if (w !== undefined && h !== undefined) {
-      this.width = w;
-      this.height = h;
-    } else {
-      this.width = this.container.offsetWidth;
-      this.height = this.container.offsetHeight;
-
-      w = this.width;
-      h = this.height;
-    }
+            // Normalize color:
+            color = sigma.utils.floatColor(color);
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = 1.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = 1.0;
+            data[i++] = color;
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = 0.0;
+            data[i++] = color;
+        },
+        render: function (gl, program, data, params) {
+            var buffer;
+
+            // Define attributes:
+            var colorLocation =
+                    gl.getAttribLocation(program, 'a_color'),
+                positionLocation1 =
+                    gl.getAttribLocation(program, 'a_position1'),
+                positionLocation2 =
+                    gl.getAttribLocation(program, 'a_position2'),
+                thicknessLocation =
+                    gl.getAttribLocation(program, 'a_thickness'),
+                minusLocation =
+                    gl.getAttribLocation(program, 'a_minus'),
+                resolutionLocation =
+                    gl.getUniformLocation(program, 'u_resolution'),
+                matrixLocation =
+                    gl.getUniformLocation(program, 'u_matrix'),
+                matrixHalfPiLocation =
+                    gl.getUniformLocation(program, 'u_matrixHalfPi'),
+                matrixHalfPiMinusLocation =
+                    gl.getUniformLocation(program, 'u_matrixHalfPiMinus'),
+                ratioLocation =
+                    gl.getUniformLocation(program, 'u_ratio'),
+                scaleLocation =
+                    gl.getUniformLocation(program, 'u_scale');
+
+            buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
+
+            gl.uniform2f(resolutionLocation, params.width, params.height);
+            gl.uniform1f(
+                ratioLocation,
+                params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio'))
+            );
+            gl.uniform1f(scaleLocation, params.scalingRatio);
+            gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
+            gl.uniformMatrix2fv(
+                matrixHalfPiLocation,
+                false,
+                sigma.utils.matrices.rotation(Math.PI / 2, true)
+            );
+            gl.uniformMatrix2fv(
+                matrixHalfPiMinusLocation,
+                false,
+                sigma.utils.matrices.rotation(-Math.PI / 2, true)
+            );
 
-    if (oldWidth !== this.width || oldHeight !== this.height) {
-      for (k in this.domElements) {
-        this.domElements[k].style.width = w + 'px';
-        this.domElements[k].style.height = h + 'px';
-
-        if (this.domElements[k].tagName.toLowerCase() === 'canvas') {
-          // If simple 2D canvas:
-          if (this.contexts[k] && this.contexts[k].scale) {
-            this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px');
-            this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px');
-
-            if (pixelRatio !== 1)
-              this.contexts[k].scale(pixelRatio, pixelRatio);
-          } else {
-            this.domElements[k].setAttribute(
-              'width',
-              (w * this.settings('webglOversamplingRatio')) + 'px'
+            gl.enableVertexAttribArray(colorLocation);
+            gl.enableVertexAttribArray(positionLocation1);
+            gl.enableVertexAttribArray(positionLocation2);
+            gl.enableVertexAttribArray(thicknessLocation);
+            gl.enableVertexAttribArray(minusLocation);
+
+            gl.vertexAttribPointer(positionLocation1,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                0
             );
-            this.domElements[k].setAttribute(
-              'height',
-              (h * this.settings('webglOversamplingRatio')) + 'px'
+            gl.vertexAttribPointer(positionLocation2,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                8
+            );
+            gl.vertexAttribPointer(thicknessLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                16
+            );
+            gl.vertexAttribPointer(minusLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                20
+            );
+            gl.vertexAttribPointer(colorLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                24
             );
-          }
-        }
-      }
-    }
 
-    // Scale:
-    for (k in this.contexts)
-      if (this.contexts[k] && this.contexts[k].viewport)
-        this.contexts[k].viewport(
-          0,
-          0,
-          this.width * this.settings('webglOversamplingRatio'),
-          this.height * this.settings('webglOversamplingRatio')
-        );
+            gl.drawArrays(
+                gl.TRIANGLES,
+                params.start || 0,
+                params.count || (data.length / this.ATTRIBUTES)
+            );
+        },
+        initProgram: function (gl) {
+            var vertexShader,
+                fragmentShader,
+                program;
+
+            vertexShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'attribute vec2 a_position1;',
+                    'attribute vec2 a_position2;',
+                    'attribute float a_thickness;',
+                    'attribute float a_minus;',
+                    'attribute float a_color;',
+
+                    'uniform vec2 u_resolution;',
+                    'uniform float u_ratio;',
+                    'uniform float u_scale;',
+                    'uniform mat3 u_matrix;',
+                    'uniform mat2 u_matrixHalfPi;',
+                    'uniform mat2 u_matrixHalfPiMinus;',
+
+                    'varying vec4 color;',
+
+                    'void main() {',
+                    // Find the good point:
+                    'vec2 position = a_thickness * u_ratio *',
+                    'normalize(a_position2 - a_position1);',
+
+                    'mat2 matrix = a_minus * u_matrixHalfPiMinus +',
+                    '(1.0 - a_minus) * u_matrixHalfPi;',
+
+                    'position = matrix * position + a_position1;',
+
+                    // Scale from [[-1 1] [-1 1]] to the container:
+                    'gl_Position = vec4(',
+                    '((u_matrix * vec3(position, 1)).xy /',
+                    'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
+                    '0,',
+                    '1',
+                    ');',
+
+                    // Extract the color:
+                    'float c = a_color;',
+                    'color.b = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.g = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
+                    'color.a = 1.0;',
+                    '}'
+                ].join('\n'),
+                gl.VERTEX_SHADER
+            );
 
-    return this;
-  };
-
-  /**
-   * This method clears each canvas.
-   *
-   * @return {sigma.renderers.webgl} Returns the instance itself.
-   */
-  sigma.renderers.webgl.prototype.clear = function() {
-    this.contexts.labels.clearRect(0, 0, this.width, this.height);
-    this.contexts.nodes.clear(this.contexts.nodes.COLOR_BUFFER_BIT);
-    this.contexts.edges.clear(this.contexts.edges.COLOR_BUFFER_BIT);
-
-    return this;
-  };
-
-  /**
-   * This method kills contexts and other attributes.
-   */
-  sigma.renderers.webgl.prototype.kill = function() {
-    var k,
-        captor;
-
-    // Kill captors:
-    while ((captor = this.captors.pop()))
-      captor.kill();
-    delete this.captors;
-
-    // Kill contexts:
-    for (k in this.domElements) {
-      this.domElements[k].parentNode.removeChild(this.domElements[k]);
-      delete this.domElements[k];
-      delete this.contexts[k];
-    }
-    delete this.domElements;
-    delete this.contexts;
-  };
-
-
-
-
-  /**
-   * The object "sigma.webgl.nodes" contains the different WebGL node
-   * renderers. The default one draw nodes as discs. Here are the attributes
-   * any node renderer must have:
-   *
-   * {number}   POINTS      The number of points required to draw a node.
-   * {number}   ATTRIBUTES  The number of attributes needed to draw one point.
-   * {function} addNode     A function that adds a node to the data stack that
-   *                        will be given to the buffer. Here is the arguments:
-   *                        > {object}       node
-   *                        > {number}       index   The node index in the
-   *                                                 nodes array.
-   *                        > {Float32Array} data    The stack.
-   *                        > {object}       options Some options.
-   * {function} render      The function that will effectively render the nodes
-   *                        into the buffer.
-   *                        > {WebGLRenderingContext} gl
-   *                        > {WebGLProgram}          program
-   *                        > {Float32Array} data    The stack to give to the
-   *                                                 buffer.
-   *                        > {object}       params  An object containing some
-   *                                                 options, like width,
-   *                                                 height, the camera ratio.
-   * {function} initProgram The function that will initiate the program, with
-   *                        the relevant shaders and parameters. It must return
-   *                        the newly created program.
-   *
-   * Check sigma.webgl.nodes.def or sigma.webgl.nodes.fast to see how it
-   * works more precisely.
-   */
-  sigma.utils.pkg('sigma.webgl.nodes');
-
-
-
-
-  /**
-   * The object "sigma.webgl.edges" contains the different WebGL edge
-   * renderers. The default one draw edges as direct lines. Here are the
-   * attributes any edge renderer must have:
-   *
-   * {number}   POINTS      The number of points required to draw an edge.
-   * {number}   ATTRIBUTES  The number of attributes needed to draw one point.
-   * {function} addEdge     A function that adds an edge to the data stack that
-   *                        will be given to the buffer. Here is the arguments:
-   *                        > {object}       edge
-   *                        > {object}       source
-   *                        > {object}       target
-   *                        > {Float32Array} data    The stack.
-   *                        > {object}       options Some options.
-   * {function} render      The function that will effectively render the edges
-   *                        into the buffer.
-   *                        > {WebGLRenderingContext} gl
-   *                        > {WebGLProgram}          program
-   *                        > {Float32Array} data    The stack to give to the
-   *                                                 buffer.
-   *                        > {object}       params  An object containing some
-   *                                                 options, like width,
-   *                                                 height, the camera ratio.
-   * {function} initProgram The function that will initiate the program, with
-   *                        the relevant shaders and parameters. It must return
-   *                        the newly created program.
-   *
-   * Check sigma.webgl.edges.def or sigma.webgl.edges.fast to see how it
-   * works more precisely.
-   */
-  sigma.utils.pkg('sigma.webgl.edges');
-
-
-
-
-  /**
-   * The object "sigma.canvas.labels" contains the different
-   * label renderers for the WebGL renderer. Since displaying texts in WebGL is
-   * definitely painful and since there a way less labels to display than nodes
-   * or edges, the default renderer simply renders them in a canvas.
-   *
-   * A labels renderer is a simple function, taking as arguments the related
-   * node, the renderer and a settings function.
-   */
-  sigma.utils.pkg('sigma.canvas.labels');
-}).call(this);
+            fragmentShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'precision mediump float;',
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  if (typeof conrad === 'undefined')
-    throw 'conrad is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.renderers');
-
-  /**
-   * This function is the constructor of the svg sigma's renderer.
-   *
-   * @param  {sigma.classes.graph}            graph    The graph to render.
-   * @param  {sigma.classes.camera}           camera   The camera.
-   * @param  {configurable}           settings The sigma instance settings
-   *                                           function.
-   * @param  {object}                 object   The options object.
-   * @return {sigma.renderers.svg}             The renderer instance.
-   */
-  sigma.renderers.svg = function(graph, camera, settings, options) {
-    if (typeof options !== 'object')
-      throw 'sigma.renderers.svg: Wrong arguments.';
-
-    if (!(options.container instanceof HTMLElement))
-      throw 'Container not found.';
-
-    var i,
-        l,
-        a,
-        fn,
-        self = this;
-
-    sigma.classes.dispatcher.extend(this);
-
-    // Initialize main attributes:
-    this.graph = graph;
-    this.camera = camera;
-    this.domElements = {
-      graph: null,
-      groups: {},
-      nodes: {},
-      edges: {},
-      labels: {},
-      hovers: {}
-    };
-    this.measurementCanvas = null;
-    this.options = options;
-    this.container = this.options.container;
-    this.settings = (
-        typeof options.settings === 'object' &&
-        options.settings
-      ) ?
-        settings.embedObjects(options.settings) :
-        settings;
-
-    // Is the renderer meant to be freestyle?
-    this.settings('freeStyle', !!this.options.freeStyle);
-
-    // SVG xmlns
-    this.settings('xmlns', 'http://www.w3.org/2000/svg');
-
-    // Indexes:
-    this.nodesOnScreen = [];
-    this.edgesOnScreen = [];
-
-    // Find the prefix:
-    this.options.prefix = 'renderer' + sigma.utils.id() + ':';
-
-    // Initialize the DOM elements
-    this.initDOM('svg');
-
-    // Initialize captors:
-    this.captors = [];
-    a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch];
-    for (i = 0, l = a.length; i < l; i++) {
-      fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]];
-      this.captors.push(
-        new fn(
-          this.domElements.graph,
-          this.camera,
-          this.settings
-        )
-      );
-    }
+                    'varying vec4 color;',
 
-    // Bind resize:
-    window.addEventListener('resize', function() {
-      self.resize();
-    });
+                    'void main(void) {',
+                    'gl_FragColor = color;',
+                    '}'
+                ].join('\n'),
+                gl.FRAGMENT_SHADER
+            );
 
-    // Deal with sigma events:
-    // TODO: keep an option to override the DOM events?
-    sigma.misc.bindDOMEvents.call(this, this.domElements.graph);
-    this.bindHovers(this.options.prefix);
-
-    // Resize
-    this.resize(false);
-  };
-
-  /**
-   * This method renders the graph on the svg scene.
-   *
-   * @param  {?object}                options Eventually an object of options.
-   * @return {sigma.renderers.svg}            Returns the instance itself.
-   */
-  sigma.renderers.svg.prototype.render = function(options) {
-    options = options || {};
-
-    var a,
-        i,
-        k,
-        e,
-        l,
-        o,
-        source,
-        target,
-        start,
-        edges,
-        renderers,
-        subrenderers,
-        index = {},
-        graph = this.graph,
-        nodes = this.graph.nodes,
-        prefix = this.options.prefix || '',
-        drawEdges = this.settings(options, 'drawEdges'),
-        drawNodes = this.settings(options, 'drawNodes'),
-        drawLabels = this.settings(options, 'drawLabels'),
-        embedSettings = this.settings.embedObjects(options, {
-          prefix: this.options.prefix,
-          forceLabels: this.options.forceLabels
-        });
+            program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
 
-    // Check the 'hideEdgesOnMove' setting:
-    if (this.settings(options, 'hideEdgesOnMove'))
-      if (this.camera.isAnimated || this.camera.isMoving)
-        drawEdges = false;
-
-    // Apply the camera's view:
-    this.camera.applyView(
-      undefined,
-      this.options.prefix,
-      {
-        width: this.width,
-        height: this.height
-      }
-    );
-
-    // Hiding everything
-    // TODO: find a more sensible way to perform this operation
-    this.hideDOMElements(this.domElements.nodes);
-    this.hideDOMElements(this.domElements.edges);
-    this.hideDOMElements(this.domElements.labels);
-
-    // Find which nodes are on screen
-    this.edgesOnScreen = [];
-    this.nodesOnScreen = this.camera.quadtree.area(
-      this.camera.getRectangle(this.width, this.height)
-    );
-
-    // Node index
-    for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++)
-      index[a[i].id] = a[i];
-
-    // Find which edges are on screen
-    for (a = graph.edges(), i = 0, l = a.length; i < l; i++) {
-      o = a[i];
-      if (
-        (index[o.source] || index[o.target]) &&
-        (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden)
-      )
-        this.edgesOnScreen.push(o);
-    }
+            return program;
+        }
+    };
+})();
+
+;(function () {
+    'use strict';
+
+    sigma.utils.pkg('sigma.webgl.edges');
+
+    /**
+     * This edge renderer will display edges as lines with the gl.LINES display
+     * mode. Since this mode does not support well thickness, edges are all drawn
+     * with the same thickness (3px), independantly of the edge attributes or the
+     * zooming ratio.
+     */
+    sigma.webgl.edges.fast = {
+        POINTS: 2,
+        ATTRIBUTES: 3,
+        addEdge: function (edge, source, target, data, i, prefix, settings) {
+            var w = (edge[prefix + 'size'] || 1) / 2,
+                x1 = source[prefix + 'x'],
+                y1 = source[prefix + 'y'],
+                x2 = target[prefix + 'x'],
+                y2 = target[prefix + 'y'],
+                color = edge.color;
+
+            if (!color)
+                switch (settings('edgeColor')) {
+                    case 'source':
+                        color = source.color || settings('defaultNodeColor');
+                        break;
+                    case 'target':
+                        color = target.color || settings('defaultNodeColor');
+                        break;
+                    default:
+                        color = settings('defaultEdgeColor');
+                        break;
+                }
 
-    // Display nodes
-    //---------------
-    renderers = sigma.svg.nodes;
-    subrenderers = sigma.svg.labels;
+            // Normalize color:
+            color = sigma.utils.floatColor(color);
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = color;
+        },
+        render: function (gl, program, data, params) {
+            var buffer;
+
+            // Define attributes:
+            var colorLocation =
+                    gl.getAttribLocation(program, 'a_color'),
+                positionLocation =
+                    gl.getAttribLocation(program, 'a_position'),
+                resolutionLocation =
+                    gl.getUniformLocation(program, 'u_resolution'),
+                matrixLocation =
+                    gl.getUniformLocation(program, 'u_matrix');
+
+            buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
+
+            gl.uniform2f(resolutionLocation, params.width, params.height);
+            gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
+
+            gl.enableVertexAttribArray(positionLocation);
+            gl.enableVertexAttribArray(colorLocation);
+
+            gl.vertexAttribPointer(positionLocation,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                0
+            );
+            gl.vertexAttribPointer(colorLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                8
+            );
+
+            gl.lineWidth(3);
+            gl.drawArrays(
+                gl.LINES,
+                params.start || 0,
+                params.count || (data.length / this.ATTRIBUTES)
+            );
+        },
+        initProgram: function (gl) {
+            var vertexShader,
+                fragmentShader,
+                program;
+
+            vertexShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'attribute vec2 a_position;',
+                    'attribute float a_color;',
+
+                    'uniform vec2 u_resolution;',
+                    'uniform mat3 u_matrix;',
+
+                    'varying vec4 color;',
+
+                    'void main() {',
+                    // Scale from [[-1 1] [-1 1]] to the container:
+                    'gl_Position = vec4(',
+                    '((u_matrix * vec3(a_position, 1)).xy /',
+                    'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
+                    '0,',
+                    '1',
+                    ');',
+
+                    // Extract the color:
+                    'float c = a_color;',
+                    'color.b = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.g = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
+                    'color.a = 1.0;',
+                    '}'
+                ].join('\n'),
+                gl.VERTEX_SHADER
+            );
 
-    //-- First we create the nodes which are not already created
-    if (drawNodes)
-      for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) {
-        if (!a[i].hidden && !this.domElements.nodes[a[i].id]) {
+            fragmentShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'precision mediump float;',
 
-          // Node
-          e = (renderers[a[i].type] || renderers.def).create(
-            a[i],
-            embedSettings
-          );
+                    'varying vec4 color;',
 
-          this.domElements.nodes[a[i].id] = e;
-          this.domElements.groups.nodes.appendChild(e);
+                    'void main(void) {',
+                    'gl_FragColor = color;',
+                    '}'
+                ].join('\n'),
+                gl.FRAGMENT_SHADER
+            );
 
-          // Label
-          e = (subrenderers[a[i].type] || subrenderers.def).create(
-            a[i],
-            embedSettings
-          );
+            program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
 
-          this.domElements.labels[a[i].id] = e;
-          this.domElements.groups.labels.appendChild(e);
+            return program;
         }
-      }
+    };
+})();
 
-    //-- Second we update the nodes
-    if (drawNodes)
-      for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) {
+;(function () {
+    'use strict';
 
-        if (a[i].hidden)
-          continue;
+    sigma.utils.pkg('sigma.webgl.edges');
 
-        // Node
-        (renderers[a[i].type] || renderers.def).update(
-          a[i],
-          this.domElements.nodes[a[i].id],
-          embedSettings
-        );
+    /**
+     * This edge renderer will display edges as arrows going from the source node
+     * to the target node. To deal with edge thicknesses, the lines are made of
+     * three triangles: two forming rectangles, with the gl.TRIANGLES drawing
+     * mode.
+     *
+     * It is expensive, since drawing a single edge requires 9 points, each
+     * having a lot of attributes.
+     */
+    sigma.webgl.edges.arrow = {
+        POINTS: 9,
+        ATTRIBUTES: 11,
+        addEdge: function (edge, source, target, data, i, prefix, settings) {
+            var w = (edge[prefix + 'size'] || 1) / 2,
+                x1 = source[prefix + 'x'],
+                y1 = source[prefix + 'y'],
+                x2 = target[prefix + 'x'],
+                y2 = target[prefix + 'y'],
+                targetSize = target[prefix + 'size'],
+                color = edge.color;
+
+            if (!color)
+                switch (settings('edgeColor')) {
+                    case 'source':
+                        color = source.color || settings('defaultNodeColor');
+                        break;
+                    case 'target':
+                        color = target.color || settings('defaultNodeColor');
+                        break;
+                    default:
+                        color = settings('defaultEdgeColor');
+                        break;
+                }
 
-        // Label
-        (subrenderers[a[i].type] || subrenderers.def).update(
-          a[i],
-          this.domElements.labels[a[i].id],
-          embedSettings
-        );
-      }
+            // Normalize color:
+            color = sigma.utils.floatColor(color);
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 0.0;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            // Arrow head:
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 1.0;
+            data[i++] = -1.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = color;
+
+            data[i++] = x2;
+            data[i++] = y2;
+            data[i++] = x1;
+            data[i++] = y1;
+            data[i++] = w;
+            data[i++] = targetSize;
+            data[i++] = 1.0;
+            data[i++] = 0.0;
+            data[i++] = 1.0;
+            data[i++] = 1.0;
+            data[i++] = color;
+        },
+        render: function (gl, program, data, params) {
+            var buffer;
+
+            // Define attributes:
+            var positionLocation1 =
+                    gl.getAttribLocation(program, 'a_pos1'),
+                positionLocation2 =
+                    gl.getAttribLocation(program, 'a_pos2'),
+                thicknessLocation =
+                    gl.getAttribLocation(program, 'a_thickness'),
+                targetSizeLocation =
+                    gl.getAttribLocation(program, 'a_tSize'),
+                delayLocation =
+                    gl.getAttribLocation(program, 'a_delay'),
+                minusLocation =
+                    gl.getAttribLocation(program, 'a_minus'),
+                headLocation =
+                    gl.getAttribLocation(program, 'a_head'),
+                headPositionLocation =
+                    gl.getAttribLocation(program, 'a_headPosition'),
+                colorLocation =
+                    gl.getAttribLocation(program, 'a_color'),
+                resolutionLocation =
+                    gl.getUniformLocation(program, 'u_resolution'),
+                matrixLocation =
+                    gl.getUniformLocation(program, 'u_matrix'),
+                matrixHalfPiLocation =
+                    gl.getUniformLocation(program, 'u_matrixHalfPi'),
+                matrixHalfPiMinusLocation =
+                    gl.getUniformLocation(program, 'u_matrixHalfPiMinus'),
+                ratioLocation =
+                    gl.getUniformLocation(program, 'u_ratio'),
+                nodeRatioLocation =
+                    gl.getUniformLocation(program, 'u_nodeRatio'),
+                arrowHeadLocation =
+                    gl.getUniformLocation(program, 'u_arrowHead'),
+                scaleLocation =
+                    gl.getUniformLocation(program, 'u_scale');
+
+            buffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
+
+            gl.uniform2f(resolutionLocation, params.width, params.height);
+            gl.uniform1f(
+                ratioLocation,
+                params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio'))
+            );
+            gl.uniform1f(
+                nodeRatioLocation,
+                Math.pow(params.ratio, params.settings('nodesPowRatio')) /
+                params.ratio
+            );
+            gl.uniform1f(arrowHeadLocation, 5.0);
+            gl.uniform1f(scaleLocation, params.scalingRatio);
+            gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
+            gl.uniformMatrix2fv(
+                matrixHalfPiLocation,
+                false,
+                sigma.utils.matrices.rotation(Math.PI / 2, true)
+            );
+            gl.uniformMatrix2fv(
+                matrixHalfPiMinusLocation,
+                false,
+                sigma.utils.matrices.rotation(-Math.PI / 2, true)
+            );
 
-    // Display edges
-    //---------------
-    renderers = sigma.svg.edges;
+            gl.enableVertexAttribArray(positionLocation1);
+            gl.enableVertexAttribArray(positionLocation2);
+            gl.enableVertexAttribArray(thicknessLocation);
+            gl.enableVertexAttribArray(targetSizeLocation);
+            gl.enableVertexAttribArray(delayLocation);
+            gl.enableVertexAttribArray(minusLocation);
+            gl.enableVertexAttribArray(headLocation);
+            gl.enableVertexAttribArray(headPositionLocation);
+            gl.enableVertexAttribArray(colorLocation);
+
+            gl.vertexAttribPointer(positionLocation1,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                0
+            );
+            gl.vertexAttribPointer(positionLocation2,
+                2,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                8
+            );
+            gl.vertexAttribPointer(thicknessLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                16
+            );
+            gl.vertexAttribPointer(targetSizeLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                20
+            );
+            gl.vertexAttribPointer(delayLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                24
+            );
+            gl.vertexAttribPointer(minusLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                28
+            );
+            gl.vertexAttribPointer(headLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                32
+            );
+            gl.vertexAttribPointer(headPositionLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                36
+            );
+            gl.vertexAttribPointer(colorLocation,
+                1,
+                gl.FLOAT,
+                false,
+                this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
+                40
+            );
 
-    //-- First we create the edges which are not already created
-    if (drawEdges)
-      for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
-        if (!this.domElements.edges[a[i].id]) {
-          source = nodes(a[i].source);
-          target = nodes(a[i].target);
+            gl.drawArrays(
+                gl.TRIANGLES,
+                params.start || 0,
+                params.count || (data.length / this.ATTRIBUTES)
+            );
+        },
+        initProgram: function (gl) {
+            var vertexShader,
+                fragmentShader,
+                program;
+
+            vertexShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'attribute vec2 a_pos1;',
+                    'attribute vec2 a_pos2;',
+                    'attribute float a_thickness;',
+                    'attribute float a_tSize;',
+                    'attribute float a_delay;',
+                    'attribute float a_minus;',
+                    'attribute float a_head;',
+                    'attribute float a_headPosition;',
+                    'attribute float a_color;',
+
+                    'uniform vec2 u_resolution;',
+                    'uniform float u_ratio;',
+                    'uniform float u_nodeRatio;',
+                    'uniform float u_arrowHead;',
+                    'uniform float u_scale;',
+                    'uniform mat3 u_matrix;',
+                    'uniform mat2 u_matrixHalfPi;',
+                    'uniform mat2 u_matrixHalfPiMinus;',
+
+                    'varying vec4 color;',
+
+                    'void main() {',
+                    // Find the good point:
+                    'vec2 pos = normalize(a_pos2 - a_pos1);',
+
+                    'mat2 matrix = (1.0 - a_head) *',
+                    '(',
+                    'a_minus * u_matrixHalfPiMinus +',
+                    '(1.0 - a_minus) * u_matrixHalfPi',
+                    ') + a_head * (',
+                    'a_headPosition * u_matrixHalfPiMinus * 0.6 +',
+                    '(a_headPosition * a_headPosition - 1.0) * mat2(1.0)',
+                    ');',
+
+                    'pos = a_pos1 + (',
+                    // Deal with body:
+                    '(1.0 - a_head) * a_thickness * u_ratio * matrix * pos +',
+                    // Deal with head:
+                    'a_head * u_arrowHead * a_thickness * u_ratio * matrix * pos +',
+                    // Deal with delay:
+                    'a_delay * pos * (',
+                    'a_tSize / u_nodeRatio +',
+                    'u_arrowHead * a_thickness * u_ratio',
+                    ')',
+                    ');',
+
+                    // Scale from [[-1 1] [-1 1]] to the container:
+                    'gl_Position = vec4(',
+                    '((u_matrix * vec3(pos, 1)).xy /',
+                    'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
+                    '0,',
+                    '1',
+                    ');',
+
+                    // Extract the color:
+                    'float c = a_color;',
+                    'color.b = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.g = mod(c, 256.0); c = floor(c / 256.0);',
+                    'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
+                    'color.a = 1.0;',
+                    '}'
+                ].join('\n'),
+                gl.VERTEX_SHADER
+            );
 
-          e = (renderers[a[i].type] || renderers.def).create(
-            a[i],
-            source,
-            target,
-            embedSettings
-          );
-
-          this.domElements.edges[a[i].id] = e;
-          this.domElements.groups.edges.appendChild(e);
-        }
-       }
-
-    //-- Second we update the edges
-    if (drawEdges)
-      for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) {
-        source = nodes(a[i].source);
-        target = nodes(a[i].target);
-
-        (renderers[a[i].type] || renderers.def).update(
-          a[i],
-          this.domElements.edges[a[i].id],
-          source,
-          target,
-          embedSettings
-        );
-       }
-
-    this.dispatchEvent('render');
-
-    return this;
-  };
-
-  /**
-   * This method creates a DOM element of the specified type, switches its
-   * position to "absolute", references it to the domElements attribute, and
-   * finally appends it to the container.
-   *
-   * @param  {string} tag The label tag.
-   * @param  {string} id  The id of the element (to store it in "domElements").
-   */
-  sigma.renderers.svg.prototype.initDOM = function(tag) {
-    var dom = document.createElementNS(this.settings('xmlns'), tag),
-        c = this.settings('classPrefix'),
-        g,
-        l,
-        i;
-
-    dom.style.position = 'absolute';
-    dom.setAttribute('class', c + '-svg');
-
-    // Setting SVG namespace
-    dom.setAttribute('xmlns', this.settings('xmlns'));
-    dom.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
-    dom.setAttribute('version', '1.1');
-
-    // Creating the measurement canvas
-    var canvas = document.createElement('canvas');
-    canvas.setAttribute('class', c + '-measurement-canvas');
-
-    // Appending elements
-    this.domElements.graph = this.container.appendChild(dom);
-
-    // Creating groups
-    var groups = ['edges', 'nodes', 'labels', 'hovers'];
-    for (i = 0, l = groups.length; i < l; i++) {
-      g = document.createElementNS(this.settings('xmlns'), 'g');
-
-      g.setAttributeNS(null, 'id', c + '-group-' + groups[i]);
-      g.setAttributeNS(null, 'class', c + '-group');
-
-      this.domElements.groups[groups[i]] =
-        this.domElements.graph.appendChild(g);
-    }
+            fragmentShader = sigma.utils.loadShader(
+                gl,
+                [
+                    'precision mediump float;',
 
-    // Appending measurement canvas
-    this.container.appendChild(canvas);
-    this.measurementCanvas = canvas.getContext('2d');
-  };
-
-  /**
-   * This method hides a batch of SVG DOM elements.
-   *
-   * @param  {array}                  elements  An array of elements to hide.
-   * @param  {object}                 renderer  The renderer to use.
-   * @return {sigma.renderers.svg}              Returns the instance itself.
-   */
-  sigma.renderers.svg.prototype.hideDOMElements = function(elements) {
-    var o,
-        i;
-
-    for (i in elements) {
-      o = elements[i];
-      sigma.svg.utils.hide(o);
-    }
+                    'varying vec4 color;',
 
-    return this;
-  };
-
-  /**
-   * This method binds the hover events to the renderer.
-   *
-   * @param  {string} prefix The renderer prefix.
-   */
-  // TODO: add option about whether to display hovers or not
-  sigma.renderers.svg.prototype.bindHovers = function(prefix) {
-    var renderers = sigma.svg.hovers,
-        self = this,
-        hoveredNode;
-
-    function overNode(e) {
-      var node = e.data.node,
-          embedSettings = self.settings.embedObjects({
-            prefix: prefix
-          });
-
-      if (!embedSettings('enableHovering'))
-        return;
-
-      var hover = (renderers[node.type] || renderers.def).create(
-        node,
-        self.domElements.nodes[node.id],
-        self.measurementCanvas,
-        embedSettings
-      );
-
-      self.domElements.hovers[node.id] = hover;
-
-      // Inserting the hover in the dom
-      self.domElements.groups.hovers.appendChild(hover);
-      hoveredNode = node;
-    }
+                    'void main(void) {',
+                    'gl_FragColor = color;',
+                    '}'
+                ].join('\n'),
+                gl.FRAGMENT_SHADER
+            );
 
-    function outNode(e) {
-      var node = e.data.node,
-          embedSettings = self.settings.embedObjects({
-            prefix: prefix
-          });
-
-      if (!embedSettings('enableHovering'))
-        return;
-
-      // Deleting element
-      self.domElements.groups.hovers.removeChild(
-        self.domElements.hovers[node.id]
-      );
-      hoveredNode = null;
-      delete self.domElements.hovers[node.id];
-
-      // Reinstate
-      self.domElements.groups.nodes.appendChild(
-        self.domElements.nodes[node.id]
-      );
-    }
+            program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
 
-    // OPTIMIZE: perform a real update rather than a deletion
-    function update() {
-      if (!hoveredNode)
-        return;
+            return program;
+        }
+    };
+})();
 
-      var embedSettings = self.settings.embedObjects({
-            prefix: prefix
-          });
+;(function (undefined) {
+    'use strict';
 
-      // Deleting element before update
-      self.domElements.groups.hovers.removeChild(
-        self.domElements.hovers[hoveredNode.id]
-      );
-      delete self.domElements.hovers[hoveredNode.id];
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      var hover = (renderers[hoveredNode.type] || renderers.def).create(
-        hoveredNode,
-        self.domElements.nodes[hoveredNode.id],
-        self.measurementCanvas,
-        embedSettings
-      );
+    // Initialize packages:
+    sigma.utils.pkg('sigma.canvas.labels');
 
-      self.domElements.hovers[hoveredNode.id] = hover;
+    /**
+     * This label renderer will just display the label on the right of the node.
+     *
+     * @param  {object}                   node     The node object.
+     * @param  {CanvasRenderingContext2D} context  The canvas context.
+     * @param  {configurable}             settings The settings function.
+     */
+    sigma.canvas.labels.def = function (node, context, settings) {
+        var fontSize,
+            prefix = settings('prefix') || '',
+            size = node[prefix + 'size'];
 
-      // Inserting the hover in the dom
-      self.domElements.groups.hovers.appendChild(hover);
-    }
+        if (size < settings('labelThreshold'))
+            return;
 
-    // Binding events
-    this.bind('overNode', overNode);
-    this.bind('outNode', outNode);
-
-    // Update on render
-    this.bind('render', update);
-  };
-
-  /**
-   * This method resizes each DOM elements in the container and stores the new
-   * dimensions. Then, it renders the graph.
-   *
-   * @param  {?number}                width  The new width of the container.
-   * @param  {?number}                height The new height of the container.
-   * @return {sigma.renderers.svg}           Returns the instance itself.
-   */
-  sigma.renderers.svg.prototype.resize = function(w, h) {
-    var oldWidth = this.width,
-        oldHeight = this.height,
-        pixelRatio = 1;
-
-    if (w !== undefined && h !== undefined) {
-      this.width = w;
-      this.height = h;
-    } else {
-      this.width = this.container.offsetWidth;
-      this.height = this.container.offsetHeight;
-
-      w = this.width;
-      h = this.height;
-    }
+        if (!node.label || typeof node.label !== 'string')
+            return;
 
-    if (oldWidth !== this.width || oldHeight !== this.height) {
-      this.domElements.graph.style.width = w + 'px';
-      this.domElements.graph.style.height = h + 'px';
+        fontSize = (settings('labelSize') === 'fixed') ?
+            settings('defaultLabelSize') :
+        settings('labelSizeRatio') * size;
 
-      if (this.domElements.graph.tagName.toLowerCase() === 'svg') {
-        this.domElements.graph.setAttribute('width', (w * pixelRatio));
-        this.domElements.graph.setAttribute('height', (h * pixelRatio));
-      }
-    }
+        context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
+            fontSize + 'px ' + settings('font');
+        context.fillStyle = (settings('labelColor') === 'node') ?
+            (node.color || settings('defaultNodeColor')) :
+            settings('defaultLabelColor');
 
-    return this;
-  };
-
-
-  /**
-   * The labels, nodes and edges renderers are stored in the three following
-   * objects. When an element is drawn, its type will be checked and if a
-   * renderer with the same name exists, it will be used. If not found, the
-   * default renderer will be used instead.
-   *
-   * They are stored in different files, in the "./svg" folder.
-   */
-  sigma.utils.pkg('sigma.svg.nodes');
-  sigma.utils.pkg('sigma.svg.edges');
-  sigma.utils.pkg('sigma.svg.labels');
+        context.fillText(
+            node.label,
+            Math.round(node[prefix + 'x'] + size + 3),
+            Math.round(node[prefix + 'y'] + fontSize / 3)
+        );
+    };
 }).call(this);
 
-;(function(global) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.renderers');
-
-  // Check if WebGL is enabled:
-  var canvas,
-      webgl = !!global.WebGLRenderingContext;
-  if (webgl) {
-    canvas = document.createElement('canvas');
-    try {
-      webgl = !!(
-        canvas.getContext('webgl') ||
-        canvas.getContext('experimental-webgl')
-      );
-    } catch (e) {
-      webgl = false;
-    }
-  }
+;(function (undefined) {
+    'use strict';
 
-  // Copy the good renderer:
-  sigma.renderers.def = webgl ?
-    sigma.renderers.webgl :
-    sigma.renderers.canvas;
-})(this);
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.webgl.nodes');
-
-  /**
-   * This node renderer will display nodes as discs, shaped in triangles with
-   * the gl.TRIANGLES display mode. So, to be more precise, to draw one node,
-   * it will store three times the center of node, with the color and the size,
-   * and an angle indicating which "corner" of the triangle to draw.
-   *
-   * The fragment shader does not deal with anti-aliasing, so make sure that
-   * you deal with it somewhere else in the code (by default, the WebGL
-   * renderer will oversample the rendering through the webglOversamplingRatio
-   * value).
-   */
-  sigma.webgl.nodes.def = {
-    POINTS: 3,
-    ATTRIBUTES: 5,
-    addNode: function(node, data, i, prefix, settings) {
-      var color = sigma.utils.floatColor(
-        node.color || settings('defaultNodeColor')
-      );
-
-      data[i++] = node[prefix + 'x'];
-      data[i++] = node[prefix + 'y'];
-      data[i++] = node[prefix + 'size'];
-      data[i++] = color;
-      data[i++] = 0;
-
-      data[i++] = node[prefix + 'x'];
-      data[i++] = node[prefix + 'y'];
-      data[i++] = node[prefix + 'size'];
-      data[i++] = color;
-      data[i++] = 2 * Math.PI / 3;
-
-      data[i++] = node[prefix + 'x'];
-      data[i++] = node[prefix + 'y'];
-      data[i++] = node[prefix + 'size'];
-      data[i++] = color;
-      data[i++] = 4 * Math.PI / 3;
-    },
-    render: function(gl, program, data, params) {
-      var buffer;
-
-      // Define attributes:
-      var positionLocation =
-            gl.getAttribLocation(program, 'a_position'),
-          sizeLocation =
-            gl.getAttribLocation(program, 'a_size'),
-          colorLocation =
-            gl.getAttribLocation(program, 'a_color'),
-          angleLocation =
-            gl.getAttribLocation(program, 'a_angle'),
-          resolutionLocation =
-            gl.getUniformLocation(program, 'u_resolution'),
-          matrixLocation =
-            gl.getUniformLocation(program, 'u_matrix'),
-          ratioLocation =
-            gl.getUniformLocation(program, 'u_ratio'),
-          scaleLocation =
-            gl.getUniformLocation(program, 'u_scale');
-
-      buffer = gl.createBuffer();
-      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-      gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
-
-      gl.uniform2f(resolutionLocation, params.width, params.height);
-      gl.uniform1f(
-        ratioLocation,
-        1 / Math.pow(params.ratio, params.settings('nodesPowRatio'))
-      );
-      gl.uniform1f(scaleLocation, params.scalingRatio);
-      gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
-
-      gl.enableVertexAttribArray(positionLocation);
-      gl.enableVertexAttribArray(sizeLocation);
-      gl.enableVertexAttribArray(colorLocation);
-      gl.enableVertexAttribArray(angleLocation);
-
-      gl.vertexAttribPointer(
-        positionLocation,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        0
-      );
-      gl.vertexAttribPointer(
-        sizeLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        8
-      );
-      gl.vertexAttribPointer(
-        colorLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        12
-      );
-      gl.vertexAttribPointer(
-        angleLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        16
-      );
-
-      gl.drawArrays(
-        gl.TRIANGLES,
-        params.start || 0,
-        params.count || (data.length / this.ATTRIBUTES)
-      );
-    },
-    initProgram: function(gl) {
-      var vertexShader,
-          fragmentShader,
-          program;
-
-      vertexShader = sigma.utils.loadShader(
-        gl,
-        [
-          'attribute vec2 a_position;',
-          'attribute float a_size;',
-          'attribute float a_color;',
-          'attribute float a_angle;',
-
-          'uniform vec2 u_resolution;',
-          'uniform float u_ratio;',
-          'uniform float u_scale;',
-          'uniform mat3 u_matrix;',
-
-          'varying vec4 color;',
-          'varying vec2 center;',
-          'varying float radius;',
-
-          'void main() {',
-            // Multiply the point size twice:
-            'radius = a_size * u_ratio;',
-
-            // Scale from [[-1 1] [-1 1]] to the container:
-            'vec2 position = (u_matrix * vec3(a_position, 1)).xy;',
-            // 'center = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);',
-            'center = position * u_scale;',
-            'center = vec2(center.x, u_scale * u_resolution.y - center.y);',
-
-            'position = position +',
-              '2.0 * radius * vec2(cos(a_angle), sin(a_angle));',
-            'position = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);',
-
-            'radius = radius * u_scale;',
-
-            'gl_Position = vec4(position, 0, 1);',
-
-            // Extract the color:
-            'float c = a_color;',
-            'color.b = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.g = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
-            'color.a = 1.0;',
-          '}'
-        ].join('\n'),
-        gl.VERTEX_SHADER
-      );
-
-      fragmentShader = sigma.utils.loadShader(
-        gl,
-        [
-          'precision mediump float;',
-
-          'varying vec4 color;',
-          'varying vec2 center;',
-          'varying float radius;',
-
-          'void main(void) {',
-            'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);',
-
-            'vec2 m = gl_FragCoord.xy - center;',
-            'float diff = radius - sqrt(m.x * m.x + m.y * m.y);',
-
-            // Here is how we draw a disc instead of a square:
-            'if (diff > 0.0)',
-              'gl_FragColor = color;',
-            'else',
-              'gl_FragColor = color0;',
-          '}'
-        ].join('\n'),
-        gl.FRAGMENT_SHADER
-      );
-
-      program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
-
-      return program;
-    }
-  };
-})();
+    // Initialize packages:
+    sigma.utils.pkg('sigma.canvas.hovers');
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.webgl.nodes');
-
-  /**
-   * This node renderer will display nodes in the fastest way: Nodes are basic
-   * squares, drawn through the gl.POINTS drawing method. The size of the nodes
-   * are represented with the "gl_PointSize" value in the vertex shader.
-   *
-   * It is the fastest node renderer here since the buffer just takes one line
-   * to draw each node (with attributes "x", "y", "size" and "color").
-   *
-   * Nevertheless, this method has some problems, especially due to some issues
-   * with the gl.POINTS:
-   *  - First, if the center of a node is outside the scene, the point will not
-   *    be drawn, even if it should be partly on screen.
-   *  - I tried applying a fragment shader similar to the one in the default
-   *    node renderer to display them as discs, but it did not work fine on
-   *    some computers settings, filling the discs with weird gradients not
-   *    depending on the actual color.
-   */
-  sigma.webgl.nodes.fast = {
-    POINTS: 1,
-    ATTRIBUTES: 4,
-    addNode: function(node, data, i, prefix, settings) {
-      data[i++] = node[prefix + 'x'];
-      data[i++] = node[prefix + 'y'];
-      data[i++] = node[prefix + 'size'];
-      data[i++] = sigma.utils.floatColor(
-        node.color || settings('defaultNodeColor')
-      );
-    },
-    render: function(gl, program, data, params) {
-      var buffer;
-
-      // Define attributes:
-      var positionLocation =
-            gl.getAttribLocation(program, 'a_position'),
-          sizeLocation =
-            gl.getAttribLocation(program, 'a_size'),
-          colorLocation =
-            gl.getAttribLocation(program, 'a_color'),
-          resolutionLocation =
-            gl.getUniformLocation(program, 'u_resolution'),
-          matrixLocation =
-            gl.getUniformLocation(program, 'u_matrix'),
-          ratioLocation =
-            gl.getUniformLocation(program, 'u_ratio'),
-          scaleLocation =
-            gl.getUniformLocation(program, 'u_scale');
-
-      buffer = gl.createBuffer();
-      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-      gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
-
-      gl.uniform2f(resolutionLocation, params.width, params.height);
-      gl.uniform1f(
-        ratioLocation,
-        1 / Math.pow(params.ratio, params.settings('nodesPowRatio'))
-      );
-      gl.uniform1f(scaleLocation, params.scalingRatio);
-      gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
-
-      gl.enableVertexAttribArray(positionLocation);
-      gl.enableVertexAttribArray(sizeLocation);
-      gl.enableVertexAttribArray(colorLocation);
-
-      gl.vertexAttribPointer(
-        positionLocation,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        0
-      );
-      gl.vertexAttribPointer(
-        sizeLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        8
-      );
-      gl.vertexAttribPointer(
-        colorLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        12
-      );
-
-      gl.drawArrays(
-        gl.POINTS,
-        params.start || 0,
-        params.count || (data.length / this.ATTRIBUTES)
-      );
-    },
-    initProgram: function(gl) {
-      var vertexShader,
-          fragmentShader,
-          program;
-
-      vertexShader = sigma.utils.loadShader(
-        gl,
-        [
-          'attribute vec2 a_position;',
-          'attribute float a_size;',
-          'attribute float a_color;',
-
-          'uniform vec2 u_resolution;',
-          'uniform float u_ratio;',
-          'uniform float u_scale;',
-          'uniform mat3 u_matrix;',
-
-          'varying vec4 color;',
-
-          'void main() {',
-            // Scale from [[-1 1] [-1 1]] to the container:
-            'gl_Position = vec4(',
-              '((u_matrix * vec3(a_position, 1)).xy /',
-                'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
-              '0,',
-              '1',
-            ');',
-
-            // Multiply the point size twice:
-            //  - x SCALING_RATIO to correct the canvas scaling
-            //  - x 2 to correct the formulae
-            'gl_PointSize = a_size * u_ratio * u_scale * 2.0;',
-
-            // Extract the color:
-            'float c = a_color;',
-            'color.b = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.g = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
-            'color.a = 1.0;',
-          '}'
-        ].join('\n'),
-        gl.VERTEX_SHADER
-      );
-
-      fragmentShader = sigma.utils.loadShader(
-        gl,
-        [
-          'precision mediump float;',
-
-          'varying vec4 color;',
-
-          'void main(void) {',
-            'float border = 0.01;',
-            'float radius = 0.5;',
-
-            'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);',
-            'vec2 m = gl_PointCoord - vec2(0.5, 0.5);',
-            'float dist = radius - sqrt(m.x * m.x + m.y * m.y);',
-
-            'float t = 0.0;',
-            'if (dist > border)',
-              't = 1.0;',
-            'else if (dist > 0.0)',
-              't = dist / border;',
-
-            'gl_FragColor = mix(color0, color, t);',
-          '}'
-        ].join('\n'),
-        gl.FRAGMENT_SHADER
-      );
-
-      program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
-
-      return program;
-    }
-  };
-})();
+    /**
+     * This hover renderer will basically display the label with a background.
+     *
+     * @param  {object}                   node     The node object.
+     * @param  {CanvasRenderingContext2D} context  The canvas context.
+     * @param  {configurable}             settings The settings function.
+     */
+    sigma.canvas.hovers.def = function (node, context, settings) {
+        var x,
+            y,
+            w,
+            h,
+            e,
+            fontStyle = settings('hoverFontStyle') || settings('fontStyle'),
+            prefix = settings('prefix') || '',
+            size = node[prefix + 'size'],
+            fontSize = (settings('labelSize') === 'fixed') ?
+                settings('defaultLabelSize') :
+            settings('labelSizeRatio') * size;
+
+        // Label background:
+        context.font = (fontStyle ? fontStyle + ' ' : '') +
+            fontSize + 'px ' + (settings('hoverFont') || settings('font'));
+
+        context.beginPath();
+        context.fillStyle = settings('labelHoverBGColor') === 'node' ?
+            (node.color || settings('defaultNodeColor')) :
+            settings('defaultHoverLabelBGColor');
+
+        if (node.label && settings('labelHoverShadow')) {
+            context.shadowOffsetX = 0;
+            context.shadowOffsetY = 0;
+            context.shadowBlur = 8;
+            context.shadowColor = settings('labelHoverShadowColor');
+        }
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.webgl.edges');
-
-  /**
-   * This edge renderer will display edges as lines going from the source node
-   * to the target node. To deal with edge thicknesses, the lines are made of
-   * two triangles forming rectangles, with the gl.TRIANGLES drawing mode.
-   *
-   * It is expensive, since drawing a single edge requires 6 points, each
-   * having 7 attributes (source position, target position, thickness, color
-   * and a flag indicating which vertice of the rectangle it is).
-   */
-  sigma.webgl.edges.def = {
-    POINTS: 6,
-    ATTRIBUTES: 7,
-    addEdge: function(edge, source, target, data, i, prefix, settings) {
-      var w = (edge[prefix + 'size'] || 1) / 2,
-          x1 = source[prefix + 'x'],
-          y1 = source[prefix + 'y'],
-          x2 = target[prefix + 'x'],
-          y2 = target[prefix + 'y'],
-          color = edge.color;
-
-      if (!color)
-        switch (settings('edgeColor')) {
-          case 'source':
-            color = source.color || settings('defaultNodeColor');
-            break;
-          case 'target':
-            color = target.color || settings('defaultNodeColor');
-            break;
-          default:
-            color = settings('defaultEdgeColor');
-            break;
-        }
-
-      // Normalize color:
-      color = sigma.utils.floatColor(color);
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = 1.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = 1.0;
-      data[i++] = color;
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = 0.0;
-      data[i++] = color;
-    },
-    render: function(gl, program, data, params) {
-      var buffer;
-
-      // Define attributes:
-      var colorLocation =
-            gl.getAttribLocation(program, 'a_color'),
-          positionLocation1 =
-            gl.getAttribLocation(program, 'a_position1'),
-          positionLocation2 =
-            gl.getAttribLocation(program, 'a_position2'),
-          thicknessLocation =
-            gl.getAttribLocation(program, 'a_thickness'),
-          minusLocation =
-            gl.getAttribLocation(program, 'a_minus'),
-          resolutionLocation =
-            gl.getUniformLocation(program, 'u_resolution'),
-          matrixLocation =
-            gl.getUniformLocation(program, 'u_matrix'),
-          matrixHalfPiLocation =
-            gl.getUniformLocation(program, 'u_matrixHalfPi'),
-          matrixHalfPiMinusLocation =
-            gl.getUniformLocation(program, 'u_matrixHalfPiMinus'),
-          ratioLocation =
-            gl.getUniformLocation(program, 'u_ratio'),
-          scaleLocation =
-            gl.getUniformLocation(program, 'u_scale');
-
-      buffer = gl.createBuffer();
-      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-      gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
-
-      gl.uniform2f(resolutionLocation, params.width, params.height);
-      gl.uniform1f(
-        ratioLocation,
-        params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio'))
-      );
-      gl.uniform1f(scaleLocation, params.scalingRatio);
-      gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
-      gl.uniformMatrix2fv(
-        matrixHalfPiLocation,
-        false,
-        sigma.utils.matrices.rotation(Math.PI / 2, true)
-      );
-      gl.uniformMatrix2fv(
-        matrixHalfPiMinusLocation,
-        false,
-        sigma.utils.matrices.rotation(-Math.PI / 2, true)
-      );
-
-      gl.enableVertexAttribArray(colorLocation);
-      gl.enableVertexAttribArray(positionLocation1);
-      gl.enableVertexAttribArray(positionLocation2);
-      gl.enableVertexAttribArray(thicknessLocation);
-      gl.enableVertexAttribArray(minusLocation);
-
-      gl.vertexAttribPointer(positionLocation1,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        0
-      );
-      gl.vertexAttribPointer(positionLocation2,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        8
-      );
-      gl.vertexAttribPointer(thicknessLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        16
-      );
-      gl.vertexAttribPointer(minusLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        20
-      );
-      gl.vertexAttribPointer(colorLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        24
-      );
-
-      gl.drawArrays(
-        gl.TRIANGLES,
-        params.start || 0,
-        params.count || (data.length / this.ATTRIBUTES)
-      );
-    },
-    initProgram: function(gl) {
-      var vertexShader,
-          fragmentShader,
-          program;
-
-      vertexShader = sigma.utils.loadShader(
-        gl,
-        [
-          'attribute vec2 a_position1;',
-          'attribute vec2 a_position2;',
-          'attribute float a_thickness;',
-          'attribute float a_minus;',
-          'attribute float a_color;',
-
-          'uniform vec2 u_resolution;',
-          'uniform float u_ratio;',
-          'uniform float u_scale;',
-          'uniform mat3 u_matrix;',
-          'uniform mat2 u_matrixHalfPi;',
-          'uniform mat2 u_matrixHalfPiMinus;',
-
-          'varying vec4 color;',
-
-          'void main() {',
-            // Find the good point:
-            'vec2 position = a_thickness * u_ratio *',
-              'normalize(a_position2 - a_position1);',
-
-            'mat2 matrix = a_minus * u_matrixHalfPiMinus +',
-              '(1.0 - a_minus) * u_matrixHalfPi;',
-
-            'position = matrix * position + a_position1;',
-
-            // Scale from [[-1 1] [-1 1]] to the container:
-            'gl_Position = vec4(',
-              '((u_matrix * vec3(position, 1)).xy /',
-                'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
-              '0,',
-              '1',
-            ');',
-
-            // Extract the color:
-            'float c = a_color;',
-            'color.b = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.g = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
-            'color.a = 1.0;',
-          '}'
-        ].join('\n'),
-        gl.VERTEX_SHADER
-      );
-
-      fragmentShader = sigma.utils.loadShader(
-        gl,
-        [
-          'precision mediump float;',
-
-          'varying vec4 color;',
-
-          'void main(void) {',
-            'gl_FragColor = color;',
-          '}'
-        ].join('\n'),
-        gl.FRAGMENT_SHADER
-      );
-
-      program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
-
-      return program;
-    }
-  };
-})();
+        if (node.label && typeof node.label === 'string') {
+            x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2);
+            y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2);
+            w = Math.round(
+                context.measureText(node.label).width + fontSize / 2 + size + 7
+            );
+            h = Math.round(fontSize + 4);
+            e = Math.round(fontSize / 2 + 2);
+
+            context.moveTo(x, y + e);
+            context.arcTo(x, y, x + e, y, e);
+            context.lineTo(x + w, y);
+            context.lineTo(x + w, y + h);
+            context.lineTo(x + e, y + h);
+            context.arcTo(x, y + h, x, y + h - e, e);
+            context.lineTo(x, y + e);
+
+            context.closePath();
+            context.fill();
+
+            context.shadowOffsetX = 0;
+            context.shadowOffsetY = 0;
+            context.shadowBlur = 0;
+        }
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.webgl.edges');
-
-  /**
-   * This edge renderer will display edges as lines with the gl.LINES display
-   * mode. Since this mode does not support well thickness, edges are all drawn
-   * with the same thickness (3px), independantly of the edge attributes or the
-   * zooming ratio.
-   */
-  sigma.webgl.edges.fast = {
-    POINTS: 2,
-    ATTRIBUTES: 3,
-    addEdge: function(edge, source, target, data, i, prefix, settings) {
-      var w = (edge[prefix + 'size'] || 1) / 2,
-          x1 = source[prefix + 'x'],
-          y1 = source[prefix + 'y'],
-          x2 = target[prefix + 'x'],
-          y2 = target[prefix + 'y'],
-          color = edge.color;
-
-      if (!color)
-        switch (settings('edgeColor')) {
-          case 'source':
-            color = source.color || settings('defaultNodeColor');
-            break;
-          case 'target':
-            color = target.color || settings('defaultNodeColor');
-            break;
-          default:
-            color = settings('defaultEdgeColor');
-            break;
-        }
-
-      // Normalize color:
-      color = sigma.utils.floatColor(color);
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = color;
-    },
-    render: function(gl, program, data, params) {
-      var buffer;
-
-      // Define attributes:
-      var colorLocation =
-            gl.getAttribLocation(program, 'a_color'),
-          positionLocation =
-            gl.getAttribLocation(program, 'a_position'),
-          resolutionLocation =
-            gl.getUniformLocation(program, 'u_resolution'),
-          matrixLocation =
-            gl.getUniformLocation(program, 'u_matrix');
-
-      buffer = gl.createBuffer();
-      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-      gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);
-
-      gl.uniform2f(resolutionLocation, params.width, params.height);
-      gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
-
-      gl.enableVertexAttribArray(positionLocation);
-      gl.enableVertexAttribArray(colorLocation);
-
-      gl.vertexAttribPointer(positionLocation,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        0
-      );
-      gl.vertexAttribPointer(colorLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        8
-      );
-
-      gl.lineWidth(3);
-      gl.drawArrays(
-        gl.LINES,
-        params.start || 0,
-        params.count || (data.length / this.ATTRIBUTES)
-      );
-    },
-    initProgram: function(gl) {
-      var vertexShader,
-          fragmentShader,
-          program;
-
-      vertexShader = sigma.utils.loadShader(
-        gl,
-        [
-          'attribute vec2 a_position;',
-          'attribute float a_color;',
-
-          'uniform vec2 u_resolution;',
-          'uniform mat3 u_matrix;',
-
-          'varying vec4 color;',
-
-          'void main() {',
-            // Scale from [[-1 1] [-1 1]] to the container:
-            'gl_Position = vec4(',
-              '((u_matrix * vec3(a_position, 1)).xy /',
-                'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
-              '0,',
-              '1',
-            ');',
-
-            // Extract the color:
-            'float c = a_color;',
-            'color.b = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.g = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
-            'color.a = 1.0;',
-          '}'
-        ].join('\n'),
-        gl.VERTEX_SHADER
-      );
-
-      fragmentShader = sigma.utils.loadShader(
-        gl,
-        [
-          'precision mediump float;',
-
-          'varying vec4 color;',
-
-          'void main(void) {',
-            'gl_FragColor = color;',
-          '}'
-        ].join('\n'),
-        gl.FRAGMENT_SHADER
-      );
-
-      program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
-
-      return program;
-    }
-  };
-})();
+        // Node border:
+        if (settings('borderSize') > 0) {
+            context.beginPath();
+            context.fillStyle = settings('nodeBorderColor') === 'node' ?
+                (node.color || settings('defaultNodeColor')) :
+                settings('defaultNodeBorderColor');
+            context.arc(
+                node[prefix + 'x'],
+                node[prefix + 'y'],
+                size + settings('borderSize'),
+                0,
+                Math.PI * 2,
+                true
+            );
+            context.closePath();
+            context.fill();
+        }
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.webgl.edges');
-
-  /**
-   * This edge renderer will display edges as arrows going from the source node
-   * to the target node. To deal with edge thicknesses, the lines are made of
-   * three triangles: two forming rectangles, with the gl.TRIANGLES drawing
-   * mode.
-   *
-   * It is expensive, since drawing a single edge requires 9 points, each
-   * having a lot of attributes.
-   */
-  sigma.webgl.edges.arrow = {
-    POINTS: 9,
-    ATTRIBUTES: 11,
-    addEdge: function(edge, source, target, data, i, prefix, settings) {
-      var w = (edge[prefix + 'size'] || 1) / 2,
-          x1 = source[prefix + 'x'],
-          y1 = source[prefix + 'y'],
-          x2 = target[prefix + 'x'],
-          y2 = target[prefix + 'y'],
-          targetSize = target[prefix + 'size'],
-          color = edge.color;
-
-      if (!color)
-        switch (settings('edgeColor')) {
-          case 'source':
-            color = source.color || settings('defaultNodeColor');
-            break;
-          case 'target':
-            color = target.color || settings('defaultNodeColor');
-            break;
-          default:
-            color = settings('defaultEdgeColor');
-            break;
-        }
-
-      // Normalize color:
-      color = sigma.utils.floatColor(color);
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 0.0;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      // Arrow head:
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 1.0;
-      data[i++] = -1.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = color;
-
-      data[i++] = x2;
-      data[i++] = y2;
-      data[i++] = x1;
-      data[i++] = y1;
-      data[i++] = w;
-      data[i++] = targetSize;
-      data[i++] = 1.0;
-      data[i++] = 0.0;
-      data[i++] = 1.0;
-      data[i++] = 1.0;
-      data[i++] = color;
-    },
-    render: function(gl, program, data, params) {
-      var buffer;
-
-      // Define attributes:
-      var positionLocation1 =
-            gl.getAttribLocation(program, 'a_pos1'),
-          positionLocation2 =
-            gl.getAttribLocation(program, 'a_pos2'),
-          thicknessLocation =
-            gl.getAttribLocation(program, 'a_thickness'),
-          targetSizeLocation =
-            gl.getAttribLocation(program, 'a_tSize'),
-          delayLocation =
-            gl.getAttribLocation(program, 'a_delay'),
-          minusLocation =
-            gl.getAttribLocation(program, 'a_minus'),
-          headLocation =
-            gl.getAttribLocation(program, 'a_head'),
-          headPositionLocation =
-            gl.getAttribLocation(program, 'a_headPosition'),
-          colorLocation =
-            gl.getAttribLocation(program, 'a_color'),
-          resolutionLocation =
-            gl.getUniformLocation(program, 'u_resolution'),
-          matrixLocation =
-            gl.getUniformLocation(program, 'u_matrix'),
-          matrixHalfPiLocation =
-            gl.getUniformLocation(program, 'u_matrixHalfPi'),
-          matrixHalfPiMinusLocation =
-            gl.getUniformLocation(program, 'u_matrixHalfPiMinus'),
-          ratioLocation =
-            gl.getUniformLocation(program, 'u_ratio'),
-          nodeRatioLocation =
-            gl.getUniformLocation(program, 'u_nodeRatio'),
-          arrowHeadLocation =
-            gl.getUniformLocation(program, 'u_arrowHead'),
-          scaleLocation =
-            gl.getUniformLocation(program, 'u_scale');
-
-      buffer = gl.createBuffer();
-      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
-      gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
-
-      gl.uniform2f(resolutionLocation, params.width, params.height);
-      gl.uniform1f(
-        ratioLocation,
-        params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio'))
-      );
-      gl.uniform1f(
-        nodeRatioLocation,
-        Math.pow(params.ratio, params.settings('nodesPowRatio')) /
-        params.ratio
-      );
-      gl.uniform1f(arrowHeadLocation, 5.0);
-      gl.uniform1f(scaleLocation, params.scalingRatio);
-      gl.uniformMatrix3fv(matrixLocation, false, params.matrix);
-      gl.uniformMatrix2fv(
-        matrixHalfPiLocation,
-        false,
-        sigma.utils.matrices.rotation(Math.PI / 2, true)
-      );
-      gl.uniformMatrix2fv(
-        matrixHalfPiMinusLocation,
-        false,
-        sigma.utils.matrices.rotation(-Math.PI / 2, true)
-      );
-
-      gl.enableVertexAttribArray(positionLocation1);
-      gl.enableVertexAttribArray(positionLocation2);
-      gl.enableVertexAttribArray(thicknessLocation);
-      gl.enableVertexAttribArray(targetSizeLocation);
-      gl.enableVertexAttribArray(delayLocation);
-      gl.enableVertexAttribArray(minusLocation);
-      gl.enableVertexAttribArray(headLocation);
-      gl.enableVertexAttribArray(headPositionLocation);
-      gl.enableVertexAttribArray(colorLocation);
-
-      gl.vertexAttribPointer(positionLocation1,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        0
-      );
-      gl.vertexAttribPointer(positionLocation2,
-        2,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        8
-      );
-      gl.vertexAttribPointer(thicknessLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        16
-      );
-      gl.vertexAttribPointer(targetSizeLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        20
-      );
-      gl.vertexAttribPointer(delayLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        24
-      );
-      gl.vertexAttribPointer(minusLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        28
-      );
-      gl.vertexAttribPointer(headLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        32
-      );
-      gl.vertexAttribPointer(headPositionLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        36
-      );
-      gl.vertexAttribPointer(colorLocation,
-        1,
-        gl.FLOAT,
-        false,
-        this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
-        40
-      );
-
-      gl.drawArrays(
-        gl.TRIANGLES,
-        params.start || 0,
-        params.count || (data.length / this.ATTRIBUTES)
-      );
-    },
-    initProgram: function(gl) {
-      var vertexShader,
-          fragmentShader,
-          program;
-
-      vertexShader = sigma.utils.loadShader(
-        gl,
-        [
-          'attribute vec2 a_pos1;',
-          'attribute vec2 a_pos2;',
-          'attribute float a_thickness;',
-          'attribute float a_tSize;',
-          'attribute float a_delay;',
-          'attribute float a_minus;',
-          'attribute float a_head;',
-          'attribute float a_headPosition;',
-          'attribute float a_color;',
-
-          'uniform vec2 u_resolution;',
-          'uniform float u_ratio;',
-          'uniform float u_nodeRatio;',
-          'uniform float u_arrowHead;',
-          'uniform float u_scale;',
-          'uniform mat3 u_matrix;',
-          'uniform mat2 u_matrixHalfPi;',
-          'uniform mat2 u_matrixHalfPiMinus;',
-
-          'varying vec4 color;',
-
-          'void main() {',
-            // Find the good point:
-            'vec2 pos = normalize(a_pos2 - a_pos1);',
-
-            'mat2 matrix = (1.0 - a_head) *',
-              '(',
-                'a_minus * u_matrixHalfPiMinus +',
-                '(1.0 - a_minus) * u_matrixHalfPi',
-              ') + a_head * (',
-                'a_headPosition * u_matrixHalfPiMinus * 0.6 +',
-                '(a_headPosition * a_headPosition - 1.0) * mat2(1.0)',
-              ');',
-
-            'pos = a_pos1 + (',
-              // Deal with body:
-              '(1.0 - a_head) * a_thickness * u_ratio * matrix * pos +',
-              // Deal with head:
-              'a_head * u_arrowHead * a_thickness * u_ratio * matrix * pos +',
-              // Deal with delay:
-              'a_delay * pos * (',
-                'a_tSize / u_nodeRatio +',
-                'u_arrowHead * a_thickness * u_ratio',
-              ')',
-            ');',
-
-            // Scale from [[-1 1] [-1 1]] to the container:
-            'gl_Position = vec4(',
-              '((u_matrix * vec3(pos, 1)).xy /',
-                'u_resolution * 2.0 - 1.0) * vec2(1, -1),',
-              '0,',
-              '1',
-            ');',
-
-            // Extract the color:
-            'float c = a_color;',
-            'color.b = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.g = mod(c, 256.0); c = floor(c / 256.0);',
-            'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;',
-            'color.a = 1.0;',
-          '}'
-        ].join('\n'),
-        gl.VERTEX_SHADER
-      );
-
-      fragmentShader = sigma.utils.loadShader(
-        gl,
-        [
-          'precision mediump float;',
-
-          'varying vec4 color;',
-
-          'void main(void) {',
-            'gl_FragColor = color;',
-          '}'
-        ].join('\n'),
-        gl.FRAGMENT_SHADER
-      );
-
-      program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]);
-
-      return program;
-    }
-  };
-})();
+        // Node:
+        var nodeRenderer = sigma.canvas.nodes[node.type] || sigma.canvas.nodes.def;
+        nodeRenderer(node, context, settings);
+
+        // Display the label:
+        if (node.label && typeof node.label === 'string') {
+            context.fillStyle = (settings('labelHoverColor') === 'node') ?
+                (node.color || settings('defaultNodeColor')) :
+                settings('defaultLabelHoverColor');
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.canvas.labels');
-
-  /**
-   * This label renderer will just display the label on the right of the node.
-   *
-   * @param  {object}                   node     The node object.
-   * @param  {CanvasRenderingContext2D} context  The canvas context.
-   * @param  {configurable}             settings The settings function.
-   */
-  sigma.canvas.labels.def = function(node, context, settings) {
-    var fontSize,
-        prefix = settings('prefix') || '',
-        size = node[prefix + 'size'];
-
-    if (size < settings('labelThreshold'))
-      return;
-
-    if (!node.label || typeof node.label !== 'string')
-      return;
-
-    fontSize = (settings('labelSize') === 'fixed') ?
-      settings('defaultLabelSize') :
-      settings('labelSizeRatio') * size;
-
-    context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
-      fontSize + 'px ' + settings('font');
-    context.fillStyle = (settings('labelColor') === 'node') ?
-      (node.color || settings('defaultNodeColor')) :
-      settings('defaultLabelColor');
-
-    context.fillText(
-      node.label,
-      Math.round(node[prefix + 'x'] + size + 3),
-      Math.round(node[prefix + 'y'] + fontSize / 3)
-    );
-  };
+            context.fillText(
+                node.label,
+                Math.round(node[prefix + 'x'] + size + 3),
+                Math.round(node[prefix + 'y'] + fontSize / 3)
+            );
+        }
+    };
 }).call(this);
 
-;(function(undefined) {
-  'use strict';
+;(function () {
+    'use strict';
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
+    sigma.utils.pkg('sigma.canvas.nodes');
 
-  // Initialize packages:
-  sigma.utils.pkg('sigma.canvas.hovers');
+    /**
+     * The default node renderer. It renders the node as a simple disc.
+     *
+     * @param  {object}                   node     The node object.
+     * @param  {CanvasRenderingContext2D} context  The canvas context.
+     * @param  {configurable}             settings The settings function.
+     */
+    sigma.canvas.nodes.def = function (node, context, settings) {
+        var prefix = settings('prefix') || '';
+
+        context.fillStyle = node.color || settings('defaultNodeColor');
+        context.beginPath();
+        context.arc(
+            node[prefix + 'x'],
+            node[prefix + 'y'],
+            node[prefix + 'size'],
+            0,
+            Math.PI * 2,
+            true
+        );
 
-  /**
-   * This hover renderer will basically display the label with a background.
-   *
-   * @param  {object}                   node     The node object.
-   * @param  {CanvasRenderingContext2D} context  The canvas context.
-   * @param  {configurable}             settings The settings function.
-   */
-  sigma.canvas.hovers.def = function(node, context, settings) {
-    var x,
-        y,
-        w,
-        h,
-        e,
-        fontStyle = settings('hoverFontStyle') || settings('fontStyle'),
-        prefix = settings('prefix') || '',
-        size = node[prefix + 'size'],
-        fontSize = (settings('labelSize') === 'fixed') ?
-          settings('defaultLabelSize') :
-          settings('labelSizeRatio') * size;
-
-    // Label background:
-    context.font = (fontStyle ? fontStyle + ' ' : '') +
-      fontSize + 'px ' + (settings('hoverFont') || settings('font'));
-
-    context.beginPath();
-    context.fillStyle = settings('labelHoverBGColor') === 'node' ?
-      (node.color || settings('defaultNodeColor')) :
-      settings('defaultHoverLabelBGColor');
-
-    if (node.label && settings('labelHoverShadow')) {
-      context.shadowOffsetX = 0;
-      context.shadowOffsetY = 0;
-      context.shadowBlur = 8;
-      context.shadowColor = settings('labelHoverShadowColor');
-    }
+        context.closePath();
+        context.fill();
+    };
+})();
 
-    if (node.label && typeof node.label === 'string') {
-      x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2);
-      y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2);
-      w = Math.round(
-        context.measureText(node.label).width + fontSize / 2 + size + 7
-      );
-      h = Math.round(fontSize + 4);
-      e = Math.round(fontSize / 2 + 2);
-
-      context.moveTo(x, y + e);
-      context.arcTo(x, y, x + e, y, e);
-      context.lineTo(x + w, y);
-      context.lineTo(x + w, y + h);
-      context.lineTo(x + e, y + h);
-      context.arcTo(x, y + h, x, y + h - e, e);
-      context.lineTo(x, y + e);
-
-      context.closePath();
-      context.fill();
-
-      context.shadowOffsetX = 0;
-      context.shadowOffsetY = 0;
-      context.shadowBlur = 0;
-    }
+;(function () {
+    'use strict';
 
-    // Node border:
-    if (settings('borderSize') > 0) {
-      context.beginPath();
-      context.fillStyle = settings('nodeBorderColor') === 'node' ?
-        (node.color || settings('defaultNodeColor')) :
-        settings('defaultNodeBorderColor');
-      context.arc(
-        node[prefix + 'x'],
-        node[prefix + 'y'],
-        size + settings('borderSize'),
-        0,
-        Math.PI * 2,
-        true
-      );
-      context.closePath();
-      context.fill();
-    }
+    sigma.utils.pkg('sigma.canvas.edges');
 
-    // Node:
-    var nodeRenderer = sigma.canvas.nodes[node.type] || sigma.canvas.nodes.def;
-    nodeRenderer(node, context, settings);
-
-    // Display the label:
-    if (node.label && typeof node.label === 'string') {
-      context.fillStyle = (settings('labelHoverColor') === 'node') ?
-        (node.color || settings('defaultNodeColor')) :
-        settings('defaultLabelHoverColor');
-
-      context.fillText(
-        node.label,
-        Math.round(node[prefix + 'x'] + size + 3),
-        Math.round(node[prefix + 'y'] + fontSize / 3)
-      );
-    }
-  };
-}).call(this);
+    /**
+     * The default edge renderer. It renders the edge as a simple line.
+     *
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
+     */
+    sigma.canvas.edges.def = function (edge, source, target, context, settings) {
+        var color = edge.color,
+            prefix = settings('prefix') || '',
+            size = edge[prefix + 'size'] || 1,
+            edgeColor = settings('edgeColor'),
+            defaultNodeColor = settings('defaultNodeColor'),
+            defaultEdgeColor = settings('defaultEdgeColor');
+
+        if (!color)
+            switch (edgeColor) {
+                case 'source':
+                    color = source.color || defaultNodeColor;
+                    break;
+                case 'target':
+                    color = target.color || defaultNodeColor;
+                    break;
+                default:
+                    color = defaultEdgeColor;
+                    break;
+            }
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.nodes');
-
-  /**
-   * The default node renderer. It renders the node as a simple disc.
-   *
-   * @param  {object}                   node     The node object.
-   * @param  {CanvasRenderingContext2D} context  The canvas context.
-   * @param  {configurable}             settings The settings function.
-   */
-  sigma.canvas.nodes.def = function(node, context, settings) {
-    var prefix = settings('prefix') || '';
-
-    context.fillStyle = node.color || settings('defaultNodeColor');
-    context.beginPath();
-    context.arc(
-      node[prefix + 'x'],
-      node[prefix + 'y'],
-      node[prefix + 'size'],
-      0,
-      Math.PI * 2,
-      true
-    );
-
-    context.closePath();
-    context.fill();
-  };
+        context.strokeStyle = color;
+        context.lineWidth = size;
+        context.beginPath();
+        context.moveTo(
+            source[prefix + 'x'],
+            source[prefix + 'y']
+        );
+        context.lineTo(
+            target[prefix + 'x'],
+            target[prefix + 'y']
+        );
+        context.stroke();
+    };
 })();
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edges');
-
-  /**
-   * The default edge renderer. It renders the edge as a simple line.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edges.def = function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        size = edge[prefix + 'size'] || 1,
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor');
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(
-      source[prefix + 'x'],
-      source[prefix + 'y']
-    );
-    context.lineTo(
-      target[prefix + 'x'],
-      target[prefix + 'y']
-    );
-    context.stroke();
-  };
-})();
+;(function () {
+    'use strict';
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edges');
-
-  /**
-   * This edge renderer will display edges as curves.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edges.curve = function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        size = edge[prefix + 'size'] || 1,
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        cp = {},
-        sSize = source[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'];
-
-    cp = (source.id === target.id) ?
-      sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) :
-      sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    if (source.id === target.id) {
-      context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
-    } else {
-      context.quadraticCurveTo(cp.x, cp.y, tX, tY);
-    }
-    context.stroke();
-  };
-})();
+    sigma.utils.pkg('sigma.canvas.edges');
+
+    /**
+     * This edge renderer will display edges as curves.
+     *
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
+     */
+    sigma.canvas.edges.curve = function (edge, source, target, context, settings) {
+        var color = edge.color,
+            prefix = settings('prefix') || '',
+            size = edge[prefix + 'size'] || 1,
+            edgeColor = settings('edgeColor'),
+            defaultNodeColor = settings('defaultNodeColor'),
+            defaultEdgeColor = settings('defaultEdgeColor'),
+            cp = {},
+            sSize = source[prefix + 'size'],
+            sX = source[prefix + 'x'],
+            sY = source[prefix + 'y'],
+            tX = target[prefix + 'x'],
+            tY = target[prefix + 'y'];
+
+        cp = (source.id === target.id) ?
+            sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) :
+            sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
+
+        if (!color)
+            switch (edgeColor) {
+                case 'source':
+                    color = source.color || defaultNodeColor;
+                    break;
+                case 'target':
+                    color = target.color || defaultNodeColor;
+                    break;
+                default:
+                    color = defaultEdgeColor;
+                    break;
+            }
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edges');
-
-  /**
-   * This edge renderer will display edges as arrows going from the source node
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edges.arrow = function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        size = edge[prefix + 'size'] || 1,
-        tSize = target[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'],
-        aSize = Math.max(size * 2.5, settings('minArrowSize')),
-        d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)),
-        aX = sX + (tX - sX) * (d - aSize - tSize) / d,
-        aY = sY + (tY - sY) * (d - aSize - tSize) / d,
-        vX = (tX - sX) * aSize / d,
-        vY = (tY - sY) * aSize / d;
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    context.lineTo(
-      aX,
-      aY
-    );
-    context.stroke();
-
-    context.fillStyle = color;
-    context.beginPath();
-    context.moveTo(aX + vX, aY + vY);
-    context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
-    context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
-    context.lineTo(aX + vX, aY + vY);
-    context.closePath();
-    context.fill();
-  };
+        context.strokeStyle = color;
+        context.lineWidth = size;
+        context.beginPath();
+        context.moveTo(sX, sY);
+        if (source.id === target.id) {
+            context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
+        } else {
+            context.quadraticCurveTo(cp.x, cp.y, tX, tY);
+        }
+        context.stroke();
+    };
 })();
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edges');
-
-  /**
-   * This edge renderer will display edges as curves with arrow heading.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edges.curvedArrow =
-    function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        cp = {},
-        size = edge[prefix + 'size'] || 1,
-        tSize = target[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'],
-        aSize = Math.max(size * 2.5, settings('minArrowSize')),
-        d,
-        aX,
-        aY,
-        vX,
-        vY;
-
-    cp = (source.id === target.id) ?
-      sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) :
-      sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
-
-    if (source.id === target.id) {
-      d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
-      aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
-      aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
-      vX = (tX - cp.x1) * aSize / d;
-      vY = (tY - cp.y1) * aSize / d;
-    }
-    else {
-      d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
-      aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
-      aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
-      vX = (tX - cp.x) * aSize / d;
-      vY = (tY - cp.y) * aSize / d;
-    }
+;(function () {
+    'use strict';
 
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    if (source.id === target.id) {
-      context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
-    } else {
-      context.quadraticCurveTo(cp.x, cp.y, aX, aY);
-    }
-    context.stroke();
-
-    context.fillStyle = color;
-    context.beginPath();
-    context.moveTo(aX + vX, aY + vY);
-    context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
-    context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
-    context.lineTo(aX + vX, aY + vY);
-    context.closePath();
-    context.fill();
-  };
-})();
+    sigma.utils.pkg('sigma.canvas.edges');
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edgehovers');
-
-  /**
-   * This hover renderer will display the edge with a different color or size.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edgehovers.def =
-    function(edge, source, target, context, settings) {
-      var color = edge.color,
-        prefix = settings('prefix') || '',
-        size = edge[prefix + 'size'] || 1,
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor');
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    if (settings('edgeHoverColor') === 'edge') {
-      color = edge.hover_color || color;
-    } else {
-      color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
-    }
-    size *= settings('edgeHoverSizeRatio');
-
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(
-      source[prefix + 'x'],
-      source[prefix + 'y']
-    );
-    context.lineTo(
-      target[prefix + 'x'],
-      target[prefix + 'y']
-    );
-    context.stroke();
-  };
+    /**
+     * This edge renderer will display edges as arrows going from the source node
+     *
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
+     */
+    sigma.canvas.edges.arrow = function (edge, source, target, context, settings) {
+        var color = edge.color,
+            prefix = settings('prefix') || '',
+            edgeColor = settings('edgeColor'),
+            defaultNodeColor = settings('defaultNodeColor'),
+            defaultEdgeColor = settings('defaultEdgeColor'),
+            size = edge[prefix + 'size'] || 1,
+            tSize = target[prefix + 'size'],
+            sX = source[prefix + 'x'],
+            sY = source[prefix + 'y'],
+            tX = target[prefix + 'x'],
+            tY = target[prefix + 'y'],
+            aSize = Math.max(size * 2.5, settings('minArrowSize')),
+            d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)),
+            aX = sX + (tX - sX) * (d - aSize - tSize) / d,
+            aY = sY + (tY - sY) * (d - aSize - tSize) / d,
+            vX = (tX - sX) * aSize / d,
+            vY = (tY - sY) * aSize / d;
+
+        if (!color)
+            switch (edgeColor) {
+                case 'source':
+                    color = source.color || defaultNodeColor;
+                    break;
+                case 'target':
+                    color = target.color || defaultNodeColor;
+                    break;
+                default:
+                    color = defaultEdgeColor;
+                    break;
+            }
+
+        context.strokeStyle = color;
+        context.lineWidth = size;
+        context.beginPath();
+        context.moveTo(sX, sY);
+        context.lineTo(
+            aX,
+            aY
+        );
+        context.stroke();
+
+        context.fillStyle = color;
+        context.beginPath();
+        context.moveTo(aX + vX, aY + vY);
+        context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
+        context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
+        context.lineTo(aX + vX, aY + vY);
+        context.closePath();
+        context.fill();
+    };
 })();
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edgehovers');
-
-  /**
-   * This hover renderer will display the edge with a different color or size.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edgehovers.curve =
-    function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1),
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        cp = {},
-        sSize = source[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'];
-
-    cp = (source.id === target.id) ?
-      sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) :
-      sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    if (settings('edgeHoverColor') === 'edge') {
-      color = edge.hover_color || color;
-    } else {
-      color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
-    }
+;(function () {
+    'use strict';
 
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    if (source.id === target.id) {
-      context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
-    } else {
-      context.quadraticCurveTo(cp.x, cp.y, tX, tY);
-    }
-    context.stroke();
-  };
-})();
+    sigma.utils.pkg('sigma.canvas.edges');
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edgehovers');
-
-  /**
-   * This hover renderer will display the edge with a different color or size.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edgehovers.arrow =
-    function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        size = edge[prefix + 'size'] || 1,
-        tSize = target[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'];
-
-    size = (edge.hover) ?
-      settings('edgeHoverSizeRatio') * size : size;
-    var aSize = size * 2.5,
-        d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)),
-        aX = sX + (tX - sX) * (d - aSize - tSize) / d,
-        aY = sY + (tY - sY) * (d - aSize - tSize) / d,
-        vX = (tX - sX) * aSize / d,
-        vY = (tY - sY) * aSize / d;
-
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    if (settings('edgeHoverColor') === 'edge') {
-      color = edge.hover_color || color;
-    } else {
-      color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
-    }
+    /**
+     * This edge renderer will display edges as curves with arrow heading.
+     *
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
+     */
+    sigma.canvas.edges.curvedArrow =
+        function (edge, source, target, context, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor'),
+                cp = {},
+                size = edge[prefix + 'size'] || 1,
+                tSize = target[prefix + 'size'],
+                sX = source[prefix + 'x'],
+                sY = source[prefix + 'y'],
+                tX = target[prefix + 'x'],
+                tY = target[prefix + 'y'],
+                aSize = Math.max(size * 2.5, settings('minArrowSize')),
+                d,
+                aX,
+                aY,
+                vX,
+                vY;
+
+            cp = (source.id === target.id) ?
+                sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) :
+                sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
+
+            if (source.id === target.id) {
+                d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
+                aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
+                aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
+                vX = (tX - cp.x1) * aSize / d;
+                vY = (tY - cp.y1) * aSize / d;
+            }
+            else {
+                d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
+                aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
+                aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
+                vX = (tX - cp.x) * aSize / d;
+                vY = (tY - cp.y) * aSize / d;
+            }
 
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    context.lineTo(
-      aX,
-      aY
-    );
-    context.stroke();
-
-    context.fillStyle = color;
-    context.beginPath();
-    context.moveTo(aX + vX, aY + vY);
-    context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
-    context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
-    context.lineTo(aX + vX, aY + vY);
-    context.closePath();
-    context.fill();
-  };
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
+
+            context.strokeStyle = color;
+            context.lineWidth = size;
+            context.beginPath();
+            context.moveTo(sX, sY);
+            if (source.id === target.id) {
+                context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
+            } else {
+                context.quadraticCurveTo(cp.x, cp.y, aX, aY);
+            }
+            context.stroke();
+
+            context.fillStyle = color;
+            context.beginPath();
+            context.moveTo(aX + vX, aY + vY);
+            context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
+            context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
+            context.lineTo(aX + vX, aY + vY);
+            context.closePath();
+            context.fill();
+        };
 })();
 
-;(function() {
-  'use strict';
-
-  sigma.utils.pkg('sigma.canvas.edgehovers');
-
-  /**
-   * This hover renderer will display the edge with a different color or size.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.edgehovers.curvedArrow =
-    function(edge, source, target, context, settings) {
-    var color = edge.color,
-        prefix = settings('prefix') || '',
-        edgeColor = settings('edgeColor'),
-        defaultNodeColor = settings('defaultNodeColor'),
-        defaultEdgeColor = settings('defaultEdgeColor'),
-        cp = {},
-        size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1),
-        tSize = target[prefix + 'size'],
-        sX = source[prefix + 'x'],
-        sY = source[prefix + 'y'],
-        tX = target[prefix + 'x'],
-        tY = target[prefix + 'y'],
-        d,
-        aSize,
-        aX,
-        aY,
-        vX,
-        vY;
-
-    cp = (source.id === target.id) ?
-      sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) :
-      sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
-
-    if (source.id === target.id) {
-      d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
-      aSize = size * 2.5;
-      aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
-      aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
-      vX = (tX - cp.x1) * aSize / d;
-      vY = (tY - cp.y1) * aSize / d;
-    }
-    else {
-      d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
-      aSize = size * 2.5;
-      aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
-      aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
-      vX = (tX - cp.x) * aSize / d;
-      vY = (tY - cp.y) * aSize / d;
-    }
+;(function () {
+    'use strict';
 
-    if (!color)
-      switch (edgeColor) {
-        case 'source':
-          color = source.color || defaultNodeColor;
-          break;
-        case 'target':
-          color = target.color || defaultNodeColor;
-          break;
-        default:
-          color = defaultEdgeColor;
-          break;
-      }
-
-    if (settings('edgeHoverColor') === 'edge') {
-      color = edge.hover_color || color;
-    } else {
-      color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
-    }
+    sigma.utils.pkg('sigma.canvas.edgehovers');
 
-    context.strokeStyle = color;
-    context.lineWidth = size;
-    context.beginPath();
-    context.moveTo(sX, sY);
-    if (source.id === target.id) {
-      context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
-    } else {
-      context.quadraticCurveTo(cp.x, cp.y, aX, aY);
-    }
-    context.stroke();
-
-    context.fillStyle = color;
-    context.beginPath();
-    context.moveTo(aX + vX, aY + vY);
-    context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
-    context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
-    context.lineTo(aX + vX, aY + vY);
-    context.closePath();
-    context.fill();
-  };
-})();
+    /**
+     * This hover renderer will display the edge with a different color or size.
+     *
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
+     */
+    sigma.canvas.edgehovers.def =
+        function (edge, source, target, context, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                size = edge[prefix + 'size'] || 1,
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor');
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.canvas.extremities');
-
-  /**
-   * The default renderer for hovered edge extremities. It renders the edge
-   * extremities as hovered.
-   *
-   * @param  {object}                   edge         The edge object.
-   * @param  {object}                   source node  The edge source node.
-   * @param  {object}                   target node  The edge target node.
-   * @param  {CanvasRenderingContext2D} context      The canvas context.
-   * @param  {configurable}             settings     The settings function.
-   */
-  sigma.canvas.extremities.def =
-    function(edge, source, target, context, settings) {
-    // Source Node:
-    (
-      sigma.canvas.hovers[source.type] ||
-      sigma.canvas.hovers.def
-    ) (
-      source, context, settings
-    );
-
-    // Target Node:
-    (
-      sigma.canvas.hovers[target.type] ||
-      sigma.canvas.hovers.def
-    ) (
-      target, context, settings
-    );
-  };
-}).call(this);
+            if (settings('edgeHoverColor') === 'edge') {
+                color = edge.hover_color || color;
+            } else {
+                color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
+            }
+            size *= settings('edgeHoverSizeRatio');
 
-;(function() {
-  'use strict';
+            context.strokeStyle = color;
+            context.lineWidth = size;
+            context.beginPath();
+            context.moveTo(
+                source[prefix + 'x'],
+                source[prefix + 'y']
+            );
+            context.lineTo(
+                target[prefix + 'x'],
+                target[prefix + 'y']
+            );
+            context.stroke();
+        };
+})();
 
-  sigma.utils.pkg('sigma.svg.utils');
+;(function () {
+    'use strict';
 
-  /**
-   * Some useful functions used by sigma's SVG renderer.
-   */
-  sigma.svg.utils = {
+    sigma.utils.pkg('sigma.canvas.edgehovers');
 
     /**
-     * SVG Element show.
+     * This hover renderer will display the edge with a different color or size.
      *
-     * @param  {DOMElement}               element   The DOM element to show.
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
      */
-    show: function(element) {
-      element.style.display = '';
-      return this;
-    },
+    sigma.canvas.edgehovers.curve =
+        function (edge, source, target, context, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1),
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor'),
+                cp = {},
+                sSize = source[prefix + 'size'],
+                sX = source[prefix + 'x'],
+                sY = source[prefix + 'y'],
+                tX = target[prefix + 'x'],
+                tY = target[prefix + 'y'];
+
+            cp = (source.id === target.id) ?
+                sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) :
+                sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
+
+            if (settings('edgeHoverColor') === 'edge') {
+                color = edge.hover_color || color;
+            } else {
+                color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
+            }
+
+            context.strokeStyle = color;
+            context.lineWidth = size;
+            context.beginPath();
+            context.moveTo(sX, sY);
+            if (source.id === target.id) {
+                context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY);
+            } else {
+                context.quadraticCurveTo(cp.x, cp.y, tX, tY);
+            }
+            context.stroke();
+        };
+})();
+
+;(function () {
+    'use strict';
+
+    sigma.utils.pkg('sigma.canvas.edgehovers');
 
     /**
-     * SVG Element hide.
+     * This hover renderer will display the edge with a different color or size.
      *
-     * @param  {DOMElement}               element   The DOM element to hide.
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
      */
-    hide: function(element) {
-      element.style.display = 'none';
-      return this;
-    }
-  };
-})();
+    sigma.canvas.edgehovers.arrow =
+        function (edge, source, target, context, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor'),
+                size = edge[prefix + 'size'] || 1,
+                tSize = target[prefix + 'size'],
+                sX = source[prefix + 'x'],
+                sY = source[prefix + 'y'],
+                tX = target[prefix + 'x'],
+                tY = target[prefix + 'y'];
+
+            size = (edge.hover) ?
+            settings('edgeHoverSizeRatio') * size : size;
+            var aSize = size * 2.5,
+                d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)),
+                aX = sX + (tX - sX) * (d - aSize - tSize) / d,
+                aY = sY + (tY - sY) * (d - aSize - tSize) / d,
+                vX = (tX - sX) * aSize / d,
+                vY = (tY - sY) * aSize / d;
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
+
+            if (settings('edgeHoverColor') === 'edge') {
+                color = edge.hover_color || color;
+            } else {
+                color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
+            }
 
-;(function() {
-  'use strict';
+            context.strokeStyle = color;
+            context.lineWidth = size;
+            context.beginPath();
+            context.moveTo(sX, sY);
+            context.lineTo(
+                aX,
+                aY
+            );
+            context.stroke();
+
+            context.fillStyle = color;
+            context.beginPath();
+            context.moveTo(aX + vX, aY + vY);
+            context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
+            context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
+            context.lineTo(aX + vX, aY + vY);
+            context.closePath();
+            context.fill();
+        };
+})();
 
-  sigma.utils.pkg('sigma.svg.nodes');
+;(function () {
+    'use strict';
 
-  /**
-   * The default node renderer. It renders the node as a simple disc.
-   */
-  sigma.svg.nodes.def = {
+    sigma.utils.pkg('sigma.canvas.edgehovers');
 
     /**
-     * SVG Element creation.
+     * This hover renderer will display the edge with a different color or size.
      *
-     * @param  {object}                   node     The node object.
-     * @param  {configurable}             settings The settings function.
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
      */
-    create: function(node, settings) {
-      var prefix = settings('prefix') || '',
-          circle = document.createElementNS(settings('xmlns'), 'circle');
+    sigma.canvas.edgehovers.curvedArrow =
+        function (edge, source, target, context, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor'),
+                cp = {},
+                size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1),
+                tSize = target[prefix + 'size'],
+                sX = source[prefix + 'x'],
+                sY = source[prefix + 'y'],
+                tX = target[prefix + 'x'],
+                tY = target[prefix + 'y'],
+                d,
+                aSize,
+                aX,
+                aY,
+                vX,
+                vY;
+
+            cp = (source.id === target.id) ?
+                sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) :
+                sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY);
+
+            if (source.id === target.id) {
+                d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2));
+                aSize = size * 2.5;
+                aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d;
+                aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d;
+                vX = (tX - cp.x1) * aSize / d;
+                vY = (tY - cp.y1) * aSize / d;
+            }
+            else {
+                d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2));
+                aSize = size * 2.5;
+                aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d;
+                aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d;
+                vX = (tX - cp.x) * aSize / d;
+                vY = (tY - cp.y) * aSize / d;
+            }
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
+
+            if (settings('edgeHoverColor') === 'edge') {
+                color = edge.hover_color || color;
+            } else {
+                color = edge.hover_color || settings('defaultEdgeHoverColor') || color;
+            }
+
+            context.strokeStyle = color;
+            context.lineWidth = size;
+            context.beginPath();
+            context.moveTo(sX, sY);
+            if (source.id === target.id) {
+                context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY);
+            } else {
+                context.quadraticCurveTo(cp.x, cp.y, aX, aY);
+            }
+            context.stroke();
+
+            context.fillStyle = color;
+            context.beginPath();
+            context.moveTo(aX + vX, aY + vY);
+            context.lineTo(aX + vY * 0.6, aY - vX * 0.6);
+            context.lineTo(aX - vY * 0.6, aY + vX * 0.6);
+            context.lineTo(aX + vX, aY + vY);
+            context.closePath();
+            context.fill();
+        };
+})();
+
+;(function (undefined) {
+    'use strict';
 
-      // Defining the node's circle
-      circle.setAttributeNS(null, 'data-node-id', node.id);
-      circle.setAttributeNS(null, 'class', settings('classPrefix') + '-node');
-      circle.setAttributeNS(
-        null, 'fill', node.color || settings('defaultNodeColor'));
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      // Returning the DOM Element
-      return circle;
-    },
+    // Initialize packages:
+    sigma.utils.pkg('sigma.canvas.extremities');
 
     /**
-     * SVG Element update.
+     * The default renderer for hovered edge extremities. It renders the edge
+     * extremities as hovered.
      *
-     * @param  {object}                   node     The node object.
-     * @param  {DOMElement}               circle   The node DOM element.
-     * @param  {configurable}             settings The settings function.
+     * @param  {object}                   edge         The edge object.
+     * @param  {object}                   source node  The edge source node.
+     * @param  {object}                   target node  The edge target node.
+     * @param  {CanvasRenderingContext2D} context      The canvas context.
+     * @param  {configurable}             settings     The settings function.
      */
-    update: function(node, circle, settings) {
-      var prefix = settings('prefix') || '';
+    sigma.canvas.extremities.def =
+        function (edge, source, target, context, settings) {
+            // Source Node:
+            (
+                sigma.canvas.hovers[source.type] ||
+                sigma.canvas.hovers.def
+            )(
+                source, context, settings
+            );
 
-      // Applying changes
-      // TODO: optimize - check if necessary
-      circle.setAttributeNS(null, 'cx', node[prefix + 'x']);
-      circle.setAttributeNS(null, 'cy', node[prefix + 'y']);
-      circle.setAttributeNS(null, 'r', node[prefix + 'size']);
+            // Target Node:
+            (
+                sigma.canvas.hovers[target.type] ||
+                sigma.canvas.hovers.def
+            )(
+                target, context, settings
+            );
+        };
+}).call(this);
 
-      // Updating only if not freestyle
-      if (!settings('freeStyle'))
-        circle.setAttributeNS(
-          null, 'fill', node.color || settings('defaultNodeColor'));
+;(function () {
+    'use strict';
 
-      // Showing
-      circle.style.display = '';
+    sigma.utils.pkg('sigma.svg.utils');
 
-      return this;
-    }
-  };
+    /**
+     * Some useful functions used by sigma's SVG renderer.
+     */
+    sigma.svg.utils = {
+
+        /**
+         * SVG Element show.
+         *
+         * @param  {DOMElement}               element   The DOM element to show.
+         */
+        show: function (element) {
+            element.style.display = '';
+            return this;
+        },
+
+        /**
+         * SVG Element hide.
+         *
+         * @param  {DOMElement}               element   The DOM element to hide.
+         */
+        hide: function (element) {
+            element.style.display = 'none';
+            return this;
+        }
+    };
 })();
 
-;(function() {
-  'use strict';
+;(function () {
+    'use strict';
+
+    sigma.utils.pkg('sigma.svg.nodes');
+
+    /**
+     * The default node renderer. It renders the node as a simple disc.
+     */
+    sigma.svg.nodes.def = {
+
+        /**
+         * SVG Element creation.
+         *
+         * @param  {object}                   node     The node object.
+         * @param  {configurable}             settings The settings function.
+         */
+        create: function (node, settings) {
+            var prefix = settings('prefix') || '',
+                circle = document.createElementNS(settings('xmlns'), 'circle');
+
+            // Defining the node's circle
+            circle.setAttributeNS(null, 'data-node-id', node.id);
+            circle.setAttributeNS(null, 'class', settings('classPrefix') + '-node');
+            circle.setAttributeNS(
+                null, 'fill', node.color || settings('defaultNodeColor'));
+
+            // Returning the DOM Element
+            return circle;
+        },
+
+        /**
+         * SVG Element update.
+         *
+         * @param  {object}                   node     The node object.
+         * @param  {DOMElement}               circle   The node DOM element.
+         * @param  {configurable}             settings The settings function.
+         */
+        update: function (node, circle, settings) {
+            var prefix = settings('prefix') || '';
+
+            // Applying changes
+            // TODO: optimize - check if necessary
+            circle.setAttributeNS(null, 'cx', node[prefix + 'x']);
+            circle.setAttributeNS(null, 'cy', node[prefix + 'y']);
+            circle.setAttributeNS(null, 'r', node[prefix + 'size']);
+
+            // Updating only if not freestyle
+            if (!settings('freeStyle'))
+                circle.setAttributeNS(
+                    null, 'fill', node.color || settings('defaultNodeColor'));
+
+            // Showing
+            circle.style.display = '';
+
+            return this;
+        }
+    };
+})();
 
-  sigma.utils.pkg('sigma.svg.edges');
+;(function () {
+    'use strict';
 
-  /**
-   * The default edge renderer. It renders the node as a simple line.
-   */
-  sigma.svg.edges.def = {
+    sigma.utils.pkg('sigma.svg.edges');
 
     /**
-     * SVG Element creation.
-     *
-     * @param  {object}                   edge       The edge object.
-     * @param  {object}                   source     The source node object.
-     * @param  {object}                   target     The target node object.
-     * @param  {configurable}             settings   The settings function.
+     * The default edge renderer. It renders the node as a simple line.
      */
-    create: function(edge, source, target, settings) {
-      var color = edge.color,
-          prefix = settings('prefix') || '',
-          edgeColor = settings('edgeColor'),
-          defaultNodeColor = settings('defaultNodeColor'),
-          defaultEdgeColor = settings('defaultEdgeColor');
+    sigma.svg.edges.def = {
+
+        /**
+         * SVG Element creation.
+         *
+         * @param  {object}                   edge       The edge object.
+         * @param  {object}                   source     The source node object.
+         * @param  {object}                   target     The target node object.
+         * @param  {configurable}             settings   The settings function.
+         */
+        create: function (edge, source, target, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor');
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
 
-      if (!color)
-        switch (edgeColor) {
-          case 'source':
-            color = source.color || defaultNodeColor;
-            break;
-          case 'target':
-            color = target.color || defaultNodeColor;
-            break;
-          default:
-            color = defaultEdgeColor;
-            break;
+            var line = document.createElementNS(settings('xmlns'), 'line');
+
+            // Attributes
+            line.setAttributeNS(null, 'data-edge-id', edge.id);
+            line.setAttributeNS(null, 'class', settings('classPrefix') + '-edge');
+            line.setAttributeNS(null, 'stroke', color);
+
+            return line;
+        },
+
+        /**
+         * SVG Element update.
+         *
+         * @param  {object}                   edge       The edge object.
+         * @param  {DOMElement}               line       The line DOM Element.
+         * @param  {object}                   source     The source node object.
+         * @param  {object}                   target     The target node object.
+         * @param  {configurable}             settings   The settings function.
+         */
+        update: function (edge, line, source, target, settings) {
+            var prefix = settings('prefix') || '';
+
+            line.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1);
+            line.setAttributeNS(null, 'x1', source[prefix + 'x']);
+            line.setAttributeNS(null, 'y1', source[prefix + 'y']);
+            line.setAttributeNS(null, 'x2', target[prefix + 'x']);
+            line.setAttributeNS(null, 'y2', target[prefix + 'y']);
+
+            // Showing
+            line.style.display = '';
+
+            return this;
         }
+    };
+})();
 
-      var line = document.createElementNS(settings('xmlns'), 'line');
-
-      // Attributes
-      line.setAttributeNS(null, 'data-edge-id', edge.id);
-      line.setAttributeNS(null, 'class', settings('classPrefix') + '-edge');
-      line.setAttributeNS(null, 'stroke', color);
+;(function () {
+    'use strict';
 
-      return line;
-    },
+    sigma.utils.pkg('sigma.svg.edges');
 
     /**
-     * SVG Element update.
-     *
-     * @param  {object}                   edge       The edge object.
-     * @param  {DOMElement}               line       The line DOM Element.
-     * @param  {object}                   source     The source node object.
-     * @param  {object}                   target     The target node object.
-     * @param  {configurable}             settings   The settings function.
+     * The curve edge renderer. It renders the node as a bezier curve.
      */
-    update: function(edge, line, source, target, settings) {
-      var prefix = settings('prefix') || '';
+    sigma.svg.edges.curve = {
+
+        /**
+         * SVG Element creation.
+         *
+         * @param  {object}                   edge       The edge object.
+         * @param  {object}                   source     The source node object.
+         * @param  {object}                   target     The target node object.
+         * @param  {configurable}             settings   The settings function.
+         */
+        create: function (edge, source, target, settings) {
+            var color = edge.color,
+                prefix = settings('prefix') || '',
+                edgeColor = settings('edgeColor'),
+                defaultNodeColor = settings('defaultNodeColor'),
+                defaultEdgeColor = settings('defaultEdgeColor');
+
+            if (!color)
+                switch (edgeColor) {
+                    case 'source':
+                        color = source.color || defaultNodeColor;
+                        break;
+                    case 'target':
+                        color = target.color || defaultNodeColor;
+                        break;
+                    default:
+                        color = defaultEdgeColor;
+                        break;
+                }
+
+            var path = document.createElementNS(settings('xmlns'), 'path');
+
+            // Attributes
+            path.setAttributeNS(null, 'data-edge-id', edge.id);
+            path.setAttributeNS(null, 'class', settings('classPrefix') + '-edge');
+            path.setAttributeNS(null, 'stroke', color);
+
+            return path;
+        },
+
+        /**
+         * SVG Element update.
+         *
+         * @param  {object}                   edge       The edge object.
+         * @param  {DOMElement}               line       The line DOM Element.
+         * @param  {object}                   source     The source node object.
+         * @param  {object}                   target     The target node object.
+         * @param  {configurable}             settings   The settings function.
+         */
+        update: function (edge, path, source, target, settings) {
+            var prefix = settings('prefix') || '';
+
+            path.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1);
+
+            // Control point
+            var cx = (source[prefix + 'x'] + target[prefix + 'x']) / 2 +
+                    (target[prefix + 'y'] - source[prefix + 'y']) / 4,
+                cy = (source[prefix + 'y'] + target[prefix + 'y']) / 2 +
+                    (source[prefix + 'x'] - target[prefix + 'x']) / 4;
+
+            // Path
+            var p = 'M' + source[prefix + 'x'] + ',' + source[prefix + 'y'] + ' ' +
+                'Q' + cx + ',' + cy + ' ' +
+                target[prefix + 'x'] + ',' + target[prefix + 'y'];
+
+            // Updating attributes
+            path.setAttributeNS(null, 'd', p);
+            path.setAttributeNS(null, 'fill', 'none');
+
+            // Showing
+            path.style.display = '';
+
+            return this;
+        }
+    };
+})();
 
-      line.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1);
-      line.setAttributeNS(null, 'x1', source[prefix + 'x']);
-      line.setAttributeNS(null, 'y1', source[prefix + 'y']);
-      line.setAttributeNS(null, 'x2', target[prefix + 'x']);
-      line.setAttributeNS(null, 'y2', target[prefix + 'y']);
+;(function (undefined) {
+    'use strict';
 
-      // Showing
-      line.style.display = '';
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      return this;
-    }
-  };
-})();
+    // Initialize packages:
+    sigma.utils.pkg('sigma.svg.labels');
+
+    /**
+     * The default label renderer. It renders the label as a simple text.
+     */
+    sigma.svg.labels.def = {
+
+        /**
+         * SVG Element creation.
+         *
+         * @param  {object}                   node       The node object.
+         * @param  {configurable}             settings   The settings function.
+         */
+        create: function (node, settings) {
+            var prefix = settings('prefix') || '',
+                size = node[prefix + 'size'],
+                text = document.createElementNS(settings('xmlns'), 'text');
+
+            var fontSize = (settings('labelSize') === 'fixed') ?
+                settings('defaultLabelSize') :
+            settings('labelSizeRatio') * size;
+
+            var fontColor = (settings('labelColor') === 'node') ?
+                (node.color || settings('defaultNodeColor')) :
+                settings('defaultLabelColor');
+
+            text.setAttributeNS(null, 'data-label-target', node.id);
+            text.setAttributeNS(null, 'class', settings('classPrefix') + '-label');
+            text.setAttributeNS(null, 'font-size', fontSize);
+            text.setAttributeNS(null, 'font-family', settings('font'));
+            text.setAttributeNS(null, 'fill', fontColor);
+
+            text.innerHTML = node.label;
+            text.textContent = node.label;
+
+            return text;
+        },
+
+        /**
+         * SVG Element update.
+         *
+         * @param  {object}                   node     The node object.
+         * @param  {DOMElement}               text     The label DOM element.
+         * @param  {configurable}             settings The settings function.
+         */
+        update: function (node, text, settings) {
+            var prefix = settings('prefix') || '',
+                size = node[prefix + 'size'];
+
+            var fontSize = (settings('labelSize') === 'fixed') ?
+                settings('defaultLabelSize') :
+            settings('labelSizeRatio') * size;
+
+            // Case when we don't want to display the label
+            if (!settings('forceLabels') && size < settings('labelThreshold'))
+                return;
+
+            if (typeof node.label !== 'string')
+                return;
+
+            // Updating
+            text.setAttributeNS(null, 'x',
+                Math.round(node[prefix + 'x'] + size + 3));
+            text.setAttributeNS(null, 'y',
+                Math.round(node[prefix + 'y'] + fontSize / 3));
+
+            // Showing
+            text.style.display = '';
+
+            return this;
+        }
+    };
+}).call(this);
 
-;(function() {
-  'use strict';
+;(function (undefined) {
+    'use strict';
 
-  sigma.utils.pkg('sigma.svg.edges');
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-  /**
-   * The curve edge renderer. It renders the node as a bezier curve.
-   */
-  sigma.svg.edges.curve = {
+    // Initialize packages:
+    sigma.utils.pkg('sigma.svg.hovers');
 
     /**
-     * SVG Element creation.
-     *
-     * @param  {object}                   edge       The edge object.
-     * @param  {object}                   source     The source node object.
-     * @param  {object}                   target     The target node object.
-     * @param  {configurable}             settings   The settings function.
+     * The default hover renderer.
      */
-    create: function(edge, source, target, settings) {
-      var color = edge.color,
-          prefix = settings('prefix') || '',
-          edgeColor = settings('edgeColor'),
-          defaultNodeColor = settings('defaultNodeColor'),
-          defaultEdgeColor = settings('defaultEdgeColor');
+    sigma.svg.hovers.def = {
+
+        /**
+         * SVG Element creation.
+         *
+         * @param  {object}           node               The node object.
+         * @param  {CanvasElement}    measurementCanvas  A fake canvas handled by
+         *                            the svg to perform some measurements and
+         *                            passed by the renderer.
+         * @param  {DOMElement}       nodeCircle         The node DOM Element.
+         * @param  {configurable}     settings           The settings function.
+         */
+        create: function (node, nodeCircle, measurementCanvas, settings) {
+
+            // Defining visual properties
+            var x,
+                y,
+                w,
+                h,
+                e,
+                d,
+                fontStyle = settings('hoverFontStyle') || settings('fontStyle'),
+                prefix = settings('prefix') || '',
+                size = node[prefix + 'size'],
+                fontSize = (settings('labelSize') === 'fixed') ?
+                    settings('defaultLabelSize') :
+                settings('labelSizeRatio') * size,
+                fontColor = (settings('labelHoverColor') === 'node') ?
+                    (node.color || settings('defaultNodeColor')) :
+                    settings('defaultLabelHoverColor');
+
+            // Creating elements
+            var group = document.createElementNS(settings('xmlns'), 'g'),
+                rectangle = document.createElementNS(settings('xmlns'), 'rect'),
+                circle = document.createElementNS(settings('xmlns'), 'circle'),
+                text = document.createElementNS(settings('xmlns'), 'text');
+
+            // Defining properties
+            group.setAttributeNS(null, 'class', settings('classPrefix') + '-hover');
+            group.setAttributeNS(null, 'data-node-id', node.id);
+
+            if (typeof node.label === 'string') {
+
+                // Text
+                text.innerHTML = node.label;
+                text.textContent = node.label;
+                text.setAttributeNS(
+                    null,
+                    'class',
+                    settings('classPrefix') + '-hover-label');
+                text.setAttributeNS(null, 'font-size', fontSize);
+                text.setAttributeNS(null, 'font-family', settings('font'));
+                text.setAttributeNS(null, 'fill', fontColor);
+                text.setAttributeNS(null, 'x',
+                    Math.round(node[prefix + 'x'] + size + 3));
+                text.setAttributeNS(null, 'y',
+                    Math.round(node[prefix + 'y'] + fontSize / 3));
+
+                // Measures
+                // OPTIMIZE: Find a better way than a measurement canvas
+                x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2);
+                y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2);
+                w = Math.round(
+                    measurementCanvas.measureText(node.label).width +
+                    fontSize / 2 + size + 9
+                );
+                h = Math.round(fontSize + 4);
+                e = Math.round(fontSize / 2 + 2);
+
+                // Circle
+                circle.setAttributeNS(
+                    null,
+                    'class',
+                    settings('classPrefix') + '-hover-area');
+                circle.setAttributeNS(null, 'fill', '#fff');
+                circle.setAttributeNS(null, 'cx', node[prefix + 'x']);
+                circle.setAttributeNS(null, 'cy', node[prefix + 'y']);
+                circle.setAttributeNS(null, 'r', e);
+
+                // Rectangle
+                rectangle.setAttributeNS(
+                    null,
+                    'class',
+                    settings('classPrefix') + '-hover-area');
+                rectangle.setAttributeNS(null, 'fill', '#fff');
+                rectangle.setAttributeNS(null, 'x', node[prefix + 'x'] + e / 4);
+                rectangle.setAttributeNS(null, 'y', node[prefix + 'y'] - e);
+                rectangle.setAttributeNS(null, 'width', w);
+                rectangle.setAttributeNS(null, 'height', h);
+            }
 
-      if (!color)
-        switch (edgeColor) {
-          case 'source':
-            color = source.color || defaultNodeColor;
-            break;
-          case 'target':
-            color = target.color || defaultNodeColor;
-            break;
-          default:
-            color = defaultEdgeColor;
-            break;
+            // Appending childs
+            group.appendChild(circle);
+            group.appendChild(rectangle);
+            group.appendChild(text);
+            group.appendChild(nodeCircle);
+
+            return group;
         }
+    };
+}).call(this);
 
-      var path = document.createElementNS(settings('xmlns'), 'path');
+;(function (undefined) {
+    'use strict';
 
-      // Attributes
-      path.setAttributeNS(null, 'data-edge-id', edge.id);
-      path.setAttributeNS(null, 'class', settings('classPrefix') + '-edge');
-      path.setAttributeNS(null, 'stroke', color);
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      return path;
-    },
+    // Initialize packages:
+    sigma.utils.pkg('sigma.middlewares');
+    sigma.utils.pkg('sigma.utils');
 
     /**
-     * SVG Element update.
+     * This middleware will rescale the graph such that it takes an optimal space
+     * on the renderer.
+     *
+     * As each middleware, this function is executed in the scope of the sigma
+     * instance.
      *
-     * @param  {object}                   edge       The edge object.
-     * @param  {DOMElement}               line       The line DOM Element.
-     * @param  {object}                   source     The source node object.
-     * @param  {object}                   target     The target node object.
-     * @param  {configurable}             settings   The settings function.
+     * @param {?string} readPrefix  The read prefix.
+     * @param {?string} writePrefix The write prefix.
+     * @param {object}  options     The parameters.
      */
-    update: function(edge, path, source, target, settings) {
-      var prefix = settings('prefix') || '';
+    sigma.middlewares.rescale = function (readPrefix, writePrefix, options) {
+        var i,
+            l,
+            a,
+            b,
+            c,
+            d,
+            scale,
+            margin,
+            n = this.graph.nodes(),
+            e = this.graph.edges(),
+            settings = this.settings.embedObjects(options || {}),
+            bounds = settings('bounds') || sigma.utils.getBoundaries(
+                    this.graph,
+                    readPrefix,
+                    true
+                ),
+            minX = bounds.minX,
+            minY = bounds.minY,
+            maxX = bounds.maxX,
+            maxY = bounds.maxY,
+            sizeMax = bounds.sizeMax,
+            weightMax = bounds.weightMax,
+            w = settings('width') || 1,
+            h = settings('height') || 1,
+            rescaleSettings = settings('autoRescale'),
+            validSettings = {
+                nodePosition: 1,
+                nodeSize: 1,
+                edgeSize: 1
+            };
+
+        /**
+         * What elements should we rescale?
+         */
+        if (!(rescaleSettings instanceof Array))
+            rescaleSettings = ['nodePosition', 'nodeSize', 'edgeSize'];
+
+        for (i = 0, l = rescaleSettings.length; i < l; i++)
+            if (!validSettings[rescaleSettings[i]])
+                throw new Error(
+                    'The rescale setting "' + rescaleSettings[i] + '" is not recognized.'
+                );
+
+        var np = ~rescaleSettings.indexOf('nodePosition'),
+            ns = ~rescaleSettings.indexOf('nodeSize'),
+            es = ~rescaleSettings.indexOf('edgeSize');
+
+        /**
+         * First, we compute the scaling ratio, without considering the sizes
+         * of the nodes : Each node will have its center in the canvas, but might
+         * be partially out of it.
+         */
+        scale = settings('scalingMode') === 'outside' ?
+            Math.max(
+                w / Math.max(maxX - minX, 1),
+                h / Math.max(maxY - minY, 1)
+            ) :
+            Math.min(
+                w / Math.max(maxX - minX, 1),
+                h / Math.max(maxY - minY, 1)
+            );
 
-      path.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1);
+        /**
+         * Then, we correct that scaling ratio considering a margin, which is
+         * basically the size of the biggest node.
+         * This has to be done as a correction since to compare the size of the
+         * biggest node to the X and Y values, we have to first get an
+         * approximation of the scaling ratio.
+         **/
+        margin =
+            (
+                settings('rescaleIgnoreSize') ?
+                    0 :
+                (settings('maxNodeSize') || sizeMax) / scale
+            ) +
+            (settings('sideMargin') || 0);
+        maxX += margin;
+        minX -= margin;
+        maxY += margin;
+        minY -= margin;
+
+        // Fix the scaling with the new extrema:
+        scale = settings('scalingMode') === 'outside' ?
+            Math.max(
+                w / Math.max(maxX - minX, 1),
+                h / Math.max(maxY - minY, 1)
+            ) :
+            Math.min(
+                w / Math.max(maxX - minX, 1),
+                h / Math.max(maxY - minY, 1)
+            );
 
-      // Control point
-      var cx = (source[prefix + 'x'] + target[prefix + 'x']) / 2 +
-        (target[prefix + 'y'] - source[prefix + 'y']) / 4,
-          cy = (source[prefix + 'y'] + target[prefix + 'y']) / 2 +
-        (source[prefix + 'x'] - target[prefix + 'x']) / 4;
+        // Size homothetic parameters:
+        if (!settings('maxNodeSize') && !settings('minNodeSize')) {
+            a = 1;
+            b = 0;
+        } else if (settings('maxNodeSize') === settings('minNodeSize')) {
+            a = 0;
+            b = +settings('maxNodeSize');
+        } else {
+            a = (settings('maxNodeSize') - settings('minNodeSize')) / sizeMax;
+            b = +settings('minNodeSize');
+        }
 
-      // Path
-      var p = 'M' + source[prefix + 'x'] + ',' + source[prefix + 'y'] + ' ' +
-              'Q' + cx + ',' + cy + ' ' +
-              target[prefix + 'x'] + ',' + target[prefix + 'y'];
+        if (!settings('maxEdgeSize') && !settings('minEdgeSize')) {
+            c = 1;
+            d = 0;
+        } else if (settings('maxEdgeSize') === settings('minEdgeSize')) {
+            c = 0;
+            d = +settings('minEdgeSize');
+        } else {
+            c = (settings('maxEdgeSize') - settings('minEdgeSize')) / weightMax;
+            d = +settings('minEdgeSize');
+        }
 
-      // Updating attributes
-      path.setAttributeNS(null, 'd', p);
-      path.setAttributeNS(null, 'fill', 'none');
+        // Rescale the nodes and edges:
+        for (i = 0, l = e.length; i < l; i++)
+            e[i][writePrefix + 'size'] =
+                e[i][readPrefix + 'size'] * (es ? c : 1) + (es ? d : 0);
+
+        for (i = 0, l = n.length; i < l; i++) {
+            n[i][writePrefix + 'size'] =
+                n[i][readPrefix + 'size'] * (ns ? a : 1) + (ns ? b : 0);
+            n[i][writePrefix + 'x'] =
+                (n[i][readPrefix + 'x'] - (maxX + minX) / 2) * (np ? scale : 1);
+            n[i][writePrefix + 'y'] =
+                (n[i][readPrefix + 'y'] - (maxY + minY) / 2) * (np ? scale : 1);
+        }
+    };
 
-      // Showing
-      path.style.display = '';
+    sigma.utils.getBoundaries = function (graph, prefix, doEdges) {
+        var i,
+            l,
+            e = graph.edges(),
+            n = graph.nodes(),
+            weightMax = -Infinity,
+            sizeMax = -Infinity,
+            minX = Infinity,
+            minY = Infinity,
+            maxX = -Infinity,
+            maxY = -Infinity;
+
+        if (doEdges)
+            for (i = 0, l = e.length; i < l; i++)
+                weightMax = Math.max(e[i][prefix + 'size'], weightMax);
+
+        for (i = 0, l = n.length; i < l; i++) {
+            sizeMax = Math.max(n[i][prefix + 'size'], sizeMax);
+            maxX = Math.max(n[i][prefix + 'x'], maxX);
+            minX = Math.min(n[i][prefix + 'x'], minX);
+            maxY = Math.max(n[i][prefix + 'y'], maxY);
+            minY = Math.min(n[i][prefix + 'y'], minY);
+        }
 
-      return this;
-    }
-  };
-})();
+        weightMax = weightMax || 1;
+        sizeMax = sizeMax || 1;
 
-;(function(undefined) {
-  'use strict';
+        return {
+            weightMax: weightMax,
+            sizeMax: sizeMax,
+            minX: minX,
+            minY: minY,
+            maxX: maxX,
+            maxY: maxY
+        };
+    };
+}).call(this);
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
+;(function (undefined) {
+    'use strict';
 
-  // Initialize packages:
-  sigma.utils.pkg('sigma.svg.labels');
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-  /**
-   * The default label renderer. It renders the label as a simple text.
-   */
-  sigma.svg.labels.def = {
+    // Initialize packages:
+    sigma.utils.pkg('sigma.middlewares');
 
     /**
-     * SVG Element creation.
+     * This middleware will just copy the graphic properties.
      *
-     * @param  {object}                   node       The node object.
-     * @param  {configurable}             settings   The settings function.
+     * @param {?string} readPrefix  The read prefix.
+     * @param {?string} writePrefix The write prefix.
      */
-    create: function(node, settings) {
-      var prefix = settings('prefix') || '',
-          size = node[prefix + 'size'],
-          text = document.createElementNS(settings('xmlns'), 'text');
+    sigma.middlewares.copy = function (readPrefix, writePrefix) {
+        var i,
+            l,
+            a;
 
-      var fontSize = (settings('labelSize') === 'fixed') ?
-        settings('defaultLabelSize') :
-        settings('labelSizeRatio') * size;
+        if (writePrefix + '' === readPrefix + '')
+            return;
+
+        a = this.graph.nodes();
+        for (i = 0, l = a.length; i < l; i++) {
+            a[i][writePrefix + 'x'] = a[i][readPrefix + 'x'];
+            a[i][writePrefix + 'y'] = a[i][readPrefix + 'y'];
+            a[i][writePrefix + 'size'] = a[i][readPrefix + 'size'];
+        }
 
-      var fontColor = (settings('labelColor') === 'node') ?
-        (node.color || settings('defaultNodeColor')) :
-        settings('defaultLabelColor');
+        a = this.graph.edges();
+        for (i = 0, l = a.length; i < l; i++)
+            a[i][writePrefix + 'size'] = a[i][readPrefix + 'size'];
+    };
+}).call(this);
 
-      text.setAttributeNS(null, 'data-label-target', node.id);
-      text.setAttributeNS(null, 'class', settings('classPrefix') + '-label');
-      text.setAttributeNS(null, 'font-size', fontSize);
-      text.setAttributeNS(null, 'font-family', settings('font'));
-      text.setAttributeNS(null, 'fill', fontColor);
+;(function (undefined) {
+    'use strict';
 
-      text.innerHTML = node.label;
-      text.textContent = node.label;
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-      return text;
-    },
+    // Initialize packages:
+    sigma.utils.pkg('sigma.misc.animation.running');
 
     /**
-     * SVG Element update.
+     * Generates a unique ID for the animation.
      *
-     * @param  {object}                   node     The node object.
-     * @param  {DOMElement}               text     The label DOM element.
-     * @param  {configurable}             settings The settings function.
+     * @return {string} Returns the new ID.
      */
-    update: function(node, text, settings) {
-      var prefix = settings('prefix') || '',
-          size = node[prefix + 'size'];
+    var _getID = (function () {
+        var id = 0;
+        return function () {
+            return '' + (++id);
+        };
+    })();
 
-      var fontSize = (settings('labelSize') === 'fixed') ?
-        settings('defaultLabelSize') :
-        settings('labelSizeRatio') * size;
+    /**
+     * This function animates a camera. It has to be called with the camera to
+     * animate, the values of the coordinates to reach and eventually some
+     * options. It returns a number id, that you can use to kill the animation,
+     * with the method sigma.misc.animation.kill(id).
+     *
+     * The available options are:
+     *
+     *   {?number}            duration   The duration of the animation.
+     *   {?function}          onNewFrame A callback to execute when the animation
+     *                                   enter a new frame.
+     *   {?function}          onComplete A callback to execute when the animation
+     *                                   is completed or killed.
+     *   {?(string|function)} easing     The name of a function from the package
+     *                                   sigma.utils.easings, or a custom easing
+     *                                   function.
+     *
+     * @param  {camera}  camera  The camera to animate.
+     * @param  {object}  target  The coordinates to reach.
+     * @param  {?object} options Eventually an object to specify some options to
+     *                           the function. The available options are
+     *                           presented in the description of the function.
+     * @return {number}          The animation id, to make it easy to kill
+     *                           through the method "sigma.misc.animation.kill".
+     */
+    sigma.misc.animation.camera = function (camera, val, options) {
+        if (
+            !(camera instanceof sigma.classes.camera) ||
+            typeof val !== 'object' || !val
+        )
+            throw 'animation.camera: Wrong arguments.';
+
+        if (
+            typeof val.x !== 'number' &&
+            typeof val.y !== 'number' &&
+            typeof val.ratio !== 'number' &&
+            typeof val.angle !== 'number'
+        )
+            throw 'There must be at least one valid coordinate in the given val.';
+
+        var fn,
+            id,
+            anim,
+            easing,
+            duration,
+            initialVal,
+            o = options || {},
+            start = sigma.utils.dateNow();
+
+        // Store initial values:
+        initialVal = {
+            x: camera.x,
+            y: camera.y,
+            ratio: camera.ratio,
+            angle: camera.angle
+        };
 
-      // Case when we don't want to display the label
-      if (!settings('forceLabels') && size < settings('labelThreshold'))
-        return;
+        duration = o.duration;
+        easing = typeof o.easing !== 'function' ?
+            sigma.utils.easings[o.easing || 'quadraticInOut'] :
+            o.easing;
+
+        fn = function () {
+            var coef,
+                t = o.duration ? (sigma.utils.dateNow() - start) / o.duration : 1;
+
+            // If the animation is over:
+            if (t >= 1) {
+                camera.isAnimated = false;
+                camera.goTo({
+                    x: val.x !== undefined ? val.x : initialVal.x,
+                    y: val.y !== undefined ? val.y : initialVal.y,
+                    ratio: val.ratio !== undefined ? val.ratio : initialVal.ratio,
+                    angle: val.angle !== undefined ? val.angle : initialVal.angle
+                });
+
+                cancelAnimationFrame(id);
+                delete sigma.misc.animation.running[id];
+
+                // Check callbacks:
+                if (typeof o.onComplete === 'function')
+                    o.onComplete();
+
+                // Else, let's keep going:
+            } else {
+                coef = easing(t);
+                camera.isAnimated = true;
+                camera.goTo({
+                    x: val.x !== undefined ?
+                    initialVal.x + (val.x - initialVal.x) * coef :
+                        initialVal.x,
+                    y: val.y !== undefined ?
+                    initialVal.y + (val.y - initialVal.y) * coef :
+                        initialVal.y,
+                    ratio: val.ratio !== undefined ?
+                    initialVal.ratio + (val.ratio - initialVal.ratio) * coef :
+                        initialVal.ratio,
+                    angle: val.angle !== undefined ?
+                    initialVal.angle + (val.angle - initialVal.angle) * coef :
+                        initialVal.angle
+                });
+
+                // Check callbacks:
+                if (typeof o.onNewFrame === 'function')
+                    o.onNewFrame();
+
+                anim.frameId = requestAnimationFrame(fn);
+            }
+        };
 
-      if (typeof node.label !== 'string')
-        return;
+        id = _getID();
+        anim = {
+            frameId: requestAnimationFrame(fn),
+            target: camera,
+            type: 'camera',
+            options: o,
+            fn: fn
+        };
+        sigma.misc.animation.running[id] = anim;
 
-      // Updating
-      text.setAttributeNS(null, 'x',
-        Math.round(node[prefix + 'x'] + size + 3));
-      text.setAttributeNS(null, 'y',
-        Math.round(node[prefix + 'y'] + fontSize / 3));
+        return id;
+    };
 
-      // Showing
-      text.style.display = '';
+    /**
+     * Kills a running animation. It triggers the eventual onComplete callback.
+     *
+     * @param  {number} id  The id of the animation to kill.
+     * @return {object}     Returns the sigma.misc.animation package.
+     */
+    sigma.misc.animation.kill = function (id) {
+        if (arguments.length !== 1 || typeof id !== 'number')
+            throw 'animation.kill: Wrong arguments.';
 
-      return this;
-    }
-  };
-}).call(this);
+        var o = sigma.misc.animation.running[id];
 
-;(function(undefined) {
-  'use strict';
+        if (o) {
+            cancelAnimationFrame(id);
+            delete sigma.misc.animation.running[o.frameId];
 
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
+            if (o.type === 'camera')
+                o.target.isAnimated = false;
 
-  // Initialize packages:
-  sigma.utils.pkg('sigma.svg.hovers');
+            // Check callbacks:
+            if (typeof (o.options || {}).onComplete === 'function')
+                o.options.onComplete();
+        }
 
-  /**
-   * The default hover renderer.
-   */
-  sigma.svg.hovers.def = {
+        return this;
+    };
 
     /**
-     * SVG Element creation.
+     * Kills every running animations, or only the one with the specified type,
+     * if a string parameter is given.
      *
-     * @param  {object}           node               The node object.
-     * @param  {CanvasElement}    measurementCanvas  A fake canvas handled by
-     *                            the svg to perform some measurements and
-     *                            passed by the renderer.
-     * @param  {DOMElement}       nodeCircle         The node DOM Element.
-     * @param  {configurable}     settings           The settings function.
+     * @param  {?(string|object)} filter A string to filter the animations to kill
+     *                                   on their type (example: "camera"), or an
+     *                                   object to filter on their target.
+     * @return {number}                  Returns the number of animations killed
+     *                                   that way.
      */
-    create: function(node, nodeCircle, measurementCanvas, settings) {
-
-      // Defining visual properties
-      var x,
-          y,
-          w,
-          h,
-          e,
-          d,
-          fontStyle = settings('hoverFontStyle') || settings('fontStyle'),
-          prefix = settings('prefix') || '',
-          size = node[prefix + 'size'],
-          fontSize = (settings('labelSize') === 'fixed') ?
-            settings('defaultLabelSize') :
-            settings('labelSizeRatio') * size,
-          fontColor = (settings('labelHoverColor') === 'node') ?
-                        (node.color || settings('defaultNodeColor')) :
-                        settings('defaultLabelHoverColor');
-
-      // Creating elements
-      var group = document.createElementNS(settings('xmlns'), 'g'),
-          rectangle = document.createElementNS(settings('xmlns'), 'rect'),
-          circle = document.createElementNS(settings('xmlns'), 'circle'),
-          text = document.createElementNS(settings('xmlns'), 'text');
-
-      // Defining properties
-      group.setAttributeNS(null, 'class', settings('classPrefix') + '-hover');
-      group.setAttributeNS(null, 'data-node-id', node.id);
-
-      if (typeof node.label === 'string') {
-
-        // Text
-        text.innerHTML = node.label;
-        text.textContent = node.label;
-        text.setAttributeNS(
-            null,
-            'class',
-            settings('classPrefix') + '-hover-label');
-        text.setAttributeNS(null, 'font-size', fontSize);
-        text.setAttributeNS(null, 'font-family', settings('font'));
-        text.setAttributeNS(null, 'fill', fontColor);
-        text.setAttributeNS(null, 'x',
-          Math.round(node[prefix + 'x'] + size + 3));
-        text.setAttributeNS(null, 'y',
-          Math.round(node[prefix + 'y'] + fontSize / 3));
-
-        // Measures
-        // OPTIMIZE: Find a better way than a measurement canvas
-        x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2);
-        y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2);
-        w = Math.round(
-          measurementCanvas.measureText(node.label).width +
-            fontSize / 2 + size + 9
-        );
-        h = Math.round(fontSize + 4);
-        e = Math.round(fontSize / 2 + 2);
-
-        // Circle
-        circle.setAttributeNS(
-            null,
-            'class',
-            settings('classPrefix') + '-hover-area');
-        circle.setAttributeNS(null, 'fill', '#fff');
-        circle.setAttributeNS(null, 'cx', node[prefix + 'x']);
-        circle.setAttributeNS(null, 'cy', node[prefix + 'y']);
-        circle.setAttributeNS(null, 'r', e);
-
-        // Rectangle
-        rectangle.setAttributeNS(
-            null,
-            'class',
-            settings('classPrefix') + '-hover-area');
-        rectangle.setAttributeNS(null, 'fill', '#fff');
-        rectangle.setAttributeNS(null, 'x', node[prefix + 'x'] + e / 4);
-        rectangle.setAttributeNS(null, 'y', node[prefix + 'y'] - e);
-        rectangle.setAttributeNS(null, 'width', w);
-        rectangle.setAttributeNS(null, 'height', h);
-      }
-
-      // Appending childs
-      group.appendChild(circle);
-      group.appendChild(rectangle);
-      group.appendChild(text);
-      group.appendChild(nodeCircle);
-
-      return group;
-    }
-  };
-}).call(this);
-
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.middlewares');
-  sigma.utils.pkg('sigma.utils');
-
-  /**
-   * This middleware will rescale the graph such that it takes an optimal space
-   * on the renderer.
-   *
-   * As each middleware, this function is executed in the scope of the sigma
-   * instance.
-   *
-   * @param {?string} readPrefix  The read prefix.
-   * @param {?string} writePrefix The write prefix.
-   * @param {object}  options     The parameters.
-   */
-  sigma.middlewares.rescale = function(readPrefix, writePrefix, options) {
-    var i,
-        l,
-        a,
-        b,
-        c,
-        d,
-        scale,
-        margin,
-        n = this.graph.nodes(),
-        e = this.graph.edges(),
-        settings = this.settings.embedObjects(options || {}),
-        bounds = settings('bounds') || sigma.utils.getBoundaries(
-          this.graph,
-          readPrefix,
-          true
-        ),
-        minX = bounds.minX,
-        minY = bounds.minY,
-        maxX = bounds.maxX,
-        maxY = bounds.maxY,
-        sizeMax = bounds.sizeMax,
-        weightMax = bounds.weightMax,
-        w = settings('width') || 1,
-        h = settings('height') || 1,
-        rescaleSettings = settings('autoRescale'),
-        validSettings = {
-          nodePosition: 1,
-          nodeSize: 1,
-          edgeSize: 1
-        };
+    sigma.misc.animation.killAll = function (filter) {
+        var o,
+            id,
+            count = 0,
+            type = typeof filter === 'string' ? filter : null,
+            target = typeof filter === 'object' ? filter : null,
+            running = sigma.misc.animation.running;
+
+        for (id in running)
+            if (
+                (!type || running[id].type === type) &&
+                (!target || running[id].target === target)
+            ) {
+                o = sigma.misc.animation.running[id];
+                cancelAnimationFrame(o.frameId);
+                delete sigma.misc.animation.running[id];
 
-    /**
-     * What elements should we rescale?
-     */
-    if (!(rescaleSettings instanceof Array))
-      rescaleSettings = ['nodePosition', 'nodeSize', 'edgeSize'];
+                if (o.type === 'camera')
+                    o.target.isAnimated = false;
 
-    for (i = 0, l = rescaleSettings.length; i < l; i++)
-      if (!validSettings[rescaleSettings[i]])
-        throw new Error(
-          'The rescale setting "' + rescaleSettings[i] + '" is not recognized.'
-        );
+                // Increment counter:
+                count++;
 
-    var np = ~rescaleSettings.indexOf('nodePosition'),
-        ns = ~rescaleSettings.indexOf('nodeSize'),
-        es = ~rescaleSettings.indexOf('edgeSize');
-
-    /**
-     * First, we compute the scaling ratio, without considering the sizes
-     * of the nodes : Each node will have its center in the canvas, but might
-     * be partially out of it.
-     */
-    scale = settings('scalingMode') === 'outside' ?
-      Math.max(
-        w / Math.max(maxX - minX, 1),
-        h / Math.max(maxY - minY, 1)
-      ) :
-      Math.min(
-        w / Math.max(maxX - minX, 1),
-        h / Math.max(maxY - minY, 1)
-      );
-
-    /**
-     * Then, we correct that scaling ratio considering a margin, which is
-     * basically the size of the biggest node.
-     * This has to be done as a correction since to compare the size of the
-     * biggest node to the X and Y values, we have to first get an
-     * approximation of the scaling ratio.
-     **/
-    margin =
-      (
-        settings('rescaleIgnoreSize') ?
-          0 :
-          (settings('maxNodeSize') || sizeMax) / scale
-      ) +
-      (settings('sideMargin') || 0);
-    maxX += margin;
-    minX -= margin;
-    maxY += margin;
-    minY -= margin;
-
-    // Fix the scaling with the new extrema:
-    scale = settings('scalingMode') === 'outside' ?
-      Math.max(
-        w / Math.max(maxX - minX, 1),
-        h / Math.max(maxY - minY, 1)
-      ) :
-      Math.min(
-        w / Math.max(maxX - minX, 1),
-        h / Math.max(maxY - minY, 1)
-      );
-
-    // Size homothetic parameters:
-    if (!settings('maxNodeSize') && !settings('minNodeSize')) {
-      a = 1;
-      b = 0;
-    } else if (settings('maxNodeSize') === settings('minNodeSize')) {
-      a = 0;
-      b = +settings('maxNodeSize');
-    } else {
-      a = (settings('maxNodeSize') - settings('minNodeSize')) / sizeMax;
-      b = +settings('minNodeSize');
-    }
+                // Check callbacks:
+                if (typeof (o.options || {}).onComplete === 'function')
+                    o.options.onComplete();
+            }
 
-    if (!settings('maxEdgeSize') && !settings('minEdgeSize')) {
-      c = 1;
-      d = 0;
-    } else if (settings('maxEdgeSize') === settings('minEdgeSize')) {
-      c = 0;
-      d = +settings('minEdgeSize');
-    } else {
-      c = (settings('maxEdgeSize') - settings('minEdgeSize')) / weightMax;
-      d = +settings('minEdgeSize');
-    }
+        return count;
+    };
 
-    // Rescale the nodes and edges:
-    for (i = 0, l = e.length; i < l; i++)
-      e[i][writePrefix + 'size'] =
-        e[i][readPrefix + 'size'] * (es ? c : 1) + (es ? d : 0);
-
-    for (i = 0, l = n.length; i < l; i++) {
-      n[i][writePrefix + 'size'] =
-        n[i][readPrefix + 'size'] * (ns ? a : 1) + (ns ? b : 0);
-      n[i][writePrefix + 'x'] =
-        (n[i][readPrefix + 'x'] - (maxX + minX) / 2) * (np ? scale : 1);
-      n[i][writePrefix + 'y'] =
-        (n[i][readPrefix + 'y'] - (maxY + minY) / 2) * (np ? scale : 1);
-    }
-  };
-
-  sigma.utils.getBoundaries = function(graph, prefix, doEdges) {
-    var i,
-        l,
-        e = graph.edges(),
-        n = graph.nodes(),
-        weightMax = -Infinity,
-        sizeMax = -Infinity,
-        minX = Infinity,
-        minY = Infinity,
-        maxX = -Infinity,
-        maxY = -Infinity;
-
-    if (doEdges)
-      for (i = 0, l = e.length; i < l; i++)
-        weightMax = Math.max(e[i][prefix + 'size'], weightMax);
-
-    for (i = 0, l = n.length; i < l; i++) {
-      sizeMax = Math.max(n[i][prefix + 'size'], sizeMax);
-      maxX = Math.max(n[i][prefix + 'x'], maxX);
-      minX = Math.min(n[i][prefix + 'x'], minX);
-      maxY = Math.max(n[i][prefix + 'y'], maxY);
-      minY = Math.min(n[i][prefix + 'y'], minY);
-    }
+    /**
+     * Returns "true" if any animation that is currently still running matches
+     * the filter given to the function.
+     *
+     * @param  {string|object} filter A string to filter the animations to kill
+     *                                on their type (example: "camera"), or an
+     *                                object to filter on their target.
+     * @return {boolean}              Returns true if any running animation
+     *                                matches.
+     */
+    sigma.misc.animation.has = function (filter) {
+        var id,
+            type = typeof filter === 'string' ? filter : null,
+            target = typeof filter === 'object' ? filter : null,
+            running = sigma.misc.animation.running;
 
-    weightMax = weightMax || 1;
-    sizeMax = sizeMax || 1;
+        for (id in running)
+            if (
+                (!type || running[id].type === type) &&
+                (!target || running[id].target === target)
+            )
+                return true;
 
-    return {
-      weightMax: weightMax,
-      sizeMax: sizeMax,
-      minX: minX,
-      minY: minY,
-      maxX: maxX,
-      maxY: maxY
+        return false;
     };
-  };
 }).call(this);
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.middlewares');
-
-  /**
-   * This middleware will just copy the graphic properties.
-   *
-   * @param {?string} readPrefix  The read prefix.
-   * @param {?string} writePrefix The write prefix.
-   */
-  sigma.middlewares.copy = function(readPrefix, writePrefix) {
-    var i,
-        l,
-        a;
-
-    if (writePrefix + '' === readPrefix + '')
-      return;
-
-    a = this.graph.nodes();
-    for (i = 0, l = a.length; i < l; i++) {
-      a[i][writePrefix + 'x'] = a[i][readPrefix + 'x'];
-      a[i][writePrefix + 'y'] = a[i][readPrefix + 'y'];
-      a[i][writePrefix + 'size'] = a[i][readPrefix + 'size'];
-    }
-
-    a = this.graph.edges();
-    for (i = 0, l = a.length; i < l; i++)
-      a[i][writePrefix + 'size'] = a[i][readPrefix + 'size'];
-  };
-}).call(this);
+;(function (undefined) {
+    'use strict';
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.misc.animation.running');
-
-  /**
-   * Generates a unique ID for the animation.
-   *
-   * @return {string} Returns the new ID.
-   */
-  var _getID = (function() {
-    var id = 0;
-    return function() {
-      return '' + (++id);
-    };
-  })();
-
-  /**
-   * This function animates a camera. It has to be called with the camera to
-   * animate, the values of the coordinates to reach and eventually some
-   * options. It returns a number id, that you can use to kill the animation,
-   * with the method sigma.misc.animation.kill(id).
-   *
-   * The available options are:
-   *
-   *   {?number}            duration   The duration of the animation.
-   *   {?function}          onNewFrame A callback to execute when the animation
-   *                                   enter a new frame.
-   *   {?function}          onComplete A callback to execute when the animation
-   *                                   is completed or killed.
-   *   {?(string|function)} easing     The name of a function from the package
-   *                                   sigma.utils.easings, or a custom easing
-   *                                   function.
-   *
-   * @param  {camera}  camera  The camera to animate.
-   * @param  {object}  target  The coordinates to reach.
-   * @param  {?object} options Eventually an object to specify some options to
-   *                           the function. The available options are
-   *                           presented in the description of the function.
-   * @return {number}          The animation id, to make it easy to kill
-   *                           through the method "sigma.misc.animation.kill".
-   */
-  sigma.misc.animation.camera = function(camera, val, options) {
-    if (
-      !(camera instanceof sigma.classes.camera) ||
-      typeof val !== 'object' ||
-      !val
-    )
-      throw 'animation.camera: Wrong arguments.';
-
-    if (
-      typeof val.x !== 'number' &&
-      typeof val.y !== 'number' &&
-      typeof val.ratio !== 'number' &&
-      typeof val.angle !== 'number'
-    )
-      throw 'There must be at least one valid coordinate in the given val.';
-
-    var fn,
-        id,
-        anim,
-        easing,
-        duration,
-        initialVal,
-        o = options || {},
-        start = sigma.utils.dateNow();
-
-    // Store initial values:
-    initialVal = {
-      x: camera.x,
-      y: camera.y,
-      ratio: camera.ratio,
-      angle: camera.angle
-    };
-
-    duration = o.duration;
-    easing = typeof o.easing !== 'function' ?
-      sigma.utils.easings[o.easing || 'quadraticInOut'] :
-      o.easing;
-
-    fn = function() {
-      var coef,
-          t = o.duration ? (sigma.utils.dateNow() - start) / o.duration : 1;
-
-      // If the animation is over:
-      if (t >= 1) {
-        camera.isAnimated = false;
-        camera.goTo({
-          x: val.x !== undefined ? val.x : initialVal.x,
-          y: val.y !== undefined ? val.y : initialVal.y,
-          ratio: val.ratio !== undefined ? val.ratio : initialVal.ratio,
-          angle: val.angle !== undefined ? val.angle : initialVal.angle
-        });
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-        cancelAnimationFrame(id);
-        delete sigma.misc.animation.running[id];
-
-        // Check callbacks:
-        if (typeof o.onComplete === 'function')
-          o.onComplete();
-
-      // Else, let's keep going:
-      } else {
-        coef = easing(t);
-        camera.isAnimated = true;
-        camera.goTo({
-          x: val.x !== undefined ?
-            initialVal.x + (val.x - initialVal.x) * coef :
-            initialVal.x,
-          y: val.y !== undefined ?
-            initialVal.y + (val.y - initialVal.y) * coef :
-            initialVal.y,
-          ratio: val.ratio !== undefined ?
-            initialVal.ratio + (val.ratio - initialVal.ratio) * coef :
-            initialVal.ratio,
-          angle: val.angle !== undefined ?
-            initialVal.angle + (val.angle - initialVal.angle) * coef :
-            initialVal.angle
-        });
+    // Initialize packages:
+    sigma.utils.pkg('sigma.misc');
 
-        // Check callbacks:
-        if (typeof o.onNewFrame === 'function')
-          o.onNewFrame();
+    /**
+     * This helper will bind any no-DOM renderer (for instance canvas or WebGL)
+     * to its captors, to properly dispatch the good events to the sigma instance
+     * to manage clicking, hovering etc...
+     *
+     * It has to be called in the scope of the related renderer.
+     */
+    sigma.misc.bindEvents = function (prefix) {
+        var i,
+            l,
+            mX,
+            mY,
+            captor,
+            self = this;
+
+        function getNodes(e) {
+            if (e) {
+                mX = 'x' in e.data ? e.data.x : mX;
+                mY = 'y' in e.data ? e.data.y : mY;
+            }
 
-        anim.frameId = requestAnimationFrame(fn);
-      }
-    };
+            var i,
+                j,
+                l,
+                n,
+                x,
+                y,
+                s,
+                inserted,
+                selected = [],
+                modifiedX = mX + self.width / 2,
+                modifiedY = mY + self.height / 2,
+                point = self.camera.cameraPosition(
+                    mX,
+                    mY
+                ),
+                nodes = self.camera.quadtree.point(
+                    point.x,
+                    point.y
+                );
 
-    id = _getID();
-    anim = {
-      frameId: requestAnimationFrame(fn),
-      target: camera,
-      type: 'camera',
-      options: o,
-      fn: fn
-    };
-    sigma.misc.animation.running[id] = anim;
+            if (nodes.length)
+                for (i = 0, l = nodes.length; i < l; i++) {
+                    n = nodes[i];
+                    x = n[prefix + 'x'];
+                    y = n[prefix + 'y'];
+                    s = n[prefix + 'size'];
+
+                    if (
+                        !n.hidden &&
+                        modifiedX > x - s &&
+                        modifiedX < x + s &&
+                        modifiedY > y - s &&
+                        modifiedY < y + s &&
+                        Math.sqrt(
+                            Math.pow(modifiedX - x, 2) +
+                            Math.pow(modifiedY - y, 2)
+                        ) < s
+                    ) {
+                        // Insert the node:
+                        inserted = false;
+
+                        for (j = 0; j < selected.length; j++)
+                            if (n.size > selected[j].size) {
+                                selected.splice(j, 0, n);
+                                inserted = true;
+                                break;
+                            }
+
+                        if (!inserted)
+                            selected.push(n);
+                    }
+                }
 
-    return id;
-  };
+            return selected;
+        }
 
-  /**
-   * Kills a running animation. It triggers the eventual onComplete callback.
-   *
-   * @param  {number} id  The id of the animation to kill.
-   * @return {object}     Returns the sigma.misc.animation package.
-   */
-  sigma.misc.animation.kill = function(id) {
-    if (arguments.length !== 1 || typeof id !== 'number')
-      throw 'animation.kill: Wrong arguments.';
 
-    var o = sigma.misc.animation.running[id];
+        function getEdges(e) {
+            if (!self.settings('enableEdgeHovering')) {
+                // No event if the setting is off:
+                return [];
+            }
 
-    if (o) {
-      cancelAnimationFrame(id);
-      delete sigma.misc.animation.running[o.frameId];
+            var isCanvas = (
+            sigma.renderers.canvas && self instanceof sigma.renderers.canvas);
 
-      if (o.type === 'camera')
-        o.target.isAnimated = false;
+            if (!isCanvas) {
+                // A quick hardcoded rule to prevent people from using this feature
+                // with the WebGL renderer (which is not good enough at the moment):
+                throw new Error(
+                    'The edge events feature is not compatible with the WebGL renderer'
+                );
+            }
 
-      // Check callbacks:
-      if (typeof (o.options || {}).onComplete === 'function')
-        o.options.onComplete();
-    }
+            if (e) {
+                mX = 'x' in e.data ? e.data.x : mX;
+                mY = 'y' in e.data ? e.data.y : mY;
+            }
 
-    return this;
-  };
-
-  /**
-   * Kills every running animations, or only the one with the specified type,
-   * if a string parameter is given.
-   *
-   * @param  {?(string|object)} filter A string to filter the animations to kill
-   *                                   on their type (example: "camera"), or an
-   *                                   object to filter on their target.
-   * @return {number}                  Returns the number of animations killed
-   *                                   that way.
-   */
-  sigma.misc.animation.killAll = function(filter) {
-    var o,
-        id,
-        count = 0,
-        type = typeof filter === 'string' ? filter : null,
-        target = typeof filter === 'object' ? filter : null,
-        running = sigma.misc.animation.running;
-
-    for (id in running)
-      if (
-        (!type || running[id].type === type) &&
-        (!target || running[id].target === target)
-      ) {
-        o = sigma.misc.animation.running[id];
-        cancelAnimationFrame(o.frameId);
-        delete sigma.misc.animation.running[id];
-
-        if (o.type === 'camera')
-          o.target.isAnimated = false;
-
-        // Increment counter:
-        count++;
-
-        // Check callbacks:
-        if (typeof (o.options || {}).onComplete === 'function')
-          o.options.onComplete();
-      }
-
-    return count;
-  };
-
-  /**
-   * Returns "true" if any animation that is currently still running matches
-   * the filter given to the function.
-   *
-   * @param  {string|object} filter A string to filter the animations to kill
-   *                                on their type (example: "camera"), or an
-   *                                object to filter on their target.
-   * @return {boolean}              Returns true if any running animation
-   *                                matches.
-   */
-  sigma.misc.animation.has = function(filter) {
-    var id,
-        type = typeof filter === 'string' ? filter : null,
-        target = typeof filter === 'object' ? filter : null,
-        running = sigma.misc.animation.running;
-
-    for (id in running)
-      if (
-        (!type || running[id].type === type) &&
-        (!target || running[id].target === target)
-      )
-        return true;
-
-    return false;
-  };
-}).call(this);
+            var i,
+                j,
+                l,
+                a,
+                edge,
+                s,
+                maxEpsilon = self.settings('edgeHoverPrecision'),
+                source,
+                target,
+                cp,
+                nodeIndex = {},
+                inserted,
+                selected = [],
+                modifiedX = mX + self.width / 2,
+                modifiedY = mY + self.height / 2,
+                point = self.camera.cameraPosition(
+                    mX,
+                    mY
+                ),
+                edges = [];
+
+            if (isCanvas) {
+                var nodesOnScreen = self.camera.quadtree.area(
+                    self.camera.getRectangle(self.width, self.height)
+                );
+                for (a = nodesOnScreen, i = 0, l = a.length; i < l; i++)
+                    nodeIndex[a[i].id] = a[i];
+            }
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.misc');
-
-  /**
-   * This helper will bind any no-DOM renderer (for instance canvas or WebGL)
-   * to its captors, to properly dispatch the good events to the sigma instance
-   * to manage clicking, hovering etc...
-   *
-   * It has to be called in the scope of the related renderer.
-   */
-  sigma.misc.bindEvents = function(prefix) {
-    var i,
-        l,
-        mX,
-        mY,
-        captor,
-        self = this;
-
-    function getNodes(e) {
-      if (e) {
-        mX = 'x' in e.data ? e.data.x : mX;
-        mY = 'y' in e.data ? e.data.y : mY;
-      }
-
-      var i,
-          j,
-          l,
-          n,
-          x,
-          y,
-          s,
-          inserted,
-          selected = [],
-          modifiedX = mX + self.width / 2,
-          modifiedY = mY + self.height / 2,
-          point = self.camera.cameraPosition(
-            mX,
-            mY
-          ),
-          nodes = self.camera.quadtree.point(
-            point.x,
-            point.y
-          );
-
-      if (nodes.length)
-        for (i = 0, l = nodes.length; i < l; i++) {
-          n = nodes[i];
-          x = n[prefix + 'x'];
-          y = n[prefix + 'y'];
-          s = n[prefix + 'size'];
-
-          if (
-            !n.hidden &&
-            modifiedX > x - s &&
-            modifiedX < x + s &&
-            modifiedY > y - s &&
-            modifiedY < y + s &&
-            Math.sqrt(
-              Math.pow(modifiedX - x, 2) +
-              Math.pow(modifiedY - y, 2)
-            ) < s
-          ) {
-            // Insert the node:
-            inserted = false;
-
-            for (j = 0; j < selected.length; j++)
-              if (n.size > selected[j].size) {
-                selected.splice(j, 0, n);
-                inserted = true;
-                break;
-              }
+            if (self.camera.edgequadtree !== undefined) {
+                edges = self.camera.edgequadtree.point(
+                    point.x,
+                    point.y
+                );
+            }
 
-            if (!inserted)
-              selected.push(n);
-          }
-        }
+            function insertEdge(selected, edge) {
+                inserted = false;
 
-      return selected;
-    }
+                for (j = 0; j < selected.length; j++)
+                    if (edge.size > selected[j].size) {
+                        selected.splice(j, 0, edge);
+                        inserted = true;
+                        break;
+                    }
 
+                if (!inserted)
+                    selected.push(edge);
+            }
 
-    function getEdges(e) {
-      if (!self.settings('enableEdgeHovering')) {
-        // No event if the setting is off:
-        return [];
-      }
+            if (edges.length)
+                for (i = 0, l = edges.length; i < l; i++) {
+                    edge = edges[i];
+                    source = self.graph.nodes(edge.source);
+                    target = self.graph.nodes(edge.target);
+                    // (HACK) we can't get edge[prefix + 'size'] on WebGL renderer:
+                    s = edge[prefix + 'size'] ||
+                        edge['read_' + prefix + 'size'];
+
+                    // First, let's identify which edges are drawn. To do this, we keep
+                    // every edges that have at least one extremity displayed according to
+                    // the quadtree and the "hidden" attribute. We also do not keep hidden
+                    // edges.
+                    // Then, let's check if the mouse is on the edge (we suppose that it
+                    // is a line segment).
+
+                    if (
+                        !edge.hidden && !source.hidden && !target.hidden &&
+                        (!isCanvas ||
+                        (nodeIndex[edge.source] || nodeIndex[edge.target])) &&
+                        sigma.utils.getDistance(
+                            source[prefix + 'x'],
+                            source[prefix + 'y'],
+                            modifiedX,
+                            modifiedY) > source[prefix + 'size'] &&
+                        sigma.utils.getDistance(
+                            target[prefix + 'x'],
+                            target[prefix + 'y'],
+                            modifiedX,
+                            modifiedY) > target[prefix + 'size']
+                    ) {
+                        if (edge.type == 'curve' || edge.type == 'curvedArrow') {
+                            if (source.id === target.id) {
+                                cp = sigma.utils.getSelfLoopControlPoints(
+                                    source[prefix + 'x'],
+                                    source[prefix + 'y'],
+                                    source[prefix + 'size']
+                                );
+                                if (
+                                    sigma.utils.isPointOnBezierCurve(
+                                        modifiedX,
+                                        modifiedY,
+                                        source[prefix + 'x'],
+                                        source[prefix + 'y'],
+                                        target[prefix + 'x'],
+                                        target[prefix + 'y'],
+                                        cp.x1,
+                                        cp.y1,
+                                        cp.x2,
+                                        cp.y2,
+                                        Math.max(s, maxEpsilon)
+                                    )) {
+                                    insertEdge(selected, edge);
+                                }
+                            }
+                            else {
+                                cp = sigma.utils.getQuadraticControlPoint(
+                                    source[prefix + 'x'],
+                                    source[prefix + 'y'],
+                                    target[prefix + 'x'],
+                                    target[prefix + 'y']);
+                                if (
+                                    sigma.utils.isPointOnQuadraticCurve(
+                                        modifiedX,
+                                        modifiedY,
+                                        source[prefix + 'x'],
+                                        source[prefix + 'y'],
+                                        target[prefix + 'x'],
+                                        target[prefix + 'y'],
+                                        cp.x,
+                                        cp.y,
+                                        Math.max(s, maxEpsilon)
+                                    )) {
+                                    insertEdge(selected, edge);
+                                }
+                            }
+                        } else if (
+                            sigma.utils.isPointOnSegment(
+                                modifiedX,
+                                modifiedY,
+                                source[prefix + 'x'],
+                                source[prefix + 'y'],
+                                target[prefix + 'x'],
+                                target[prefix + 'y'],
+                                Math.max(s, maxEpsilon)
+                            )) {
+                            insertEdge(selected, edge);
+                        }
+                    }
+                }
 
-      var isCanvas = (
-        sigma.renderers.canvas && self instanceof sigma.renderers.canvas);
+            return selected;
+        }
 
-      if (!isCanvas) {
-        // A quick hardcoded rule to prevent people from using this feature
-        // with the WebGL renderer (which is not good enough at the moment):
-        throw new Error(
-          'The edge events feature is not compatible with the WebGL renderer'
-        );
-      }
-
-      if (e) {
-        mX = 'x' in e.data ? e.data.x : mX;
-        mY = 'y' in e.data ? e.data.y : mY;
-      }
-
-      var i,
-          j,
-          l,
-          a,
-          edge,
-          s,
-          maxEpsilon = self.settings('edgeHoverPrecision'),
-          source,
-          target,
-          cp,
-          nodeIndex = {},
-          inserted,
-          selected = [],
-          modifiedX = mX + self.width / 2,
-          modifiedY = mY + self.height / 2,
-          point = self.camera.cameraPosition(
-            mX,
-            mY
-          ),
-          edges = [];
 
-      if (isCanvas) {
-        var nodesOnScreen = self.camera.quadtree.area(
-          self.camera.getRectangle(self.width, self.height)
-        );
-        for (a = nodesOnScreen, i = 0, l = a.length; i < l; i++)
-          nodeIndex[a[i].id] = a[i];
-      }
-
-      if (self.camera.edgequadtree !== undefined) {
-        edges = self.camera.edgequadtree.point(
-          point.x,
-          point.y
-        );
-      }
+        function bindCaptor(captor) {
+            var nodes,
+                edges,
+                overNodes = {},
+                overEdges = {};
+
+            function onClick(e) {
+                if (!self.settings('eventsEnabled'))
+                    return;
+
+                self.dispatchEvent('click', e.data);
+
+                nodes = getNodes(e);
+                edges = getEdges(e);
+
+                if (nodes.length) {
+                    self.dispatchEvent('clickNode', {
+                        node: nodes[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('clickNodes', {
+                        node: nodes,
+                        captor: e.data
+                    });
+                } else if (edges.length) {
+                    self.dispatchEvent('clickEdge', {
+                        edge: edges[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('clickEdges', {
+                        edge: edges,
+                        captor: e.data
+                    });
+                } else
+                    self.dispatchEvent('clickStage', {captor: e.data});
+            }
 
-      function insertEdge(selected, edge) {
-        inserted = false;
+            function onDoubleClick(e) {
+                if (!self.settings('eventsEnabled'))
+                    return;
+
+                self.dispatchEvent('doubleClick', e.data);
+
+                nodes = getNodes(e);
+                edges = getEdges(e);
+
+                if (nodes.length) {
+                    self.dispatchEvent('doubleClickNode', {
+                        node: nodes[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('doubleClickNodes', {
+                        node: nodes,
+                        captor: e.data
+                    });
+                } else if (edges.length) {
+                    self.dispatchEvent('doubleClickEdge', {
+                        edge: edges[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('doubleClickEdges', {
+                        edge: edges,
+                        captor: e.data
+                    });
+                } else
+                    self.dispatchEvent('doubleClickStage', {captor: e.data});
+            }
 
-        for (j = 0; j < selected.length; j++)
-          if (edge.size > selected[j].size) {
-            selected.splice(j, 0, edge);
-            inserted = true;
-            break;
-          }
+            function onRightClick(e) {
+                if (!self.settings('eventsEnabled'))
+                    return;
+
+                self.dispatchEvent('rightClick', e.data);
+
+                nodes = getNodes(e);
+                edges = getEdges(e);
+
+                if (nodes.length) {
+                    self.dispatchEvent('rightClickNode', {
+                        node: nodes[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('rightClickNodes', {
+                        node: nodes,
+                        captor: e.data
+                    });
+                } else if (edges.length) {
+                    self.dispatchEvent('rightClickEdge', {
+                        edge: edges[0],
+                        captor: e.data
+                    });
+                    self.dispatchEvent('rightClickEdges', {
+                        edge: edges,
+                        captor: e.data
+                    });
+                } else
+                    self.dispatchEvent('rightClickStage', {captor: e.data});
+            }
 
-        if (!inserted)
-          selected.push(edge);
-      }
+            function onOut(e) {
+                if (!self.settings('eventsEnabled'))
+                    return;
+
+                var k,
+                    i,
+                    l,
+                    le,
+                    outNodes = [],
+                    outEdges = [];
+
+                for (k in overNodes)
+                    outNodes.push(overNodes[k]);
+
+                overNodes = {};
+                // Dispatch both single and multi events:
+                for (i = 0, l = outNodes.length; i < l; i++)
+                    self.dispatchEvent('outNode', {
+                        node: outNodes[i],
+                        captor: e.data
+                    });
+                if (outNodes.length)
+                    self.dispatchEvent('outNodes', {
+                        nodes: outNodes,
+                        captor: e.data
+                    });
+
+                overEdges = {};
+                // Dispatch both single and multi events:
+                for (i = 0, le = outEdges.length; i < le; i++)
+                    self.dispatchEvent('outEdge', {
+                        edge: outEdges[i],
+                        captor: e.data
+                    });
+                if (outEdges.length)
+                    self.dispatchEvent('outEdges', {
+                        edges: outEdges,
+                        captor: e.data
+                    });
+            }
 
-      if (edges.length)
-        for (i = 0, l = edges.length; i < l; i++) {
-          edge = edges[i];
-          source = self.graph.nodes(edge.source);
-          target = self.graph.nodes(edge.target);
-          // (HACK) we can't get edge[prefix + 'size'] on WebGL renderer:
-          s = edge[prefix + 'size'] ||
-              edge['read_' + prefix + 'size'];
-
-          // First, let's identify which edges are drawn. To do this, we keep
-          // every edges that have at least one extremity displayed according to
-          // the quadtree and the "hidden" attribute. We also do not keep hidden
-          // edges.
-          // Then, let's check if the mouse is on the edge (we suppose that it
-          // is a line segment).
-
-          if (
-            !edge.hidden &&
-            !source.hidden && !target.hidden &&
-            (!isCanvas ||
-              (nodeIndex[edge.source] || nodeIndex[edge.target])) &&
-            sigma.utils.getDistance(
-              source[prefix + 'x'],
-              source[prefix + 'y'],
-              modifiedX,
-              modifiedY) > source[prefix + 'size'] &&
-            sigma.utils.getDistance(
-              target[prefix + 'x'],
-              target[prefix + 'y'],
-              modifiedX,
-              modifiedY) > target[prefix + 'size']
-          ) {
-            if (edge.type == 'curve' || edge.type == 'curvedArrow') {
-              if (source.id === target.id) {
-                cp = sigma.utils.getSelfLoopControlPoints(
-                  source[prefix + 'x'],
-                  source[prefix + 'y'],
-                  source[prefix + 'size']
-                );
-                if (
-                  sigma.utils.isPointOnBezierCurve(
-                  modifiedX,
-                  modifiedY,
-                  source[prefix + 'x'],
-                  source[prefix + 'y'],
-                  target[prefix + 'x'],
-                  target[prefix + 'y'],
-                  cp.x1,
-                  cp.y1,
-                  cp.x2,
-                  cp.y2,
-                  Math.max(s, maxEpsilon)
-                )) {
-                  insertEdge(selected, edge);
-                }
-              }
-              else {
-                cp = sigma.utils.getQuadraticControlPoint(
-                  source[prefix + 'x'],
-                  source[prefix + 'y'],
-                  target[prefix + 'x'],
-                  target[prefix + 'y']);
-                if (
-                  sigma.utils.isPointOnQuadraticCurve(
-                  modifiedX,
-                  modifiedY,
-                  source[prefix + 'x'],
-                  source[prefix + 'y'],
-                  target[prefix + 'x'],
-                  target[prefix + 'y'],
-                  cp.x,
-                  cp.y,
-                  Math.max(s, maxEpsilon)
-                )) {
-                  insertEdge(selected, edge);
+            function onMove(e) {
+                if (!self.settings('eventsEnabled'))
+                    return;
+
+                nodes = getNodes(e);
+                edges = getEdges(e);
+
+                var i,
+                    k,
+                    node,
+                    edge,
+                    newOutNodes = [],
+                    newOverNodes = [],
+                    currentOverNodes = {},
+                    l = nodes.length,
+                    newOutEdges = [],
+                    newOverEdges = [],
+                    currentOverEdges = {},
+                    le = edges.length;
+
+                // Check newly overred nodes:
+                for (i = 0; i < l; i++) {
+                    node = nodes[i];
+                    currentOverNodes[node.id] = node;
+                    if (!overNodes[node.id]) {
+                        newOverNodes.push(node);
+                        overNodes[node.id] = node;
+                    }
                 }
-              }
-            } else if (
-                sigma.utils.isPointOnSegment(
-                modifiedX,
-                modifiedY,
-                source[prefix + 'x'],
-                source[prefix + 'y'],
-                target[prefix + 'x'],
-                target[prefix + 'y'],
-                Math.max(s, maxEpsilon)
-              )) {
-              insertEdge(selected, edge);
-            }
-          }
-        }
 
-      return selected;
-    }
+                // Check no more overred nodes:
+                for (k in overNodes)
+                    if (!currentOverNodes[k]) {
+                        newOutNodes.push(overNodes[k]);
+                        delete overNodes[k];
+                    }
+
+                // Dispatch both single and multi events:
+                for (i = 0, l = newOverNodes.length; i < l; i++)
+                    self.dispatchEvent('overNode', {
+                        node: newOverNodes[i],
+                        captor: e.data
+                    });
+                for (i = 0, l = newOutNodes.length; i < l; i++)
+                    self.dispatchEvent('outNode', {
+                        node: newOutNodes[i],
+                        captor: e.data
+                    });
+                if (newOverNodes.length)
+                    self.dispatchEvent('overNodes', {
+                        nodes: newOverNodes,
+                        captor: e.data
+                    });
+                if (newOutNodes.length)
+                    self.dispatchEvent('outNodes', {
+                        nodes: newOutNodes,
+                        captor: e.data
+                    });
+
+                // Check newly overred edges:
+                for (i = 0; i < le; i++) {
+                    edge = edges[i];
+                    currentOverEdges[edge.id] = edge;
+                    if (!overEdges[edge.id]) {
+                        newOverEdges.push(edge);
+                        overEdges[edge.id] = edge;
+                    }
+                }
 
+                // Check no more overred edges:
+                for (k in overEdges)
+                    if (!currentOverEdges[k]) {
+                        newOutEdges.push(overEdges[k]);
+                        delete overEdges[k];
+                    }
+
+                // Dispatch both single and multi events:
+                for (i = 0, le = newOverEdges.length; i < le; i++)
+                    self.dispatchEvent('overEdge', {
+                        edge: newOverEdges[i],
+                        captor: e.data
+                    });
+                for (i = 0, le = newOutEdges.length; i < le; i++)
+                    self.dispatchEvent('outEdge', {
+                        edge: newOutEdges[i],
+                        captor: e.data
+                    });
+                if (newOverEdges.length)
+                    self.dispatchEvent('overEdges', {
+                        edges: newOverEdges,
+                        captor: e.data
+                    });
+                if (newOutEdges.length)
+                    self.dispatchEvent('outEdges', {
+                        edges: newOutEdges,
+                        captor: e.data
+                    });
+            }
 
-    function bindCaptor(captor) {
-      var nodes,
-          edges,
-          overNodes = {},
-          overEdges = {};
-
-      function onClick(e) {
-        if (!self.settings('eventsEnabled'))
-          return;
-
-        self.dispatchEvent('click', e.data);
-
-        nodes = getNodes(e);
-        edges = getEdges(e);
-
-        if (nodes.length) {
-          self.dispatchEvent('clickNode', {
-            node: nodes[0],
-            captor: e.data
-          });
-          self.dispatchEvent('clickNodes', {
-            node: nodes,
-            captor: e.data
-          });
-        } else if (edges.length) {
-          self.dispatchEvent('clickEdge', {
-            edge: edges[0],
-            captor: e.data
-          });
-          self.dispatchEvent('clickEdges', {
-            edge: edges,
-            captor: e.data
-          });
-        } else
-          self.dispatchEvent('clickStage', {captor: e.data});
-      }
-
-      function onDoubleClick(e) {
-        if (!self.settings('eventsEnabled'))
-          return;
-
-        self.dispatchEvent('doubleClick', e.data);
-
-        nodes = getNodes(e);
-        edges = getEdges(e);
-
-        if (nodes.length) {
-          self.dispatchEvent('doubleClickNode', {
-            node: nodes[0],
-            captor: e.data
-          });
-          self.dispatchEvent('doubleClickNodes', {
-            node: nodes,
-            captor: e.data
-          });
-        } else if (edges.length) {
-          self.dispatchEvent('doubleClickEdge', {
-            edge: edges[0],
-            captor: e.data
-          });
-          self.dispatchEvent('doubleClickEdges', {
-            edge: edges,
-            captor: e.data
-          });
-        } else
-          self.dispatchEvent('doubleClickStage', {captor: e.data});
-      }
-
-      function onRightClick(e) {
-        if (!self.settings('eventsEnabled'))
-          return;
-
-        self.dispatchEvent('rightClick', e.data);
-
-        nodes = getNodes(e);
-        edges = getEdges(e);
-
-        if (nodes.length) {
-          self.dispatchEvent('rightClickNode', {
-            node: nodes[0],
-            captor: e.data
-          });
-          self.dispatchEvent('rightClickNodes', {
-            node: nodes,
-            captor: e.data
-          });
-        } else if (edges.length) {
-          self.dispatchEvent('rightClickEdge', {
-            edge: edges[0],
-            captor: e.data
-          });
-          self.dispatchEvent('rightClickEdges', {
-            edge: edges,
-            captor: e.data
-          });
-        } else
-          self.dispatchEvent('rightClickStage', {captor: e.data});
-      }
+            // Bind events:
+            captor.bind('click', onClick);
+            captor.bind('mousedown', onMove);
+            captor.bind('mouseup', onMove);
+            captor.bind('mousemove', onMove);
+            captor.bind('mouseout', onOut);
+            captor.bind('doubleclick', onDoubleClick);
+            captor.bind('rightclick', onRightClick);
+            self.bind('render', onMove);
+        }
 
-      function onOut(e) {
-        if (!self.settings('eventsEnabled'))
-          return;
+        for (i = 0, l = this.captors.length; i < l; i++)
+            bindCaptor(this.captors[i]);
+    };
+}).call(this);
 
-        var k,
-            i,
-            l,
-            le,
-            outNodes = [],
-            outEdges = [];
-
-        for (k in overNodes)
-          outNodes.push(overNodes[k]);
-
-        overNodes = {};
-        // Dispatch both single and multi events:
-        for (i = 0, l = outNodes.length; i < l; i++)
-          self.dispatchEvent('outNode', {
-            node: outNodes[i],
-            captor: e.data
-          });
-        if (outNodes.length)
-          self.dispatchEvent('outNodes', {
-            nodes: outNodes,
-            captor: e.data
-          });
-
-        overEdges = {};
-        // Dispatch both single and multi events:
-        for (i = 0, le = outEdges.length; i < le; i++)
-          self.dispatchEvent('outEdge', {
-            edge: outEdges[i],
-            captor: e.data
-          });
-        if (outEdges.length)
-          self.dispatchEvent('outEdges', {
-            edges: outEdges,
-            captor: e.data
-          });
-      }
-
-      function onMove(e) {
-        if (!self.settings('eventsEnabled'))
-          return;
-
-        nodes = getNodes(e);
-        edges = getEdges(e);
+;(function (undefined) {
+    'use strict';
 
-        var i,
-            k,
-            node,
-            edge,
-            newOutNodes = [],
-            newOverNodes = [],
-            currentOverNodes = {},
-            l = nodes.length,
-            newOutEdges = [],
-            newOverEdges = [],
-            currentOverEdges = {},
-            le = edges.length;
-
-        // Check newly overred nodes:
-        for (i = 0; i < l; i++) {
-          node = nodes[i];
-          currentOverNodes[node.id] = node;
-          if (!overNodes[node.id]) {
-            newOverNodes.push(node);
-            overNodes[node.id] = node;
-          }
-        }
-
-        // Check no more overred nodes:
-        for (k in overNodes)
-          if (!currentOverNodes[k]) {
-            newOutNodes.push(overNodes[k]);
-            delete overNodes[k];
-          }
-
-        // Dispatch both single and multi events:
-        for (i = 0, l = newOverNodes.length; i < l; i++)
-          self.dispatchEvent('overNode', {
-            node: newOverNodes[i],
-            captor: e.data
-          });
-        for (i = 0, l = newOutNodes.length; i < l; i++)
-          self.dispatchEvent('outNode', {
-            node: newOutNodes[i],
-            captor: e.data
-          });
-        if (newOverNodes.length)
-          self.dispatchEvent('overNodes', {
-            nodes: newOverNodes,
-            captor: e.data
-          });
-        if (newOutNodes.length)
-          self.dispatchEvent('outNodes', {
-            nodes: newOutNodes,
-            captor: e.data
-          });
-
-        // Check newly overred edges:
-        for (i = 0; i < le; i++) {
-          edge = edges[i];
-          currentOverEdges[edge.id] = edge;
-          if (!overEdges[edge.id]) {
-            newOverEdges.push(edge);
-            overEdges[edge.id] = edge;
-          }
-        }
-
-        // Check no more overred edges:
-        for (k in overEdges)
-          if (!currentOverEdges[k]) {
-            newOutEdges.push(overEdges[k]);
-            delete overEdges[k];
-          }
-
-        // Dispatch both single and multi events:
-        for (i = 0, le = newOverEdges.length; i < le; i++)
-          self.dispatchEvent('overEdge', {
-            edge: newOverEdges[i],
-            captor: e.data
-          });
-        for (i = 0, le = newOutEdges.length; i < le; i++)
-          self.dispatchEvent('outEdge', {
-            edge: newOutEdges[i],
-            captor: e.data
-          });
-        if (newOverEdges.length)
-          self.dispatchEvent('overEdges', {
-            edges: newOverEdges,
-            captor: e.data
-          });
-        if (newOutEdges.length)
-          self.dispatchEvent('outEdges', {
-            edges: newOutEdges,
-            captor: e.data
-          });
-      }
-
-      // Bind events:
-      captor.bind('click', onClick);
-      captor.bind('mousedown', onMove);
-      captor.bind('mouseup', onMove);
-      captor.bind('mousemove', onMove);
-      captor.bind('mouseout', onOut);
-      captor.bind('doubleclick', onDoubleClick);
-      captor.bind('rightclick', onRightClick);
-      self.bind('render', onMove);
-    }
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-    for (i = 0, l = this.captors.length; i < l; i++)
-      bindCaptor(this.captors[i]);
-  };
-}).call(this);
+    // Initialize packages:
+    sigma.utils.pkg('sigma.misc');
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.misc');
-
-  /**
-   * This helper will bind any DOM renderer (for instance svg)
-   * to its captors, to properly dispatch the good events to the sigma instance
-   * to manage clicking, hovering etc...
-   *
-   * It has to be called in the scope of the related renderer.
-   */
-  sigma.misc.bindDOMEvents = function(container) {
-    var self = this,
-        graph = this.graph;
-
-    // DOMElement abstraction
-    function Element(domElement) {
-
-      // Helpers
-      this.attr = function(attrName) {
-        return domElement.getAttributeNS(null, attrName);
-      };
-
-      // Properties
-      this.tag = domElement.tagName;
-      this.class = this.attr('class');
-      this.id = this.attr('id');
-
-      // Methods
-      this.isNode = function() {
-        return !!~this.class.indexOf(self.settings('classPrefix') + '-node');
-      };
-
-      this.isEdge = function() {
-        return !!~this.class.indexOf(self.settings('classPrefix') + '-edge');
-      };
-
-      this.isHover = function() {
-        return !!~this.class.indexOf(self.settings('classPrefix') + '-hover');
-      };
-    }
+    /**
+     * This helper will bind any DOM renderer (for instance svg)
+     * to its captors, to properly dispatch the good events to the sigma instance
+     * to manage clicking, hovering etc...
+     *
+     * It has to be called in the scope of the related renderer.
+     */
+    sigma.misc.bindDOMEvents = function (container) {
+        var self = this,
+            graph = this.graph;
+
+        // DOMElement abstraction
+        function Element(domElement) {
+
+            // Helpers
+            this.attr = function (attrName) {
+                return domElement.getAttributeNS(null, attrName);
+            };
+
+            // Properties
+            this.tag = domElement.tagName;
+            this.class = this.attr('class');
+            this.id = this.attr('id');
+
+            // Methods
+            this.isNode = function () {
+                return !!~this.class.indexOf(self.settings('classPrefix') + '-node');
+            };
+
+            this.isEdge = function () {
+                return !!~this.class.indexOf(self.settings('classPrefix') + '-edge');
+            };
+
+            this.isHover = function () {
+                return !!~this.class.indexOf(self.settings('classPrefix') + '-hover');
+            };
+        }
 
-    // Click
-    function click(e) {
-      if (!self.settings('eventsEnabled'))
-        return;
+        // Click
+        function click(e) {
+            if (!self.settings('eventsEnabled'))
+                return;
 
-      // Generic event
-      self.dispatchEvent('click', e);
+            // Generic event
+            self.dispatchEvent('click', e);
 
-      // Are we on a node?
-      var element = new Element(e.target);
+            // Are we on a node?
+            var element = new Element(e.target);
 
-      if (element.isNode())
-        self.dispatchEvent('clickNode', {
-          node: graph.nodes(element.attr('data-node-id'))
-        });
-      else
-        self.dispatchEvent('clickStage');
+            if (element.isNode())
+                self.dispatchEvent('clickNode', {
+                    node: graph.nodes(element.attr('data-node-id'))
+                });
+            else
+                self.dispatchEvent('clickStage');
 
-      e.preventDefault();
-      e.stopPropagation();
-    }
+            e.preventDefault();
+            e.stopPropagation();
+        }
 
-    // Double click
-    function doubleClick(e) {
-      if (!self.settings('eventsEnabled'))
-        return;
+        // Double click
+        function doubleClick(e) {
+            if (!self.settings('eventsEnabled'))
+                return;
 
-      // Generic event
-      self.dispatchEvent('doubleClick', e);
+            // Generic event
+            self.dispatchEvent('doubleClick', e);
 
-      // Are we on a node?
-      var element = new Element(e.target);
+            // Are we on a node?
+            var element = new Element(e.target);
 
-      if (element.isNode())
-        self.dispatchEvent('doubleClickNode', {
-          node: graph.nodes(element.attr('data-node-id'))
-        });
-      else
-        self.dispatchEvent('doubleClickStage');
+            if (element.isNode())
+                self.dispatchEvent('doubleClickNode', {
+                    node: graph.nodes(element.attr('data-node-id'))
+                });
+            else
+                self.dispatchEvent('doubleClickStage');
 
-      e.preventDefault();
-      e.stopPropagation();
-    }
+            e.preventDefault();
+            e.stopPropagation();
+        }
 
-    // On over
-    function onOver(e) {
-      var target = e.toElement || e.target;
+        // On over
+        function onOver(e) {
+            var target = e.toElement || e.target;
 
-      if (!self.settings('eventsEnabled') || !target)
-        return;
+            if (!self.settings('eventsEnabled') || !target)
+                return;
 
-      var el = new Element(target);
+            var el = new Element(target);
 
-      if (el.isNode()) {
-        self.dispatchEvent('overNode', {
-          node: graph.nodes(el.attr('data-node-id'))
-        });
-      }
-      else if (el.isEdge()) {
-        var edge = graph.edges(el.attr('data-edge-id'));
-        self.dispatchEvent('overEdge', {
-          edge: edge,
-          source: graph.nodes(edge.source),
-          target: graph.nodes(edge.target)
-        });
-      }
-    }
+            if (el.isNode()) {
+                self.dispatchEvent('overNode', {
+                    node: graph.nodes(el.attr('data-node-id'))
+                });
+            }
+            else if (el.isEdge()) {
+                var edge = graph.edges(el.attr('data-edge-id'));
+                self.dispatchEvent('overEdge', {
+                    edge: edge,
+                    source: graph.nodes(edge.source),
+                    target: graph.nodes(edge.target)
+                });
+            }
+        }
 
-    // On out
-    function onOut(e) {
-      var target = e.fromElement || e.originalTarget;
+        // On out
+        function onOut(e) {
+            var target = e.fromElement || e.originalTarget;
 
-      if (!self.settings('eventsEnabled'))
-        return;
+            if (!self.settings('eventsEnabled'))
+                return;
 
-      var el = new Element(target);
+            var el = new Element(target);
 
-      if (el.isNode()) {
-        self.dispatchEvent('outNode', {
-          node: graph.nodes(el.attr('data-node-id'))
-        });
-      }
-      else if (el.isEdge()) {
-        var edge = graph.edges(el.attr('data-edge-id'));
-        self.dispatchEvent('outEdge', {
-          edge: edge,
-          source: graph.nodes(edge.source),
-          target: graph.nodes(edge.target)
-        });
-      }
-    }
+            if (el.isNode()) {
+                self.dispatchEvent('outNode', {
+                    node: graph.nodes(el.attr('data-node-id'))
+                });
+            }
+            else if (el.isEdge()) {
+                var edge = graph.edges(el.attr('data-edge-id'));
+                self.dispatchEvent('outEdge', {
+                    edge: edge,
+                    source: graph.nodes(edge.source),
+                    target: graph.nodes(edge.target)
+                });
+            }
+        }
 
-    // Registering Events:
+        // Registering Events:
 
-    // Click
-    container.addEventListener('click', click, false);
-    sigma.utils.doubleClick(container, 'click', doubleClick);
+        // Click
+        container.addEventListener('click', click, false);
+        sigma.utils.doubleClick(container, 'click', doubleClick);
 
-    // Touch counterparts
-    container.addEventListener('touchstart', click, false);
-    sigma.utils.doubleClick(container, 'touchstart', doubleClick);
+        // Touch counterparts
+        container.addEventListener('touchstart', click, false);
+        sigma.utils.doubleClick(container, 'touchstart', doubleClick);
 
-    // Mouseover
-    container.addEventListener('mouseover', onOver, true);
+        // Mouseover
+        container.addEventListener('mouseover', onOver, true);
 
-    // Mouseout
-    container.addEventListener('mouseout', onOut, true);
-  };
+        // Mouseout
+        container.addEventListener('mouseout', onOut, true);
+    };
 }).call(this);
 
-;(function(undefined) {
-  'use strict';
-
-  if (typeof sigma === 'undefined')
-    throw 'sigma is not declared';
-
-  // Initialize packages:
-  sigma.utils.pkg('sigma.misc');
-
-  /**
-   * This method listens to "overNode", "outNode", "overEdge" and "outEdge"
-   * events from a renderer and renders the nodes differently on the top layer.
-   * The goal is to make any node label readable with the mouse, and to
-   * highlight hovered nodes and edges.
-   *
-   * It has to be called in the scope of the related renderer.
-   */
-  sigma.misc.drawHovers = function(prefix) {
-    var self = this,
-        hoveredNodes = {},
-        hoveredEdges = {};
-
-    this.bind('overNode', function(event) {
-      var node = event.data.node;
-      if (!node.hidden) {
-        hoveredNodes[node.id] = node;
-        draw();
-      }
-    });
-
-    this.bind('outNode', function(event) {
-      delete hoveredNodes[event.data.node.id];
-      draw();
-    });
+;(function (undefined) {
+    'use strict';
 
-    this.bind('overEdge', function(event) {
-      var edge = event.data.edge;
-      if (!edge.hidden) {
-        hoveredEdges[edge.id] = edge;
-        draw();
-      }
-    });
+    if (typeof sigma === 'undefined')
+        throw 'sigma is not declared';
 
-    this.bind('outEdge', function(event) {
-      delete hoveredEdges[event.data.edge.id];
-      draw();
-    });
+    // Initialize packages:
+    sigma.utils.pkg('sigma.misc');
 
-    this.bind('render', function(event) {
-      draw();
-    });
+    /**
+     * This method listens to "overNode", "outNode", "overEdge" and "outEdge"
+     * events from a renderer and renders the nodes differently on the top layer.
+     * The goal is to make any node label readable with the mouse, and to
+     * highlight hovered nodes and edges.
+     *
+     * It has to be called in the scope of the related renderer.
+     */
+    sigma.misc.drawHovers = function (prefix) {
+        var self = this,
+            hoveredNodes = {},
+            hoveredEdges = {};
+
+        this.bind('overNode', function (event) {
+            var node = event.data.node;
+            if (!node.hidden) {
+                hoveredNodes[node.id] = node;
+                draw();
+            }
+        });
 
-    function draw() {
-
-      var k,
-          source,
-          target,
-          hoveredNode,
-          hoveredEdge,
-          c = self.contexts.hover.canvas,
-          defaultNodeType = self.settings('defaultNodeType'),
-          defaultEdgeType = self.settings('defaultEdgeType'),
-          nodeRenderers = sigma.canvas.hovers,
-          edgeRenderers = sigma.canvas.edgehovers,
-          extremitiesRenderers = sigma.canvas.extremities,
-          embedSettings = self.settings.embedObjects({
-            prefix: prefix
-          });
-
-      // Clear self.contexts.hover:
-      self.contexts.hover.clearRect(0, 0, c.width, c.height);
-
-      // Node render: single hover
-      if (
-        embedSettings('enableHovering') &&
-        embedSettings('singleHover') &&
-        Object.keys(hoveredNodes).length
-      ) {
-        hoveredNode = hoveredNodes[Object.keys(hoveredNodes)[0]];
-        (
-          nodeRenderers[hoveredNode.type] ||
-          nodeRenderers[defaultNodeType] ||
-          nodeRenderers.def
-        )(
-          hoveredNode,
-          self.contexts.hover,
-          embedSettings
-        );
-      }
-
-      // Node render: multiple hover
-      if (
-        embedSettings('enableHovering') &&
-        !embedSettings('singleHover')
-      )
-        for (k in hoveredNodes)
-          (
-            nodeRenderers[hoveredNodes[k].type] ||
-            nodeRenderers[defaultNodeType] ||
-            nodeRenderers.def
-          )(
-            hoveredNodes[k],
-            self.contexts.hover,
-            embedSettings
-          );
-
-      // Edge render: single hover
-      if (
-        embedSettings('enableEdgeHovering') &&
-        embedSettings('singleHover') &&
-        Object.keys(hoveredEdges).length
-      ) {
-        hoveredEdge = hoveredEdges[Object.keys(hoveredEdges)[0]];
-        source = self.graph.nodes(hoveredEdge.source);
-        target = self.graph.nodes(hoveredEdge.target);
-
-        if (! hoveredEdge.hidden) {
-          (
-            edgeRenderers[hoveredEdge.type] ||
-            edgeRenderers[defaultEdgeType] ||
-            edgeRenderers.def
-          ) (
-            hoveredEdge,
-            source,
-            target,
-            self.contexts.hover,
-            embedSettings
-          );
+        this.bind('outNode', function (event) {
+            delete hoveredNodes[event.data.node.id];
+            draw();
+        });
 
-          if (embedSettings('edgeHoverExtremities')) {
-            (
-              extremitiesRenderers[hoveredEdge.type] ||
-              extremitiesRenderers.def
-            )(
-              hoveredEdge,
-              source,
-              target,
-              self.contexts.hover,
-              embedSettings
-            );
+        this.bind('overEdge', function (event) {
+            var edge = event.data.edge;
+            if (!edge.hidden) {
+                hoveredEdges[edge.id] = edge;
+                draw();
+            }
+        });
 
-          } else {
-            // Avoid edges rendered over nodes:
-            (
-              sigma.canvas.nodes[source.type] ||
-              sigma.canvas.nodes.def
-            ) (
-              source,
-              self.contexts.hover,
-              embedSettings
-            );
-            (
-              sigma.canvas.nodes[target.type] ||
-              sigma.canvas.nodes.def
-            ) (
-              target,
-              self.contexts.hover,
-              embedSettings
-            );
-          }
-        }
-      }
+        this.bind('outEdge', function (event) {
+            delete hoveredEdges[event.data.edge.id];
+            draw();
+        });
 
-      // Edge render: multiple hover
-      if (
-        embedSettings('enableEdgeHovering') &&
-        !embedSettings('singleHover')
-      ) {
-        for (k in hoveredEdges) {
-          hoveredEdge = hoveredEdges[k];
-          source = self.graph.nodes(hoveredEdge.source);
-          target = self.graph.nodes(hoveredEdge.target);
+        this.bind('render', function (event) {
+            draw();
+        });
 
-          if (!hoveredEdge.hidden) {
-            (
-              edgeRenderers[hoveredEdge.type] ||
-              edgeRenderers[defaultEdgeType] ||
-              edgeRenderers.def
-            ) (
-              hoveredEdge,
-              source,
-              target,
-              self.contexts.hover,
-              embedSettings
-            );
+        function draw() {
 
-            if (embedSettings('edgeHoverExtremities')) {
-              (
-                extremitiesRenderers[hoveredEdge.type] ||
-                extremitiesRenderers.def
-              )(
-                hoveredEdge,
-                source,
-                target,
-                self.contexts.hover,
-                embedSettings
-              );
-            } else {
-              // Avoid edges rendered over nodes:
-              (
-                sigma.canvas.nodes[source.type] ||
-                sigma.canvas.nodes.def
-              ) (
+            var k,
                 source,
-                self.contexts.hover,
-                embedSettings
-              );
-              (
-                sigma.canvas.nodes[target.type] ||
-                sigma.canvas.nodes.def
-              ) (
                 target,
-                self.contexts.hover,
-                embedSettings
-              );
+                hoveredNode,
+                hoveredEdge,
+                c = self.contexts.hover.canvas,
+                defaultNodeType = self.settings('defaultNodeType'),
+                defaultEdgeType = self.settings('defaultEdgeType'),
+                nodeRenderers = sigma.canvas.hovers,
+                edgeRenderers = sigma.canvas.edgehovers,
+                extremitiesRenderers = sigma.canvas.extremities,
+                embedSettings = self.settings.embedObjects({
+                    prefix: prefix
+                });
+
+            // Clear self.contexts.hover:
+            self.contexts.hover.clearRect(0, 0, c.width, c.height);
+
+            // Node render: single hover
+            if (
+                embedSettings('enableHovering') &&
+                embedSettings('singleHover') &&
+                Object.keys(hoveredNodes).length
+            ) {
+                hoveredNode = hoveredNodes[Object.keys(hoveredNodes)[0]];
+                (
+                    nodeRenderers[hoveredNode.type] ||
+                    nodeRenderers[defaultNodeType] ||
+                    nodeRenderers.def
+                )(
+                    hoveredNode,
+                    self.contexts.hover,
+                    embedSettings
+                );
+            }
+
+            // Node render: multiple hover
+            if (
+                embedSettings('enableHovering') && !embedSettings('singleHover')
+            )
+                for (k in hoveredNodes)
+                    (
+                        nodeRenderers[hoveredNodes[k].type] ||
+                        nodeRenderers[defaultNodeType] ||
+                        nodeRenderers.def
+                    )(
+                        hoveredNodes[k],
+                        self.contexts.hover,
+                        embedSettings
+                    );
+
+            // Edge render: single hover
+            if (
+                embedSettings('enableEdgeHovering') &&
+                embedSettings('singleHover') &&
+                Object.keys(hoveredEdges).length
+            ) {
+                hoveredEdge = hoveredEdges[Object.keys(hoveredEdges)[0]];
+                source = self.graph.nodes(hoveredEdge.source);
+                target = self.graph.nodes(hoveredEdge.target);
+
+                if (!hoveredEdge.hidden) {
+                    (
+                        edgeRenderers[hoveredEdge.type] ||
+                        edgeRenderers[defaultEdgeType] ||
+                        edgeRenderers.def
+                    )(
+                        hoveredEdge,
+                        source,
+                        target,
+                        self.contexts.hover,
+                        embedSettings
+                    );
+
+                    if (embedSettings('edgeHoverExtremities')) {
+                        (
+                            extremitiesRenderers[hoveredEdge.type] ||
+                            extremitiesRenderers.def
+                        )(
+                            hoveredEdge,
+                            source,
+                            target,
+                            self.contexts.hover,
+                            embedSettings
+                        );
+
+                    } else {
+                        // Avoid edges rendered over nodes:
+                        (
+                            sigma.canvas.nodes[source.type] ||
+                            sigma.canvas.nodes.def
+                        )(
+                            source,
+                            self.contexts.hover,
+                            embedSettings
+                        );
+                        (
+                            sigma.canvas.nodes[target.type] ||
+                            sigma.canvas.nodes.def
+                        )(
+                            target,
+                            self.contexts.hover,
+                            embedSettings
+                        );
+                    }
+                }
+            }
+
+            // Edge render: multiple hover
+            if (
+                embedSettings('enableEdgeHovering') && !embedSettings('singleHover')
+            ) {
+                for (k in hoveredEdges) {
+                    hoveredEdge = hoveredEdges[k];
+                    source = self.graph.nodes(hoveredEdge.source);
+                    target = self.graph.nodes(hoveredEdge.target);
+
+                    if (!hoveredEdge.hidden) {
+                        (
+                            edgeRenderers[hoveredEdge.type] ||
+                            edgeRenderers[defaultEdgeType] ||
+                            edgeRenderers.def
+                        )(
+                            hoveredEdge,
+                            source,
+                            target,
+                            self.contexts.hover,
+                            embedSettings
+                        );
+
+                        if (embedSettings('edgeHoverExtremities')) {
+                            (
+                                extremitiesRenderers[hoveredEdge.type] ||
+                                extremitiesRenderers.def
+                            )(
+                                hoveredEdge,
+                                source,
+                                target,
+                                self.contexts.hover,
+                                embedSettings
+                            );
+                        } else {
+                            // Avoid edges rendered over nodes:
+                            (
+                                sigma.canvas.nodes[source.type] ||
+                                sigma.canvas.nodes.def
+                            )(
+                                source,
+                                self.contexts.hover,
+                                embedSettings
+                            );
+                            (
+                                sigma.canvas.nodes[target.type] ||
+                                sigma.canvas.nodes.def
+                            )(
+                                target,
+                                self.contexts.hover,
+                                embedSettings
+                            );
+                        }
+                    }
+                }
             }
-          }
         }
-      }
-    }
-  };
+    };
 }).call(this);
index 05fc3da..735ccb8 100644 (file)
  * limitations under the License.\r
  */\r
 \r
\r
-function loadUnderlayData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading underlay data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting underlay data : " + xhr.responseText);  \r
-                                       }\r
-                               });\r
+\r
+function loadUnderlayData() {\r
+    var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading underlay data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting underlay data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function deleteUnderlayData(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns/"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("deleting underlay data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting underlay data : " + xhr.responseText);         \r
-                                       }\r
-                               });\r
+function deleteUnderlayData(objectId) {\r
+    var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns/" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("deleting underlay data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting underlay data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadOverlayData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.overlayvpnservice/openoapi/sdnooverlayvpn/v1/site2dc-vpn";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading Overlay data...");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting Overlayvpn data : " + xhr.responseText);        \r
-                                       }\r
-                               });\r
+function loadOverlayData() {\r
+    var requestUrl = "http://localhost:8080/org.openo.sdno.overlayvpnservice/openoapi/sdnooverlayvpn/v1/site2dc-vpn";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading Overlay data...");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting Overlayvpn data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function refressTpDataTable(overlayTable,TpTable){\r
-       alert("refesssing Tp data table");\r
+function refressTpDataTable(overlayTable, TpTable) {\r
+    alert("refesssing Tp data table");\r
 }\r
-$(function(){\r
-       $.fn.serializeObject = function() {\r
-                               var o = {};\r
-                               var a = this.serializeArray();\r
-                               $.each(a, function() {\r
-                                       if (o[this.name] !== undefined) {\r
-                                               if (!o[this.name].push) {\r
-                                                       o[this.name] = [ o[this.name] ];\r
-                                               }\r
-                                       o[this.name].push(this.value || '');\r
-                                       } else {\r
-                                               o[this.name] = this.value || '';\r
-                                       }\r
-                               });\r
-                       return o;\r
-                       };\r
-       $('#createUnderlay').click(function(){\r
-                               var formData = JSON.stringify($("#underlayForm").serializeObject());\r
-                               alert(formData);\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details saved successfully!!!");\r
-                                               //var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
-                                               //TODO: update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-       $('.underlayNameLink').click(function(){\r
-               alert("coming here");\r
-               var data = $(this).parent().parent().parent().find('td:last').find('div:last').html();\r
-               alert(data);\r
-               var jsonObj = JSON.parse(data);\r
-               for(var i = 0; i < jsonObj.length; i++) {\r
-                   var obj = jsonObj[i];\r
-                       var rowData = [obj.tpName,obj.peName,obj.vlanId,obj.siteCidr,obj.ip];\r
-                       $('#underlayTpDataTable').DataTable();\r
-                       $('#underlayTpDataTable').dataTable().fnAddData(rowData);\r
-               }\r
+$(function () {\r
+    $.fn.serializeObject = function () {\r
+        var o = {};\r
+        var a = this.serializeArray();\r
+        $.each(a, function () {\r
+            if (o[this.name] !== undefined) {\r
+                if (!o[this.name].push) {\r
+                    o[this.name] = [o[this.name]];\r
+                }\r
+                o[this.name].push(this.value || '');\r
+            } else {\r
+                o[this.name] = this.value || '';\r
+            }\r
+        });\r
+        return o;\r
+    };\r
+    $('#createUnderlay').click(function () {\r
+        var formData = JSON.stringify($("#underlayForm").serializeObject());\r
+        alert(formData);\r
+        var jsonobj = JSON.parse(formData);\r
+        var requestUrl = "http://localhost:8080/org.openo.sdno.l3vpnservice/openoapi/sdnol3vpn/v1/l3vpns";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonobj) {\r
+                    alert("Details saved successfully!!!");\r
+                    //var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
+                    //TODO: update the table\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+    $('.underlayNameLink').click(function () {\r
+        alert("coming here");\r
+        var data = $(this).parent().parent().parent().find('td:last').find('div:last').html();\r
+        alert(data);\r
+        var jsonObj = JSON.parse(data);\r
+        for (var i = 0; i < jsonObj.length; i++) {\r
+            var obj = jsonObj[i];\r
+            var rowData = [obj.tpName, obj.peName, obj.vlanId, obj.siteCidr, obj.ip];\r
+            $('#underlayTpDataTable').DataTable();\r
+            $('#underlayTpDataTable').dataTable().fnAddData(rowData);\r
+        }\r
+\r
+    });\r
 \r
-       });\r
-       \r
 })
\ No newline at end of file
index eaa53e6..1c220f6 100644 (file)
  * limitations under the License.\r
  */\r
 \r
\r
-function deleteSite(objectId){\r
-       alert(objectId);\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details deleted successfully!!!");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting site: " + xhr.responseText);   \r
-                                       }\r
-                               });\r
+\r
+function deleteSite(objectId) {\r
+    alert(objectId);\r
+    var requestUrl = "/openoapi/sdnobrs/v1/sites" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("Details deleted successfully!!!");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting site: " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function deleteLink(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details deleted successfully!!!");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting link : " + xhr.responseText);  \r
-                                       }\r
-                               });\r
+function deleteLink(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/topological-links" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("Details deleted successfully!!!");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting link : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
 \r
-function deleteNe(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/sdnobrs/v1/managed-elements"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details deleted successfully!!!");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting ne : " + xhr.responseText);    \r
-                                       }\r
-                               });\r
+function deleteNe(objectId) {\r
+    var requestUrl = "/sdnobrs/v1/managed-elements" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("Details deleted successfully!!!");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting ne : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
 \r
-function deletePort(objectId){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points"+objectId;\r
-                       $\r
-                               .ajax({\r
-                                       type : "DELETE",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details deleted successfully!!!");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on deleting port : " + xhr.responseText);  \r
-                                       }\r
-                               });\r
+function deletePort(objectId) {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points" + objectId;\r
+    $\r
+        .ajax({\r
+            type: "DELETE",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("Details deleted successfully!!!");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on deleting port : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadSiteData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading Site data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting site data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadSiteData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/sites";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading Site data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting site data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadLinkData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading Link data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting link data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadLinkData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/topological-links";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading Link data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting link data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadNeData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/sdnobrs/v1/managed-elements";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading NE data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting ne data : " + xhr.responseText);        \r
-                                       }\r
-                               });\r
+function loadNeData() {\r
+    var requestUrl = "/sdnobrs/v1/managed-elements";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading NE data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting ne data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-function loadPortData(){\r
-       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points";\r
-                       $\r
-                               .ajax({\r
-                                       type : "GET",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       success : function(jsonobj) {\r
-                                               alert("loading port data");\r
-                                               //TODO: Update the table\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on getting port data : " + xhr.responseText);      \r
-                                       }\r
-                               });\r
+function loadPortData() {\r
+    var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points";\r
+    $\r
+        .ajax({\r
+            type: "GET",\r
+            url: requestUrl,\r
+            contentType: "application/json",\r
+            success: function (jsonobj) {\r
+                alert("loading port data");\r
+                //TODO: Update the table\r
+            },\r
+            error: function (xhr, ajaxOptions, thrownError) {\r
+                alert("Error on getting port data : " + xhr.responseText);\r
+            }\r
+        });\r
 }\r
-$(function(){\r
-                       $('.creat-btn').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                               \r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('.detail-top ul li').click(function(){\r
-                               $(this).addClass('current').siblings().removeClass('current');\r
-                       });\r
-                       $('.para').click(function(){                            \r
-                               if($('#serviceTemplateName').val() == ''){\r
-                                       alert('Please choose the service templet!');\r
-                                       $('#flavorTab').css('display','none');\r
-                               }else{\r
-                                       $('#flavorTab').css('display','block');\r
-                               }\r
-                               $('#basicTab').css('display','block');\r
-                       });\r
-                       $('.basic').click(function(){\r
-                               $('#flavorTab').css('display','none');\r
-                       });\r
-                       \r
-                       $('.table tbody tr').click(function(){\r
-                               $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
-                       });\r
-                       $('.table tr:odd').addClass('active');\r
-                       $('#false').click(function(){\r
-                               $('#vmAppDialog').addClass('in').css({'display':'block'});\r
-                       });\r
-                       $('.close,.button-previous').click(function(){\r
-                               $('#vmAppDialog').removeClass('in').css('display','none');\r
-                       });\r
-                       $('#filterTpLogicalType').click(function(){\r
-                               $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
-                               $('#filterTpLogicalType').toggleClass('openo-focus');\r
-                               var oLeft = $('#open_base_tpL_td6').offset().left;\r
-                       var oTop = $('#open_base_tpL_td6').offset().top;\r
-                       var oHeight = $('#open_base_tpL_td6').height();\r
-                       $('#filterTpLogicalType_select_popupcontainer').css({'left':oLeft,'top':oTop + oHeight + 10});\r
-                       });\r
-                       $('div.openo-select-popup-container>div.openo-select-item>label').click(function(){\r
-                               var Lvalue = $(this).html();\r
-                               $('#filterTpLogicalType_select_input').attr('value',Lvalue);\r
-                               $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
-                               $('#filterTpLogicalType').removeClass('openo-focus');\r
-                       });\r
-                       $.fn.serializeObject = function() {\r
-                               var o = {};\r
-                               var a = this.serializeArray();\r
-                               $.each(a, function() {\r
-                                       if (o[this.name] !== undefined) {\r
-                                               if (!o[this.name].push) {\r
-                                                       o[this.name] = [ o[this.name] ];\r
-                                               }\r
-                                       o[this.name].push(this.value || '');\r
-                                       } else {\r
-                                               o[this.name] = this.value || '';\r
-                                       }\r
-                               });\r
-                       return o;\r
-                       };\r
-                       $('#createSite').click(function(){\r
-                               var formData = JSON.stringify($("#vmAppForm").serializeObject());\r
-                               alert(formData);\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/sites";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details saved successfully!!!");\r
-                                               var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
-                                               $('#example').dataTable().fnAddData(data);\r
-                                               $('.modal').modal('hide');\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createNe').click(function(){\r
-                               var formData = JSON.stringify($("#neForm").serializeObject());\r
-                               alert(formData);\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/sdnobrs/v1/managed-elements";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details saved successfully!!!");\r
-                                               var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
-                                               $('#example').dataTable().fnAddData(data);\r
-                                               $('.modal').modal('hide');\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createPort').click(function(){\r
-                               var formData = JSON.stringify($("#portForm").serializeObject());\r
-                               alert(formData);\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/logical-termination-points";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details saved successfully!!!");\r
-                                               var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
-                                               $('#example').dataTable().fnAddData(data);\r
-                                               $('.modal').modal('hide');\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-                       $('#createLink').click(function(){\r
-                               var formData = JSON.stringify($("#linkForm").serializeObject());\r
-                               alert(formData);\r
-                       var jsonobj = JSON.parse(formData);\r
-                       var requestUrl = "http://localhost:8080/org.openo.sdno.brs/openoapi/sdnobrs/v1/topological-links";\r
-                       $\r
-                               .ajax({\r
-                                       type : "POST",\r
-                                       url : requestUrl,\r
-                                       contentType : "application/json",\r
-                                       dataType : "json",\r
-                                       data : formData,\r
-                                       success : function(jsonobj) {\r
-                                               alert("Details saved successfully!!!");\r
-                                               var data = [jsonobj.name,jsonobj.hostName,jsonobj.productName,jsonobj.vendor,jsonobj.description];\r
-                                               $('#example').dataTable().fnAddData(data);\r
-                                               $('.modal').modal('hide');\r
-                                       },\r
-                                       error : function(xhr, ajaxOptions, thrownError) {\r
-                                               alert("Error on page : " + xhr.responseText);   \r
-                                       }\r
-                               });\r
-                       });\r
-                       \r
-               })
\ No newline at end of file
+$(function () {\r
+    $('.creat-btn').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('.detail-top ul li').click(function () {\r
+        $(this).addClass('current').siblings().removeClass('current');\r
+    });\r
+    $('.para').click(function () {\r
+        if ($('#serviceTemplateName').val() == '') {\r
+            alert('Please choose the service templet!');\r
+            $('#flavorTab').css('display', 'none');\r
+        } else {\r
+            $('#flavorTab').css('display', 'block');\r
+        }\r
+        $('#basicTab').css('display', 'block');\r
+    });\r
+    $('.basic').click(function () {\r
+        $('#flavorTab').css('display', 'none');\r
+    });\r
+\r
+    $('.table tbody tr').click(function () {\r
+        $(this).addClass('openoTable_row_selected').siblings().removeClass('openoTable_row_selected');\r
+    });\r
+    $('.table tr:odd').addClass('active');\r
+    $('#false').click(function () {\r
+        $('#vmAppDialog').addClass('in').css({'display': 'block'});\r
+    });\r
+    $('.close,.button-previous').click(function () {\r
+        $('#vmAppDialog').removeClass('in').css('display', 'none');\r
+    });\r
+    $('#filterTpLogicalType').click(function () {\r
+        $('#filterTpLogicalType_select_popupcontainer').toggleClass('openo-hide');\r
+        $('#filterTpLogicalType').toggleClass('openo-focus');\r
+        var oLeft = $('#open_base_tpL_td6').offset().left;\r
+        var oTop = $('#open_base_tpL_td6').offset().top;\r
+        var oHeight = $('#open_base_tpL_td6').height();\r
+        $('#filterTpLogicalType_select_popupcontainer').css({'left': oLeft, 'top': oTop + oHeight + 10});\r
+    });\r
+    $('div.openo-select-popup-container>div.openo-select-item>label').click(function () {\r
+        var Lvalue = $(this).html();\r
+        $('#filterTpLogicalType_select_input').attr('value', Lvalue);\r
+        $('#filterTpLogicalType_select_popupcontainer').addClass('openo-hide');\r
+        $('#filterTpLogicalType').removeClass('openo-focus');\r
+    });\r
+    $.fn.serializeObject = function () {\r
+        var o = {};\r
+        var a = this.serializeArray();\r
+        $.each(a, function () {\r
+            if (o[this.name] !== undefined) {\r
+                if (!o[this.name].push) {\r
+                    o[this.name] = [o[this.name]];\r
+                }\r
+                o[this.name].push(this.value || '');\r
+            } else {\r
+                o[this.name] = this.value || '';\r
+            }\r
+        });\r
+        return o;\r
+    };\r
+    $('#createSite').click(function () {\r
+        var formData = JSON.stringify($("#vmAppForm").serializeObject());\r
+        alert(formData);\r
+        var jsonobj = JSON.parse(formData);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/sites";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonobj) {\r
+                    alert("Details saved successfully!!!");\r
+                    var data = [jsonobj.name, jsonobj.hostName, jsonobj.productName, jsonobj.vendor, jsonobj.description];\r
+                    $('#example').dataTable().fnAddData(data);\r
+                    $('.modal').modal('hide');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createNe').click(function () {\r
+        var formData = JSON.stringify($("#neForm").serializeObject());\r
+        alert(formData);\r
+        var jsonobj = JSON.parse(formData);\r
+        var requestUrl = "/sdnobrs/v1/managed-elements";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonobj) {\r
+                    alert("Details saved successfully!!!");\r
+                    var data = [jsonobj.name, jsonobj.hostName, jsonobj.productName, jsonobj.vendor, jsonobj.description];\r
+                    $('#example').dataTable().fnAddData(data);\r
+                    $('.modal').modal('hide');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createPort').click(function () {\r
+        var formData = JSON.stringify($("#portForm").serializeObject());\r
+        alert(formData);\r
+        var jsonobj = JSON.parse(formData);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/logical-termination-points";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonobj) {\r
+                    alert("Details saved successfully!!!");\r
+                    var data = [jsonobj.name, jsonobj.hostName, jsonobj.productName, jsonobj.vendor, jsonobj.description];\r
+                    $('#example').dataTable().fnAddData(data);\r
+                    $('.modal').modal('hide');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+    $('#createLink').click(function () {\r
+        var formData = JSON.stringify($("#linkForm").serializeObject());\r
+        alert(formData);\r
+        var jsonobj = JSON.parse(formData);\r
+        var requestUrl = "/openoapi/sdnobrs/v1/topological-links";\r
+        $\r
+            .ajax({\r
+                type: "POST",\r
+                url: requestUrl,\r
+                contentType: "application/json",\r
+                dataType: "json",\r
+                data: formData,\r
+                success: function (jsonobj) {\r
+                    alert("Details saved successfully!!!");\r
+                    var data = [jsonobj.name, jsonobj.hostName, jsonobj.productName, jsonobj.vendor, jsonobj.description];\r
+                    $('#example').dataTable().fnAddData(data);\r
+                    $('.modal').modal('hide');\r
+                },\r
+                error: function (xhr, ajaxOptions, thrownError) {\r
+                    alert("Error on page : " + xhr.responseText);\r
+                }\r
+            });\r
+    });\r
+\r
+})
\ No newline at end of file
index 7822706..5fbc611 100644 (file)
     <head lang="en">
         <meta charset="UTF-8">
         <title></title>
-        <link href="../common/thirdparty/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
-        <link href="../common/thirdparty/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
-        <link href="../common/thirdparty/uniform/css/uniform.default.min.css" rel="stylesheet" />
+        <link href="../common/thirdparty/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
+        <link href="../common/thirdparty/bootstrap/css/bootstrap.min.css" rel="stylesheet"/>
+        <link href="../common/thirdparty/uniform/css/uniform.default.min.css" rel="stylesheet"/>
         <link href="../common/css/style.css" rel="stylesheet"/>
         <link href="../common/css/ngict-component.css" rel="stylesheet"/>
         <link href="../common/css/plugins.css" rel="stylesheet"/>
         <link href="../catalog/css/platform/animate.min.css" rel="stylesheet"/>
         <link href="../catalog/css/datatable-sort.css" rel="stylesheet"/>
-        <link href="../catalog/css/templateDetail.css" rel="stylesheet" />
-        <link href="../catalog/css/topology.css" rel="stylesheet" />
+        <link href="../catalog/css/templateDetail.css" rel="stylesheet"/>
+        <link href="../catalog/css/topology.css" rel="stylesheet"/>
         <style type="text/css">
             .ms-controller {
                 visibility: hidden;
             }
+
             .ms-nodedetail {
                 display: none;
             }
         </style>
     </head>
 <body>
-    <div ms-controller="tmNodesController" class="container-fluid ms-controller">
-        <div class="row">
-            <div class="col-xs-6 col-md-6 col-sm-6 col-lg-6 titlefont">
-                <span id="nfv-template-nodes-iui-title" name_i18n="com_zte_nfv_nsoc_i18n"></span>
-            </div>
-        </div>
-        <div class="separator-line"></div>
-        <div class="row-fluid" data-name="table_zone">
-            <div class="col-xs-12" id='ict_nodes_template_table_div'></div>
+<div ms-controller="tmNodesController" class="container-fluid ms-controller">
+    <div class="row">
+        <div class="col-xs-6 col-md-6 col-sm-6 col-lg-6 titlefont">
+            <span id="nfv-template-nodes-iui-title" name_i18n="com_zte_nfv_nsoc_i18n"></span>
         </div>
+    </div>
+    <div class="separator-line"></div>
+    <div class="row-fluid" data-name="table_zone">
+        <div class="col-xs-12" id='ict_nodes_template_table_div'></div>
+    </div>
 
-        <script type="text/javascript" src="../common/thirdparty/jquery/jquery-1.10.2.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/bootstrap/js/bootstrap.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/jquery.i18n/jquery.i18n.properties-1.0.9.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/jquery.i18n/jquery.i18n.properties-1.0.9.js"></script>
 
-        <script type="text/javascript" src="../common/thirdparty/bootstrap-growl/bootstrap-growl.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/avalon/avalon.modern.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/bootstrap-growl/bootstrap-growl.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/avalon/avalon.modern.js"></script>
 
-        <script type="text/javascript" src="../common/js/tools.js"></script>
+    <script type="text/javascript" src="../common/js/tools.js"></script>
 
-        <script type="text/javascript" src="../catalog/js/component/commonUtil.js"></script>
-        <script type="text/javascript" src="../catalog/js/component/serverPageTable.js"></script>
-        <script type="text/javascript" src="../catalog/js/component/loadi18n_nsoc.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/commonUtil.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/serverPageTable.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/loadi18n_nsoc.js"></script>
 
-        <script type="text/javascript" src="../catalog/js/template/tmNodesDetailUtil.js"></script>
-        <script type="text/javascript" src="../catalog/js/template/tmUtil.js"></script>
-        <script type="text/javascript" src="js/tmNodesController.js"></script>
-        <script type="text/javascript" src="../catalog/js/template/topoUtil.js"></script>
-    </div>
+    <script type="text/javascript" src="../catalog/js/template/tmNodesDetailUtil.js"></script>
+    <script type="text/javascript" src="../catalog/js/template/tmUtil.js"></script>
+    <script type="text/javascript" src="js/tmNodesController.js"></script>
+    <script type="text/javascript" src="../catalog/js/template/topoUtil.js"></script>
+</div>
 </body>
 </html>
\ No newline at end of file
index 7ebb411..4e82686 100644 (file)
     <head lang="en">
         <meta charset="UTF-8">
         <title></title>
-        <link href="../common/thirdparty/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
-        <link href="../common/thirdparty/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
-        <link href="../common/thirdparty/uniform/css/uniform.default.min.css" rel="stylesheet" />
+        <link href="../common/thirdparty/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
+        <link href="../common/thirdparty/bootstrap/css/bootstrap.min.css" rel="stylesheet"/>
+        <link href="../common/thirdparty/uniform/css/uniform.default.min.css" rel="stylesheet"/>
         <link href="../common/css/style.css" rel="stylesheet"/>
         <link href="../common/css/ngict-component.css" rel="stylesheet"/>
         <link href="../common/css/plugins.css" rel="stylesheet"/>
         <link href="../catalog/css/platform/animate.min.css" rel="stylesheet"/>
         <link href="../catalog/css/datatable-sort.css" rel="stylesheet"/>
-        <link href="../catalog/css/templateDetail.css" rel="stylesheet" />
-        <link href="../catalog/css/topology.css" rel="stylesheet" />
+        <link href="../catalog/css/templateDetail.css" rel="stylesheet"/>
+        <link href="../catalog/css/topology.css" rel="stylesheet"/>
         <style type="text/css">
             .ms-controller {
                 visibility: hidden;
             }
+
             .ms-nodedetail {
                 display: none;
             }
         </style>
     </head>
 <body>
-    <div ms-controller="tmTopoController" class="container-fluid ms-controller">
-        <div class="row">
-            <div class="col-xs-6 col-md-6 col-sm-6 col-lg-6 titlefont">
-                <span id="nfv-template-topo-iui-title" name_i18n="com_zte_nfv_nsoc_i18n"></span>
-            </div>
+<div ms-controller="tmTopoController" class="container-fluid ms-controller">
+    <div class="row">
+        <div class="col-xs-6 col-md-6 col-sm-6 col-lg-6 titlefont">
+            <span id="nfv-template-topo-iui-title" name_i18n="com_zte_nfv_nsoc_i18n"></span>
         </div>
-        <div class="separator-line"></div>
-        <div class="container-fluid">
-            <div id="networks" style="float:left;display:inline-block">
-                <div class="networksContainer">
-                    <div class="network" ms-repeat-network="topologyTab.networkTopoDatas">
-                        <div class="name" tooltip="" ms-attr-title="network.name" ms-if="network.name"
-                             ms-click="topologyTab.$showTopo(network.id, network.name)">
-                            <div ms-if="topologyTab.isShowNum" ms-text="network.num" class="badge">0</div>
-                            <span>{{network.name}}</span>
-                        </div>
-                        <div class="subnet" ms-repeat-subnet="network.subnets">
-                            <div class="line">
-                                <div class="vlan" ms-attr-id="subnet.id" ms-css-background-color="topologyTab.$getColor($index+$outer.$index)" ms-attr-title="subnet.name" ms-click="topologyTab.$showTopo(subnet.id, subnet.name)">
-                                    <div ms-if="topologyTab.isShowNum" ms-text="subnet.num" class="badge">0</div>
-                                    <p>{{subnet.name}}</p>
-                                    <p class="cidr" ms-text="topologyTab.$getCidr(subnet.properties)"></p>
-                                </div>
+    </div>
+    <div class="separator-line"></div>
+    <div class="container-fluid">
+        <div id="networks" style="float:left;display:inline-block">
+            <div class="networksContainer">
+                <div class="network" ms-repeat-network="topologyTab.networkTopoDatas">
+                    <div class="name" tooltip="" ms-attr-title="network.name" ms-if="network.name"
+                         ms-click="topologyTab.$showTopo(network.id, network.name)">
+                        <div ms-if="topologyTab.isShowNum" ms-text="network.num" class="badge">0</div>
+                        <span>{{network.name}}</span>
+                    </div>
+                    <div class="subnet" ms-repeat-subnet="network.subnets">
+                        <div class="line">
+                            <div class="vlan" ms-attr-id="subnet.id"
+                                 ms-css-background-color="topologyTab.$getColor($index+$outer.$index)"
+                                 ms-attr-title="subnet.name" ms-click="topologyTab.$showTopo(subnet.id, subnet.name)">
+                                <div ms-if="topologyTab.isShowNum" ms-text="subnet.num" class="badge">0</div>
+                                <p>{{subnet.name}}</p>
+                                <p class="cidr" ms-text="topologyTab.$getCidr(subnet.properties)"></p>
                             </div>
-                        </div><!--end repeat network.subnets-->
-                    </div><!--end repeat topologyTab.networkTopoDatas-->
-                </div>
+                        </div>
+                    </div><!--end repeat network.subnets-->
+                </div><!--end repeat topologyTab.networkTopoDatas-->
             </div>
-            <div id="topo" style="float:left;display:inline-block">
-                <div class="row-fluid" data-name="topo_zone">
-                    <div class="bpContainer" ms-each-host="topologyTab.boxTopoDatas">
-                        <div>
-                            <div class="box" ms-attr-id="host.id">
-                                <div class="piProgress" size="55">
-                                    <div class="circle">
-                                        <i class="gs-node-icon fa fa-desktop" ></i>
-                                        <div ms-if="topologyTab.isShowNum" ms-text="host.num" class="badge">1</div>
-                                    </div>
-                                    <div class="smallCircle" ms-repeat-cp="host.cp" ms-attr-id="cp.id" ms-title="cp.name"
-                                         ms-click="topologyTab.$showTopo(cp.id,cp.name)" ms-css-top="topologyTab.$getCpTop($index,host.id)">
-                                        <i class="gs-cp-icon fa fa-credit-card" ></i>
-                                    </div>
+        </div>
+        <div id="topo" style="float:left;display:inline-block">
+            <div class="row-fluid" data-name="topo_zone">
+                <div class="bpContainer" ms-each-host="topologyTab.boxTopoDatas">
+                    <div>
+                        <div class="box" ms-attr-id="host.id">
+                            <div class="piProgress" size="55">
+                                <div class="circle">
+                                    <i class="gs-node-icon fa fa-desktop"></i>
+                                    <div ms-if="topologyTab.isShowNum" ms-text="host.num" class="badge">1</div>
                                 </div>
-                                <div class="head"  ms-hover="boxHover" tooltip  ms-attr-title="host.name" ms-text="host.name" ms-click="topologyTab.$showTopo(host.id, host.name)">
+                                <div class="smallCircle" ms-repeat-cp="host.cp" ms-attr-id="cp.id" ms-title="cp.name"
+                                     ms-click="topologyTab.$showTopo(cp.id,cp.name)"
+                                     ms-css-top="topologyTab.$getCpTop($index,host.id)">
+                                    <i class="gs-cp-icon fa fa-credit-card"></i>
                                 </div>
-                                <div class="holder">
-                                    <div class="nest" ms-if="host.vnfdid" ms-click="topologyTab.$showVnfTopo(host.vnfdid)"
-                                         ms-attr-title="topologyTab.vnfTip"><!-- only display nested ns template  -->
-                                        <div class="plus">
-                                            <i class="fa fa-plus" style="color: #3aaeda;"></i>
-                                        </div>
+                            </div>
+                            <div class="head" ms-hover="boxHover" tooltip ms-attr-title="host.name" ms-text="host.name"
+                                 ms-click="topologyTab.$showTopo(host.id, host.name)">
+                            </div>
+                            <div class="holder">
+                                <div class="nest" ms-if="host.vnfdid" ms-click="topologyTab.$showVnfTopo(host.vnfdid)"
+                                     ms-attr-title="topologyTab.vnfTip"><!-- only display nested ns template  -->
+                                    <div class="plus">
+                                        <i class="fa fa-plus" style="color: #3aaeda;"></i>
                                     </div>
-                                    <div ms-each-box="host.children" ><!-- ngRepeat: node in map track by node.name -->
-                                        <div>
-                                            <div class="box" ms-attr-id="box.id">
-                                                <div class="piProgress" size="55">
-                                                    <div class="circle">
-                                                        <i class="gs-node-icon fa fa-cogs"></i>
-                                                        <div ms-if="topologyTab.isShowNum" ms-text="box.num" class="badge">1</div>
-                                                    </div>
-                                                    <div class="smallCircle" ms-repeat-cp="box.cp" ms-attr-id="cp.id" ms-title="cp.name" ms-click="topologyTab.$showTopo(cp.id,cp.name)" ms-css-top="topologyTab.$getCpTop($index,box.id)">
-                                                        <i class="gs-cp-icon fa fa-credit-card" ></i>
+                                </div>
+                                <div ms-each-box="host.children"><!-- ngRepeat: node in map track by node.name -->
+                                    <div>
+                                        <div class="box" ms-attr-id="box.id">
+                                            <div class="piProgress" size="55">
+                                                <div class="circle">
+                                                    <i class="gs-node-icon fa fa-cogs"></i>
+                                                    <div ms-if="topologyTab.isShowNum" ms-text="box.num" class="badge">
+                                                        1
                                                     </div>
                                                 </div>
-                                                <div class="head"  ms-hover="boxHover"
-                                                     tooltip="" ms-click="topologyTab.$showTopo(box.id, box.name)" ms-attr-title="box.name" ms-text="box.name"></div>
-                                                <div class="holder" >
-                                                    <div ms-each-app="box.children">
-                                                        <!-- ngRepeat: node in map track by node.name -->
-                                                        <div>
-                                                            <div  class="app" ms-attr-id="app.id"  ms-click="topologyTab.$showTopo(app.id, app.name)" ms-hover="appHover">
-                                                                <div class="piProgress" size="55">
-                                                                    <div class="circle" >
-                                                                        <i class="gs-node-icon fa fa-cog" ></i>
-                                                                        <div ms-if="topologyTab.isShowNum" ms-text="app.num" class="badge">1</div>
+                                                <div class="smallCircle" ms-repeat-cp="box.cp" ms-attr-id="cp.id"
+                                                     ms-title="cp.name" ms-click="topologyTab.$showTopo(cp.id,cp.name)"
+                                                     ms-css-top="topologyTab.$getCpTop($index,box.id)">
+                                                    <i class="gs-cp-icon fa fa-credit-card"></i>
+                                                </div>
+                                            </div>
+                                            <div class="head" ms-hover="boxHover"
+                                                 tooltip="" ms-click="topologyTab.$showTopo(box.id, box.name)"
+                                                 ms-attr-title="box.name" ms-text="box.name"></div>
+                                            <div class="holder">
+                                                <div ms-each-app="box.children">
+                                                    <!-- ngRepeat: node in map track by node.name -->
+                                                    <div>
+                                                        <div class="app" ms-attr-id="app.id"
+                                                             ms-click="topologyTab.$showTopo(app.id, app.name)"
+                                                             ms-hover="appHover">
+                                                            <div class="piProgress" size="55">
+                                                                <div class="circle">
+                                                                    <i class="gs-node-icon fa fa-cog"></i>
+                                                                    <div ms-if="topologyTab.isShowNum" ms-text="app.num"
+                                                                         class="badge">1
                                                                     </div>
                                                                 </div>
-                                                                <p tooltip="" ms-attr-id="app.id" ms-attr-title="app.name" ms-text="app.name"></p>
                                                             </div>
+                                                            <p tooltip="" ms-attr-id="app.id" ms-attr-title="app.name"
+                                                               ms-text="app.name"></p>
                                                         </div>
-                                                        <!-- end ngRepeat: node in map track by node.name -->
                                                     </div>
-                                                </div><!-- end ngIf: node.isApp == false -->
-                                            </div><!-- end ngRepeat: node in map track by node.name -->
-                                        </div>
+                                                    <!-- end ngRepeat: node in map track by node.name -->
+                                                </div>
+                                            </div><!-- end ngIf: node.isApp == false -->
+                                        </div><!-- end ngRepeat: node in map track by node.name -->
                                     </div>
                                 </div>
                             </div>
                     </div>
                 </div>
             </div>
-            <div>
-                <div class="coordinates">
-                    <svg id="svg_vl" width="100%" height="100%" fill="silver">
-                        <g transform="translate(0, 0)" >
-                        </g>
-                    </svg>
-                </div>
-                <div class="coordinates" style="z-index:3;">
-                    <svg id="svg_vdu" width="100%" height="100%" fill="silver">
-                        <g transform="translate(0, 0)" >
-                        </g>
-                        <defs>
-                            <marker id="arrowhead" viewBox="0 0 20 20" refX="16" refY="10" markerUnits="userSpaceOnUse" markerWidth="16" markerHeight="12" orient="auto" fill="#7A7A7A">
-                                <path d="M 0 0 L 20 10 L 0 20 z"></path>
-                            </marker>
-                        </defs>
-                    </svg>
-                </div>
+        </div>
+        <div>
+            <div class="coordinates">
+                <svg id="svg_vl" width="100%" height="100%" fill="silver">
+                    <g transform="translate(0, 0)">
+                    </g>
+                </svg>
+            </div>
+            <div class="coordinates" style="z-index:3;">
+                <svg id="svg_vdu" width="100%" height="100%" fill="silver">
+                    <g transform="translate(0, 0)">
+                    </g>
+                    <defs>
+                        <marker id="arrowhead" viewBox="0 0 20 20" refX="16" refY="10" markerUnits="userSpaceOnUse"
+                                markerWidth="16" markerHeight="12" orient="auto" fill="#7A7A7A">
+                            <path d="M 0 0 L 20 10 L 0 20 z"></path>
+                        </marker>
+                    </defs>
+                </svg>
             </div>
         </div>
+    </div>
 
-        <div id="right-menu" class="ms-nodedetail" ms-css-display="nodesDetail.isShow">
+    <div id="right-menu" class="ms-nodedetail" ms-css-display="nodesDetail.isShow">
+        <div>
+            <div class="title"><h4>{{nodesDetail.detailTitle}}</h4>
+                <div class="rigth right-button-pointer" ms-click="nodesDetail.$showDetails('none')">
+                    <button type="button" class="btn btn-default">
+                        <span id="nfv-templateDetail-nodesTab-iui-btn-close" name_i18n="com_zte_nfv_nsoc_i18n"></span>
+                    </button>
+                </div>
+            </div>
             <div>
-                <div class="title"><h4>{{nodesDetail.detailTitle}}</h4>
-                    <div class="rigth right-button-pointer" ms-click="nodesDetail.$showDetails('none')">
-                        <button type="button" class="btn btn-default">
-                            <span id="nfv-templateDetail-nodesTab-iui-btn-close" name_i18n="com_zte_nfv_nsoc_i18n"></span>
-                        </button>
-                    </div>
+                <div class="btn-group">
+                    <button type="button" class="btn btn-default" ms-repeat="nodesDetail.detailData"
+                            ms-click="nodesDetail.detailCondChange($index)" ms-attr-id="el.id"
+                            ms-class="active: el.isActive">{{el.name}}
+                    </button>
                 </div>
-                <div>
-                    <div class="btn-group" >
-                        <button type="button" class="btn btn-default" ms-repeat="nodesDetail.detailData" ms-click="nodesDetail.detailCondChange($index)" ms-attr-id="el.id"
-                                ms-class="active: el.isActive">{{el.name}}
-                        </button>
+                <div ms-if="nodesDetail.detailIndex === 0">
+                    <div class="row-fluid" data-name="table_zone">
+                        <div id='ict_table_general_div' class="nodesDetail"></div>
                     </div>
-                    <div ms-if="nodesDetail.detailIndex === 0">
-                        <div class="row-fluid" data-name="table_zone">
-                            <div id='ict_table_general_div' class="nodesDetail"></div>
-                        </div>
-                    </div>
-                    <div ms-if="nodesDetail.detailIndex === 1">
-                        <div class="row-fluid" data-name="table_zone">
-                            <div id='ict_table_properties_div' class="nodesDetail"></div>
-                        </div>
+                </div>
+                <div ms-if="nodesDetail.detailIndex === 1">
+                    <div class="row-fluid" data-name="table_zone">
+                        <div id='ict_table_properties_div' class="nodesDetail"></div>
                     </div>
-                    <div ms-if="nodesDetail.detailIndex === 2">
-                        <div class="row-fluid" data-name="table_zone">
-                            <div id='ict_table_relationShips_div' class="nodesDetail"></div>
-                        </div>
+                </div>
+                <div ms-if="nodesDetail.detailIndex === 2">
+                    <div class="row-fluid" data-name="table_zone">
+                        <div id='ict_table_relationShips_div' class="nodesDetail"></div>
                     </div>
                 </div>
             </div>
         </div>
+    </div>
 
-        <script type="text/javascript" src="../common/thirdparty/jquery/jquery-1.10.2.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/bootstrap/js/bootstrap.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/jquery.i18n/jquery.i18n.properties-1.0.9.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/jquery/jquery-1.10.2.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/bootstrap/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/data-tables/jquery.dataTables.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/jquery.i18n/jquery.i18n.properties-1.0.9.js"></script>
 
-        <script type="text/javascript" src="../common/thirdparty/bootstrap-growl/bootstrap-growl.min.js"></script>
-        <script type="text/javascript" src="../common/thirdparty/avalon/avalon.modern.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/bootstrap-growl/bootstrap-growl.min.js"></script>
+    <script type="text/javascript" src="../common/thirdparty/avalon/avalon.modern.js"></script>
 
-        <script type="text/javascript" src="../common/js/tools.js"></script>
+    <script type="text/javascript" src="../common/js/tools.js"></script>
 
-        <script type="text/javascript" src="../catalog/js/component/commonUtil.js"></script>
-        <script type="text/javascript" src="../catalog/js/component/serverPageTable.js"></script>
-        <script type="text/javascript" src="../catalog/js/component/loadi18n_nsoc.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/commonUtil.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/serverPageTable.js"></script>
+    <script type="text/javascript" src="../catalog/js/component/loadi18n_nsoc.js"></script>
 
-        <script type="text/javascript" src="../js/template/tmDetailUtil.js"></script>
-        <script type="text/javascript" src="../js/template/tmUtil.js"></script>
-        <script type="text/javascript" src="js/tmTopoController.js"></script>
-        <script type="text/javascript" src="../js/template/topoUtil.js"></script>
-    </div>
+    <script type="text/javascript" src="../js/template/tmDetailUtil.js"></script>
+    <script type="text/javascript" src="../js/template/tmUtil.js"></script>
+    <script type="text/javascript" src="js/tmTopoController.js"></script>
+    <script type="text/javascript" src="../js/template/topoUtil.js"></script>
+</div>
 </body>
 </html>
\ No newline at end of file
index 1a7355c..7de57fc 100644 (file)
 <!DOCTYPE html>\r
 <html>\r
 <head>\r
-       <head lang="en">\r
-       <meta charset="UTF-8">\r
-       <title></title>\r
-       <link href="css/bootstrap.min.css" rel="stylesheet" />\r
-       <link href="css/VMMain.css" rel="stylesheet" />\r
-       <link href="css/bootstrap-table.min.css" rel="stylesheet" />\r
-       <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
-    <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
-    <script type="text/javascript" src="js/brs.js"></script>   \r
-    <script type="text/javascript" src="js/underlay.js"></script>\r
-    <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
-       <style type="text/css">\r
-       </style>\r
-       <script type="text/javascript">\r
-       $(document).ready(function() {\r
-               var jsondata = [];\r
-               jsondata = loadOverlayData();\r
+    <head lang="en">\r
+        <meta charset="UTF-8">\r
+        <title></title>\r
+        <link href="css/bootstrap.min.css" rel="stylesheet"/>\r
+        <link href="css/VMMain.css" rel="stylesheet"/>\r
+        <link href="css/bootstrap-table.min.css" rel="stylesheet"/>\r
+        <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
+        <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
+        <script type="text/javascript" src="js/brs.js"></script>\r
+        <script type="text/javascript" src="js/underlay.js"></script>\r
+        <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
+        <style type="text/css">\r
+        </style>\r
+        <script type="text/javascript">\r
+            $(document).ready(function () {\r
+                var jsondata = [];\r
+                jsondata = loadOverlayData();\r
 \r
-                       $('#sai').bootstrapTable({\r
-                       //Assigning data to table\r
-                               data: jsondata\r
-                       });\r
-               \r
-    });\r
-       function operateFormatter(value, row, index) {\r
-        return [\r
-            '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
-        ].join('');\r
-        \r
-    }\r
-        window.operateEvents = {\r
-         'click .siteDeleteImg': function (e, value, row, index) {\r
-             // TO DO ajex call for delete\r
-             console.log(value, row, index);\r
-         }\r
-     };\r
-       </script>\r
-</head>\r
+                $('#sai').bootstrapTable({\r
+                    //Assigning data to table\r
+                    data: jsondata\r
+                });\r
+\r
+            });\r
+            function operateFormatter(value, row, index) {\r
+                return [\r
+                    '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
+                ].join('');\r
+\r
+            }\r
+            window.operateEvents = {\r
+                'click .siteDeleteImg': function (e, value, row, index) {\r
+                    // TO DO ajex call for delete\r
+                    console.log(value, row, index);\r
+                }\r
+            };\r
+        </script>\r
+    </head>\r
 <body id="open_base_vpn_cotentBody" class="cotentBody ng-scope">\r
-       <div class="container-fluid ms-controller">\r
-               \r
-       <h3>    Overlay VPN     </h3>\r
-               <div class="row-fluid" data-name="table_zone">\r
-                       <div id='ict_virtualApplication_table_div'>\r
-                <div>\r
-                    <div class="top">\r
-                        <table id="sai" data-pagination="true" data-page-size="5" data-pagination-first-text="First" data-pagination-pre-text="Previous" data-pagination-next-text="Next" data-pagination-last-text="Last">\r
-                            <thead id="soverlayTable_thead" class="openo-table-thead">\r
-                                                               <tr class="active">\r
-                                                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayName" data-sortable="true">\r
-                                                                               <div class="openo-table-th-border"></div>\r
-                                                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                                                       <span id="overlayName_sorticon" class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element">Name\r
+<div class="container-fluid ms-controller">\r
+\r
+    <h3> Overlay VPN </h3>\r
+    <div class="row-fluid" data-name="table_zone">\r
+        <div id='ict_virtualApplication_table_div'>\r
+            <div>\r
+                <div class="top">\r
+                    <table id="sai" data-pagination="true" data-page-size="5" data-pagination-first-text="First"\r
+                           data-pagination-pre-text="Previous" data-pagination-next-text="Next"\r
+                           data-pagination-last-text="Last">\r
+                        <thead id="soverlayTable_thead" class="openo-table-thead">\r
+                        <tr class="active">\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                                                       <span id="overlayName_sorticon"\r
+                                                  class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element">Name\r
                     </span>\r
-                                       </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayDesc" data-sortable="true">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="overlayDesc_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element "> Description\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayThincCPE" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayThincCPE_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Thin CPE\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayPortVlanID" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayPortVlanID_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Port:Vlan ID\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayDCName" data-sortable="true">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="overlayDCName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">DC Name\r
-                    </span></div></th>                 \r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayVPC" data-sortable="true">\r
-                                          <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                             <span id="overlayVPC_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VPC\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayDesc" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                       <span id="overlayDesc_sorticon"\r
+                                  class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element "> Description\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayThincCPE" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="overlayThincCPE_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Thin CPE\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayPortVlanID" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="overlayPortVlanID_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Port:Vlan ID\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayDCName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="overlayDCName_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">DC Name\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayVPC" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                             <span id="overlayVPC_sorticon"\r
+                                class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VPC\r
                           </span>\r
-                                          </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayVPCCIDR" data-sortable="true">\r
-                                          <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                             <span id="overlayVPCCIDR_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VPC CIDR\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayVPCCIDR" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                             <span id="overlayVPCCIDR_sorticon"\r
+                                class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VPC CIDR\r
                           </span>\r
-                                          </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="overlayOperation"  align="center" data-formatter = "operateFormatter" data-events="operateEvents">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="portAction_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action</span>\r
-                                               </div>\r
-                                       </th>                                   \r
-                               </tr></thead>\r
-                                                       <!-- <tbody>\r
-                                                               <tr style="display: none;">\r
-                                                                       <td colspan="7" style="text-align: center;">NULL</td>\r
-                                                               </tr>\r
-                                                               <tr class="odd  openo-table-tr openo-table-disable-element" data-rowid="0" data-tableid="overlayTable">\r
-                                                                       <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayName" data-tableid="overlayTable">\r
-                                                                               <div class="openo-table-disable-element overflow_elip leftDataAlign">\r
-                                                                                       <a class="openo-table-disable-element hyperLinkRow" href="javascript:void(0)" id="overlayTable_0_overlayName_link">overlay1</a></div></td>\r
-                                                                       <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayDesc" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayDesc_custom_el">overlay 101</div>\r
-                                    </td>\r
-                                    <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayThincCPE" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayThincCPE_custom_el">chaxuanyue</div>\r
-                                    </td>\r
-                                    <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayPortVlanID" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayPortVlanID_custom_el">Bangalore</div>\r
-                                    </td>\r
-                                                                   <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayDCName" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayDCName_custom_el">Bangalore</div>\r
-                                    </td>\r
-                                                                   <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayVPC" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayVPC_custom_el">Bangalore</div>\r
-                                    </td>\r
-                                                                   <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayVPCCIDR" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayVPCCIDR_custom_el">Bangalore</div>\r
-                                    </td>\r
-                                    <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayOperation" data-tableid="overlayTable">\r
-                                        <div class="openo-table-disable-element overflow_elip leftDataAlign openo-table-custom-el" id="overlayTable_0_overlayOperation_custom_el">\r
-                                                                                   <div>\r
-                                                                                           <img src="images/delete.png" href="javascript:void(0)" onclick="deleteoverlay('this')" opertype="overlayDelete" style="cursor: pointer" title="Delete" id="bac4ff3c-d693-4f54-86cd-25af1ea22f59" rowid="0/">\r
-                                                                                       </div>\r
-                                                                               </div>\r
-                                                                       </td>\r
-                                                               </tr>\r
-                                                       </tbody> -->\r
-                        </table>\r
-                    </div>\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="overlayOperation" align="center" data-formatter="operateFormatter"\r
+                                data-events="operateEvents">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                    <span id="portAction_sorticon"\r
+                                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action</span>\r
+                                </div>\r
+                            </th>\r
+                        </tr>\r
+                        </thead>\r
+                        <!-- <tbody>\r
+                            <tr style="display: none;">\r
+                                <td colspan="7" style="text-align: center;">NULL</td>\r
+                            </tr>\r
+                            <tr class="odd  openo-table-tr openo-table-disable-element" data-rowid="0" data-tableid="overlayTable">\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayName" data-tableid="overlayTable">\r
+                                    <div class="openo-table-disable-element overflow_elip leftDataAlign">\r
+                                        <a class="openo-table-disable-element hyperLinkRow" href="javascript:void(0)" id="overlayTable_0_overlayName_link">overlay1</a></div></td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayDesc" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayDesc_custom_el">overlay 101</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayThincCPE" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayThincCPE_custom_el">chaxuanyue</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayPortVlanID" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayPortVlanID_custom_el">Bangalore</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayDCName" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayDCName_custom_el">Bangalore</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayVPC" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayVPC_custom_el">Bangalore</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayVPCCIDR" data-tableid="overlayTable"><div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="overlayTable_0_overlayVPCCIDR_custom_el">Bangalore</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="overlayOperation" data-tableid="overlayTable">\r
+                                    <div class="openo-table-disable-element overflow_elip leftDataAlign openo-table-custom-el" id="overlayTable_0_overlayOperation_custom_el">\r
+                                        <div>\r
+                                            <img src="images/delete.png" href="javascript:void(0)" onclick="deleteoverlay('this')" opertype="overlayDelete" style="cursor: pointer" title="Delete" id="bac4ff3c-d693-4f54-86cd-25af1ea22f59" rowid="0/">\r
+                                        </div>\r
+                                    </div>\r
+                                </td>\r
+                            </tr>\r
+                        </tbody> -->\r
+                    </table>\r
                 </div>\r
             </div>\r
-               </div>\r
-               \r
-               \r
-       \r
+        </div>\r
+    </div>\r
+\r
 \r
 </body>\r
 </html>
\ No newline at end of file
index ddd8eaa..5b4bcd1 100644 (file)
 <!DOCTYPE html>\r
 <html>\r
 <head>\r
-<style type="text/css">\r
-  #container {\r
-      top: 0;\r
-      bottom: 0;\r
-      left: 0;\r
-      right: 0;\r
-      position: absolute;\r
-  }\r
-</style>\r
+    <style type="text/css">\r
+        #container {\r
+            top: 0;\r
+            bottom: 0;\r
+            left: 0;\r
+            right: 0;\r
+            position: absolute;\r
+        }\r
+    </style>\r
 </head>\r
 <body>\r
 <div id="container"></div>\r
index 75d41cc..c4d5067 100644 (file)
 <!doctype html>\r
 <html>\r
 <head>\r
-<meta charset="utf-8">\r
-<title></title>\r
-       <link href="css/bootstrap.min.css" rel="stylesheet" />\r
-       <link href="css/RMain.css" rel="stylesheet" />\r
+    <meta charset="utf-8">\r
+    <title></title>\r
+    <link href="css/bootstrap.min.css" rel="stylesheet"/>\r
+    <link href="css/RMain.css" rel="stylesheet"/>\r
     <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
     <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
 </head>\r
 <script type="text/javascript">\r
-    $(function(){\r
-        $('.openo_accordion_ui-icon-expand,.header').click(function(){\r
+    $(function () {\r
+        $('.openo_accordion_ui-icon-expand,.header').click(function () {\r
             $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL').slideToggle(500);\r
             $('.openo_accordion_ui-icon-expand').toggleClass('current')\r
         });\r
-        $('.openoAccordian_showHideArrow_hide').click(function(){\r
+        $('.openoAccordian_showHideArrow_hide').click(function () {\r
             // $('#open_base_openo').css('margin-left','-200px');\r
             // $('#open_base_openo').css('display','none');\r
             // $('.bar').css('display','block');\r
-            if($('#accordionmenuid').width() >= 200){\r
+            if ($('#accordionmenuid').width() >= 200) {\r
                 $('#accordionmenuid').width('18px');\r
-                $('.openo_accordion_ui-icon-expand,.header,#accordionmenuid_ul_0_0_brAppTopMenuID_UL li a').css('display','none');\r
-                $('#accordionmenuid_arrow').attr('classname','openoAccordian_showHideArrow_show');\r
-                $('#iframeContainer').css('width','1284px');                \r
-            }else if($('#accordionmenuid').width() == 18){\r
+                $('.openo_accordion_ui-icon-expand,.header,#accordionmenuid_ul_0_0_brAppTopMenuID_UL li a').css('display', 'none');\r
+                $('#accordionmenuid_arrow').attr('classname', 'openoAccordian_showHideArrow_show');\r
+                $('#iframeContainer').css('width', '1284px');\r
+            } else if ($('#accordionmenuid').width() == 18) {\r
                 $('#accordionmenuid').width('220px');\r
-                $('.openo_accordion_ui-icon-expand,.header,#accordionmenuid_ul_0_0_brAppTopMenuID_UL li a').css('display','block');\r
-                $('#accordionmenuid_arrow').attr('classname','openoAccordian_showHideArrow_hide');\r
-                $('#iframeContainer').css('width','1063px');\r
+                $('.openo_accordion_ui-icon-expand,.header,#accordionmenuid_ul_0_0_brAppTopMenuID_UL li a').css('display', 'block');\r
+                $('#accordionmenuid_arrow').attr('classname', 'openoAccordian_showHideArrow_hide');\r
+                $('#iframeContainer').css('width', '1063px');\r
             }\r
-            \r
+\r
         });\r
-        $('.bar span').click(function(){\r
-            $('#open_base_openo').css('display','block');\r
-            $('.bar').css('display','none');\r
-             $('#iframeContainer').css('width','1063px');\r
+        $('.bar span').click(function () {\r
+            $('#open_base_openo').css('display', 'block');\r
+            $('.bar').css('display', 'none');\r
+            $('#iframeContainer').css('width', '1063px');\r
         });\r
-        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL li').click(function(){\r
+        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL li').click(function () {\r
             $(this).addClass('openo_accordion_selected').siblings().removeClass('openo_accordion_selected');\r
         });\r
-        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_0_brAppSiteMenuID').click(function(){\r
-            $('#accordionContent').attr('src','overlayvpn.html');\r
+        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_0_brAppSiteMenuID').click(function () {\r
+            $('#accordionContent').attr('src', 'overlayvpn.html');\r
         });\r
-        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_1_brAppMeMenuID').click(function(){\r
-            $('#accordionContent').attr('src','underlayvpn.html');\r
+        $('#accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_1_brAppMeMenuID').click(function () {\r
+            $('#accordionContent').attr('src', 'underlayvpn.html');\r
         });\r
     })\r
 </script>\r
 <body>\r
-    <div id="febDiv" style="overflow: hidden;">\r
+<div id="febDiv" style="overflow: hidden;">\r
     <div id="open_base_feb">\r
         <!--use for store menu come from feb service, maybe just a temple plan-->\r
         <div id="app">\r
                             <span></span>\r
                         </td>\r
                         <td id="open_base_openo" class="three-cols-column three-cols-left">\r
-                            <div id="accordionmenuid" allow-resize="true" dataset="dataArr" height="resHeight" listeners="callBacklisteners" resize-callback="resizehandler" current-select="currentselect" click="clickHandler" class="ng-isolate-scope accordion_parent openo_accordion_main_menu" style="height: 870px;">\r
+                            <div id="accordionmenuid" allow-resize="true" dataset="dataArr" height="resHeight"\r
+                                 listeners="callBacklisteners" resize-callback="resizehandler"\r
+                                 current-select="currentselect" click="clickHandler"\r
+                                 class="ng-isolate-scope accordion_parent openo_accordion_main_menu"\r
+                                 style="height: 870px;">\r
                                 <div class="openo-accordion-resizable-handle" style="cursor: auto;"></div>\r
                                 <ul id="accordionmenuid_ul" class="openoAccordian_accordionmenu">\r
                                     <li id="accordionmenuid_ul_0_0_brAppTopMenuID" nodeid="brAppTopMenuID">\r
-                                        <span class="openo_accordion_ui-icon-expand" style="padding-left: 20px; height: 60px;cursor: pointer;"></span>\r
-                                        <span class="openoAccordian_showHideArrow_hide" id="accordionmenuid_arrow" style="cursor: pointer;"></span>\r
-                                        <a title="brApp" class="header opened" style="padding-left: 10px; cursor: pointer;">VPN Manager</a>\r
+                                        <span class="openo_accordion_ui-icon-expand"\r
+                                              style="padding-left: 20px; height: 60px;cursor: pointer;"></span>\r
+                                        <span class="openoAccordian_showHideArrow_hide" id="accordionmenuid_arrow"\r
+                                              style="cursor: pointer;"></span>\r
+                                        <a title="brApp" class="header opened"\r
+                                           style="padding-left: 10px; cursor: pointer;">VPN Manager</a>\r
                                         <ul id="accordionmenuid_ul_0_0_brAppTopMenuID_UL">\r
-                                            <li id="accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_0_brAppSiteMenuID" nodeid="brAppSiteMenuID" class="" style="display: list-item;">\r
+                                            <li id="accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_0_brAppSiteMenuID"\r
+                                                nodeid="brAppSiteMenuID" class="" style="display: list-item;">\r
                                                 <a title="点击访问站点" class="" style="padding-left: 62px;">Overlay VPN</a>\r
-                                                                                       </li>\r
-                                            <li id="accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_1_brAppMeMenuID" nodeid="brAppMeMenuID" style="display: list-item;">\r
+                                            </li>\r
+                                            <li id="accordionmenuid_ul_0_0_brAppTopMenuID_UL_1_1_brAppMeMenuID"\r
+                                                nodeid="brAppMeMenuID" style="display: list-item;">\r
                                                 <a title="点击访问网元" style="padding-left: 62px;">Underlay VPN</a>\r
                                             </li>\r
                                         </ul>\r
index bd4535c..6a6c34c 100644 (file)
 <!DOCTYPE html>\r
 <html>\r
 <head>\r
-       <head lang="en">\r
-       <meta charset="UTF-8">\r
-       <title></title>\r
-       <link href="css/bootstrap.min.css" rel="stylesheet" />\r
-       <link href="css/jquery.dataTables.min.css" rel="stylesheet" />\r
-       <link href="css/VMMain.css" rel="stylesheet" />\r
-       <link href="css/bootstrap-table.min.css" rel="stylesheet" />\r
-       <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
-       <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
-       <script type="text/javascript" src="js/brs.js"></script>\r
-    <script type="text/javascript" src="js/underlay.js"></script>\r
-    <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
-       <style type="text/css">\r
-       hr {\r
-  ##-moz-border-bottom-colors: none;\r
-  -moz-border-image: none;\r
-  -moz-border-left-colors: none;\r
-  -moz-border-right-colors: none;\r
-  -moz-border-top-colors: none;\r
-  ##border-color: #EEEEEE -moz-use-text-color #FFFFFF;\r
-  border-style: solid none;\r
-  border-width: 1px 0;\r
-  margin: 50px 0;\r
-}\r
-       </style>\r
-       <script type="text/javascript">\r
-       $(document).ready(function() {\r
\r
+    <head lang="en">\r
+        <meta charset="UTF-8">\r
+        <title></title>\r
+        <link href="css/bootstrap.min.css" rel="stylesheet"/>\r
+        <link href="css/jquery.dataTables.min.css" rel="stylesheet"/>\r
+        <link href="css/VMMain.css" rel="stylesheet"/>\r
+        <link href="css/bootstrap-table.min.css" rel="stylesheet"/>\r
+        <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>\r
+        <script type="text/javascript" src="js/bootstrap.min.js"></script>\r
+        <script type="text/javascript" src="js/brs.js"></script>\r
+        <script type="text/javascript" src="js/underlay.js"></script>\r
+        <script type="text/javascript" src="js/bootstrap-table.min.js"></script>\r
+        <style type="text/css">\r
+            hr {\r
+                # #-moz-border-bottom-colors: none;\r
+                -moz-border-image: none;\r
+                -moz-border-left-colors: none;\r
+                -moz-border-right-colors: none;\r
+                -moz-border-top-colors: none;\r
+                # #border-color: #EEEEEE -moz-use-text-color #FFFFFF;\r
+                border-style: solid none;\r
+                border-width: 1px 0;\r
+                margin: 50px 0;\r
+            }\r
+        </style>\r
+        <script type="text/javascript">\r
+            $(document).ready(function () {\r
 \r
-var jsondata =loadUnderlayData();\r
-               $('#tbl_overlay').bootstrapTable({\r
-               //Assigning data to table\r
-                       data: jsondata\r
-               });\r
-               $('#underlayTpDataTable').bootstrapTable({\r
-                       //Assigning data to table\r
-                               data: {}\r
-                       });\r
-    });\r
-       function operateFormatter(value, row, index) {\r
-        return [\r
-            '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
-        ].join('');\r
-        \r
-    }\r
-        window.operateEvents = {\r
-         'click .siteDeleteImg': function (e, value, row, index) {\r
-             // TO DO ajex call for delete\r
-             console.log(value, row, index);\r
-         }\r
-     };\r
 \r
-        \r
-        function nameFormatter(value, row) {\r
-               jsonForTP = row.json.data;\r
-               var name=JSON.stringify(row.json.data);\r
-               var temp = "<a class='underlayNameLink' onclick='getMethod(this)' name='"+ name + "' data-events='operateEventsU'>" + value + "</a>";\r
-        return temp;\r
-    }\r
-        function getMethod(obj){\r
-                //Update the lower table here\r
-                \r
-                $('#underlayTpDataTable').bootstrapTable(\r
-                       //Assigning data to table\r
-                               "append", JSON.parse(obj.name)\r
-                       );\r
-        }\r
-       </script>\r
-</head>\r
+                var jsondata = loadUnderlayData();\r
+                $('#tbl_overlay').bootstrapTable({\r
+                    //Assigning data to table\r
+                    data: jsondata\r
+                });\r
+                $('#underlayTpDataTable').bootstrapTable({\r
+                    //Assigning data to table\r
+                    data: {}\r
+                });\r
+            });\r
+            function operateFormatter(value, row, index) {\r
+                return [\r
+                    '<img class="siteDeleteImg" src="images/delete.png" href="javascript:void(0)" style="cursor: pointer" name="title" title="Delete" />'\r
+                ].join('');\r
+\r
+            }\r
+            window.operateEvents = {\r
+                'click .siteDeleteImg': function (e, value, row, index) {\r
+                    // TO DO ajex call for delete\r
+                    console.log(value, row, index);\r
+                }\r
+            };\r
+\r
+\r
+            function nameFormatter(value, row) {\r
+                jsonForTP = row.json.data;\r
+                var name = JSON.stringify(row.json.data);\r
+                var temp = "<a class='underlayNameLink' onclick='getMethod(this)' name='" + name + "' data-events='operateEventsU'>" + value + "</a>";\r
+                return temp;\r
+            }\r
+            function getMethod(obj) {\r
+                //Update the lower table here\r
+\r
+                $('#underlayTpDataTable').bootstrapTable(\r
+                        //Assigning data to table\r
+                        "append", JSON.parse(obj.name)\r
+                );\r
+            }\r
+        </script>\r
+    </head>\r
 <body id="open_base_vpn_cotentBody" class="cotentBody ng-scope">\r
-       <div class="container-fluid ms-controller">\r
-                               <h3>Underlay VPN</h3>\r
-               <div class="row-fluid" data-name="table_zone">\r
-                       <div id='ict_virtualApplication_table_div'>\r
-                <div>\r
-                    <div class="top">\r
-                        <table id="tbl_overlay" data-pagination="true" data-page-size="5" data-pagination-first-text="First" data-pagination-pre-text="Previous" data-pagination-next-text="Next" data-pagination-last-text="Last">\r
-                            <thead id="sunderlayTable_thead" class="openo-table-thead">\r
-                                                               <tr class="active">\r
-                                                               \r
-               \r
-                                                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-formatter="nameFormatter" data-field="underlayName" data-sortable="true">\r
-                                                                               <div class="openo-table-th-border"></div>\r
-                                                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                                                       <span id="underlayName_sorticon" class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element ">Name\r
+<div class="container-fluid ms-controller">\r
+    <h3>Underlay VPN</h3>\r
+    <div class="row-fluid" data-name="table_zone">\r
+        <div id='ict_virtualApplication_table_div'>\r
+            <div>\r
+                <div class="top">\r
+                    <table id="tbl_overlay" data-pagination="true" data-page-size="5" data-pagination-first-text="First"\r
+                           data-pagination-pre-text="Previous" data-pagination-next-text="Next"\r
+                           data-pagination-last-text="Last">\r
+                        <thead id="sunderlayTable_thead" class="openo-table-thead">\r
+                        <tr class="active">\r
+\r
+\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-formatter="nameFormatter" data-field="underlayName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                                                       <span id="underlayName_sorticon"\r
+                                                  class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element ">Name\r
                     </span>\r
-                                       </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName" data-sortable="true">\r
-                                           <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                   <span id="underlayTenantName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">State\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayTenantName" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                   <span id="underlayTenantName_sorticon"\r
+                                  class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">State\r
                             </span>\r
-                                               </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayType" data-sortable="true">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="underlayType_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element " >Description\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayDescription" align="center" data-formatter = "operateFormatter" data-events="operateEvents">\r
-                                          <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                             <span id="underlayDescription_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayType" data-sortable="true">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                       <span id="underlayType_sorticon"\r
+                                  class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Description\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayDescription" align="center" data-formatter="operateFormatter"\r
+                                data-events="operateEvents">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                             <span id="underlayDescription_sorticon"\r
+                                class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Action\r
                           </span>\r
-                                          </div>\r
-                                       </th>\r
-                                       <!-- <th style="display: none;" class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName">\r
-                           <div class="openo-table-th-border"></div>\r
-                                   <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="underlayObjId_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">ID\r
-                                </span>\r
-                           </div>\r
-                       </th>\r
-                                                                       <th style="display: none;" class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName">\r
-                                                           <div class="openo-table-th-border"></div>\r
-                                                                   <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                                       <span id="underlayObjData_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Data\r
-                                                </span>\r
-                                                                   </div>\r
-                                                       </th> -->\r
-                                       </tr>\r
-                                       </thead>\r
-                                                   <!-- <tbody>\r
-                                                               <tr style="display: none;">\r
-                                                                       <td colspan="7" style="text-align: center;">NULL</td>\r
-                                                               </tr>\r
-                                                               <tr class="odd  openo-table-tr openo-table-disable-element" data-rowid="0" data-tableid="underlayTable">\r
-                                                               \r
-                                                                       <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayName" data-tableid="underlayTable">\r
-                                                                               <div class="openo-table-disable-element overflow_elip leftDataAlign">\r
-                                                                                       <a class="underlayNameLink" href="javascript:void(0)" id="underlayTable_0_underlayName_link">underlay1</a>\r
-                                                                               </div>\r
-                                                                       </td>\r
-                                                                       <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
-                                                                           <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">underlay 101</div>\r
-                                    </td>\r
-                                    <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayTenantName" data-tableid="underlayTable">\r
-                                                                           <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayTenantName_custom_el">chaxuanyue</div>\r
-                                    </td>\r
-                                    <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayOperation" data-tableid="underlayTable">\r
-                                        <div class="openo-table-disable-element overflow_elip leftDataAlign openo-table-custom-el" id="underlayTable_0_underlayOperation_custom_el">\r
-                                                                                   <div>\r
-                                                                                           <img src="images/delete.png" href="javascript:void(0)" onclick="deleteUnderlayData('this')" opertype="underlayDelete" style="cursor: pointer" title="Delete" id="bac4ff3c-d693-4f54-86cd-25af1ea22f59" rowid="0/">\r
-                                                                                       </div>\r
-                                                                               </div>\r
-                                                                       </td>\r
-                                                                       <td style="display: none;" class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
-                                                                           <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">ID12345</div>\r
-                                    </td>\r
-                                                                       <td style="display: none;" class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
-                                                                           <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">[{"tpName":"tp345","peName":"pe123","vlanId":"12344","siteCidr":"tettd","ip":"1.1.1.1"},{"tpName":"tp345","peName":"8xzxze123","vlanId":"234","siteCidr":"tettd","ip":"10.10.1.10"}]</div>\r
-                                    </td>\r
-                                                               </tr>\r
-                                                       </tbody> -->\r
-                        </table>\r
-                    </div>\r
+                                </div>\r
+                            </th>\r
+                            <!-- <th style="display: none;" class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName">\r
+                                <div class="openo-table-th-border"></div>\r
+                                    <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                        <span id="underlayObjId_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">ID\r
+                                        </span>\r
+                                </div>\r
+                            </th>\r
+                                            <th style="display: none;" class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName">\r
+                                                <div class="openo-table-th-border"></div>\r
+                                                    <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                        <span id="underlayObjData_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Data\r
+                                                        </span>\r
+                                                    </div>\r
+                                            </th> -->\r
+                        </tr>\r
+                        </thead>\r
+                        <!-- <tbody>\r
+                            <tr style="display: none;">\r
+                                <td colspan="7" style="text-align: center;">NULL</td>\r
+                            </tr>\r
+                            <tr class="odd  openo-table-tr openo-table-disable-element" data-rowid="0" data-tableid="underlayTable">\r
+\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayName" data-tableid="underlayTable">\r
+                                    <div class="openo-table-disable-element overflow_elip leftDataAlign">\r
+                                        <a class="underlayNameLink" href="javascript:void(0)" id="underlayTable_0_underlayName_link">underlay1</a>\r
+                                    </div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
+                                    <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">underlay 101</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayTenantName" data-tableid="underlayTable">\r
+                                    <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayTenantName_custom_el">chaxuanyue</div>\r
+                                </td>\r
+                                <td class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayOperation" data-tableid="underlayTable">\r
+                                    <div class="openo-table-disable-element overflow_elip leftDataAlign openo-table-custom-el" id="underlayTable_0_underlayOperation_custom_el">\r
+                                        <div>\r
+                                            <img src="images/delete.png" href="javascript:void(0)" onclick="deleteUnderlayData('this')" opertype="underlayDelete" style="cursor: pointer" title="Delete" id="bac4ff3c-d693-4f54-86cd-25af1ea22f59" rowid="0/">\r
+                                        </div>\r
+                                    </div>\r
+                                </td>\r
+                                <td style="display: none;" class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
+                                    <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">ID12345</div>\r
+                                </td>\r
+                                <td style="display: none;" class="openo-table-disable-element openo-table-td overflow_elip leftDataAlign tableHeaderTDTopBorderColor" data-colid="underlayType" data-tableid="underlayTable">\r
+                                    <div class="overflow_elip leftDataAlign openo-table-custom-el openo-table-disable-element" id="underlayTable_0_underlayType_custom_el">[{"tpName":"tp345","peName":"pe123","vlanId":"12344","siteCidr":"tettd","ip":"1.1.1.1"},{"tpName":"tp345","peName":"8xzxze123","vlanId":"234","siteCidr":"tettd","ip":"10.10.1.10"}]</div>\r
+                                </td>\r
+                            </tr>\r
+                        </tbody> -->\r
+                    </table>\r
                 </div>\r
             </div>\r
-               </div>\r
-               <hr>\r
-               <h3>TP Details</h3>\r
-               <div class="row-fluid" data-name="table_zone">\r
-                       <div id='ict_virtualApplication_table_div'>\r
-                <div>\r
-                    <div class="top">\r
-                        <table id="underlayTpDataTable" data-pagination="true" data-page-size="5" data-pagination-first-text="First" data-pagination-pre-text="Previous" data-pagination-next-text="Next" data-pagination-last-text="Last">\r
-                            <thead id="underlayTable_thead" class="openo-table-thead">\r
-                                                               <tr class="active">\r
-                                                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayName">\r
-                                                                               <div class="openo-table-th-border"></div>\r
-                                                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                                                       <span id="underlayName_sorticon" class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element ">TP Name\r
+        </div>\r
+    </div>\r
+    <hr>\r
+    <h3>TP Details</h3>\r
+    <div class="row-fluid" data-name="table_zone">\r
+        <div id='ict_virtualApplication_table_div'>\r
+            <div>\r
+                <div class="top">\r
+                    <table id="underlayTpDataTable" data-pagination="true" data-page-size="5"\r
+                           data-pagination-first-text="First" data-pagination-pre-text="Previous"\r
+                           data-pagination-next-text="Next" data-pagination-last-text="Last">\r
+                        <thead id="underlayTable_thead" class="openo-table-thead">\r
+                        <tr class="active">\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayName">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                                                       <span id="underlayName_sorticon"\r
+                                                  class="openo-table-th-sorticon overflow_elip openoTable_sortable leftHeaderAlign  openo-table-disable-element ">TP Name\r
                     </span>\r
-                                       </div>\r
-                                       </th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayType">\r
-                                               <div class="openo-table-th-border"></div>\r
-                                               <div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                                       <span id="underlayType_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">PE Name\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantName">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="underlayTenantName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VLAN ID\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantunderlayName" >\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="underlayTenantunderlayName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Site CIDR\r
-                    </span></div></th>\r
-                                       <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign" data-field="underlayTenantunderlayIP">\r
-                                       <div class="openo-table-th-border"></div><div class="DataTables_sort_wrapper openo-ellipsis ">\r
-                                       <span id="underlayTenantunderlayName_sorticon" class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">IP\r
-                    </span></div></th>\r
-                                       </tr></thead>\r
-                                                       <!-- <tbody>\r
-                                                       </tbody> -->\r
-                        </table>\r
-                    </div>\r
+                                </div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayType">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                                       <span id="underlayType_sorticon"\r
+                                  class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">PE Name\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayTenantName">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="underlayTenantName_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">VLAN ID\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayTenantunderlayName">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="underlayTenantunderlayName_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">Site CIDR\r
+                    </span></div>\r
+                            </th>\r
+                            <th class="openo-table-state-default openo-table-th openo-table-disable-element  leftHeaderAlign"\r
+                                data-field="underlayTenantunderlayIP">\r
+                                <div class="openo-table-th-border"></div>\r
+                                <div class="DataTables_sort_wrapper openo-ellipsis ">\r
+                                       <span id="underlayTenantunderlayName_sorticon"\r
+                          class="openo-table-th-sorticon overflow_elip  leftHeaderAlign  openo-table-disable-element ">IP\r
+                    </span></div>\r
+                            </th>\r
+                        </tr>\r
+                        </thead>\r
+                        <!-- <tbody>\r
+                        </tbody> -->\r
+                    </table>\r
                 </div>\r
             </div>\r
-               </div>\r
-       </div>\r
-       <div id="filterTpLogicalType_select_popupcontainer" class="openo openo-select-popup-container openo-hide" style="width: 155px; max-height: 130px; left: 628px; top: 104px; z-index: 1761;"><div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_0"><label class="openo-ellipsis openo-select-blank-item" style="width: 100%; display: block; height: 20px;"></label></div><div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_1"><label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">ETH</label></div><div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_2"><label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;" title="POS">POS</label></div><div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_3"><label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Trunk</label></div><div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_4"><label class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Loopback</label></div></div>\r
+        </div>\r
+    </div>\r
+</div>\r
+<div id="filterTpLogicalType_select_popupcontainer" class="openo openo-select-popup-container openo-hide"\r
+     style="width: 155px; max-height: 130px; left: 628px; top: 104px; z-index: 1761;">\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_0"><label\r
+            class="openo-ellipsis openo-select-blank-item" style="width: 100%; display: block; height: 20px;"></label>\r
+    </div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_1"><label\r
+            class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">ETH</label></div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_2"><label\r
+            class="openo-ellipsis " style="width: 100%; display: block; height: 20px;" title="POS">POS</label></div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_3"><label\r
+            class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Trunk</label></div>\r
+    <div class="openo-select-item openo-ellipsis  " id="filterTpLogicalType_openo-select-id_4"><label\r
+            class="openo-ellipsis " style="width: 100%; display: block; height: 20px;">Loopback</label></div>\r
+</div>\r
 </body>\r
 </html>
\ No newline at end of file