Browse Source

updated docs partially

flowchartTest
Alex de Mulder 9 years ago
parent
commit
3fbab7cd9d
17 changed files with 12212 additions and 11897 deletions
  1. +11941
    -11819
      dist/vis.js
  2. +4
    -0
      docs/css/newdocs.css
  3. +15
    -0
      docs/js/googleAnalytics.js
  4. +16
    -16
      docs/network/canvas.html
  5. +9
    -7
      docs/network/clustering.html
  6. +70
    -16
      docs/network/configure.html
  7. +1
    -0
      docs/network/interaction.html
  8. +5
    -5
      examples/network/01_basic_usage.html
  9. +2
    -2
      lib/network/Network.js
  10. +1
    -0
      lib/network/modules/Canvas.js
  11. +36
    -8
      lib/network/modules/EdgesHandler.js
  12. +6
    -0
      lib/network/modules/InteractionHandler.js
  13. +47
    -13
      lib/network/modules/LayoutEngine.js
  14. +36
    -8
      lib/network/modules/ManipulationSystem.js
  15. +20
    -0
      lib/network/modules/NodesHandler.js
  16. +1
    -1
      lib/network/modules/View.js
  17. +2
    -2
      lib/network/modules/components/Node.js

+ 11941
- 11819
dist/vis.js
File diff suppressed because it is too large
View File


+ 4
- 0
docs/css/newdocs.css View File

@ -181,4 +181,8 @@ td.eventProperties {
td.methodName { td.methodName {
width:250px; width:250px;
}
pre.options {
max-width:500px;
} }

+ 15
- 0
docs/js/googleAnalytics.js View File

@ -0,0 +1,15 @@
/**
* Created by Alex on 4/23/2015.
*/
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o), m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-61231638-1', 'auto');
ga('send', 'pageview');

+ 16
- 16
docs/network/canvas.html View File

@ -1,19 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script>(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o), m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-61231638-1', 'auto');
ga('send', 'pageview');</script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -26,7 +13,9 @@
<link href="../css/bootstrap.css" rel="stylesheet"> <link href="../css/bootstrap.css" rel="stylesheet">
<link href="../css/newdocs.css" rel="stylesheet"> <link href="../css/newdocs.css" rel="stylesheet">
<link href="../css/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../js/googleAnalytics.js"></script>
<script type="text/javascript" src="../js/prettify/prettify.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
@ -42,7 +31,7 @@
</head> </head>
<!-- NAVBAR <!-- NAVBAR
================================================== --> ================================================== -->
<body>
<body onload="prettyPrint();">
<div class="navbar-wrapper"> <div class="navbar-wrapper">
<div class="container"> <div class="container">
@ -91,7 +80,18 @@
<h3>Options</h3> <h3>Options</h3>
<p>This is a list of all the methods in the public API. They are collected here from all individual modules.</p>
<p>The options for the canvas have to be contained in an object titled 'canvas'.</p>
<pre class="prettyprint lang-js options">
var options = {
canvas:{
width:'100%', // other format: '400px'
height:'100%'
}
}
network.setOptions(options);
</pre>
<p>All of the individual options are explained here:</p>
<table class="moduleTable"> <table class="moduleTable">
<tr class="header"> <tr class="header">
<td class="name">name</td> <td class="name">name</td>

