Browse Source

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

Conflicts:
	dist/vis-light.js
v3_develop
jos 10 years ago
parent
commit
cd2483bc88
10 changed files with 8889 additions and 8610 deletions
  1. +8
    -0
      HISTORY.md
  2. +8624
    -8537
      dist/vis.js
  3. +79
    -0
      docs/network.html
  4. +2
    -1
      examples/network/29_neighbourhood_highlight.html
  5. +122
    -43
      examples/network/30_importing_from_gephi.html
  6. +2
    -0
      examples/network/index.html
  7. +2
    -1
      index.js
  8. +18
    -6
      lib/network/Network.js
  9. +23
    -22
      lib/network/gephiParser.js
  10. +9
    -0
      lib/util.js

+ 8
- 0
HISTORY.md View File

@ -35,6 +35,14 @@ http://visjs.org
- Added borderWidth option for nodes. - Added borderWidth option for nodes.
- Implemented new Hierarchical view solver. - Implemented new Hierarchical view solver.
- Fixed an issue with selecting nodes when the web page is scrolled down. - Fixed an issue with selecting nodes when the web page is scrolled down.
- Added Gephi JSON parser
- Added Neighbour Highlight example
- Added Import From Gephi example
- Enabled color parsing for nodes when supplied with rgb(xxx,xxx,xxx) value.
### DataSet
- Added .get() returnType option to return as JSON object, Array or Google DataTable.

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


+ 79
- 0
docs/network.html View File

