Browse Source

numerous bugfixes, partial progress with examples

flowchartTest
Alex de Mulder 9 years ago
parent
commit
c3883970e4
34 changed files with 814 additions and 509 deletions
  1. +514
    -425
      dist/vis.js
  2. +9
    -3
      docs/network/physics.html
  3. +4
    -4
      examples/network/categories/02_random_nodes.html
  4. +8
    -4
      examples/network/categories/28_world_cup_network_performance.html
  5. +14
    -15
      examples/network/categories/labels/label_alignment.html
  6. +57
    -0
      examples/network/categories/labels/label_background.html
  7. +61
    -0
      examples/network/categories/labels/label_color_and_size.html
  8. +10
    -8
      examples/network/categories/labels/label_stroke.html
  9. +14
    -8
      examples/network/categories/nodeStyles/colors.html
  10. +15
    -3
      examples/network/categories/nodeStyles/icons.html
  11. +1
    -1
      lib/network/Network.js
  12. +38
    -0
      lib/network/modules/CanvasRenderer.js
  13. +0
    -1
      lib/network/modules/LayoutEngine.js
  14. +14
    -5
      lib/network/modules/PhysicsEngine.js
  15. +1
    -1
      lib/network/modules/View.js
  16. +0
    -1
      lib/network/modules/components/Edge.js
  17. +6
    -0
      lib/network/modules/components/Node.js
  18. +1
    -0
      lib/network/modules/components/nodes/shapes/Box.js
  19. +1
    -0
      lib/network/modules/components/nodes/shapes/Circle.js
  20. +1
    -0
      lib/network/modules/components/nodes/shapes/CircularImage.js
  21. +1
    -0
      lib/network/modules/components/nodes/shapes/Database.js
  22. +1
    -0
      lib/network/modules/components/nodes/shapes/Ellipse.js
  23. +0
    -21
      lib/network/modules/components/nodes/shapes/Empty.js
  24. +1
    -0
      lib/network/modules/components/nodes/shapes/Icon.js
  25. +1
    -0
      lib/network/modules/components/nodes/shapes/Text.js
  26. +1
    -0
      lib/network/modules/components/nodes/util/CircleImageBase.js
  27. +2
    -0
      lib/network/modules/components/nodes/util/NodeBase.js
  28. +1
    -0
      lib/network/modules/components/nodes/util/ShapeBase.js
  29. +7
    -1
      lib/network/modules/components/physics/BarnesHutSolver.js
  30. +5
    -0
      lib/network/modules/components/physics/FA2BasedRepulsionSolver.js
  31. +13
    -2
      lib/network/modules/components/physics/SpringSolver.js
  32. +1
    -1
      lib/network/modules/components/shared/Label.js
  33. +9
    -3
      lib/network/options.js
  34. +2
    -2
      test/timeline_groups.html

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


+ 9
- 3
docs/network/physics.html View File

