Browse Source

Merge remote-tracking branch 'origin/v4' into v4

flowchartTest
jos 9 years ago
parent
commit
c817962b35
18 changed files with 2723 additions and 2559 deletions
  1. +2448
    -2437
      dist/vis.js
  2. +3
    -3
      docs/network/edges.html
  3. +3
    -3
      docs/network/nodes.html
  4. +0
    -45
      examples/network/categories/02_random_nodes.html
  5. +140
    -0
      examples/network/categories/data/datasets.html
  6. +3
    -3
      examples/network/categories/data/dot_language.html
  7. +5
    -5
      examples/network/categories/data/dynamic_data.html
  8. +10
    -19
      examples/network/categories/data/importing_from_gephi.html
  9. +1
    -1
      examples/network/categories/data/scaling_nodes_edges.html
  10. +70
    -0
      examples/network/exampleUtil.js
  11. +4
    -0
      lib/network/Network.js
  12. +1
    -1
      lib/network/modules/EdgesHandler.js
  13. +3
    -3
      lib/network/modules/NodesHandler.js
  14. +4
    -4
      lib/network/modules/components/Edge.js
  15. +2
    -3
      lib/network/modules/components/Node.js
  16. +3
    -15
      lib/network/modules/components/physics/SpringSolver.js
  17. +1
    -3
      lib/network/options.js
  18. +22
    -14
      lib/util.js

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


+ 3
- 3
docs/network/edges.html View File