@ -54,6 +54,7 @@
<li><a href="#Nodes">Nodes</a></li> <li><a href="#Nodes">Nodes</a></li>
<li><a href="#Edges">Edges</a></li> <li><a href="#Edges">Edges</a></li>
<li><a href="#DOT_language">DOT language</a></li> <li><a href="#DOT_language">DOT language</a></li>
<li><a href="#Gephi_import">Gephi import</a></li>
</ul> </ul>
</li> </li>
<li> <li>
@ -759,7 +760,85 @@ var data = {
var network = new vis.Network(container, data); var network = new vis.Network(container, data);
</pre> </pre>
<h3 id="Gephi_import">Gephi import (JSON)</h3>
<p>
network can import data straight from an exported json file from gephi. You can get the JSON exporter here:
<a href="https://marketplace.gephi.org/plugin/json-exporter/" target="_blank">https://marketplace.gephi.org/plugin/json-exporter/</a>.
An example exists showing how to get a JSON file into Vis: <a href="../examples/Network/30_importing_from_gephi.html">30_importing_from_gephi</a>.
</p>
<p>
Example usage:
</p>
<pre class="prettyprint lang-js">
// load the JSON file containing the Gephi network.
var gephiJSON = loadJSON("./data/WorldCup2014.json"); // code in example 30
// create a data object with the gephi key:
var data = {
gephi: gephiJSON
};
// create a network
var network = new vis.Network(container, data);
</pre>
Alternatively you can use the parser manually:
<pre class="prettyprint lang-js">
// load the JSON file containing the Gephi network.
var gephiJSON = loadJSON("./data/WorldCup2014.json"); // code in example 30
// parse the gephi file to receive an object
// containing nodes and edges in vis format.
var parsed = vis.network.gephiParser.parseGephi(gephiJSON);
// provide data in the normal fashion
var data = {
nodes: parsed.nodes,
edged: parsed.edges
};
// create a network
var network = new vis.Network(container, data);
</pre>
<h4>Gephi parser options</h4>
There are a few options you can use to tell Vis what to do with the data from Gephi.
<pre class="prettyprint lang-js">
var parserOptions = {
allowedToMove: false,
parseColor: false
}
var parsed = vis.network.gephiParser.parseGephi(gephiJSON, parserOptions);
</pre>
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
<tr>
<td>allowedToMove</td>
<td>Boolean</td>
<td>false</td>
<td>
If true, the nodes will move according to the physics model after import. If false, the nodes do not move at all.
</td>
</tr>
<tr>
<td>parseColor</td>
<td>Boolean</td>
<td>false</td>
<td>
If true, the color will be parsed by the vis parser, generating extra colors for the borders, highlighs and hover. If false, the node will be the supplied color.
</td>
</tr>
</table>
<h2 id="Configuration_options">Configuration options</h2> <h2 id="Configuration_options">Configuration options</h2>

+ 2
- 1
examples/network/29_neighbourhood_highlight.html View File

@ -18,10 +18,11 @@
<body> <body>
<h2>Dynamic Data - Neighbourhood Highlight</h2> <h2>Dynamic Data - Neighbourhood Highlight</h2>
<div style="width:700px; font-size:14px;">
<div style="width:800px; font-size:14px;">
This example shows the power of the DataSet. Once a node is clicked, all nodes are greyed out except for the first and second order connected nodes. This example shows the power of the DataSet. Once a node is clicked, all nodes are greyed out except for the first and second order connected nodes.
In this example we show how you can determine the order of connection per node as well as applying individual styling to the nodes based on whether or not In this example we show how you can determine the order of connection per node as well as applying individual styling to the nodes based on whether or not
they are connected to the selected node. The code doing the highlighting only takes about 20ms, the rest of the time is the redrawing of the network (9200 edges..). they are connected to the selected node. The code doing the highlighting only takes about 20ms, the rest of the time is the redrawing of the network (9200 edges..).
<br /><br />
</div> </div>
<div id="mynetwork"></div> <div id="mynetwork"></div>

+ 122
- 43
examples/network/30_importing_from_gephi.html View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- saved from url=(0044)http://kenedict.com/networks/worldcup14/vis/ , thanks Andre!--> <!-- saved from url=(0044)http://kenedict.com/networks/worldcup14/vis/ , thanks Andre!-->
<html><head><meta http-equiv="content-type" content="text/html; charset=UTF8"> <html><head><meta http-equiv="content-type" content="text/html; charset=UTF8">
<title>Network | Static smooth curves - World Cup Network</title>
<title>Dynamic Data - Importing from Gephi (JSON)</title>
<script type="text/javascript" src="../../dist/vis.js"></script> <script type="text/javascript" src="../../dist/vis.js"></script>
<link type="text/css" rel="stylesheet" href="../../dist/vis.css"> <link type="text/css" rel="stylesheet" href="../../dist/vis.css">
@ -12,74 +11,154 @@
height: 800px; height: 800px;
border: 1px solid lightgray; border: 1px solid lightgray;
} }
div.nodeContent {
position: relative;
border: 1px solid lightgray;
width:480px;
height:780px;
margin-top: -802px;
margin-left: 810px;
padding:10px;
}
pre {padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
</style> </style>
</head> </head>
<body> <body>
<h2>Dynamic Data - Neighbourhood Highlight</h2>
<h2>Dynamic Data - Importing from Gephi (JSON)</h2>
<div style="width:700px; font-size:14px;"> <div style="width:700px; font-size:14px;">
This example shows the power of the DataSet. Once a node is clicked, all nodes are greyed out except for the first and second order connected nodes.
In this example we show how you can determine the order of connection per node as well as applying individual styling to the nodes based on whether or not
they are connected to the selected node. The code doing the highlighting only takes about 20ms, the rest of the time is the redrawing of the network (9200 edges..).
This example shows how to import a JSON file exported by Gephi. The two options available for the import are
available through the checkboxes. You can download the Gephi JSON exporter here:
<a href="https://marketplace.gephi.org/plugin/json-exporter/" target="_blank">https://marketplace.gephi.org/plugin/json-exporter/</a>.
All of Gephi's attributes are also contained within the node elements. This means you can access all of this data through the DataSet.
<br />
</div> </div>
<input type="checkbox" id="allowedToMove">: Allow to move after import. <br/>
<input type="checkbox" id="parseColor">: Parse the color instead of copy (adds borders, highlights etc.)
<div id="mynetwork"></div> <div id="mynetwork"></div>
<div class="nodeContent"><h4>Node Content:</h4> <pre id="nodeContent"></pre></div>
<script type="text/javascript"> <script type="text/javascript">
var network; var network;
var nodes = new vis.DataSet(); var nodes = new vis.DataSet();
var edges = new vis.DataSet(); var edges = new vis.DataSet();
var gephiImported;
var allowedToMoveCheckbox = document.getElementById("allowedToMove");
allowedToMoveCheckbox.onchange = redrawAll;
var parseColorCheckbox = document.getElementById("parseColor");
parseColorCheckbox.onchange = redrawAll;
var nodeContent = document.getElementById("nodeContent");
loadJSON("./data/WorldCup2014.json",redrawAll);
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
shape: 'dot',
fontFace: "Tahoma"
},
edges: {
width: 0.15,
inheritColor: "from"
},
tooltip: {
delay: 200,
fontSize: 12,
color: {
background: "#fff"
}
},
smoothCurves: {dynamic:false, type: "continuous"},
stabilize: false,
physics: {barnesHut: {gravitationalConstant: -10000, springConstant: 0.002, springLength: 150}},
hideEdgesOnDrag: true
};
network = new vis.Network(container, data, options);
/**
* This function fills the DataSets. These DataSets will update the network.
*/
function redrawAll(gephiJSON) {
if (gephiJSON.nodes === undefined) {
gephiJSON = gephiImported;
}
else {
gephiImported = gephiJSON;
}
function redrawAll() {
nodes.clear(); nodes.clear();
edges.clear(); edges.clear();
network = null;
// create an array with nodes
var allowedToMove = allowedToMoveCheckbox.checked;
var parseColor = parseColorCheckbox.checked;
var parsed = vis.network.gephiParser.parseGephi(gephiJSON, {allowedToMove:allowedToMove, parseColor:parseColor});
// add the parsed data to the DataSets.
nodes.add(parsed.nodes);
edges.add(parsed.edges);
var data = nodes.get(2); // get the data from node 2
nodeContent.innerHTML = syntaxHighlight(data); // show the data in the div
network.zoomExtent(); // zoom to fit
}
nodes.add(nodesData);
edges.add(edgesData);
// from http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript
function syntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {
nodes: {
shape: 'dot',
radiusMin: 10,
radiusMax: 30,
fontSize: 12,
fontFace: "Tahoma"
},
edges: {
width: 0.15,
inheritColor: "from"
},
tooltip: {
delay: 200,
fontSize: 12,
color: {
background: "#fff"
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);
} }
},
smoothCurves: {dynamic:false, type: "continuous"},
stabilize: false,
physics: {barnesHut: {gravitationalConstant: 0, centralGravity: 0, springConstant: 0}},
hideEdgesOnDrag: true
}
}; };
network = new vis.Network(container, data, options);
xhr.open("GET", path, true);
xhr.send();
} }
redrawAll()
</script> </script>