@ -90,7 +90,8 @@ var options = {
centralGravity: 0.3,
springLength: 95,
springConstant: 0.04,
damping: 0.09
damping: 0.09,
avoidOverlap: false
},
forceAtlas2Based: {
theta: 0.5,
@ -98,14 +99,16 @@ var options = {
centralGravity: 0.01,
springConstant: 0.08,
springLength: 100,
damping: 0.4
damping: 0.4,
avoidOverlap: false
},
repulsion: {
centralGravity: 0.2,
springLength: 200,
springConstant: 0.05,
nodeDistance: 100,
damping: 0.09
damping: 0.09,
avoidOverlap: false
},
hierarchicalRepulsion: {
centralGravity: 0.0,
@ -149,6 +152,7 @@ network.setOptions(options);
<tr parent="barnesHut" class="hidden"><td class="indent">barnesHut.springLength</td> <td class="mid">Number</td> <td class="mid"><code>95</code></td> <td>The edges are modelled as springs. This springLength here is the the rest length of the spring.</td></tr>
<tr parent="barnesHut" class="hidden"><td class="indent">barnesHut.springConstant</td> <td class="mid">Number</td> <td class="mid"><code>0.04</code></td> <td>This is how 'sturdy' the springs are. Higher values mean stronger springs.</td></tr>
<tr parent="barnesHut" class="hidden"><td class="indent">barnesHut.damping</td> <td class="mid">Number</td> <td class="mid"><code>0.09</code></td> <td>Accepted range: <code>[0 .. 1]</code>. The damping factor is how much of the velocity from the previous physics simulation iteration carries over to the next iteration.</td></tr>
<tr parent="barnesHut" class="hidden"><td class="indent">barnesHut.avoidOverlap</td> <td class="mid">Number</td> <td class="mid"><code>0</code></td> <td>Accepted range: <code>[0 .. 1]</code>. When larger than 0, the size of the node is taken into account. The distance will be calculated from the radius of the encompassing circle of the node for both the gravity model and the spring model. Value 1 is maximum overlap avoidance.</td></tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','forceAtlas2Based', this);"><td><span parent="forceAtlas2Based" class="right-caret"></span> forceAtlas2Based</td> <td class="mid">Object</td> <td class="mid"><code>Object</code></td> <td>Force Atlas 2 has been developed by <a href="http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679" target="_blank">Jacomi <i>et al</i> (2014)</a> for use with Gephi. The forceAtlas2Based solver makes use of some of the equations provided
by them and makes use of the barnesHut implementation in vis. The main differences are the central gravity model,
@ -159,6 +163,7 @@ network.setOptions(options);
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.springLength</td> <td class="mid">Number</td> <td class="mid"><code>100</code></td> <td>The edges are modelled as springs. This springLength here is the the rest length of the spring.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.springConstant</td> <td class="mid">Number</td> <td class="mid"><code>0.08</code></td> <td>This is how 'sturdy' the springs are. Higher values mean stronger springs.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.damping</td> <td class="mid">Number</td> <td class="mid"><code>0.4</code></td> <td>Accepted range: <code>[0 .. 1]</code>. The damping factor is how much of the velocity from the previous physics simulation iteration carries over to the next iteration.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.avoidOverlap</td> <td class="mid">Number</td> <td class="mid"><code>0</code></td> <td>Accepted range: <code>[0 .. 1]</code>. When larger than 0, the size of the node is taken into account. The distance will be calculated from the radius of the encompassing circle of the node for both the gravity model and the spring model. Value 1 is maximum overlap avoidance.</td></tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','repulsion', this);"><td><span parent="repulsion" class="right-caret"></span> repulsion</td> <td class="mid">Object</td> <td class="mid"><code>Object</code></td> <td>The repulsion model assumes nodes have a simplified repulsion field around them. It's force linearly decreases from 1 (at 0.5*nodeDistance and smaller) to 0 (at 2*nodeDistance).</td></tr>
<tr parent="repulsion" class="hidden"><td class="indent">repulsion.nodeDistance</td> <td class="mid">Number</td> <td class="mid"><code>100</code></td> <td>This is the range of influence for the repulsion.</td></tr>
@ -166,6 +171,7 @@ network.setOptions(options);
<tr parent="repulsion" class="hidden"><td class="indent">repulsion.springLength</td> <td class="mid">Number</td> <td class="mid"><code>200</code></td> <td>The edges are modelled as springs. This springLength here is the the rest length of the spring.</td></tr>
<tr parent="repulsion" class="hidden"><td class="indent">repulsion.springConstant</td> <td class="mid">Number</td> <td class="mid"><code>0.05</code></td> <td>This is how 'sturdy' the springs are. Higher values mean stronger springs.</td></tr>
<tr parent="repulsion" class="hidden"><td class="indent">repulsion.damping</td> <td class="mid">Number</td> <td class="mid"><code>0.09</code></td> <td>Accepted range: <code>[0 .. 1]</code>. The damping factor is how much of the velocity from the previous physics simulation iteration carries over to the next iteration.</td></tr>
<tr parent="repulsion" class="hidden"><td class="indent">repulsion.avoidOverlap</td> <td class="mid">Number</td> <td class="mid"><code>0</code></td> <td>Accepted range: <code>[0 .. 1]</code>. When larger than 0, the size of the node is taken into account. The distance will be calculated from the radius of the encompassing circle of the node for the spring model. Value 1 is maximum overlap avoidance.</td></tr>
<tr class='toggle collapsible' onclick="toggleTable('optionTable','hierarchicalRepulsion', this);"><td><span parent="hierarchicalRepulsion" class="right-caret"></span> hierarchicalRepulsion</td> <td class="mid">Object</td> <td class="mid"><code>Object</code></td> <td>This model is based on the repulsion solver but the levels are taken into account and the forces are normalized.</td></tr>
<tr parent="hierarchicalRepulsion" class="hidden"><td class="indent">hierarchicalRepulsion.nodeDistance</td> <td class="mid">Number</td> <td class="mid"><code>120</code></td> <td>This is the range of influence for the repulsion.</td></tr>

+ 4
- 4
examples/network/categories/02_random_nodes.html View File

@ -14,8 +14,8 @@
}
</style>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link href="../../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var nodes = null;
@ -85,14 +85,14 @@
edges: edges
};
var options = {
physics: { stabilization: false }
physics: { stabilization: true }
};
network = new vis.Network(container, data, options);
}
</script>
<script src="../googleAnalytics.js"></script>
<script src="../../googleAnalytics.js"></script>
</head>
<body onload="draw();">
<p>

