Browse Source

- Fixed #1362: Layout of hierarchicaly systems no longer overlaps NODES.

fixDataView
Alex de Mulder 8 years ago
parent
commit
5302f74521
21 changed files with 129 additions and 113 deletions
  1. +1
    -0
      HISTORY.md
  2. BIN
      dist/img/network/acceptDeleteIcon.png
  3. BIN
      dist/img/network/addNodeIcon.png
  4. BIN
      dist/img/network/backIcon.png
  5. BIN
      dist/img/network/connectIcon.png
  6. BIN
      dist/img/network/cross.png
  7. BIN
      dist/img/network/cross2.png
  8. BIN
      dist/img/network/deleteIcon.png
  9. BIN
      dist/img/network/downArrow.png
  10. BIN
      dist/img/network/editIcon.png
  11. BIN
      dist/img/network/leftArrow.png
  12. BIN
      dist/img/network/minus.png
  13. BIN
      dist/img/network/plus.png
  14. BIN
      dist/img/network/rightArrow.png
  15. BIN
      dist/img/network/upArrow.png
  16. BIN
      dist/img/network/zoomExtends.png
  17. BIN
      dist/img/timeline/delete.png
  18. +75
    -44
      dist/vis.js
  19. +4
    -2
      lib/network/modules/LayoutEngine.js
  20. +3
    -6
      lib/network/modules/ManipulationSystem.js
  21. +46
    -61
      test/networkTest.html

+ 1
- 0
HISTORY.md View File

@ -16,6 +16,7 @@ http://visjs.org
- Fixed #1343: Connected edges are now deselected too when deselecting a node.
- Fixed #1398: Support nodes start with the correct positions.
- Fixed #1324: Labels now scale again.
- Fixed #1362: Layout of hierarchicaly systems no longer overlaps NODES.
### Timeline

BIN
dist/img/network/acceptDeleteIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/addNodeIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/backIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/connectIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/cross.png View File

Before After
Width: 7  |  Height: 7  |  Size: 18 KiB

BIN
dist/img/network/cross2.png View File

Before After
Width: 5  |  Height: 5  |  Size: 17 KiB

BIN
dist/img/network/deleteIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/downArrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

BIN
dist/img/network/editIcon.png View File

Before After
Width: 24  |  Height: 24  |  Size: 20 KiB

BIN
dist/img/network/leftArrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

BIN
dist/img/network/minus.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.0 KiB

BIN
dist/img/network/plus.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.2 KiB

BIN
dist/img/network/rightArrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

BIN
dist/img/network/upArrow.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

BIN
dist/img/network/zoomExtends.png View File

Before After
Width: 30  |  Height: 30  |  Size: 4.4 KiB

BIN
dist/img/timeline/delete.png View File

Before After
Width: 16  |  Height: 16  |  Size: 665 B

+ 75
- 44
dist/vis.js View File