+ 9
- 7
docs/network/clustering.html View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"><head><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-61231638-1', 'auto');ga('send', 'pageview');</script><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<html lang="en"><head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -12,7 +12,9 @@
<link href="../css/bootstrap.css" rel="stylesheet"> <link href="../css/bootstrap.css" rel="stylesheet">
<link href="../css/newdocs.css" rel="stylesheet"> <link href="../css/newdocs.css" rel="stylesheet">
<link href="../css/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../js/googleAnalytics.js"></script>
<script type="text/javascript" src="../js/prettify/prettify.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
@ -38,7 +40,7 @@
</head> </head>
<!-- NAVBAR <!-- NAVBAR
================================================== --> ================================================== -->
<body>
<body onload="prettyPrint();">
<div class="navbar-wrapper"> <div class="navbar-wrapper">
<div class="container"> <div class="container">
@ -96,11 +98,11 @@
<tr><td>openCluster(<br>&nbsp;&nbsp; <tr><td>openCluster(<br>&nbsp;&nbsp;
<code>String nodeId</code><br>)</td> <td class="mid">none</td> <td>Opens the cluster, releases the contained nodes and edges, removing the cluster node and cluster edges.</td></tr> <code>String nodeId</code><br>)</td> <td class="mid">none</td> <td>Opens the cluster, releases the contained nodes and edges, removing the cluster node and cluster edges.</td></tr>
<tr><td>cluster(<br>&nbsp;&nbsp; <tr><td>cluster(<br>&nbsp;&nbsp;
<code>Object options</code><br>)</td> <td class="mid">none</td> <td>The options object is explained in full <a href="#optionsObject">below</a>. The joinCondition function is presented with all nodes.</td></tr>
<code>Object options</code><br>)</td> <td class="mid">none</td> <td>The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>. The joinCondition function is presented with all nodes.</td></tr>
<tr><td>clusterByConnection(<br> <tr><td>clusterByConnection(<br>
&nbsp;&nbsp;<code>String nodeId</code>,<br> &nbsp;&nbsp;<code>String nodeId</code>,<br>
&nbsp;&nbsp;<code>[Object options]</code><br> &nbsp;&nbsp;<code>[Object options]</code><br>
)</td> <td class="mid">none</td> <td>This method looks at the provided node and makes a cluster of it and all it's connected nodes. The behaviour can be customized by proving the options object. All options of this object are explained <a href="#optionsObject">below</a>. The joinCondition is only presented with the connected nodes.</td></tr>
)</td> <td class="mid">none</td> <td>This method looks at the provided node and makes a cluster of it and all it's connected nodes. The behaviour can be customized by proving the options object. All options of this object are explained <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>. The joinCondition is only presented with the connected nodes.</td></tr>
<tr><td>clusterByHubsize(<br> <tr><td>clusterByHubsize(<br>
&nbsp;&nbsp;<code>Number hubsize</code>,<br> &nbsp;&nbsp;<code>Number hubsize</code>,<br>
&nbsp;&nbsp;<code>[Object options]</code><br>)</td><td class="mid">none</td> <td>This method checks all nodes in the network and those with a equal or higher amount of edges than specified with the <code>hubsize</code> qualify. Cluster by connection is performed on each of them. The options object is described for <code>clusterByConnection</code> and does the same here.</td></tr> &nbsp;&nbsp;<code>[Object options]</code><br>)</td><td class="mid">none</td> <td>This method checks all nodes in the network and those with a equal or higher amount of edges than specified with the <code>hubsize</code> qualify. Cluster by connection is performed on each of them. The options object is described for <code>clusterByConnection</code> and does the same here.</td></tr>
@ -117,7 +119,7 @@
<td><i>Optional for all but the cluster method. </i> The cluster module loops over all nodes that are selected to be in the cluster and calls this function with their data as argument. <td><i>Optional for all but the cluster method. </i> The cluster module loops over all nodes that are selected to be in the cluster and calls this function with their data as argument.
If this function returns true, this node will be added to the cluster. You have access to all options (including the default) If this function returns true, this node will be added to the cluster. You have access to all options (including the default)
as well as any custom fields you may have added to the node to determine whether or not to include it in the cluster. Example: as well as any custom fields you may have added to the node to determine whether or not to include it in the cluster. Example:
<pre class="code">
<pre class="prettyprint lang-js">
var nodes = [ var nodes = [
{id: 4, label: 'Node 4'}, {id: 4, label: 'Node 4'},
{id: 5, label: 'Node 5'}, {id: 5, label: 'Node 5'},
@ -135,7 +137,7 @@ network.clustering.cluster(options);
</pre></td></tr> </pre></td></tr>
<tr><td>processProperties(<br>&nbsp;&nbsp;<code>Object nodeOptions</code><br>)</td> <td class="mid">Function</td> <td><i>Optional. </i> Before creating the new cluster node, this (optional) function will be called with the properties supplied by you (<code>clusterNodeProperties</code>), all contained nodes and all contained edges. You can use this to update the <tr><td>processProperties(<br>&nbsp;&nbsp;<code>Object nodeOptions</code><br>)</td> <td class="mid">Function</td> <td><i>Optional. </i> Before creating the new cluster node, this (optional) function will be called with the properties supplied by you (<code>clusterNodeProperties</code>), all contained nodes and all contained edges. You can use this to update the
properties of the cluster based on which items it contains. The function should return the properties to create the cluster node. In the example below, we ensure preservation of mass and value when forming the cluster: properties of the cluster based on which items it contains. The function should return the properties to create the cluster node. In the example below, we ensure preservation of mass and value when forming the cluster:
<pre class="code">
<pre class="prettyprint lang-js">
var options = { var options = {
processProperties: function (clusterOptions, childNodes, childEdges) { processProperties: function (clusterOptions, childNodes, childEdges) {
var totalMass = 0; var totalMass = 0;

+ 70
- 16
docs/network/configure.html View File

@ -1,5 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"><head><script>(function(i,s,o,g,r,a,m){i[GoogleAnalyticsObject]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,script,//www.google-analytics.com/analytics.js,ga);ga(create, UA-61231638-1, auto);ga(send, pageview);</script><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -19,6 +22,9 @@
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]--> <![endif]-->
<link href="../css/prettify.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../js/googleAnalytics.js"></script>
<script type="text/javascript" src="../js/prettify/prettify.js"></script>
<script src="../js/smooth-scroll.min.js"></script> <script src="../js/smooth-scroll.min.js"></script>
<script language="JavaScript"> <script language="JavaScript">
@ -31,14 +37,15 @@
</head> </head>
<!-- NAVBAR <!-- NAVBAR
================================================== --> ================================================== -->
<body>
<body onload="prettyPrint();">
<div class="navbar-wrapper"> <div class="navbar-wrapper">
<div class="container"> <div class="container">
<nav class="navbar navbar-inverse navbar-static-top" role="navigation"> <nav class="navbar navbar-inverse navbar-static-top" role="navigation">
<div class="container"> <div class="container">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
@ -49,7 +56,9 @@
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="../index.html#modules">Modules</a></li> <li><a href="../index.html#modules">Modules</a></li>
<li class="active"><a href="./docs/index.html" target="_blank">Documentation <img class="icon" src="../img/external-link-icons/external-link-icon-white.png"></a></li>
<li class="active"><a href="./docs/index.html" target="_blank">Documentation <img class="icon"
src="../img/external-link-icons/external-link-icon-white.png"></a>
</li>
<li><a href="../blog.html">Blog</a></li> <li><a href="../blog.html">Blog</a></li>
<li><a href="../index.html#download_install">Download</a></li> <li><a href="../index.html#download_install">Download</a></li>
<li><a href="../showcase/index.html">Showcase</a></li> <li><a href="../showcase/index.html">Showcase</a></li>
@ -64,32 +73,77 @@
</div> </div>
</div> </div>
<a href="https://github.com/almende/vis" class="hidden-xs hidden-sm hidden-md"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
<a href="https://github.com/almende/vis" class="hidden-xs hidden-sm hidden-md"><img
style="position: absolute; top: 0; right: 0; border: 0;"
src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67"
alt="Fork me on GitHub"
data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>
<div class="container full"> <div class="container full">
<h1>Network - configure</h1> <h1>Network - configure</h1>
<p>Handles the HTML part of the canvas.</p> <p>Handles the HTML part of the canvas.</p>
<h3>Options</h3> <h3>Options</h3>
<p>Alternative to supplying an object, you can supply a <code>String</code>, <code>Array</code> or <code>Boolean</code>. These will do the same as the filter option described below.</p>
<p>The options for the canvas have to be contained in an object titled 'canvas'.</p>
<pre class="prettyprint lang-js options">
var options = {
configure:{
filter: 'nodes, physics', // or ['nodes','physics'] or true
container: document.getElementById("configDiv")
}
}
// alternative:
var options = {
configure: 'nodes, physics', // or ['nodes','physics'] or true
}
network.setOptions(options);
</pre>
<p>As shown above, alternative to supplying an object, you can supply a <code>String</code>, <code>Array</code> or
<code>Boolean</code>. These will do the same as the filter option described below.</p>
<table class="moduleTable"> <table class="moduleTable">
<tr class="header"><td class="nameSmall">name</td><td class="type">type</td><td class="default">default</td><td class="description">description</td></tr>
<tr><td>filter</td> <td class="mid">String or Array or Boolean</td> <td class="mid"><code>true</code></td><td>When a boolean, true gives you all options, false will not show any. If a string is supplied, any combination of the following is allowed: nodes, edges, layout, interaction, manipulation, physics, selection, renderer. Feel free to come up with a fun seperating character. Finally, when supplied an array of strings, any of the previously mentioned fields are accepted.</td></tr>
<tr><td>container</td> <td class="mid">DOM element</td> <td class="mid"><code>undefined</code></td><td>This allows you to put the configure list in another HTML container than below the network.</td></tr>
<tr class="header">
<td class="nameSmall">name</td>
<td class="type">type</td>
<td class="default">default</td>
<td class="description">description</td>
</tr>
<tr>
<td>filter</td>
<td class="mid">String or Array or Boolean</td>
<td class="mid"><code>true</code></td>
<td>When a boolean, true gives you all options, false will not show any. If a string is supplied, any
combination of the following is allowed: nodes, edges, layout, interaction, manipulation, physics,
selection, renderer. Feel free to come up with a fun seperating character. Finally, when supplied an
array of strings, any of the previously mentioned fields are accepted.
</td>
</tr>
<tr>
<td>container</td>
<td class="mid">DOM element</td>
<td class="mid"><code>undefined</code></td>
<td>This allows you to put the configure list in another HTML container than below the network.</td>
</tr>
</table> </table>
<h3>Methods</h3> <h3>Methods</h3>
<p>The configure module has no methods.</p> <p>The configure module has no methods.</p>
<h3>Events</h3> <h3>Events</h3>
<p>The configure module has no Events.</p> <p>The configure module has no Events.</p>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
</div> </div>
<!-- Bootstrap core JavaScript <!-- Bootstrap core JavaScript

+ 1
- 0
docs/network/interaction.html View File

@ -108,6 +108,7 @@
</pre> </pre>
</td><td>Fired when the user clicks the mouse or taps on a touchscreen device.</td></tr> </td><td>Fired when the user clicks the mouse or taps on a touchscreen device.</td></tr>
<tr><td>doubleClick</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the user double clicks the mouse or double taps on a touchscreen device. Since a double click is in fact 2 clicks, 2 click events are fired, followed by a double click event. If you do not want to use the click events if a double click event is fired, just check the time between click events before processing them.</td></tr> <tr><td>doubleClick</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the user double clicks the mouse or double taps on a touchscreen device. Since a double click is in fact 2 clicks, 2 click events are fired, followed by a double click event. If you do not want to use the click events if a double click event is fired, just check the time between click events before processing them.</td></tr>
<tr><td>rightClick</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the user click on the canvas with the right mouse button. The right mouse button does not select by default. You can use <a href="./selection.html">getNodeAt</a> to select the node if you want.</td></tr>
<tr><td>hold</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the user clicks and holds the mouse or taps and holds on a touchscreen device. A click event is also fired in this case.</td></tr> <tr><td>hold</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the user clicks and holds the mouse or taps and holds on a touchscreen device. A click event is also fired in this case.</td></tr>
<tr><td>release</td> <td class="mid">same as <code>click</code>.</td><td>Fired after drawing on the canvas has been completed. Can be used to draw on top of the network.</td></tr> <tr><td>release</td> <td class="mid">same as <code>click</code>.</td><td>Fired after drawing on the canvas has been completed. Can be used to draw on top of the network.</td></tr>
<tr><td>select</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the selection has changed by user action. This means a node or edge has been selected, added to the selection or deselected. <b>All select events are only triggerd on click and hold</b>.</td></tr> <tr><td>select</td> <td class="mid">same as <code>click</code>.</td><td>Fired when the selection has changed by user action. This means a node or edge has been selected, added to the selection or deselected. <b>All select events are only triggerd on click and hold</b>.</td></tr>

+ 5
- 5
examples/network/01_basic_usage.html View File

@ -28,13 +28,13 @@
]; ];
// create an array with edges // create an array with edges
var edges = [
{from: 1, to: 1, id:'e1'},
{from: 1, to: 3, dashes:{pattern:[10,15,2,5]}},
var edges = new vis.DataSet([
{from: 1, to: 1},
{from: 1, to: 3,id:'e1', dashes:{pattern:[10,15,2,5]}},
{from: 1, to: 2}, {from: 1, to: 2},
{from: 2, to: 4}, {from: 2, to: 4},
{from: 2, to: 5} {from: 2, to: 5}
];
]);
// create a network // create a network
var container = document.getElementById('mynetwork'); var container = document.getElementById('mynetwork');
@ -51,7 +51,7 @@
} }
var network = new vis.Network(container, data, options); var network = new vis.Network(container, data, options);
// network.setOptions({nodes:{color:'red'}}) // network.setOptions({nodes:{color:'red'}})
network.on("rightClick",function(e){console.log(e)})
</script> </script>
</body> </body>

+ 2
- 2
lib/network/Network.js View File

@ -80,7 +80,8 @@ function Network (container, data, options) {
onMouseWheel: function() {}, onMouseWheel: function() {},
onPinch: function() {}, onPinch: function() {},
onMouseMove: function() {}, onMouseMove: function() {},
onRelease: function() {}
onRelease: function() {},
onContext: function() {}
}, },
container: container, container: container,
view: { view: {
@ -134,7 +135,6 @@ Network.prototype.setOptions = function (options) {
// the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system. // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
options = this.layoutEngine.setOptions(options.layout, options); options = this.layoutEngine.setOptions(options.layout, options);
// pass the options to the modules // pass the options to the modules
this.groups.setOptions(options.groups); this.groups.setOptions(options.groups);
this.nodesHandler.setOptions(options.nodes); this.nodesHandler.setOptions(options.nodes);

+ 1
- 0
lib/network/modules/Canvas.js View File

@ -139,6 +139,7 @@ class Canvas {
this.frame.canvas.addEventListener('DOMMouseScroll', (event) => {this.body.eventListeners.onMouseWheel(event)}); this.frame.canvas.addEventListener('DOMMouseScroll', (event) => {this.body.eventListeners.onMouseWheel(event)});
this.frame.canvas.addEventListener('mousemove', (event) => {this.body.eventListeners.onMouseMove(event)}); this.frame.canvas.addEventListener('mousemove', (event) => {this.body.eventListeners.onMouseMove(event)});
this.frame.canvas.addEventListener('contextmenu', (event) => {this.body.eventListeners.onContext(event)});
this.hammerFrame = new Hammer(this.frame); this.hammerFrame = new Hammer(this.frame);
hammerUtil.onRelease(this.hammerFrame, (event) => {this.body.eventListeners.onRelease(event)}); hammerUtil.onRelease(this.hammerFrame, (event) => {this.body.eventListeners.onRelease(event)});

+ 36
- 8
lib/network/modules/EdgesHandler.js View File

@ -99,15 +99,24 @@ class EdgesHandler {
let emitChange = false; let emitChange = false;
for (let edgeId in this.body.edges) { for (let edgeId in this.body.edges) {
if (this.body.edges.hasOwnProperty(edgeId)) { if (this.body.edges.hasOwnProperty(edgeId)) {
let edgeOptions = this.body.edges[edgeId].options.smooth;
if (edgeOptions.enabled === true && edgeOptions.dynamic === true) {
if (type === undefined) {
edge.setOptions({smooth:false});
let edge = this.body.edges[edgeId];
let edgeData = this.body.data.edges._data[edgeId];
// only forcilby remove the smooth curve if the data has been set of the edge has the smooth curves defined.
// this is because a change in the global would not affect these curves.
if (edgeData !== undefined) {
let edgeOptions = edgeData.smooth;
if (edgeOptions !== undefined) {
if (edgeOptions.enabled === true && edgeOptions.dynamic === true) {
if (type === undefined) {
edge.setOptions({smooth: false});
}
else {
edge.setOptions({smooth: {dynamic: false, type: type}});
}
emitChange = true;
}
} }
else {
edge.setOptions({smooth:{dynamic:false, type:type}});
}
emitChange = true;
} }
} }
} }
@ -122,10 +131,15 @@ class EdgesHandler {
this.markAllEdgesAsDirty(); this.markAllEdgesAsDirty();
}); });
// refresh the edges. Used when reverting from hierarchical layout
this.body.emitter.on("refreshEdges", this.refresh.bind(this));
this.body.emitter.on("refresh", this.refresh.bind(this));
} }
setOptions(options) { setOptions(options) {
if (options !== undefined) { if (options !== undefined) {
console.log('edge',options)
// use the parser from the Edge class to fill in all shorthand notations // use the parser from the Edge class to fill in all shorthand notations
Edge.parseOptions(this.options, options); Edge.parseOptions(this.options, options);
@ -297,6 +311,20 @@ class EdgesHandler {
this.body.emitter.emit("_dataChanged"); this.body.emitter.emit("_dataChanged");
} }
refresh() {
let edges = this.body.edges;
for (let edgeId in edges) {
let edge = undefined;
if (edges.hasOwnProperty(edgeId)) {
edge = edges[edgeId];
}
let data = this.body.data.edges._data[edgeId];
if (edge !== undefined && data !== undefined) {
edge.setOptions(data);
}
}
}
create(properties) { create(properties) {
return new Edge(properties, this.body, this.options) return new Edge(properties, this.body, this.options)
} }

+ 6
- 0
lib/network/modules/InteractionHandler.js View File

@ -22,6 +22,7 @@ class InteractionHandler {
this.body.eventListeners.onPinch = this.onPinch.bind(this); this.body.eventListeners.onPinch = this.onPinch.bind(this);
this.body.eventListeners.onMouseMove = this.onMouseMove.bind(this); this.body.eventListeners.onMouseMove = this.onMouseMove.bind(this);
this.body.eventListeners.onRelease = this.onRelease.bind(this); this.body.eventListeners.onRelease = this.onRelease.bind(this);
this.body.eventListeners.onContext = this.onContext.bind(this);
this.touchTime = 0; this.touchTime = 0;
this.drag = {}; this.drag = {};
@ -152,6 +153,11 @@ class InteractionHandler {
} }
} }
onContext(event) {
let pointer = this.getPointer({x:event.pageX, y:event.pageY});
this.selectionHandler._generateClickEvent('rightClick',pointer);
}
/** /**
* *

+ 47
- 13
lib/network/modules/LayoutEngine.js View File

@ -7,26 +7,34 @@ class LayoutEngine {
this.initialRandomSeed = Math.round(Math.random() * 1000000); this.initialRandomSeed = Math.round(Math.random() * 1000000);
this.randomSeed = this.initialRandomSeed; this.randomSeed = this.initialRandomSeed;
this.options = {}; this.options = {};
this.optionsBackup = {};
this.defaultOptions = { this.defaultOptions = {
randomSeed: undefined, randomSeed: undefined,
hierarchical: { hierarchical: {
enabled:false, enabled:false,
levelSeparation: 150, levelSeparation: 150,
direction: "UD", // UD, DU, LR, RL
sortMethod: "hubsize" // hubsize, directed
direction: 'UD', // UD, DU, LR, RL
sortMethod: 'hubsize' // hubsize, directed
} }
} }
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.hierarchicalLevels = {}; this.hierarchicalLevels = {};
this.body.emitter.on("_dataChanged", () => {
this.body.emitter.on('_dataChanged', () => {
this.setupHierarchicalLayout();
})
this.body.emitter.on('_resetHierarchicalLayout', () => {
this.setupHierarchicalLayout(); this.setupHierarchicalLayout();
this.body.emitter.emit('fit',{duration:0});
}) })
} }
setOptions(options, allOptions) { setOptions(options, allOptions) {
if (options !== undefined) { if (options !== undefined) {
let prevHierarchicalState = this.options.hierarchical.enabled;
util.mergeOptions(this.options, options, 'hierarchical'); util.mergeOptions(this.options, options, 'hierarchical');
if (options.randomSeed !== undefined) { if (options.randomSeed !== undefined) {
this.randomSeed = options.randomSeed; this.randomSeed = options.randomSeed;
@ -34,7 +42,7 @@ class LayoutEngine {
if (this.options.hierarchical.enabled === true) { if (this.options.hierarchical.enabled === true) {
// make sure the level seperation is the right way up // make sure the level seperation is the right way up
if (this.options.hierarchical.direction === "RL" || this.options.hierarchical.direction === "DU") {
if (this.options.hierarchical.direction === 'RL' || this.options.hierarchical.direction === 'DU') {
if (this.options.hierarchical.levelSeparation > 0) { if (this.options.hierarchical.levelSeparation > 0) {
this.options.hierarchical.levelSeparation *= -1; this.options.hierarchical.levelSeparation *= -1;
} }
@ -45,9 +53,17 @@ class LayoutEngine {
} }
} }
this.body.emitter.emit('_resetHierarchicalLayout');
// because the hierarchical system needs it's own physics and smooth curve settings, we adapt the other options if needed. // because the hierarchical system needs it's own physics and smooth curve settings, we adapt the other options if needed.
return this.adaptAllOptions(allOptions); return this.adaptAllOptions(allOptions);
} }
else {
if (prevHierarchicalState === true) {
// refresh the overridden options for nodes and edges.
this.body.emitter.emit('refresh');
return util.deepExtend(allOptions,this.optionsBackup);
}
}
} }
return allOptions; return allOptions;
} }
@ -57,29 +73,47 @@ class LayoutEngine {
// set the physics // set the physics
if (allOptions.physics === undefined || allOptions.physics === true) { if (allOptions.physics === undefined || allOptions.physics === true) {
allOptions.physics = {solver: 'hierarchicalRepulsion'}; allOptions.physics = {solver: 'hierarchicalRepulsion'};
this.optionsBackup.physics = {solver:'barnesHut'};
}
else if (typeof options.physics === 'object') {
this.optionsBackup.physics = {solver:'barnesHut'};
if (options.physics.solver !== undefined) {
this.optionsBackup.physics = {solver:options.physics.solver};
}
allOptions.physics['solver'] = 'hierarchicalRepulsion';
} }
else if (options.physics !== false) { else if (options.physics !== false) {
this.optionsBackup.physics = {solver:'barnesHut'};
allOptions.physics['solver'] = 'hierarchicalRepulsion'; allOptions.physics['solver'] = 'hierarchicalRepulsion';
} }
// get the type of static smooth curve in case it is required // get the type of static smooth curve in case it is required
let type = 'horizontal'; let type = 'horizontal';
if (this.options.hierarchical.direction === "RL" || this.options.hierarchical.direction === "LR") {
if (this.options.hierarchical.direction === 'RL' || this.options.hierarchical.direction === 'LR') {
type = 'vertical'; type = 'vertical';
} }
// disable smooth curves if nothing is defined. If smooth curves have been turned on, turn them into static smooth curves. // disable smooth curves if nothing is defined. If smooth curves have been turned on, turn them into static smooth curves.
if (allOptions.edges === undefined) { if (allOptions.edges === undefined) {
this.optionsBackup.edges = {smooth:true, dynamic:true};
allOptions.edges = {smooth: false}; allOptions.edges = {smooth: false};
} }
else if (allOptions.edges.smooth === undefined) { else if (allOptions.edges.smooth === undefined) {
this.optionsBackup.edges = {smooth:true, dynamic:true};
allOptions.edges.smooth = false; allOptions.edges.smooth = false;
} }
else { else {
allOptions.edges.smooth = {enabled: true, dynamic: false, type:type}
if (typeof allOptions.edges.smooth === 'boolean') {
this.optionsBackup.edges = {smooth:allOptions.edges.smooth, dynamic:true};
allOptions.edges.smooth = {enabled: allOptions.edges.smooth, dynamic: false, type:type}
}
else {
this.optionsBackup.edges = {smooth: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled, dynamic:true};
allOptions.edges.smooth = {enabled: allOptions.edges.smooth.enabled === undefined ? true : allOptions.edges.smooth.enabled, dynamic: false, type:type}
}
} }
// force all edges into static smooth curves.
// force all edges into static smooth curves. Only applies to edges that do not use the global options for smooth.
this.body.emitter.emit('_forceDisableDynamicCurves', type); this.body.emitter.emit('_forceDisableDynamicCurves', type);
} }
return allOptions; return allOptions;
@ -143,7 +177,7 @@ class LayoutEngine {
// if the user defined some levels but not all, alert and run without hierarchical layout // if the user defined some levels but not all, alert and run without hierarchical layout
if (undefinedLevel === true && definedLevel === true) { if (undefinedLevel === true && definedLevel === true) {
throw new Error("To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes.");
throw new Error('To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes.');
return; return;
} }
else { else {
@ -152,10 +186,10 @@ class LayoutEngine {
// define levels if undefined by the users. Based on hubsize // define levels if undefined by the users. Based on hubsize
if (undefinedLevel === true) { if (undefinedLevel === true) {
if (this.options.hierarchical.sortMethod === "hubsize") {
if (this.options.hierarchical.sortMethod === 'hubsize') {
this._determineLevelsByHubsize(); this._determineLevelsByHubsize();
} }
else if (this.options.hierarchical.sortMethod === "directed" || "direction") {
else if (this.options.hierarchical.sortMethod === 'directed' || 'direction') {
this._determineLevelsDirected(); this._determineLevelsDirected();
} }
} }
@ -186,7 +220,7 @@ class LayoutEngine {
node = distribution[level].nodes[nodeId]; node = distribution[level].nodes[nodeId];
if (this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU") {
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
if (node.x === undefined) {node.x = distribution[level].distance;} if (node.x === undefined) {node.x = distribution[level].distance;}
distribution[level].distance = node.x + this.nodeSpacing; distribution[level].distance = node.x + this.nodeSpacing;
} }
@ -220,7 +254,7 @@ class LayoutEngine {
if (this.body.nodes.hasOwnProperty(nodeId)) { if (this.body.nodes.hasOwnProperty(nodeId)) {
node = this.body.nodes[nodeId]; node = this.body.nodes[nodeId];
let level = this.hierarchicalLevels[nodeId] === undefined ? 0 : this.hierarchicalLevels[nodeId]; let level = this.hierarchicalLevels[nodeId] === undefined ? 0 : this.hierarchicalLevels[nodeId];
if (this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU") {
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
node.y = this.options.hierarchical.levelSeparation * level; node.y = this.options.hierarchical.levelSeparation * level;
node.options.fixed.y = true; node.options.fixed.y = true;
} }
@ -404,7 +438,7 @@ class LayoutEngine {
if (this.positionedNodes[childNode.id] === undefined) { if (this.positionedNodes[childNode.id] === undefined) {
// if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here.
if (childNodeLevel > parentLevel) { if (childNodeLevel > parentLevel) {
if (this.options.hierarchical.direction === "UD" || this.options.hierarchical.direction === "DU") {
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
if (childNode.x === undefined) { if (childNode.x === undefined) {
childNode.x = Math.max(distribution[childNodeLevel].distance, parentNode.x); childNode.x = Math.max(distribution[childNodeLevel].distance, parentNode.x);
} }

+ 36
- 8
lib/network/modules/ManipulationSystem.js View File

@ -27,6 +27,7 @@ class ManipulationSystem {
this.touchTime = 0; this.touchTime = 0;
this.temporaryIds = {nodes: [], edges:[]}; this.temporaryIds = {nodes: [], edges:[]};
this.guiEnabled = false; this.guiEnabled = false;
this.inMode = false;
this.selectedControlNode = undefined; this.selectedControlNode = undefined;
this.options = {}; this.options = {};
@ -61,11 +62,27 @@ class ManipulationSystem {
} }
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.body.emitter.on("destroy", () => {this._clean()});
this.body.emitter.on("_resetData", () => {this._clean()});
this.body.emitter.on('destroy', () => {this._clean();});
this.body.emitter.on('_dataChanged',this._restore.bind(this));
this.body.emitter.on('_resetData', this._restore.bind(this));
} }
/**
* If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
* @private
*/
_restore() {
if (this.inMode !== false) {
if (this.options.initiallyActive === true) {
this.enableEditMode();
}
else {
this.disableEditMode();
}
}
}
/** /**
* Set the Options * Set the Options
* @param options * @param options
@ -220,6 +237,7 @@ class ManipulationSystem {
// restore the state of any bound functions or events, remove control nodes, restore physics // restore the state of any bound functions or events, remove control nodes, restore physics
this._clean(); this._clean();
this.inMode = 'addNode';
if (this.guiEnabled === true) { if (this.guiEnabled === true) {
let locale = this.options.locales[this.options.locale]; let locale = this.options.locales[this.options.locale];
this.manipulationDOM = {}; this.manipulationDOM = {};
@ -248,6 +266,7 @@ class ManipulationSystem {
// restore the state of any bound functions or events, remove control nodes, restore physics // restore the state of any bound functions or events, remove control nodes, restore physics
this._clean(); this._clean();
this.inMode = 'editNode';
if (typeof this.options.handlerFunctions.editNode === 'function') { if (typeof this.options.handlerFunctions.editNode === 'function') {
let node = this.selectionHandler._getSelectedNode(); let node = this.selectionHandler._getSelectedNode();
if (node.isCluster !== true) { if (node.isCluster !== true) {
@ -257,8 +276,10 @@ class ManipulationSystem {
if (this.options.handlerFunctions.editNode.length === 2) { if (this.options.handlerFunctions.editNode.length === 2) {
this.options.handlerFunctions.editNode(data, (finalizedData) => { this.options.handlerFunctions.editNode(data, (finalizedData) => {
this.body.data.nodes.update(finalizedData);
this.showManipulatorToolbar();
if (finalizedData !== null && finalizedData !== undefined && this.inMode === 'delete') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
this.body.data.nodes.update(finalizedData);
this.showManipulatorToolbar();
}
}); });
} }
else { else {
@ -289,6 +310,7 @@ class ManipulationSystem {
// restore the state of any bound functions or events, remove control nodes, restore physics // restore the state of any bound functions or events, remove control nodes, restore physics
this._clean(); this._clean();
this.inMode = 'addEdge';
if (this.guiEnabled === true) { if (this.guiEnabled === true) {
let locale = this.options.locales[this.options.locale]; let locale = this.options.locales[this.options.locale];
this.manipulationDOM = {}; this.manipulationDOM = {};
@ -324,6 +346,7 @@ class ManipulationSystem {
// restore the state of any bound functions or events, remove control nodes, restore physics // restore the state of any bound functions or events, remove control nodes, restore physics
this._clean(); this._clean();
this.inMode = 'editEdge';
if (this.guiEnabled === true) { if (this.guiEnabled === true) {
let locale = this.options.locales[this.options.locale]; let locale = this.options.locales[this.options.locale];
this.manipulationDOM = {}; this.manipulationDOM = {};
@ -390,6 +413,7 @@ class ManipulationSystem {
// restore the state of any bound functions or events, remove control nodes, restore physics // restore the state of any bound functions or events, remove control nodes, restore physics
this._clean(); this._clean();
this.inMode = 'delete';
let selectedNodes = this.selectionHandler.getSelectedNodes(); let selectedNodes = this.selectionHandler.getSelectedNodes();
let selectedEdges = this.selectionHandler.getSelectedEdges(); let selectedEdges = this.selectionHandler.getSelectedEdges();
let deleteFunction = undefined; let deleteFunction = undefined;
@ -415,7 +439,7 @@ class ManipulationSystem {
let data = {nodes: selectedNodes, edges: selectedEdges}; let data = {nodes: selectedNodes, edges: selectedEdges};
if (deleteFunction.length === 2) { if (deleteFunction.length === 2) {
deleteFunction(data, (finalizedData) => { deleteFunction(data, (finalizedData) => {
if (finalizedData !== null && finalizedData !== undefined) {
if (finalizedData !== null && finalizedData !== undefined && this.inMode === 'delete') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
this.body.data.edges.remove(finalizedData.edges); this.body.data.edges.remove(finalizedData.edges);
this.body.data.nodes.remove(finalizedData.nodes); this.body.data.nodes.remove(finalizedData.nodes);
this.body.emitter.emit('startSimulation'); this.body.emitter.emit('startSimulation');
@ -554,6 +578,9 @@ class ManipulationSystem {
* @private * @private
*/ */
_clean() { _clean() {
// not in mode
this.inMode = false;
// _clean the divs // _clean the divs
if (this.guiEnabled === true) { if (this.guiEnabled === true) {
util.recursiveDOMDelete(this.editModeDiv); util.recursiveDOMDelete(this.editModeDiv);
@ -667,6 +694,7 @@ class ManipulationSystem {
} }
_createButton(id, className, label, labelClassName = 'vis-label') { _createButton(id, className, label, labelClassName = 'vis-label') {
this.manipulationDOM[id+'Div'] = document.createElement('div'); this.manipulationDOM[id+'Div'] = document.createElement('div');
this.manipulationDOM[id+'Div'].className = className; this.manipulationDOM[id+'Div'].className = className;
this.manipulationDOM[id+'Label'] = document.createElement('div'); this.manipulationDOM[id+'Label'] = document.createElement('div');
@ -1014,7 +1042,7 @@ class ManipulationSystem {
if (typeof this.options.handlerFunctions.addNode === 'function') { if (typeof this.options.handlerFunctions.addNode === 'function') {
if (this.options.handlerFunctions.addNode.length === 2) { if (this.options.handlerFunctions.addNode.length === 2) {
this.options.handlerFunctions.addNode(defaultData, (finalizedData) => { this.options.handlerFunctions.addNode(defaultData, (finalizedData) => {
if (finalizedData !== null && finalizedData !== undefined) {
if (finalizedData !== null && finalizedData !== undefined && this.inMode === 'addNode') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback
this.body.data.nodes.add(finalizedData); this.body.data.nodes.add(finalizedData);
this.showManipulatorToolbar(); this.showManipulatorToolbar();
} }
@ -1042,7 +1070,7 @@ class ManipulationSystem {
if (this.options.handlerFunctions.addEdge) { if (this.options.handlerFunctions.addEdge) {
if (this.options.handlerFunctions.addEdge.length === 2) { if (this.options.handlerFunctions.addEdge.length === 2) {
this.options.handlerFunctions.addEdge(defaultData, (finalizedData) => { this.options.handlerFunctions.addEdge(defaultData, (finalizedData) => {
if (finalizedData !== null && finalizedData !== undefined) {
if (finalizedData !== null && finalizedData !== undefined && this.inMode === 'addEdge') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback
this.body.data.edges.add(finalizedData); this.body.data.edges.add(finalizedData);
this.selectionHandler.unselectAll(); this.selectionHandler.unselectAll();
this.showManipulatorToolbar(); this.showManipulatorToolbar();
@ -1070,7 +1098,7 @@ class ManipulationSystem {
if (this.options.handlerFunctions.editEdge) { if (this.options.handlerFunctions.editEdge) {
if (this.options.handlerFunctions.editEdge.length === 2) { if (this.options.handlerFunctions.editEdge.length === 2) {
this.options.handlerFunctions.editEdge(defaultData, (finalizedData) => { this.options.handlerFunctions.editEdge(defaultData, (finalizedData) => {
if (finalizedData === null || finalizedData === undefined) {
if (finalizedData === null || finalizedData === undefined || this.inMode !== 'editEdge') { // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
this.body.edges[defaultData.id].updateEdgeType(); this.body.edges[defaultData.id].updateEdgeType();
this.body.emitter.emit('_redraw'); this.body.emitter.emit('_redraw');
} }

+ 20
- 0
lib/network/modules/NodesHandler.js View File

@ -22,6 +22,11 @@ class NodesHandler {
}; };
// refresh the nodes. Used when reverting from hierarchical layout
this.body.emitter.on('refreshNodes', this.refresh.bind(this));
this.body.emitter.on('refresh', this.refresh.bind(this));
this.options = {}; this.options = {};
this.defaultOptions = { this.defaultOptions = {
borderWidth: 1, borderWidth: 1,
@ -274,6 +279,21 @@ class NodesHandler {
} }
refresh() {
let nodes = this.body.nodes;
for (let nodeId in nodes) {
let node = undefined;
if (nodes.hasOwnProperty(nodeId)) {
node = nodes[nodeId];
}
let data = this.body.data.nodes._data[nodeId];
if (node !== undefined && data !== undefined) {
node.setOptions({fixed:false});
node.setOptions(data);
}
}
}
/** /**
* Returns the positions of the nodes. * Returns the positions of the nodes.
* @param ids --> optional, can be array of nodeIds, can be string * @param ids --> optional, can be array of nodeIds, can be string

+ 1
- 1
lib/network/modules/View.js View File

@ -18,7 +18,7 @@ class View {
this.viewFunction = undefined; this.viewFunction = undefined;
this.body.emitter.on("fit", this.fit.bind(this));
this.body.emitter.on("fit", this.fit.bind(this));
this.body.emitter.on("animationFinished", () => {this.body.emitter.emit("_stopRendering");}); this.body.emitter.on("animationFinished", () => {this.body.emitter.emit("_stopRendering");});
this.body.emitter.on("unlockNode", this.releaseNode.bind(this)); this.body.emitter.on("unlockNode", this.releaseNode.bind(this));
} }

+ 2
- 2
lib/network/modules/components/Node.js View File

@ -174,8 +174,8 @@ class Node {
if (newOptions.fixed !== undefined) { if (newOptions.fixed !== undefined) {
if (typeof newOptions.fixed === 'boolean') { if (typeof newOptions.fixed === 'boolean') {
parentOptions.fixed.x = true;
parentOptions.fixed.y = true;
parentOptions.fixed.x = newOptions.fixed;
parentOptions.fixed.y = newOptions.fixed;
} }
else { else {
if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') { if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {

Loading…
Cancel
Save