+ 8
- 4
examples/network/categories/28_world_cup_network_performance.html View File

@ -5,10 +5,10 @@
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<title>Network | Static smooth curves - World Cup Network</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link type="text/css" rel="stylesheet" href="../../dist/vis.css">
<script type="text/javascript" src="../../../dist/vis.js"></script>
<link type="text/css" rel="stylesheet" href="../../../dist/vis.css">
<script src="./data/WorldCup2014.js"></script>
<script src="../data/WorldCup2014.js"></script>
<style type="text/css">
#mynetwork {
@ -45,6 +45,11 @@
function redrawAll() {
network = null;
for (var i = 0; i < nodes.length; i++) {
delete nodes[i].x;
delete nodes[i].y;
}
// create a network
var container = document.getElementById('mynetwork');
var data = {
@ -67,7 +72,6 @@
width: 0.15,
color: {inherit: 'from'},
smooth: {
dynamic: false,
type: 'continuous'
}
},

examples/network/categories/37_label_alignment.html → examples/network/categories/labels/label_alignment.html View File

@ -3,22 +3,25 @@
<head>
<title>Network | Label alignment</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link href="../../../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 400px;
height: 400px;
width: 600px;
height: 600px;
border: 1px solid lightgray;
}
p {
max-width:600px;
}
</style>
<script src="../googleAnalytics.js"></script>
<script src="../../../googleAnalytics.js"></script>
</head>
<body>
<p>Labels can be aligned to edges in various ways.</p>
<p>Labels of edges can be aligned to edges in various ways. <br>Label alignment for nodes (top, bottom, left, right, inside) is planned but not in vis yet.</p>
<div id="mynetwork"></div>
@ -34,10 +37,10 @@
// create an array with edges
var edges = [
{from: 1, to: 2, label: 'middle', font: {align:'middle', background:'orange'}},
{from: 1, to: 3, label: 'top', font: {align: 'top', background:'green'}},
{from: 2, to: 4, label: 'horizontal', font: {align: 'horizontal', background: 'red'}},
{from: 2, to: 5, label: 'bottom', font: { align:'bottom', background: '#ccd' }}
{from: 1, to: 2, label: 'middle', font: {align: 'middle'}},
{from: 1, to: 3, label: 'top', font: {align: 'top'}},
{from: 2, to: 4, label: 'horizontal', font: {align: 'horizontal'}},
{from: 2, to: 5, label: 'bottom', font: {align: 'bottom'}}
];
// create a network
@ -46,11 +49,7 @@
nodes: nodes,
edges: edges
};
var options = {
edges: {
font: {stroke: 0}
}
};
var options = {};
var network = new vis.Network(container, data, options);
</script>

+ 57
- 0
examples/network/categories/labels/label_background.html View File