@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library.
*
* @version 4.9.1-SNAPSHOT
* @date 2015-11-02
* @date 2015-11-16
*
* @license
* Copyright (C) 2011-2015 Almende B.V, http://almende.com
@ -107,8 +107,9 @@ return /******/ (function(modules) { // webpackBootstrap
exports.Timeline = __webpack_require__(19);
exports.Graph2d = __webpack_require__(49);
exports.timeline = {
DateUtil: __webpack_require__(27),
Core: __webpack_require__(28),
DataStep: __webpack_require__(52),
DateUtil: __webpack_require__(27),
Range: __webpack_require__(24),
stack: __webpack_require__(32),
TimeStep: __webpack_require__(30),
@ -122,13 +123,13 @@ return /******/ (function(modules) { // webpackBootstrap
RangeItem: __webpack_require__(33)
},
BackgroundGroup: __webpack_require__(35),
Component: __webpack_require__(26),
CurrentTime: __webpack_require__(44),
CustomTime: __webpack_require__(42),
DataAxis: __webpack_require__(51),
GraphGroup: __webpack_require__(53),
Group: __webpack_require__(31),
BackgroundGroup: __webpack_require__(35),
ItemSet: __webpack_require__(29),
Legend: __webpack_require__(57),
LineGraph: __webpack_require__(50),
@ -5451,10 +5452,11 @@ return /******/ (function(modules) { // webpackBootstrap
var addOrUpdate = function addOrUpdate(item) {
var id = item[fieldId];
if (me._data[id]) {
var oldData = util.extend({}, me._data[id]);
// update item
id = me._updateItem(item);
updatedIds.push(id);
updatedData.push(item);
updatedData.push(oldData);
} else {
// add new item
id = me._addItem(item);
@ -5478,7 +5480,15 @@ return /******/ (function(modules) { // webpackBootstrap
this._trigger('add', { items: addedIds }, senderId);
}
if (updatedIds.length) {
this._trigger('update', { items: updatedIds, data: updatedData }, senderId);
var props = { items: updatedIds, oldData: updatedData };
// TODO: remove deprecated property 'data' some day
Object.defineProperty(props, 'data', {
'get': (function () {
console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
return this.get(updatedIds);
}).bind(this)
});
this._trigger('update', props, senderId);
}
return addedIds.concat(updatedIds);
@ -5712,7 +5722,7 @@ return /******/ (function(modules) { // webpackBootstrap
var filter = options && options.filter,
type = options && options.type || this._options.type,
data = this._data,
itemIds = Object.key(data),
itemIds = Object.keys(data),
i,
len,
item,
@ -15658,6 +15668,7 @@ return /******/ (function(modules) { // webpackBootstrap
selectable: true,
multiselect: false,
itemsAlwaysDraggable: false,
editable: {
updateTime: false,
@ -15922,7 +15933,7 @@ return /******/ (function(modules) { // webpackBootstrap
ItemSet.prototype.setOptions = function (options) {
if (options) {
// copy all options that we know
var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'itemsAlwaysDraggable', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupOrderSwap'];
util.selectiveExtend(fields, this.options, options);
if ('orientation' in options) {
@ -16766,7 +16777,7 @@ return /******/ (function(modules) { // webpackBootstrap
var me = this;
var props;
if (item && item.selected) {
if (item && (item.selected || this.options.itemsAlwaysDraggable)) {
if (!this.options.editable.updateTime && !this.options.editable.updateGroup && !item.editable) {
return;
@ -16803,7 +16814,9 @@ return /******/ (function(modules) { // webpackBootstrap
var baseGroupIndex = this._getGroupIndex(item.data.group);
this.touchParams.itemProps = this.getSelection().map((function (id) {
var itemsToDrag = this.options.itemsAlwaysDraggable && !item.selected ? [item.id] : this.getSelection();
this.touchParams.itemProps = itemsToDrag.map((function (id) {
var item = me.items[id];
var groupIndex = me._getGroupIndex(item.data.group);
return {
@ -21479,7 +21492,7 @@ return /******/ (function(modules) { // webpackBootstrap
var locale = this.options.locales[this.options.locale];
if (!locale) {
if (!this.warned) {
console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline.html#Localization');
console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
this.warned = true;
}
locale = this.options.locales['en']; // fall back on english when not available
@ -23342,6 +23355,7 @@ return /******/ (function(modules) { // webpackBootstrap
repeat: { string: string },
__type__: { object: object, array: array }
},
itemsAlwaysDraggable: { boolean: boolean },
locale: { string: string },
locales: {
__any__: { any: any },
@ -39159,62 +39173,77 @@ return /******/ (function(modules) { // webpackBootstrap
}
/**
* select zero or more nodes with the option to highlight edges
* @param {Number[] | String[]} selection An array with the ids of the
* selected nodes.
* @param {boolean} [highlightEdges]
* Updates the current selection
* @param {{nodes: Array.<String>, edges: Array.<String>}} Selection
* @param {Object} options Options
*/
}, {
key: "selectNodes",
value: function selectNodes(selection) {
var highlightEdges = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
key: "setSelection",
value: function setSelection(selection) {
var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var i = undefined,
id = undefined;
if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
if (!selection || !selection.nodes && !selection.edges) throw 'Selection must be an object with nodes and/or edges properties';
// first unselect any selected node, if option is true or undefined
if (options.unselectAll || options.unselectAll === undefined) {
this.unselectAll();
}
if (selection.nodes) {
for (i = 0; i < selection.nodes.length; i++) {
id = selection.nodes[i];
// first unselect any selected node
this.unselectAll();
var node = this.body.nodes[id];
if (!node) {
throw new RangeError('Node with id "' + id + '" not found');
}
// don't select edges with it
this.selectObject(node, options.highlightEdges);
}
}
for (i = 0; i < selection.length; i++) {
id = selection[i];
if (selection.edges) {
for (i = 0; i < selection.edges.length; i++) {
id = selection.edges[i];
var node = this.body.nodes[id];
if (!node) {
throw new RangeError('Node with id "' + id + '" not found');
var edge = this.body.edges[id];
if (!edge) {
throw new RangeError('Edge with id "' + id + '" not found');
}
this.selectObject(edge);
}
this.selectObject(node, highlightEdges);
}
this.body.emitter.emit('_requestRedraw');
}
/**
* select zero or more edges
* select zero or more nodes with the option to highlight edges
* @param {Number[] | String[]} selection An array with the ids of the
* selected nodes.
* @param {boolean} [highlightEdges]
*/
}, {
key: "selectEdges",
value: function selectEdges(selection) {
var i = undefined,
id = undefined;
key: "selectNodes",
value: function selectNodes(selection) {
var highlightEdges = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
// first unselect any selected objects
this.unselectAll();
this.setSelection({ nodes: selection }, { highlightEdges: highlightEdges });
}
for (i = 0; i < selection.length; i++) {
id = selection[i];
/**
* select zero or more edges
* @param {Number[] | String[]} selection An array with the ids of the
* selected nodes.
*/
}, {
key: "selectEdges",
value: function selectEdges(selection) {
if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
var edge = this.body.edges[id];
if (!edge) {
throw new RangeError('Edge with id "' + id + '" not found');
}
this.selectObject(edge);
}
this.body.emitter.emit('_requestRedraw');
this.setSelection({ edges: selection });
}
/**
@ -39629,12 +39658,14 @@ return /******/ (function(modules) { // webpackBootstrap
if (node.x === undefined) {
node.x = distribution[level].distance;
}
distribution[level].distance = node.x + this.nodeSpacing;
// since the placeBranchNodes can make this process not exactly sequential, we have to avoid overlap by either spacing from the node, or simply adding distance.
distribution[level].distance = Math.max(distribution[level].distance + this.nodeSpacing, node.x + this.nodeSpacing);
} else {
if (node.y === undefined) {
node.y = distribution[level].distance;
}
distribution[level].distance = node.y + this.nodeSpacing;
// since the placeBranchNodes can make this process not exactly sequential, we have to avoid overlap by either spacing from the node, or simply adding distance.
distribution[level].distance = Math.max(distribution[level].distance + this.nodeSpacing, node.y + this.nodeSpacing);
}
this.positionedNodes[nodeId] = true;

+ 4
- 2
lib/network/modules/LayoutEngine.js View File

@ -350,11 +350,13 @@ class LayoutEngine {
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
if (node.x === undefined) {node.x = distribution[level].distance;}
distribution[level].distance = node.x + this.nodeSpacing;
// since the placeBranchNodes can make this process not exactly sequential, we have to avoid overlap by either spacing from the node, or simply adding distance.
distribution[level].distance = Math.max(distribution[level].distance + this.nodeSpacing, node.x + this.nodeSpacing);
}
else {
if (node.y === undefined) {node.y = distribution[level].distance;}
distribution[level].distance = node.y + this.nodeSpacing;
// since the placeBranchNodes can make this process not exactly sequential, we have to avoid overlap by either spacing from the node, or simply adding distance.
distribution[level].distance = Math.max(distribution[level].distance + this.nodeSpacing, node.y + this.nodeSpacing);
}
this.positionedNodes[nodeId] = true;

+ 3
- 6
lib/network/modules/ManipulationSystem.js View File

@ -376,15 +376,12 @@ class ManipulationSystem {
// temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
this._temporaryBindUI('onTouch', this._controlNodeTouch.bind(this)); // used to get the position
this._temporaryBindUI('onTap', () => {
}); // disabled
this._temporaryBindUI('onHold', () => {
}); // disabled
this._temporaryBindUI('onTap', () => {}); // disabled
this._temporaryBindUI('onHold', () => {}); // disabled
this._temporaryBindUI('onDragStart', this._controlNodeDragStart.bind(this));// used to select control node
this._temporaryBindUI('onDrag', this._controlNodeDrag.bind(this)); // used to drag control node
this._temporaryBindUI('onDragEnd', this._controlNodeDragEnd.bind(this)); // used to connect or revert control nodes
this._temporaryBindUI('onMouseMove', () => {
}); // disabled
this._temporaryBindUI('onMouseMove', () => {}); // disabled
// create function to position control nodes correctly on movement
// automatically cleaned up because we use the temporary bind

+ 46
- 61
test/networkTest.html View File

@ -12,82 +12,67 @@
}
</style>
</head>
<body onload="draw();">
<body onload="draw()">
<script src="https://rawgit.com/Tooa/6e17f2d7b8e34ef94719/raw/a10096a6b88c992c57d032b1ed3079d7cc4b1f51/data.js"></script>
<div id="mynetwork"></div>
<script>
function draw() {
nodes = [];
edges = [];
for (var i = 0; i < nodes.length; i++) {
nodes[i].mass = Math.ceil(2000* nodes[i].value);
}
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var nodesDataset = new vis.DataSet(nodes);
var edgesDataset = new vis.DataSet(edges);
function redrawAll() {
var container = document.getElementById('mynetwork');
nodes.push({id: 0, label: 'Root'});
nodes.push({id: 1, label: 'Child 1'});
nodes.push({id: 2, label: 'Child 2'});
nodes.push({id: 3, label: 'Child 3'});
nodes.push({id: 4, label: 'Child 2.1'});
nodes.push({id: 5, label: 'Child 2.1.1'});
nodes.push({id: 6, label: 'Child 2.1.2'});
nodes.push({id: 7, label: 'Child 2.1.1.1'});
edges.push({from: 0, to: 1});
edges.push({from: 0, to: 2});
edges.push({from: 0, to: 3});
edges.push({from: 2, to: 4});
edges.push({from: 4, to: 5});
edges.push({from: 4, to: 6});
edges.push({from: 5, to: 7});
nodes[7].level = 0;
nodes[6].level = 1;
nodes[5].level = 1;
nodes[4].level = 2;
nodes[3].level = 3;
nodes[2].level = 3;
nodes[1].level = 3;
nodes[0].level = 4;
var options = {
nodes: {
borderWidth:4,
color: {
border: '#406897',
background: '#6AAFFF'
},
scaling: {
min: 10,
max: 200,
label: {
min: 50,
max: 100,
drawThreshold: 10,
maxVisible: 60
}
},
font: {
size: 20,
color:'#000000'
},
shapeProperties: {
useBorderWithImage: true
},
},
edges: {
scaling: {
min: 2,
max: 50
},
color: { inherit: 'from' },
smooth: {
type: 'continuous'
type: 'cubicBezier',
forceDirection: 'horizontal',
roundness: 0.4
}
},
physics: {
"barnesHut": {
"gravitationalConstant": -19050,
"centralGravity": 1.3,
"springLength": 170,
"springConstant": 0.035,
"damping": 0.23
},
"minVelocity": 0.75,
stabilization: {
enabled: false,
iterations: 2000,
updateInterval: 25
layout: {
hierarchical: {
direction: 'LR'
}
},
configure:'physics',
interaction: {
tooltipDelay: 200,
hideEdgesOnDrag: true
},
layout:{improvedLayout:false}
}
};
network = new vis.Network(container, {nodes: nodesDataset, edges: edgesDataset}, options);
network = new vis.Network(container, data, options);
}
redrawAll();
var network, nodes, edges;
</script>

Loading…
Cancel
Save