Browse Source

Fixed #1087, updated history

flowchartTest
Alex de Mulder 9 years ago
parent
commit
4ef684af2e
6 changed files with 211 additions and 115 deletions
  1. +6
    -0
      HISTORY.md
  2. +66
    -29
      dist/vis.js
  3. +5
    -0
      lib/network/modules/LayoutEngine.js
  4. +1
    -1
      lib/network/modules/NodesHandler.js
  5. +9
    -2
      lib/network/modules/components/Node.js
  6. +124
    -83
      test/networkTest.html

+ 6
- 0
HISTORY.md View File

@ -3,11 +3,17 @@ http://visjs.org
## not yet released, version 4.4.1-SNAPSHOT ## not yet released, version 4.4.1-SNAPSHOT
### General
- Docs have been greatly improved thanks to @felixhayashi! Thanks a lot!
### Network ### Network
- Properly fixed the _lockedRedraw method. - Properly fixed the _lockedRedraw method.
- Fixed node resizing on dragging. - Fixed node resizing on dragging.
- Added shapeProperties, thanks @zukomgwili! - Added shapeProperties, thanks @zukomgwili!
- Fixed missing edges during clustering.
- Fixed missing refresh of node data when changing hierarchical layout on the fly.
### Graph3d ### Graph3d

+ 66
- 29
dist/vis.js View File