@ -0,0 +1,57 @@
<!doctype html>
<html>
<head>
<title>Network | Label alignment</title>
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link href="../../../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 600px;
height: 600px;
border: 1px solid lightgray;
}
p {
max-width:600px;
}
</style>
<script src="../../../googleAnalytics.js"></script>
</head>
<body>
<p>Labels can have any color background.</p>
<div id="mynetwork"></div>
<script type="text/javascript">
// create an array with nodes
var nodes = [
{id: 1, label: 'Node 1', font: {background: 'red'}},
{id: 2, label: 'Node 2', font: {background: 'white'}},
{id: 3, label: 'Node 3', font: {background: 'cyan'}},
{id: 4, label: 'Node 4', font: {background: 'lime'}},
{id: 5, label: 'Node 5', font: {background: 'pink'}}
];
// create an array with edges
var edges = [
{from: 1, to: 2, label: 'label1', font: {background: '#ff0000'}},
{from: 1, to: 3, label: 'label2', font: {background: 'yellow'}},
{from: 2, to: 4, label: 'label3', font: {background: 'lime'}},
{from: 2, to: 5, label: 'label3', font: {background: 'pink'}}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {nodes:{font:{strokeWidth:0}}, edges:{font:{strokeWidth:0}}};
var network = new vis.Network(container, data, options);
</script>
</body>
</html>

+ 61
- 0
examples/network/categories/labels/label_color_and_size.html View File

@ -0,0 +1,61 @@
<!doctype html>
<html>
<head>
<title>Network | Label stroke</title>
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link href="../../../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 600px;
height: 600px;
border: 1px solid lightgray;
background:#d1d1d1;
}
p {
max-width:600px;
}
</style>
<script src="../../../googleAnalytics.js"></script>
</head>
<body>
<p>The style of the edges can be fully customized.</p>
<div id="mynetwork"></div>
<script type="text/javascript">
// create an array with nodes
var nodes = [
{id: 1, label: 'Node 1', font: '12px arial red'},
{id: 2, label: 'Node 2', font: {size:12, color:'lime', face:'arial'}},
{id: 3, label: 'Node 3', font: '18px verdana blue'},
{id: 4, label: 'Node 4', font: {size:12, color:'red', face:'sans', background:'white'}},
{id: 5, label: 'Node 5', font: {size:15, color:'red', face:'courier', strokeWidth:3, strokeColor:'#ffffff'}}
];
// create an array with edges
var edges = [
{from: 1, to: 2},
{from: 1, to: 3},
{from: 2, to: 4},
{from: 2, to: 5}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes : {
shape: 'dot',
size: 10
}
};
var network = new vis.Network(container, data, options);
</script>
</body>
</html>

examples/network/categories/35_label_stroke.html → examples/network/categories/labels/label_stroke.html View File

@ -2,23 +2,25 @@
<html>
<head>
<title>Network | Label stroke</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link href="../../../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 400px;
height: 400px;
width: 600px;
height: 600px;
border: 1px solid lightgray;
background: #d1d1d1;
background:#d1d1d1;
}
p {
max-width:600px;
}
</style>
<script src="../googleAnalytics.js"></script>
<script src="../../../googleAnalytics.js"></script>
</head>
<body>
<p>The font, size, and stroke of labels is fully customizable.</p>
<p>The stroke of labels is fully can have a width and color. Edgelabels by default have a white stroke for clarity.</p>
<div id="mynetwork"></div>

+ 14
- 8
examples/network/categories/nodeStyles/colors.html View File