+ 2
- 0
examples/network/index.html View File

@ -40,6 +40,8 @@
<p><a href="26_staticSmoothCurves.html">26_staticSmoothCurves.html</a></p> <p><a href="26_staticSmoothCurves.html">26_staticSmoothCurves.html</a></p>
<p><a href="27_world_cup_network.html">27_world_cup_network.html</a></p> <p><a href="27_world_cup_network.html">27_world_cup_network.html</a></p>
<p><a href="28_world_cup_network_performance.html">28_world_cup_network_performance.html</a></p> <p><a href="28_world_cup_network_performance.html">28_world_cup_network_performance.html</a></p>
<p><a href="29_neighbourhood_highlight.html">29_neighbourhood_highlight.html</a></p>
<p><a href="30_importing_from_gephi.html">30_importing_from_gephi.html</a></p>
<p><a href="graphviz/graphviz_gallery.html">graphviz_gallery.html</a></p> <p><a href="graphviz/graphviz_gallery.html">graphviz_gallery.html</a></p>
</div> </div>

+ 2
- 1
index.js View File

@ -55,7 +55,8 @@ exports.network = {
Images: require('./lib/network/Images'), Images: require('./lib/network/Images'),
Node: require('./lib/network/Node'), Node: require('./lib/network/Node'),
Popup: require('./lib/network/Popup'), Popup: require('./lib/network/Popup'),
dotparser: require('./lib/network/dotparser')
dotparser: require('./lib/network/dotparser'),
gephiParser: require('./lib/network/gephiParser')
}; };
// Deprecated since v3.0.0 // Deprecated since v3.0.0

+ 18
- 6
lib/network/Network.js View File