@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library. * A dynamic, browser-based visualization library.
* *
* @version 4.4.1-SNAPSHOT * @version 4.4.1-SNAPSHOT
* @date 2015-07-10
* @date 2015-07-16
* *
* @license * @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com * Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -13994,7 +13994,7 @@ return /******/ (function(modules) { // webpackBootstrap
Range.prototype.setOptions = function (options) { Range.prototype.setOptions = function (options) {
if (options) { if (options) {
// copy the options that we know // copy the options that we know
var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates'];
var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'activate', 'hiddenDates', 'zoomKey'];
util.selectiveExtend(fields, this.options, options); util.selectiveExtend(fields, this.options, options);
if ('start' in options || 'end' in options) { if ('start' in options || 'end' in options) {
@ -14384,6 +14384,9 @@ return /******/ (function(modules) { // webpackBootstrap
// only zoom when the mouse is inside the current range // only zoom when the mouse is inside the current range
if (!this._isInsideRange(event)) return; if (!this._isInsideRange(event)) return;
// only zoom when the according key is pressed and the zoomKey option is set
if (this.options.zoomKey && !event[this.options.zoomKey]) return;
// retrieve delta // retrieve delta
var delta = 0; var delta = 0;
if (event.wheelDelta) { if (event.wheelDelta) {
@ -18155,6 +18158,11 @@ return /******/ (function(modules) { // webpackBootstrap
if (subgroup) { if (subgroup) {
var itemIndex = subgroup.items.indexOf(item); var itemIndex = subgroup.items.indexOf(item);
subgroup.items.splice(itemIndex, 1); subgroup.items.splice(itemIndex, 1);
if (!subgroup.items.length) {
delete this.subgroups[item.data.subgroup];
this.subgroupIndex--;
}
this.orderSubgroups();
} }
} }
}; };
@ -20202,37 +20210,40 @@ return /******/ (function(modules) { // webpackBootstrap
dom.majorTexts = []; dom.majorTexts = [];
dom.minorTexts = []; dom.minorTexts = [];
var cur;
var x = 0;
var current;
var next;
var x;
var xNext;
var isMajor; var isMajor;
var xPrev = 0;
var width = 0;
var prevLine;
var prevText;
var width;
var line;
var labelMinor;
var xFirstMajorLabel = undefined; var xFirstMajorLabel = undefined;
var max = 0; var max = 0;
var className; var className;
step.first(); step.first();
next = step.getCurrent();
xNext = this.body.util.toScreen(next);
while (step.hasNext() && max < 1000) { while (step.hasNext() && max < 1000) {
max++; max++;
cur = step.getCurrent();
isMajor = step.isMajor(); isMajor = step.isMajor();
className = step.getClassName(); className = step.getClassName();
labelMinor = step.getLabelMinor();
xPrev = x;
x = this.body.util.toScreen(cur);
width = x - xPrev;
if (prevLine) {
prevLine.style.width = width + 'px';
}
if (prevText) {
prevText.style.width = width + 'px';
}
current = next;
x = xNext;
step.next();
next = step.getCurrent();
xNext = this.body.util.toScreen(next);
width = xNext - x;
var labelFits = labelMinor.length * this.props.minorCharWidth < width;
if (this.options.showMinorLabels) {
prevText = this._repaintMinorText(x, step.getLabelMinor(), orientation, className);
if (this.options.showMinorLabels && labelFits) {
this._repaintMinorText(x, labelMinor, orientation, className);
} }
if (isMajor && this.options.showMajorLabels) { if (isMajor && this.options.showMajorLabels) {
@ -20242,12 +20253,16 @@ return /******/ (function(modules) { // webpackBootstrap
} }
this._repaintMajorText(x, step.getLabelMajor(), orientation, className); this._repaintMajorText(x, step.getLabelMajor(), orientation, className);
} }
prevLine = this._repaintMajorLine(x, orientation, className);
line = this._repaintMajorLine(x, width, orientation, className);
} else { } else {
prevLine = this._repaintMinorLine(x, orientation, className);
if (labelFits) {
line = this._repaintMinorLine(x, width, orientation, className);
} else {
if (line) {
line.style.width = parseInt(line.style.width) + width + 'px';
}
}
} }
step.next();
} }
// create a major label on the left when needed // create a major label on the left when needed
@ -20339,12 +20354,13 @@ return /******/ (function(modules) { // webpackBootstrap
/** /**
* Create a minor line for the axis at position x * Create a minor line for the axis at position x
* @param {Number} x * @param {Number} x
* @param {Number} width
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @param {String} className * @param {String} className
* @return {Element} Returns the created line * @return {Element} Returns the created line
* @private * @private
*/ */
TimeAxis.prototype._repaintMinorLine = function (x, orientation, className) {
TimeAxis.prototype._repaintMinorLine = function (x, width, orientation, className) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.lines.shift(); var line = this.dom.redundant.lines.shift();
if (!line) { if (!line) {
@ -20362,6 +20378,7 @@ return /******/ (function(modules) { // webpackBootstrap
} }
line.style.height = props.minorLineHeight + 'px'; line.style.height = props.minorLineHeight + 'px';
line.style.left = x - props.minorLineWidth / 2 + 'px'; line.style.left = x - props.minorLineWidth / 2 + 'px';
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-minor ' + className; line.className = 'vis-grid vis-vertical vis-minor ' + className;
@ -20371,12 +20388,13 @@ return /******/ (function(modules) { // webpackBootstrap
/** /**
* Create a Major line for the axis at position x * Create a Major line for the axis at position x
* @param {Number} x * @param {Number} x
* @param {Number} width
* @param {String} orientation "top" or "bottom" (default) * @param {String} orientation "top" or "bottom" (default)
* @param {String} className * @param {String} className
* @return {Element} Returns the created line * @return {Element} Returns the created line
* @private * @private
*/ */
TimeAxis.prototype._repaintMajorLine = function (x, orientation, className) {
TimeAxis.prototype._repaintMajorLine = function (x, width, orientation, className) {
// reuse redundant line // reuse redundant line
var line = this.dom.redundant.lines.shift(); var line = this.dom.redundant.lines.shift();
if (!line) { if (!line) {
@ -20394,6 +20412,7 @@ return /******/ (function(modules) { // webpackBootstrap
} }
line.style.left = x - props.majorLineWidth / 2 + 'px'; line.style.left = x - props.majorLineWidth / 2 + 'px';
line.style.height = props.majorLineHeight + 'px'; line.style.height = props.majorLineHeight + 'px';
line.style.width = width + 'px';
line.className = 'vis-grid vis-vertical vis-major ' + className; line.className = 'vis-grid vis-vertical vis-major ' + className;
@ -22750,6 +22769,7 @@ return /******/ (function(modules) { // webpackBootstrap
type: { string: string }, type: { string: string },
width: { string: string, number: number }, width: { string: string, number: number },
zoomable: { boolean: boolean }, zoomable: { boolean: boolean },
zoomKey: { string: ['ctrlKey', 'altKey', 'metaKey', ''] },
zoomMax: { number: number }, zoomMax: { number: number },
zoomMin: { number: number }, zoomMin: { number: number },
@ -22834,6 +22854,7 @@ return /******/ (function(modules) { // webpackBootstrap
type: ['box', 'point', 'range', 'background'], type: ['box', 'point', 'range', 'background'],
width: '100%', width: '100%',
zoomable: true, zoomable: true,
zoomKey: ['ctrlKey', 'altKey', 'metaKey', ''],
zoomMax: [315360000000000, 10, 315360000000000, 1], zoomMax: [315360000000000, 10, 315360000000000, 1],
zoomMin: [10, 10, 315360000000000, 1] zoomMin: [10, 10, 315360000000000, 1]
} }
@ -26191,6 +26212,7 @@ return /******/ (function(modules) { // webpackBootstrap
}, },
width: { string: string, number: number }, width: { string: string, number: number },
zoomable: { boolean: boolean }, zoomable: { boolean: boolean },
zoomKey: { string: ['ctrlKey', 'altKey', 'metaKey', ''] },
zoomMax: { number: number }, zoomMax: { number: number },
zoomMin: { number: number }, zoomMin: { number: number },
__type__: { object: object } __type__: { object: object }
@ -26292,6 +26314,7 @@ return /******/ (function(modules) { // webpackBootstrap
start: '', start: '',
width: '100%', width: '100%',
zoomable: true, zoomable: true,
zoomKey: ['ctrlKey', 'altKey', 'metaKey', ''],
zoomMax: [315360000000000, 10, 315360000000000, 1], zoomMax: [315360000000000, 10, 315360000000000, 1],
zoomMin: [10, 10, 315360000000000, 1] zoomMin: [10, 10, 315360000000000, 1]
} }
@ -27408,7 +27431,7 @@ return /******/ (function(modules) { // webpackBootstrap
} }
var data = this.body.data.nodes._data[nodeId]; var data = this.body.data.nodes._data[nodeId];
if (node !== undefined && data !== undefined) { if (node !== undefined && data !== undefined) {
node.setOptions({ fixed: false });
node.setOptions({ fixed: false, x: null, y: null });
node.setOptions(data); node.setOptions(data);
} }
} }
@ -27733,11 +27756,20 @@ return /******/ (function(modules) { // webpackBootstrap
} }
// set these options locally // set these options locally
// clear x and y positions
if (options.x !== undefined) { if (options.x !== undefined) {
this.x = parseInt(options.x);this.predefinedPosition = true;
if (options.x === null) {
this.x = undefined;this.predefinedPosition = false;
} else {
this.x = parseInt(options.x);this.predefinedPosition = true;
}
} }
if (options.y !== undefined) { if (options.y !== undefined) {
this.y = parseInt(options.y);this.predefinedPosition = true;
if (options.y === null) {
this.y = undefined;this.predefinedPosition = false;
} else {
this.y = parseInt(options.y);this.predefinedPosition = true;
}
} }
if (options.size !== undefined) { if (options.size !== undefined) {
this.baseSize = options.size; this.baseSize = options.size;
@ -37934,6 +37966,11 @@ return /******/ (function(modules) { // webpackBootstrap
} }
if (this.options.hierarchical.enabled === true) { if (this.options.hierarchical.enabled === true) {
if (prevHierarchicalState === true) {
// refresh the overridden options for nodes and edges.
this.body.emitter.emit('refresh');
}
// 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) {

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

@ -46,6 +46,11 @@ class LayoutEngine {
} }
if (this.options.hierarchical.enabled === true) { if (this.options.hierarchical.enabled === true) {
if (prevHierarchicalState === true) {
// refresh the overridden options for nodes and edges.
this.body.emitter.emit('refresh');
}
// 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) {

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

@ -299,7 +299,7 @@ class NodesHandler {
} }
let data = this.body.data.nodes._data[nodeId]; let data = this.body.data.nodes._data[nodeId];
if (node !== undefined && data !== undefined) { if (node !== undefined && data !== undefined) {
node.setOptions({ fixed: false });
node.setOptions({ fixed: false, x:null, y:null });
node.setOptions(data); node.setOptions(data);
} }
} }

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

@ -120,8 +120,15 @@ class Node {
// set these options locally // set these options locally
if (options.x !== undefined) {this.x = parseInt(options.x); this.predefinedPosition = true;}
if (options.y !== undefined) {this.y = parseInt(options.y); this.predefinedPosition = true;}
// clear x and y positions
if (options.x !== undefined) {
if (options.x === null) {this.x = undefined; this.predefinedPosition = false;}
else {this.x = parseInt(options.x); this.predefinedPosition = true;}
}
if (options.y !== undefined) {
if (options.y === null) {this.y = undefined; this.predefinedPosition = false;}
else {this.y = parseInt(options.y); this.predefinedPosition = true;}
}
if (options.size !== undefined) {this.baseSize = options.size;} if (options.size !== undefined) {this.baseSize = options.size;}
if (options.value !== undefined) {options.value = parseFloat(options.value);} if (options.value !== undefined) {options.value = parseFloat(options.value);}

+ 124
- 83
test/networkTest.html View File

@ -1,107 +1,148 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>Network | Clustering</title>
<script type="text/javascript" src="../dist/vis.js"></script>
<title>Network | Hierarchical layout</title>
<style type="text/css"> <style type="text/css">
body {
font: 10pt sans;
}
#mynetwork { #mynetwork {
width: 600px; width: 600px;
height: 600px; height: 600px;
border: 1px solid lightgray; border: 1px solid lightgray;
} }
p {
max-width: 600px;
}
h4 {
margin-bottom: 3px;
}
</style> </style>
</head>
<body>
<script type="text/javascript" src="../dist/vis.js"></script>
<script type="text/javascript">
var nodes = null;
var edges = null;
var network = null;
<div id="mynetwork"></div>
function destroy() {
if (network !== null) {
network.destroy();
network = null;
}
}
<script type="text/javascript">
// create an array with nodes
var nodes = [
{id: 4, label: '4'},
{id: 5, label: '5'},
{id: 7, label: '7'},
{id: 9, label: '9'},
{id: 10, label: '10'},
{id: 101, label: '101'},
{id: 102, label: '102'},
{id: 103, label: '103'}
];
// create an array with edges
var edges = [
{from: 10, to: 4},
{from: 7, to: 5},
{from: 9, to: 7},
{from: 10, to: 9},
{from: 101, to: 102},
{from: 102, to: 103}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {layout: {randomSeed: 8}};
var network = new vis.Network(container, data, options);
function draw() {
destroy();
// randomly create some nodes and edges
var nodeCount = document.getElementById('nodeCount').value;
//var data = getScaleFreeNetwork(nodeCount)
var nodes = [
{id: 4, label: '4'},
{id: 5, label: '5'},
{id: 7, label: '7'},
{id: 9, label: '9'},
{id: 10, label: '10'},
{id: 101, label: '101'},
{id: 102, label: '102'},
{id: 103, label: '103'}
];
// create an array with edges
var edges = [
{from: 10, to: 4},
{from: 7, to: 5},
{from: 9, to: 7},
{from: 10, to: 9},
{from: 101, to: 102},
{from: 102, to: 103}
];
var data = {
nodes: nodes,
edges: edges
};
// create a network
var container = document.getElementById('mynetwork');
var directionInput = document.getElementById("direction").value;
var options = {
interaction: {
navigationButtons: true
},
layout: {
hierarchical: {
direction: directionInput
}
}
};
network = new vis.Network(container, data, options);
// add event listeners
network.on('select', function (params) {
document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes;
});
}
function changeOptions(directionInputValue) {
network.setOptions({
layout: {
hierarchical: {
direction: directionInputValue
}
}
});
}
</script>
</head>
// if we click on a node, we want to open it up!
network.on("selectNode", function (params) {
if (params.nodes.length == 1) {
if (network.isCluster(params.nodes[0]) == true) {
network.openCluster(params.nodes[0])
}
}
});
function a() {
var clusterOptionsByData = {
joinCondition: function (node) {
if (node.id == 4 || node.id == 101)
return true;
return false;
},
clusterNodeProperties: {id: "c1", label: 'c1'}
}
network.cluster(clusterOptionsByData);
<body onload="draw();">
<h2>Hierarchical Layout - Scale-Free-Network</h2>
<div style="width:700px; font-size:14px; text-align: justify;">
This example shows the randomly generated <b>scale-free-network</b> set of nodes and connected edges from example 2.
In this example, hierarchical layout has been enabled and the vertical levels are determined automatically.
</div>
<br/>
<form onsubmit="draw(); return false;">
<label for="nodeCount">Number of nodes:</label>
<input id="nodeCount" type="text" value="25" style="width: 50px;">
<input type="submit" value="Go">
</form>
<p>
<input type="button" id="btn-UD" value="Up-Down">
<input type="button" id="btn-DU" value="Down-Up">
<input type="button" id="btn-LR" value="Left-Right">
<input type="button" id="btn-RL" value="Right-Left">
<input type="hidden" id='direction' value="UD">
</p>
<script language="javascript">
var directionInput = document.getElementById("direction");
var btnUD = document.getElementById("btn-UD");
btnUD.onclick = function () {
directionInput.value = "UD";
changeOptions(directionInput.value);
} }
function b() {
var clusterOptionsByData2 = {
joinCondition: function (node) {
if (node.id == 'c1' || node.id == 5)
return true;
return false;
},
clusterNodeProperties: {id: "c2", label: 'c2'}
}
network.cluster(clusterOptionsByData2);
}
a()
b()
network.openCluster("c2")
var btnDU = document.getElementById("btn-DU");
btnDU.onclick = function () {
directionInput.value = "DU";
changeOptions(directionInput.value);
};
var btnLR = document.getElementById("btn-LR");
btnLR.onclick = function () {
directionInput.value = "LR";
changeOptions(directionInput.value);
};
var btnRL = document.getElementById("btn-RL");
btnRL.onclick = function () {
directionInput.value = "RL";
changeOptions(directionInput.value);
};
</script> </script>
<input type="button" value="a" onclick="a()">
<input type="button" value="b" onclick="b()">
<br>
<div id="mynetwork"></div>
<p id="selection"></p>
</body> </body>
</html> </html>

Loading…
Cancel
Save