@ -12,6 +12,10 @@
height: 400px;
border: 1px solid lightgray;
}
p {
max-width:700px;
}
</style>
</head>
<body>
@ -26,12 +30,12 @@
<script type="text/javascript">
// create an array with nodes
var nodes = new vis.DataSet([
{id: 1, label:'html color', color: 'red'},
{id: 2, label:'rgb color', color: 'rgb(200,12,31)'},
{id: 3, label:'hex color', color: '#ff00dd'},
{id: 4, label:'rgba color', color: 'rgba(230,53,94,0.5)'},
{id: 5, label:'colorObject', color: {background:'red', border:'blue'}},
{id: 6, label:'colorObject + highlight', color: {background:'orange', border:'blue',highlight:{background:'red',border:'blue'}}},
{id: 1, label:'html color', color: 'lime'},
{id: 2, label:'rgb color', color: 'rgb(255,168,7)'},
{id: 3, label:'hex color', color: '#7BE141'},
{id: 4, label:'rgba color', color: 'rgba(97,195,238,0.5)'},
{id: 5, label:'colorObject', color: {background:'pink', border:'purple'}},
{id: 6, label:'colorObject + highlight', color: {background:'#F03967', border:'#713E7F',highlight:{background:'red',border:'black'}}},
{id: 7, label:'colorObject + highlight + hover', color: {background:'cyan', border:'blue',highlight:{background:'red',border:'blue'},hover:{background:'white',border:'red'}}}
])
@ -40,7 +44,9 @@
{from: 1, to: 3},
{from: 1, to: 2},
{from: 2, to: 4},
{from: 2, to: 5}
{from: 2, to: 5},
{from: 2, to: 6},
{from: 4, to: 7},
]);
// create a network
@ -49,7 +55,7 @@
nodes: nodes,
edges: edges
};
var options = {interaction:{hover:true}};
var options = {nodes:{borderWidth:2},interaction:{hover:true}};
var network = new vis.Network(container, data, options);
</script>

+ 15
- 3
examples/network/categories/nodeStyles/icons.html View File

@ -15,6 +15,12 @@
#mynetworkFA,
#mynetworkIO {
height: 300px;
width: 700px;
border:1px solid lightgrey;
}
p {
max-width:700px;
}
</style>
@ -170,13 +176,19 @@
</script>
<script src="../../../googleAnalytics.js"></script>
</head>
<body onload="draw()">
<p>
Icons can be used for nodes as well. This example shows Icons from fontAwesome and Ionicons but it should work with similar packages as well.
It uses unicode and css to define the icons.<br><br> <b>Remember! Unicode in javascript is done like this: \uf274 for the unicode f274.</b>
<br> If a node is shown as a rectangle, it means the css is not loaded (or not yet loaded). A redraw will fix that.
</p>
<h2>
<i class="fa fa-flag"></i> Use FontAwesome-icons for node</h2>
<i class="fa fa-flag"></i> Use FontAwesome-icons for nodes</h2>
<div id="mynetworkFA"></div>
<h2>
<i class="ion ion-ionic"></i> Use Ionicons-icons for node</h2>
<i class="ion ion-ionic"></i> Use Ionicons-icons for nodes</h2>
<div id="mynetworkIO"></div>
</body>

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