@ -6,6 +6,7 @@ var hammerUtil = require('../hammerUtil');
var DataSet = require('../DataSet'); var DataSet = require('../DataSet');
var DataView = require('../DataView'); var DataView = require('../DataView');
var dotparser = require('./dotparser'); var dotparser = require('./dotparser');
var gephiParser = require('./gephiParser');
var Groups = require('./Groups'); var Groups = require('./Groups');
var Images = require('./Images'); var Images = require('./Images');
var Node = require('./Node'); var Node = require('./Node');
@ -503,6 +504,7 @@ Network.prototype._updateNodeIndexList = function() {
* {Array | DataSet | DataView} [nodes] Array with nodes * {Array | DataSet | DataView} [nodes] Array with nodes
* {Array | DataSet | DataView} [edges] Array with edges * {Array | DataSet | DataView} [edges] Array with edges
* {String} [dot] String containing data in DOT format * {String} [dot] String containing data in DOT format
* {String} [gephi] String containing data in gephi JSON format
* {Options} [options] Object with options * {Options} [options] Object with options
* @param {Boolean} [disableStart] | optional: disable the calling of the start function. * @param {Boolean} [disableStart] | optional: disable the calling of the start function.
*/ */
@ -528,6 +530,14 @@ Network.prototype.setData = function(data, disableStart) {
return; return;
} }
} }
else if (data && data.gephi) {
// parse DOT file
if(data && data.gephi) {
var gephiData = gephiParser.parseGephi(data.gephi);
this.setData(gephiData);
return;
}
}
else { else {
this._setNodes(data && data.nodes); this._setNodes(data && data.nodes);
this._setEdges(data && data.edges); this._setEdges(data && data.edges);
@ -1064,7 +1074,7 @@ Network.prototype._handleOnDrag = function(event) {
Network.prototype._onDragEnd = function () { Network.prototype._onDragEnd = function () {
this.drag.dragging = false; this.drag.dragging = false;
var selection = this.drag.selection; var selection = this.drag.selection;
if (selection) {
if (selection && selection.length) {
selection.forEach(function (s) { selection.forEach(function (s) {
// restore original xFixed and yFixed // restore original xFixed and yFixed
s.node.xFixed = s.xFixed; s.node.xFixed = s.xFixed;
@ -1073,7 +1083,10 @@ Network.prototype._onDragEnd = function () {
this.moving = true; this.moving = true;
this.start(); this.start();
} }
this._redraw();
else {
this._redraw();
}
}; };
/** /**
@ -2124,10 +2137,10 @@ Network.prototype._discreteStepNodes = function() {
*/ */
Network.prototype._physicsTick = function() { Network.prototype._physicsTick = function() {
if (!this.freezeSimulation) { if (!this.freezeSimulation) {
if (this.moving) {
if (this.moving == true) {
this._doInAllActiveSectors("_initializeForceCalculation"); this._doInAllActiveSectors("_initializeForceCalculation");
this._doInAllActiveSectors("_discreteStepNodes"); this._doInAllActiveSectors("_discreteStepNodes");
if (this.constants.smoothCurves) {
if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) {
this._doInSupportSector("_discreteStepNodes"); this._doInSupportSector("_discreteStepNodes");
} }
this._findCenter(this._getRange()) this._findCenter(this._getRange())
@ -2161,7 +2174,6 @@ Network.prototype._animationStep = function() {
timeRequired = Date.now() - calculationTime; timeRequired = Date.now() - calculationTime;
maxSteps++; maxSteps++;
} }
// start the rendering process // start the rendering process
var renderTime = Date.now(); var renderTime = Date.now();
this._redraw(); this._redraw();
@ -2178,7 +2190,7 @@ if (typeof window !== 'undefined') {
* Schedule a animation step with the refreshrate interval. * Schedule a animation step with the refreshrate interval.
*/ */
Network.prototype.start = function() { Network.prototype.start = function() {
if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) {
if (this.moving == true || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) {
if (!this.timer) { if (!this.timer) {
var ua = navigator.userAgent.toLowerCase(); var ua = navigator.userAgent.toLowerCase();

+ 23
- 22
lib/network/gephiParser.js View File

@ -4,52 +4,53 @@ function parseGephi(gephiJSON, options) {
var nodes = []; var nodes = [];
this.options = { this.options = {
edges: { edges: {
inheritColor: 'from'
inheritColor: true
}, },
nodes: { nodes: {
allowedToMove: false, allowedToMove: false,
parseColor: false parseColor: false
} }
}; };
if (options !== undefined) { if (options !== undefined) {
this.options.edges['inheritColor'] = options.inheritColor | 'from';
this.options.nodes['allowedToMove'] = options.allowedToMove | false; this.options.nodes['allowedToMove'] = options.allowedToMove | false;
this.options.nodes['parseColor'] = options.parseColor | false; this.options.nodes['parseColor'] = options.parseColor | false;
this.options.edges['inheritColor'] = options.inheritColor | true;
} }
var gEdges = gephiJSON.edges; var gEdges = gephiJSON.edges;
var gNodes = gephiJSON.nodes; var gNodes = gephiJSON.nodes;
for (var i = 0; i < gEdges.length; i++) { for (var i = 0; i < gEdges.length; i++) {
var edge = {}; var edge = {};
edge['id'] = gEdges.id;
edge['from'] = gEdges.source;
edge['to'] = gEdges.target;
edge['attributes'] = gEdges.attributes;
edge['value'] = gEdges.attributes !== undefined ? gEdges.attributes.Weight : undefined;
edge['width'] = gEdges.size;
edge['color'] = gEdges.color;
var gEdge = gEdges[i];
edge['id'] = gEdge.id;
edge['from'] = gEdge.source;
edge['to'] = gEdge.target;
edge['attributes'] = gEdge.attributes;
// edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined;
// edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size;
edge['color'] = gEdge.color;
edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor; edge['inheritColor'] = edge['color'] !== undefined ? false : this.options.inheritColor;
edges.push(edge); edges.push(edge);
} }
for (var i = 0; i < gNodes.length; i++) { for (var i = 0; i < gNodes.length; i++) {
var node = {}; var node = {};
node['id'] = gNodes.id;
node['attributes'] = gNodes.attributes;
node['x'] = gNodes.x;
node['y'] = gNodes.y;
node['label'] = gNodes.label;
if (this.options.parseColor == true) {
node['color'] = gNodes.color;
var gNode = gNodes[i];
node['id'] = gNode.id;
node['attributes'] = gNode.attributes;
node['x'] = gNode.x;
node['y'] = gNode.y;
node['label'] = gNode.label;
if (this.options.nodes.parseColor == true) {
node['color'] = gNode.color;
} }
else { else {
node['color'] = gNodes.color !== undefined ? {background:gNodes.color, border:gNodes.color} : undefined;
node['color'] = gNode.color !== undefined ? {background:gNode.color, border:gNode.color} : undefined;
} }
node['radius'] = gNodes.size;
node['allowedToMoveX'] = this.options.allowedToMove;
node['allowedToMoveY'] = this.options.allowedToMove;
node['shape'] = 'dot'
node['radius'] = gNode.size;
node['allowedToMoveX'] = this.options.nodes.allowedToMove;
node['allowedToMoveY'] = this.options.nodes.allowedToMove;
nodes.push(node); nodes.push(node);
} }

+ 9
- 0
lib/util.js View File

@ -753,6 +753,10 @@ exports.GiveHex = function(Dec) {
exports.parseColor = function(color) { exports.parseColor = function(color) {
var c; var c;
if (exports.isString(color)) { if (exports.isString(color)) {
if (exports.isValidRGB(color)) {
var rgb = color.substr(4).substr(0,color.length-5).split(',');
color = exports.RGBToHex(rgb[0],rgb[1],rgb[2]);
}
if (exports.isValidHex(color)) { if (exports.isValidHex(color)) {
var hsv = exports.hexToHSV(color); var hsv = exports.hexToHSV(color);
var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)}; var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)};
@ -930,6 +934,11 @@ exports.isValidHex = function(hex) {
return isOk; return isOk;
}; };
exports.isValidRGB = function(rgb) {
rgb = rgb.replace(" ","");
var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb);
return isOk;
}
/** /**
* This recursively redirects the prototype of JSON objects to the referenceObject * This recursively redirects the prototype of JSON objects to the referenceObject

Loading…
Cancel
Save