@ -89,7 +89,7 @@
<p>The options for the edges have to be contained in an object titled 'edges'. All of these options can be supplied per edge as well. Obviously, 'id' should not be defined globally but per edge. Options defined
in the global edges object, are applied to all edges. If an edge has options of its own, those will be used instead of the global options.</p>
<p><b><i>When you have given an edge an option, you will override the global option for that property. If you then set that option to <code>undefined</code> or <code>null</code>,
<p><b><i>When you have given an edge an option, you will override the global option for that property. If you then set that option to <code>null</code>,
it will revert back to the default value.</i></b>
</p>
<p>Click on the full options or shorthand options to show how these options are supposed to be used.</p>
@ -138,7 +138,7 @@ var options = {
min: 14,
max: 30,
maxVisible: 30,
drawThreshold: 3
drawThreshold: 6
},
customScalingFunction: function (min,max,total,value) {
if (max === min) {
@ -480,7 +480,7 @@ var options: {
<tr parent="scaling" class="hidden">
<td class="indent2">scaling.label.drawThreshold</td>
<td>Number</td>
<td><code>3</code></td>
<td><code>6</code></td>
<td>When zooming out, the font will be drawn smaller. This defines a lower limit for when the font is drawn.
When using font scaling, you can use this together with the maxVisible to first show labels of important
edges when zoomed out and only show the rest when zooming in.

+ 3
- 3
docs/network/nodes.html View File

@ -80,7 +80,7 @@
<h3>Options</h3>
<p>The options for the nodes have to be contained in an object titled 'nodes'. All of these options can be supplied per node as well. Obviously, 'id' should not be defined globally but per node. Options defined
in the global nodes object, are applied to all nodes. If a node has options of its own, those will be used instead of the global options.</p>
<p><b><i>When you have given a node an option, you will override the global option for that property. If you then set that option to <code>undefined</code> or <code>null</code>,
<p><b><i>When you have given a node an option, you will override the global option for that property. If you then set that option to <code>null</code>,
it will revert back to the default value.</i></b>
</p>
<p>Click on the full options or shorthand options to show how these options are supposed to be used.</p>
@ -143,7 +143,7 @@ var options = {
min: 14,
max: 30,
maxVisible: 30,
drawThreshold: 3
drawThreshold: 6
},
customScalingFunction: function (min,max,total,value) {
if (max === min) {
@ -507,7 +507,7 @@ network.setOptions(options);
<tr parent="scaling" class="hidden">
<td class="indent2">scaling.label.drawThreshold</td>
<td>Number</td>
<td><code>3</code></td>
<td><code>6</code></td>
<td>When zooming out, the font will be drawn smaller. This defines a lower limit for when the font is drawn.
When using font scaling, you can use this together with the maxVisible to first show labels of important
nodes when zoomed out and only show the rest when zooming in.

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

@ -32,52 +32,7 @@
function draw() {
destroy();
nodes = [];
edges = [];
var connectionCount = [];
// randomly create some nodes and edges
var nodeCount = document.getElementById('nodeCount').value;
for (var i = 0; i < nodeCount; i++) {
nodes.push({
id: i,
label: String(i)
});
connectionCount[i] = 0;
// create edges in a scale-free-network way
if (i == 1) {
var from = i;
var to = 0;
edges.push({
from: from,
to: to
});
connectionCount[from]++;
connectionCount[to]++;
}
else if (i > 1) {
var conn = edges.length * 2;
var rand = Math.floor(Math.random() * conn);
var cum = 0;
var j = 0;
while (j < connectionCount.length && cum < rand) {
cum += connectionCount[j];
j++;
}
var from = i;
var to = j;
edges.push({
from: from,
to: to
});
connectionCount[from]++;
connectionCount[to]++;
}
}
// create a network
var container = document.getElementById('mynetwork');
var data = {

+ 140
- 0
examples/network/categories/data/datasets.html View File

@ -0,0 +1,140 @@
<!doctype html>
<html>
<head>
<title>Network | Dynamic Data</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: 400px;
border: 1px solid lightgray;
}
p {
max-width:600px;
}
h4 {
margin-bottom:3px;
}
</style>
</head>
<p>
You can change any settings you want while the network is initialized using the vis Dataset, setOptions and setData. Finally you can destroy the network and completely reinitialize it.
</p>
<h4>DataSet (change the data while it's loaded and initialzed):</h4>
<input type="button" onclick="addNode()" value="add node dynamically"> <br />
<input type="button" onclick="changeNode1()" value="change node 1's color dynamically"> <br />
<input type="button" onclick="removeRandomNode()" value="remove a random Node"> <br />
<input type="button" onclick="resetAllNodes()" value="reload all nodes"> <br />
<input type="button" onclick="resetAllNodesStabilize()" value="reload all nodes and stabilize"> <br />
<h4>setOptions (change the global options):</h4>
<input type="button" onclick="changeOptions()" value="change the global options"><br />
<h4>setData (reinitialize the data): </h4>
<input type="button" onclick="setTheData()" value="setData. This stabilizes again if stabilization is true."><br />
<h4>Cleanly destroy the network and restart it:</h4>
<input type="button" onclick="resetAll()" value="Destroy the network and restart it."><br />
<div id="mynetwork"></div>
<script type="text/javascript">
var nodeIds, shadowState, nodesArray, nodes, edgesArray, edges, network;
function startNetwork() {
// this list is kept to remove a random node.. we do not add node 1 here because it's used for changes
nodeIds = [2, 3, 4, 5];
shadowState = false;
// create an array with nodes
nodesArray = [
{id: 1, label: 'Node 1'},
{id: 2, label: 'Node 2'},
{id: 3, label: 'Node 3'},
{id: 4, label: 'Node 4'},
{id: 5, label: 'Node 5'}
];
nodes = new vis.DataSet(nodesArray);
// create an array with edges
edgesArray = [
{from: 1, to: 3},
{from: 1, to: 2},
{from: 2, to: 4},
{from: 2, to: 5}
];
edges = new vis.DataSet(edgesArray);
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {};
network = new vis.Network(container, data, options);
}
function addNode() {
var newId = (Math.random() * 1e7).toString(32);
nodes.add({id:newId, label:"I'm new!"});
nodeIds.push(newId);
}
function changeNode1() {
var newColor = '#' + Math.floor((Math.random() * 255 * 255 * 255)).toString(16);
nodes.update([{id:1, color:{background:newColor}}]);
}
function removeRandomNode() {
var randomNodeId = nodeIds[Math.floor(Math.random() * nodeIds.length)];
nodes.remove({id:randomNodeId});
var index = nodeIds.indexOf(randomNodeId);
nodeIds.splice(index,1);
}
function changeOptions() {
shadowState = !shadowState;
network.setOptions({nodes:{shadow:shadowState},edges:{shadow:shadowState}});
}
function resetAllNodes() {
nodes.clear();
edges.clear();
nodes.add(nodesArray);
edges.add(edgesArray);
}
function resetAllNodesStabilize() {
resetAllNodes();
network.stabilize();
}
function setTheData() {
nodes = new vis.DataSet(nodesArray);
edges = new vis.DataSet(edgesArray);
network.setData({nodes:nodes, edges:edges})
}
function resetAll() {
if (network !== null) {
network.destroy();
network = null;
}
startNetwork();
}
startNetwork();
</script>
<script src="../../../googleAnalytics.js"></script>
</body>
</html>

+ 3
- 3
examples/network/categories/data/dot_language.html View File

@ -2,9 +2,9 @@
<head>
<title>Network | DOT Language</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<script src="../googleAnalytics.js"></script>
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link href="../../../../dist/vis.css" rel="stylesheet" type="text/css" />
<script src="../../../googleAnalytics.js"></script>
</head>
<body>
<p>

+ 5
- 5
examples/network/categories/data/dynamic_data.html View File

@ -53,8 +53,8 @@
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<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, edges, network;
@ -135,7 +135,7 @@
// create an array with nodes
nodes = new vis.DataSet();
nodes.subscribe('*', function () {
nodes.on('*', function () {
$('#nodes').html(toJSON(nodes.get()));
});
nodes.add([
@ -148,7 +148,7 @@
// create an array with edges
edges = new vis.DataSet();
edges.subscribe('*', function () {
edges.on('*', function () {
$('#edges').html(toJSON(edges.get()));
});
edges.add([
@ -168,7 +168,7 @@
network = new vis.Network(container, data, options);
});
</script>
<script src="../googleAnalytics.js"></script>
<script src="../../../googleAnalytics.js"></script>
</head>
<body>

+ 10
- 19
examples/network/categories/data/importing_from_gephi.html View File

@ -4,6 +4,8 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<title>Dynamic Data - Importing from Gephi (JSON)</title>
<script type="text/javascript" src="../../exampleUtil.js"></script>
<script type="text/javascript" src="../../../../dist/vis.js"></script>
<link type="text/css" rel="stylesheet" href="../../../../dist/vis.css">
@ -92,7 +94,7 @@
var nodeContent = document.getElementById('nodeContent');
loadJSON('../../data/WorldCup2014.json', redrawAll);
loadJSON('../../data/WorldCup2014.json', redrawAll, function(err) {console.log('error')});
var container = document.getElementById('mynetwork');
var data = {
@ -127,6 +129,12 @@
};
network = new vis.Network(container, data, options);
network.on('click', function (params) {
if (params.nodes.length > 0) {
var data = nodes.get(params.nodes[0]); // get the data from selected node
nodeContent.innerHTML = JSON.stringify(data, undefined, 3); // show the data in the div
}
})
/**
* This function fills the DataSets. These DataSets will update the network.
@ -154,28 +162,11 @@
nodes.add(parsed.nodes);
edges.add(parsed.edges);
var data = nodes.get(2); // get the data from node 2
var data = nodes.get(2); // get the data from node 2 as example
nodeContent.innerHTML = JSON.stringify(data,undefined,3); // show the data in the div
network.fit(); // zoom to fit
}
function loadJSON(path, success, error) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
}
else {
error(xhr);
}
}
};
xhr.open('GET', path, true);
xhr.send();
}
</script>

+ 1
- 1
examples/network/categories/data/scaling_nodes_edges.html View File

@ -72,7 +72,7 @@
</head>
<body onload="draw()">
<p>
Scale nodes and edges depending on their value. Hover over nodes and edges to get more information.
Scale nodes and edges depending on their value. Hover over the edges to get a popup with more information.
</p>
<div id="mynetwork"></div>
</body>

+ 70
- 0
examples/network/exampleUtil.js View File

@ -0,0 +1,70 @@
/**
* Created by Alex on 5/20/2015.
*/
function loadJSON(path, success, error) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
success(JSON.parse(xhr.responseText));
}
else {
error(xhr);
}
}
};
xhr.open('GET', path, true);
xhr.send();
}
function getScaleFreeNetwork(nodeCount) {
var nodes = [];
var edges = [];
var connectionCount = [];
// randomly create some nodes and edges
for (var i = 0; i < nodeCount; i++) {
nodes.push({
id: i,
label: String(i)
});
connectionCount[i] = 0;
// create edges in a scale-free-network way
if (i == 1) {
var from = i;
var to = 0;
edges.push({
from: from,
to: to
});
connectionCount[from]++;
connectionCount[to]++;
}
else if (i > 1) {
var conn = edges.length * 2;
var rand = Math.floor(Math.random() * conn);
var cum = 0;
var j = 0;
while (j < connectionCount.length && cum < rand) {
cum += connectionCount[j];
j++;
}
var from = i;
var to = j;
edges.push({
from: from,
to: to
});
connectionCount[from]++;
connectionCount[to]++;
}
}
return {nodes:nodes, edges:edges};
}

+ 4
- 0
lib/network/Network.js View File

@ -169,6 +169,10 @@ Network.prototype.setOptions = function (options) {
this.renderer.setOptions(options.interaction); // options for rendering are in interaction
this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
// reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
if (options.groups !== undefined) {
this.body.emitter.emit("refreshNodes");
}
// these two do not have options at the moment, here for completeness
//this.view.setOptions(options.view);
//this.clustering.setOptions(options.clustering);

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

@ -57,7 +57,7 @@ class EdgesHandler {
min: 14,
max: 30,
maxVisible: 30,
drawThreshold: 3
drawThreshold: 6
},
customScalingFunction: function (min,max,total,value) {
if (max === min) {

+ 3
- 3
lib/network/modules/NodesHandler.js View File

@ -72,7 +72,7 @@ class NodesHandler {
min: 14,
max: 30,
maxVisible: 30,
drawThreshold: 3
drawThreshold: 6
},
customScalingFunction: function (min,max,total,value) {
if (max === min) {
@ -106,7 +106,7 @@ 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.body.emitter.on("destroy", () => {
this.body.emitter.on('destroy', () => {
delete this.body.functions.createNode;
delete this.nodesListeners.add;
delete this.nodesListeners.update;
@ -242,7 +242,7 @@ class NodesHandler {
let data = changedData[i];
if (node !== undefined) {
// update node
node.setOptions(data, this.constants);
node.setOptions(data);
}
else {
dataChanged = true;

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

@ -115,7 +115,7 @@ class Edge {
if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
parentOptions.dashes = newOptions.dashes;
}
else if (allowDeletion === true) {
else if (allowDeletion === true && newOptions.dashes === null) {
parentOptions.dashes = undefined;
delete parentOptions.dashes;
}
@ -126,7 +126,7 @@ class Edge {
if (newOptions.scaling.max !== undefined) {parentOptions.scaling.max = newOptions.scaling.max;}
util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label');
}
else if (allowDeletion === true) {
else if (allowDeletion === true && newOptions.scaling === null) {
parentOptions.scaling = undefined;
delete parentOptions.scaling;
}
@ -148,7 +148,7 @@ class Edge {
throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + JSON.stringify(newOptions.arrows));
}
}
else if (allowDeletion === true) {
else if (allowDeletion === true && newOptions.arrows === null) {
parentOptions.arrows = undefined;
delete parentOptions.arrows;
}
@ -174,7 +174,7 @@ class Edge {
}
}
}
else if (allowDeletion === true) {
else if (allowDeletion === true && newOptions.color === null) {
parentOptions.color = undefined;
delete parentOptions.color;
}

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

@ -111,7 +111,6 @@ class Node {
if (!options) {
return;
}
// basic options
if (options.id !== undefined) {this.id = options.id;}
@ -166,7 +165,7 @@ class Node {
'fixed',
'shadow'
];
util.selectiveNotDeepExtend(fields, parentOptions, newOptions);
util.selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
// merge the shadow options into the parent.
util.mergeOptions(parentOptions, newOptions, 'shadow');
@ -176,7 +175,7 @@ class Node {
let parsedColor = util.parseColor(newOptions.color);
util.fillIfDefined(parentOptions.color, parsedColor);
}
else if (allowDeletion === true) {
else if (allowDeletion === true && newOptions.color === null) {
parentOptions.color = undefined;
delete parentOptions.color;
}

+ 3
- 15
lib/network/modules/components/physics/SpringSolver.js View File

@ -7,8 +7,6 @@ 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
}
/**
@ -58,19 +56,9 @@ class SpringSolver {
* @private
*/
_calculateSpringForce(node1, node2, edgeLength) {
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;
let dx = (node1.x - node2.x);
let dy = (node1.y - node2.y);
let distance = Math.max(Math.sqrt(dx * dx + dy * dy),0.01);
// the 1/distance is so the fx and fy can be calculated without sine or cosine.
let springForce = this.options.springConstant * (edgeLength - distance) / distance;

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

@ -238,7 +238,6 @@ let allOptions = {
springConstant: {number},
nodeDistance: {number},
damping: {number},
avoidOverlap: {number},
__type__: {object}
},
hierarchicalRepulsion: {
@ -446,8 +445,7 @@ let configureOptions = {
springLength: [200, 0, 500, 5],
springConstant: [0.05, 0, 5, 0.005],
nodeDistance: [100, 0, 500, 5],
damping: [0.09, 0, 1, 0.01],
avoidOverlap: [0, 0, 1, 0.01]
damping: [0.09, 0, 1, 0.01]
},
hierarchicalRepulsion: {
centralGravity: [0.2, 0, 10, 0.05],

+ 22
- 14
lib/util.js View File

@ -126,6 +126,8 @@ exports.fillIfDefined = function (a, b, allowDeletion = false) {
}
}
/**
* Extend object a with the properties of object b or a series of objects
* Only properties with defined values are copied
@ -214,7 +216,7 @@ exports.selectiveDeepExtend = function (props, a, b, allowDeletion = false) {
exports.deepExtend(a[prop], b[prop], false, allowDeletion);
}
else {
if ((b[prop] === undefined || b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
if ((b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
delete a[prop];
}
else {
@ -257,7 +259,7 @@ exports.selectiveNotDeepExtend = function (props, a, b, allowDeletion = false) {
exports.deepExtend(a[prop], b[prop]);
}
else {
if ((b[prop] === undefined || b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
if ((b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
delete a[prop];
}
else {
@ -281,7 +283,7 @@ exports.selectiveNotDeepExtend = function (props, a, b, allowDeletion = false) {
* @param {Object} b
* @param [Boolean] protoExtend --> optional parameter. If true, the prototype values will also be extended.
* (ie. the options objects that inherit from others will also get the inherited options)
* @param [Boolean] global --> optional parameter. If true, the values of fields that are undefined or null will not deleted
* @param [Boolean] global --> optional parameter. If true, the values of fields that are null will not deleted
* @returns {Object}
*/
exports.deepExtend = function(a, b, protoExtend, allowDeletion) {
@ -295,7 +297,7 @@ exports.deepExtend = function(a, b, protoExtend, allowDeletion) {
exports.deepExtend(a[prop], b[prop], protoExtend);
}
else {
if ((b[prop] === undefined || b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
if ((b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
delete a[prop];
}
else {
@ -1209,16 +1211,22 @@ exports.bridgeObject = function(referenceObject) {
* @param [String] option | this is the option key in the options argument
* @private
*/
exports.mergeOptions = function (mergeTarget, options, option) {
if (options[option] !== undefined) {
if (typeof options[option] == 'boolean') {
mergeTarget[option].enabled = options[option];
}
else {
mergeTarget[option].enabled = true;
for (var prop in options[option]) {
if (options[option].hasOwnProperty(prop)) {
mergeTarget[option][prop] = options[option][prop];
exports.mergeOptions = function (mergeTarget, options, option, allowDeletion = false) {
if (options[option] === null) {
mergeTarget[option] = undefined;
delete mergeTarget[option];
}
else {
if (options[option] !== undefined) {
if (typeof options[option] == 'boolean') {
mergeTarget[option].enabled = options[option];
}
else {
mergeTarget[option].enabled = true;
for (var prop in options[option]) {
if (options[option].hasOwnProperty(prop)) {
mergeTarget[option][prop] = options[option][prop];
}
}
}
}

Loading…
Cancel
Save