@ -260,7 +260,7 @@ Network.prototype.bindEventListeners = function () {
this.body.emitter.on("_dataChanged", () => {
// update shortcut lists
this._updateVisibleIndices();
this.physics.updatePhysicsIndices();
this.physics.updatePhysicsData();
// call the dataUpdated event because the only difference between the two is the updating of the indices
this.body.emitter.emit("_dataUpdated");

+ 38
- 0
lib/network/modules/CanvasRenderer.js View File

@ -36,6 +36,7 @@ class CanvasRenderer {
this.dragging = true;
});
this.body.emitter.on("dragEnd", () => this.dragging = false);
this.body.emitter.on("_resizeNodes", () => this._resizeNodes());
this.body.emitter.on("_redraw", () => {
if (this.renderingActive === false) {
this._redraw();
@ -194,6 +195,43 @@ class CanvasRenderer {
}
/**
* Redraw all nodes
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
* @param {CanvasRenderingContext2D} ctx
* @param {Boolean} [alwaysShow]
* @private
*/
_resizeNodes() {
let ctx = this.canvas.frame.canvas.getContext('2d');
if (this.pixelRatio === undefined) {
this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1);
}
ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
ctx.save();
ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
ctx.scale(this.body.view.scale, this.body.view.scale);
let nodes = this.body.nodes;
let node;
// resize all nodes
for (let nodeId in nodes) {
if (nodes.hasOwnProperty(nodeId)) {
node = nodes[nodeId];
node.resize(ctx);
node.updateBoundingBox(ctx);
}
}
// restore original scaling and translation
ctx.restore();
}
/**
* Redraw all nodes
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');

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

@ -134,7 +134,6 @@ class LayoutEngine {
if ((!node.isFixed()) && (node.x === undefined || node.y === undefined)) {
let radius = 10 * 0.1 * nodesArray.length + 10;
let angle = 2 * Math.PI * this.seededRandom();
if (node.options.fixed.x === false) {
node.x = radius * Math.cos(angle);
}

+ 14
- 5
lib/network/modules/PhysicsEngine.js View File

@ -35,7 +35,8 @@ class PhysicsEngine {
centralGravity: 0.3,
springLength: 95,
springConstant: 0.04,
damping: 0.09
damping: 0.09,
avoidOverlap: 0
},
forceAtlas2Based: {
theta: 0.5,
@ -43,14 +44,16 @@ class PhysicsEngine {
centralGravity: 0.01,
springConstant: 0.08,
springLength: 100,
damping: 0.4
damping: 0.4,
avoidOverlap: 0
},
repulsion: {
centralGravity: 0.2,
springLength: 200,
springConstant: 0.05,
nodeDistance: 100,
damping: 0.09
damping: 0.09,
avoidOverlap: 0
},
hierarchicalRepulsion: {
centralGravity: 0.0,
@ -159,7 +162,6 @@ class PhysicsEngine {
else {
this.ready = true;
this.body.emitter.emit('fit');
}
}
@ -169,6 +171,10 @@ class PhysicsEngine {
startSimulation() {
if (this.physicsEnabled === true) {
this.stabilized = false;
// this sets the width of all nodes initially which could be required for the avoidOverlap
this.body.emitter.emit("_resizeNodes");
if (this.viewFunction === undefined) {
this.viewFunction = this.simulationStep.bind(this);
this.body.emitter.on('initRedraw', this.viewFunction);
@ -273,7 +279,7 @@ class PhysicsEngine {
*
* @private
*/
updatePhysicsIndices() {
updatePhysicsData() {
this.physicsBody.forces = {};
this.physicsBody.physicsNodeIndices = [];
this.physicsBody.physicsEdgeIndices = [];
@ -478,6 +484,9 @@ class PhysicsEngine {
iterations = this.options.stabilization.iterations;
}
// this sets the width of all nodes initially which could be required for the avoidOverlap
this.body.emitter.emit("_resizeNodes");
// stop the render loop
this.stopSimulation();

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

@ -125,7 +125,7 @@ class View {
zoomLevel *= factor;
}
else {
this.body.emitter.emit("_redraw", true);
this.body.emitter.emit("_resizeNodes");
range = this._getRange(options.nodes);
var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
var yDistance = Math.abs(range.maxY - range.minY) * 1.1;

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

@ -90,7 +90,6 @@ class Edge {
static parseOptions(parentOptions, newOptions, allowDeletion = false) {
var fields = [
'id',
'font',
'from',
'hidden',
'hoverWidth',

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

@ -162,6 +162,7 @@ class Node {
static parseOptions(parentOptions, newOptions, allowDeletion = false) {
var fields = [
'color',
'font',
'fixed',
'shadow'
];
@ -194,6 +195,10 @@ class Node {
}
}
}
if (newOptions.font !== undefined) {
Label.parseOptions(parentOptions.font, newOptions);
}
}
updateLabelModule() {
@ -368,6 +373,7 @@ class Node {
this.shape.draw(ctx, this.x, this.y, this.selected, this.hover);
}
/**
* Update the bounding box of the shape
*/

+ 1
- 0
lib/network/modules/components/nodes/shapes/Box.js View File

@ -13,6 +13,7 @@ class Box extends NodeBase {
let textSize = this.labelModule.getTextSize(ctx,selected);
this.width = textSize.width + 2 * margin;
this.height = textSize.height + 2 * margin;
this.radius = 0.5*this.width;
}
}

+ 1
- 0
lib/network/modules/components/nodes/shapes/Circle.js View File

@ -16,6 +16,7 @@ class Circle extends CircleImageBase {
this.width = diameter;
this.height = diameter;
this.radius = 0.5*this.width;
}
}

+ 1
- 0
lib/network/modules/components/nodes/shapes/CircularImage.js View File

@ -17,6 +17,7 @@ class CircularImage extends CircleImageBase {
this.width = diameter;
this.height = diameter;
this._swapToImageResizeWhenImageLoaded = true;
this.radius = 0.5*this.width;
}
}
else {

+ 1
- 0
lib/network/modules/components/nodes/shapes/Database.js View File

@ -14,6 +14,7 @@ class Database extends NodeBase {
var size = textSize.width + 2 * margin;
this.width = size;
this.height = size;
this.radius = 0.5*this.width;
}
}

+ 1
- 0
lib/network/modules/components/nodes/shapes/Ellipse.js View File

@ -16,6 +16,7 @@ class Ellipse extends NodeBase {
if (this.width < this.height) {
this.width = this.height;
}
this.radius = 0.5*this.width;
}
}

+ 0
- 21
lib/network/modules/components/nodes/shapes/Empty.js View File

@ -1,21 +0,0 @@
'use strict';
import NodeBase from '../util/NodeBase'
class Empty extends NodeBase {
constructor (options, body, labelModule) {
super(options, body, labelModule);
}
setOptions() {}
resize() {}
draw() {}
distanceToBorder() {}
updateBoundingBox() {}}
export default Empty;

+ 1
- 0
lib/network/modules/components/nodes/shapes/Icon.js View File

@ -16,6 +16,7 @@ class Icon extends NodeBase {
};
this.width = iconSize.width + 2 * margin;
this.height = iconSize.height + 2 * margin;
this.radius = 0.5*this.width;
}
}

+ 1
- 0
lib/network/modules/components/nodes/shapes/Text.js View File

@ -13,6 +13,7 @@ class Text extends NodeBase {
var textSize = this.labelModule.getTextSize(ctx,selected);
this.width = textSize.width + 2 * margin;
this.height = textSize.height + 2 * margin;
this.radius = 0.5*this.width;
}
}

+ 1
- 0
lib/network/modules/components/nodes/util/CircleImageBase.js View File

@ -25,6 +25,7 @@ class CircleImageBase extends NodeBase {
}
this.width = width;
this.height = height;
this.radius = 0.5*this.width;
}
}

+ 2
- 0
lib/network/modules/components/nodes/util/NodeBase.js View File

@ -6,6 +6,8 @@ class NodeBase {
this.top = undefined;
this.left = undefined;
this.height = undefined;
this.width = undefined;
this.radius = undefined;
this.boundingBox = {top: 0, left: 0, right: 0, bottom: 0};
}

+ 1
- 0
lib/network/modules/components/nodes/util/ShapeBase.js View File

@ -10,6 +10,7 @@ class ShapeBase extends NodeBase {
var size = 2 * this.options.size;
this.width = size;
this.height = size;
this.radius = 0.5*this.width;
}
}

+ 7
- 1
lib/network/modules/components/physics/BarnesHutSolver.js View File

@ -9,7 +9,8 @@ class BarnesHutSolver {
setOptions(options) {
this.options = options;
this.thetaInversed = 1/ this.options.theta;
this.thetaInversed = 1 / this.options.theta;
this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1,this.options.avoidOverlap)); // if 1 then min distance = 0.5, if 0.5 then min distance = 0.5 + 0.5*node.shape.radius
}
@ -104,6 +105,11 @@ class BarnesHutSolver {
distance = 0.1 * Math.random();
dx = distance;
}
if (this.overlapAvoidanceFactor < 1) {
distance = Math.max(0.1 + (this.overlapAvoidanceFactor * node.shape.radius), distance - node.shape.radius);
}
// the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
// it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
let gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance,3);

+ 5
- 0
lib/network/modules/components/physics/FA2BasedRepulsionSolver.js View File

@ -20,6 +20,11 @@ class ForceAtlas2BasedRepulsionSolver extends BarnesHutSolver {
distance = 0.1 * Math.random();
dx = distance;
}
if (this.overlapAvoidanceFactor < 1) {
distance = Math.max(0.1 + (this.overlapAvoidanceFactor * node.shape.radius), distance - node.shape.radius);
}
let degree = (node.edges.length + 1);
// the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
// it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce

+ 13
- 2
lib/network/modules/components/physics/SpringSolver.js View File

@ -7,6 +7,8 @@ class SpringSolver {
setOptions(options) {
this.options = options;
this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1,this.options.avoidOverlap)); // if 1 then min distance = 0.5, if 0.5 then min distance = 0.5 + 0.5*node.shape.radius
}
/**
@ -56,8 +58,17 @@ class SpringSolver {
* @private
*/
_calculateSpringForce(node1, node2, edgeLength) {
let dx = (node1.x - node2.x);
let dy = (node1.y - node2.y);
let dx,dy;
if (this.overlapAvoidanceFactor < 1) {
let nodesWidth = this.overlapAvoidanceFactor * (node1.shape.radius + node2.shape.radius);
dx = (node1.x - node2.x) - nodesWidth;
dy = (node1.y - node2.y) - nodesWidth;
}
else {
dx = (node1.x - node2.x);
dy = (node1.y - node2.y);
}
let distance = Math.sqrt(dx * dx + dy * dy);
distance = distance === 0 ? 0.01 : distance;

+ 1
- 1
lib/network/modules/components/shared/Label.js View File

@ -92,7 +92,7 @@ class Label {
ctx.fillRect(-this.size.width * 0.5, lineMargin, this.size.width, this.size.height);
break;
default:
ctx.fillRect(this.size.left, this.size.top, this.size.width, this.size.height);
ctx.fillRect(this.size.left, this.size.top - 0.5*lineMargin, this.size.width, this.size.height);
break;
}
}

+ 9
- 3
lib/network/options.js View File

@ -220,6 +220,7 @@ let allOptions = {
springLength: {number},
springConstant: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
},
forceAtlas2Based: {
@ -228,6 +229,7 @@ let allOptions = {
springLength: {number},
springConstant: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
},
repulsion: {
@ -236,6 +238,7 @@ let allOptions = {
springConstant: {number},
nodeDistance: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
},
hierarchicalRepulsion: {
@ -426,7 +429,8 @@ let configureOptions = {
centralGravity: [0.3, 0, 10, 0.05],
springLength: [95, 0, 500, 5],
springConstant: [0.04, 0, 5, 0.005],
damping: [0.09, 0, 1, 0.01]
damping: [0.09, 0, 1, 0.01],
avoidOverlap: [0, 0, 1, 0.01]
},
forceAtlas2Based: {
//theta: [0.5, 0.1, 1, 0.05],
@ -434,14 +438,16 @@ let configureOptions = {
centralGravity: [0.01, 0, 1, 0.005],
springLength: [95, 0, 500, 5],
springConstant: [0.08, 0, 5, 0.005],
damping: [0.4, 0, 1, 0.01]
damping: [0.4, 0, 1, 0.01],
avoidOverlap: [0, 0, 1, 0.01]
},
repulsion: {
centralGravity: [0.2, 0, 10, 0.05],
springLength: [200, 0, 500, 5],
springConstant: [0.05, 0, 5, 0.005],
nodeDistance: [100, 0, 500, 5],
damping: [0.09, 0, 1, 0.01]
damping: [0.09, 0, 1, 0.01],
avoidOverlap: [0, 0, 1, 0.01]
},
hierarchicalRepulsion: {
centralGravity: [0.2, 0, 10, 0.05],

+ 2
- 2
test/timeline_groups.html View File

@ -64,7 +64,7 @@
var names = ['John (0)', 'Alston (1)', 'Lee (2)', 'Grant (3)'];
var groups = new vis.DataSet();
for (var g = 0; g < groupCount; g++) {
groups.add({id: g, content: names[g], title: 'Title of group ' + g, 'className': 'myGroup'});
groups.add({id: g, content: '<a href="http://google.com"><span style="color:#97B0F8;">' + names[g] + '</a>', title: 'Title of group ' + g, 'className': 'myGroup'});
}
// create a dataset with items
@ -77,7 +77,7 @@
id: i,
group: group,
content: 'item ' + i +
' <span style="color:#97B0F8;">(' + names[group] + ')</span>',
' <a href="http://google.com"><span style="color:#97B0F8;">(' + names[group] + ')</span></a> ',
start: start,
end: end,
title: 'Title for item ' + i,

Loading…
Cancel
Save