diff --git a/dist/vis.js b/dist/vis.js index 82b35410..6995a610 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 4.10.1-SNAPSHOT - * @date 2015-11-27 + * @date 2015-11-30 * * @license * Copyright (C) 2011-2015 Almende B.V, http://almende.com @@ -39358,7 +39358,7 @@ return /******/ (function(modules) { // webpackBootstrap }; util.extend(this.options, this.defaultOptions); - this.hierarchicalLevels = {}; + this.lastNodeOnLevel = {}; this.hierarchicalParents = {}; this.hierarchicalChildren = {}; @@ -39410,7 +39410,7 @@ return /******/ (function(modules) { // webpackBootstrap this.body.emitter.emit('_resetHierarchicalLayout'); // because the hierarchical system needs it's own physics and smooth curve settings, we adapt the other options if needed. - return this.adaptAllOptions(allOptions); + return this.adaptAllOptionsForHierarchicalLayout(allOptions); } else { if (prevHierarchicalState === true) { // refresh the overridden options for nodes and edges. @@ -39422,8 +39422,8 @@ return /******/ (function(modules) { // webpackBootstrap return allOptions; } }, { - key: 'adaptAllOptions', - value: function adaptAllOptions(allOptions) { + key: 'adaptAllOptionsForHierarchicalLayout', + value: function adaptAllOptionsForHierarchicalLayout(allOptions) { if (this.options.hierarchical.enabled === true) { // set the physics if (allOptions.physics === undefined || allOptions.physics === true) { @@ -39652,9 +39652,6 @@ return /******/ (function(modules) { // webpackBootstrap throw new Error('To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes.'); return; } else { - // setup the system to use hierarchical method. - //this._changeConstants(); - // define levels if undefined by the users. Based on hubsize if (undefinedLevel === true) { if (this.options.hierarchical.sortMethod === 'hubsize') { @@ -39667,59 +39664,28 @@ return /******/ (function(modules) { // webpackBootstrap // check the distribution of the nodes per level. var distribution = this._getDistribution(); - // add offset to distribution - this._addOffsetsToDistribution(distribution); - - this._addChildNodeWidths(distribution); + // get the parent children relations. + this._generateMap(); // place the nodes on the canvas. this._placeNodesByHierarchy(distribution); - } - } - } - }, { - key: '_addChildNodeWidths', - value: function _addChildNodeWidths(distribution) { - var levels = Object.keys(distribution); - for (var i = levels.length - 1; i > levels[0]; i--) { - for (var node in distribution[levels[i]].nodes) { - if (this.hierarchicalChildren[node] !== undefined) { - var _parent = this.hierarchicalChildren[node].parents[0]; - this.hierarchicalParents[_parent].amount += 1; - } + + // Todo: condense the whitespace. + this._condenseHierarchy(); + + // shift to center so gravity does not have to do much + this._shiftToCenter(); } } } /** - * center align the nodes in the hierarchy for quicker display. - * @param distribution + * TODO: implement. Clear whitespace after positioning. * @private */ }, { - key: '_addOffsetsToDistribution', - value: function _addOffsetsToDistribution(distribution) { - var maxDistances = 0; - // get the maximum amount of distances between nodes over all levels - for (var level in distribution) { - if (distribution.hasOwnProperty(level)) { - if (maxDistances < distribution[level].amount) { - maxDistances = distribution[level].amount; - } - } - } - // o---o---o : 3 nodes, 2 disances. hence -1 - maxDistances -= 1; - - // set the distances for all levels but normalize on the first level (0) - var zeroLevelDistance = distribution[0].amount - 1 - maxDistances; - for (var level in distribution) { - if (distribution.hasOwnProperty(level)) { - var distances = distribution[level].amount - 1 - zeroLevelDistance; - distribution[level].distance = (maxDistances - distances) * 0.5 * this.nodeSpacing; - } - } - } + key: '_condenseHierarchy', + value: function _condenseHierarchy() {} /** * This function places the nodes on the canvas based on the hierarchial distribution. @@ -39736,28 +39702,17 @@ return /******/ (function(modules) { // webpackBootstrap // start placing all the level 0 nodes first. Then recursively position their branches. for (var level in distribution) { if (distribution.hasOwnProperty(level)) { - for (nodeId in distribution[level].nodes) { - if (distribution[level].nodes.hasOwnProperty(nodeId)) { - - node = distribution[level].nodes[nodeId]; - - if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { - if (node.x === undefined) { - node.x = distribution[level].distance; - } - - // 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; - } - // 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); - } - + // sort nodes in level by position: + var nodeArray = Object.keys(distribution[level]); + this._sortNodeArray(nodeArray); + + for (var i = 0; i < nodeArray.length; i++) { + nodeId = nodeArray[i]; + node = distribution[level][nodeId]; + if (this.positionedNodes[nodeId] === undefined) { + this._setPositionForHierarchy(node, this.nodeSpacing * i); this.positionedNodes[nodeId] = true; - this._placeBranchNodes(node.edges, node.id, distribution, level); + this._placeBranchNodes(nodeId, level); } } } @@ -39791,10 +39746,9 @@ return /******/ (function(modules) { // webpackBootstrap node.options.fixed.x = true; } if (distribution[level] === undefined) { - distribution[level] = { amount: 0, nodes: {}, distance: 0 }; + distribution[level] = {}; } - distribution[level].amount += 1; - distribution[level].nodes[nodeId] = node; + distribution[level][nodeId] = node; } } return distribution; @@ -39871,7 +39825,7 @@ return /******/ (function(modules) { // webpackBootstrap } else { childNode = node.edges[i].to; } - this._setLevelByHubsize(level + 1, childNode); + this._setLevelByHubsize(level + 1, childNode, node.id); } } @@ -39899,7 +39853,7 @@ return /******/ (function(modules) { // webpackBootstrap // get the minimum level for (nodeId in this.body.nodes) { if (this.body.nodes.hasOwnProperty(nodeId)) { - minLevel = this.hierarchicalLevels[nodeId] < minLevel ? this.hierarchicalLevels[nodeId] : minLevel; + minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel); } } @@ -39924,11 +39878,6 @@ return /******/ (function(modules) { // webpackBootstrap value: function _setLevelDirected(level, node, parentId) { if (this.hierarchicalLevels[node.id] !== undefined) return; - // set the references. - if (parentId !== undefined) { - this._updateReferences(parentId, node.id); - } - var childNode = undefined; this.hierarchicalLevels[node.id] = level; @@ -39950,16 +39899,56 @@ return /******/ (function(modules) { // webpackBootstrap * @private */ }, { - key: '_updateReferences', - value: function _updateReferences(parentNodeId, childNodeId) { - if (this.hierarchicalParents[parentNodeId] === undefined) { - this.hierarchicalParents[parentNodeId] = { children: [], width: 0, amount: 0 }; - } - this.hierarchicalParents[parentNodeId].children.push(childNodeId); - if (this.hierarchicalChildren[childNodeId] === undefined) { - this.hierarchicalChildren[childNodeId] = { parents: [], width: 0, amount: 0 }; + key: '_generateMap', + value: function _generateMap() { + var _this2 = this; + + var fillInRelations = function fillInRelations(parentNode, childNode) { + if (_this2.hierarchicalLevels[childNode.id] > _this2.hierarchicalLevels[parentNode.id]) { + var parentNodeId = parentNode.id; + var childNodeId = childNode.id; + if (_this2.hierarchicalParents[parentNodeId] === undefined) { + _this2.hierarchicalParents[parentNodeId] = { children: [], amount: 0 }; + } + _this2.hierarchicalParents[parentNodeId].children.push(childNodeId); + if (_this2.hierarchicalChildren[childNodeId] === undefined) { + _this2.hierarchicalChildren[childNodeId] = { parents: [], amount: 0 }; + } + _this2.hierarchicalChildren[childNodeId].parents.push(parentNodeId); + } + }; + + this._crawlNetwork(fillInRelations); + } + }, { + key: '_crawlNetwork', + value: function _crawlNetwork() { + var callback = arguments.length <= 0 || arguments[0] === undefined ? function () {} : arguments[0]; + + var progress = {}; + var crawler = function crawler(node) { + if (progress[node.id] === undefined) { + progress[node.id] = true; + var childNode = undefined; + for (var i = 0; i < node.edges.length; i++) { + if (node.edges[i].toId === node.id) { + childNode = node.edges[i].from; + } else { + childNode = node.edges[i].to; + } + + if (node.id !== childNode.id) { + callback(node, childNode); + crawler(childNode); + } + } + } + }; + + for (var i = 0; i < this.body.nodeIndices.length; i++) { + var node = this.body.nodes[this.body.nodeIndices[i]]; + crawler(node); } - this.hierarchicalChildren[childNodeId].parents.push(parentNodeId); } /** @@ -39974,41 +39963,189 @@ return /******/ (function(modules) { // webpackBootstrap */ }, { key: '_placeBranchNodes', - value: function _placeBranchNodes(edges, parentId, distribution, parentLevel) { - for (var i = 0; i < edges.length; i++) { - var childNode = undefined; - var parentNode = undefined; - if (edges[i].toId === parentId) { - childNode = edges[i].from; - parentNode = edges[i].to; + value: function _placeBranchNodes(parentId, parentLevel) { + if (this.hierarchicalParents[parentId] === undefined) { + return; + } + + // get a list of childNodes + var childNodes = []; + for (var i = 0; i < this.hierarchicalParents[parentId].children.length; i++) { + childNodes.push(this.body.nodes[this.hierarchicalParents[parentId].children[i]]); + } + + // use the positions to order the nodes. + this._sortNodeArray(childNodes); + + // position the childNodes + for (var i = 0; i < childNodes.length; i++) { + var childNode = childNodes[i]; + var childNodeLevel = this.hierarchicalLevels[childNode.id]; + // check if the childnode is below the parent node and if it has already been positioned. + if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) { + // get the amount of space required for this node. If parent the width is based on the amount of children. + var pos = undefined; + + // we get the X or Y values we need and store them in pos and previousPos. The get and set make sure we get X or Y + if (i === 0) { + pos = this._getPositionForHierarchy(this.body.nodes[parentId]); + } else { + pos = this._getPositionForHierarchy(childNodes[i - 1]) + this.nodeSpacing; + } + this._setPositionForHierarchy(childNode, pos); + + // if overlap has been detected, we shift the branch + if (this.lastNodeOnLevel[childNodeLevel] !== undefined) { + var previousPos = this._getPositionForHierarchy(this.body.nodes[this.lastNodeOnLevel[childNodeLevel]]); + if (pos - previousPos < this.nodeSpacing) { + var diff = previousPos + this.nodeSpacing - pos; + var sharedParent = this._findCommonParent(this.lastNodeOnLevel[childNodeLevel], childNode.id); + this._shiftBlock(sharedParent.withChild, diff); + } + } + + // store change in position. + this.lastNodeOnLevel[childNodeLevel] = childNode.id; + + this.positionedNodes[childNode.id] = true; + + this._placeBranchNodes(childNode.id, childNodeLevel); } else { - childNode = edges[i].to; - parentNode = edges[i].from; + return; } - var childNodeLevel = this.hierarchicalLevels[childNode.id]; + } - if (this.positionedNodes[childNode.id] === undefined) { - // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. - if (childNodeLevel > parentLevel) { - if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { - if (childNode.x === undefined) { - childNode.x = Math.max(distribution[childNodeLevel].distance); - } - distribution[childNodeLevel].distance = childNode.x + this.nodeSpacing; - this.positionedNodes[childNode.id] = true; - } else { - if (childNode.y === undefined) { - childNode.y = Math.max(distribution[childNodeLevel].distance); - } - distribution[childNodeLevel].distance = childNode.y + this.nodeSpacing; - } - this.positionedNodes[childNode.id] = true; + // center the parent nodes. + var minPos = 1e9; + var maxPos = -1e9; + for (var i = 0; i < childNodes.length; i++) { + var childNodeId = childNodes[i].id; + minPos = Math.min(minPos, this._getPositionForHierarchy(this.body.nodes[childNodeId])); + maxPos = Math.max(maxPos, this._getPositionForHierarchy(this.body.nodes[childNodeId])); + } + this._setPositionForHierarchy(this.body.nodes[parentId], 0.5 * (minPos + maxPos)); + } + + /** + * Shift a branch a certain distance + * @param parentId + * @param diff + * @private + */ + }, { + key: '_shiftBlock', + value: function _shiftBlock(parentId, diff) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + this.body.nodes[parentId].x += diff; + } else { + this.body.nodes[parentId].y += diff; + } + if (this.hierarchicalParents[parentId] !== undefined) { + for (var i = 0; i < this.hierarchicalParents[parentId].children.length; i++) { + this._shiftBlock(this.hierarchicalParents[parentId].children[i], diff); + } + } + } + + /** + * Find a common parent between branches. + * @param childA + * @param childB + * @returns {{foundParent, withChild}} + * @private + */ + }, { + key: '_findCommonParent', + value: function _findCommonParent(childA, childB) { + var _this3 = this; - if (childNode.edges.length > 1) { - this._placeBranchNodes(childNode.edges, childNode.id, distribution, childNodeLevel); + var parents = {}; + var iterateParents = function iterateParents(parents, child) { + if (_this3.hierarchicalChildren[child] !== undefined) { + for (var i = 0; i < _this3.hierarchicalChildren[child].parents.length; i++) { + var _parent = _this3.hierarchicalChildren[child].parents[i]; + parents[_parent] = true; + iterateParents(parents, _parent); + } + } + }; + var findParent = function findParent(_x2, _x3) { + var _again = true; + + _function: while (_again) { + var parents = _x2, + child = _x3; + _again = false; + + if (_this3.hierarchicalChildren[child] !== undefined) { + for (var i = 0; i < _this3.hierarchicalChildren[child].parents.length; i++) { + var _parent2 = _this3.hierarchicalChildren[child].parents[i]; + if (parents[_parent2] !== undefined) { + return { foundParent: _parent2, withChild: child }; + } + _x2 = parents; + _x3 = _parent2; + _again = true; + i = _parent2 = undefined; + continue _function; } } + return { foundParent: null, withChild: child }; } + }; + + iterateParents(parents, childA); + return findParent(parents, childB); + } + + /** + * Abstract the getting of the position so we won't have to repeat the check for direction all the time + * @param node + * @param position + * @private + */ + }, { + key: '_setPositionForHierarchy', + value: function _setPositionForHierarchy(node, position) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + node.x = position; + } else { + node.y = position; + } + } + + /** + * Abstract the getting of the position of a node so we do not have to repeat the direction check all the time. + * @param node + * @returns {number|*} + * @private + */ + }, { + key: '_getPositionForHierarchy', + value: function _getPositionForHierarchy(node) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + return node.x; + } else { + return node.y; + } + } + + /** + * Use the x or y value to sort the array, allowing users to specify order. + * @param nodeArray + * @private + */ + }, { + key: '_sortNodeArray', + value: function _sortNodeArray(nodeArray) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + nodeArray.sort(function (a, b) { + return a.x - b.x; + }); + } else { + nodeArray.sort(function (a, b) { + return a.y - b.y; + }); } } }]); diff --git a/examples/network/exampleUtil.js b/examples/network/exampleUtil.js index aeeb2df1..3ace1e63 100644 --- a/examples/network/exampleUtil.js +++ b/examples/network/exampleUtil.js @@ -79,6 +79,7 @@ function getScaleFreeNetworkSeeded(nodeCount) { var nodes = []; var edges = []; var connectionCount = []; + randomSeed = 764; // randomly create some nodes and edges for (var i = 0; i < nodeCount; i++) { diff --git a/examples/network/layout/hierarchicalLayout.html b/examples/network/layout/hierarchicalLayout.html index 4a2539a8..d827814c 100644 --- a/examples/network/layout/hierarchicalLayout.html +++ b/examples/network/layout/hierarchicalLayout.html @@ -57,7 +57,7 @@ } - + diff --git a/lib/network/modules/LayoutEngine.js b/lib/network/modules/LayoutEngine.js index 1b2f7ebe..a07a52ed 100644 --- a/lib/network/modules/LayoutEngine.js +++ b/lib/network/modules/LayoutEngine.js @@ -25,7 +25,7 @@ class LayoutEngine { }; util.extend(this.options, this.defaultOptions); - this.hierarchicalLevels = {}; + this.lastNodeOnLevel = {}; this.hierarchicalParents = {}; this.hierarchicalChildren = {}; @@ -71,7 +71,7 @@ class LayoutEngine { this.body.emitter.emit('_resetHierarchicalLayout'); // because the hierarchical system needs it's own physics and smooth curve settings, we adapt the other options if needed. - return this.adaptAllOptions(allOptions); + return this.adaptAllOptionsForHierarchicalLayout(allOptions); } else { if (prevHierarchicalState === true) { @@ -84,7 +84,7 @@ class LayoutEngine { return allOptions; } - adaptAllOptions(allOptions) { + adaptAllOptionsForHierarchicalLayout(allOptions) { if (this.options.hierarchical.enabled === true) { // set the physics if (allOptions.physics === undefined || allOptions.physics === true) { @@ -311,9 +311,6 @@ class LayoutEngine { return; } else { - // setup the system to use hierarchical method. - //this._changeConstants(); - // define levels if undefined by the users. Based on hubsize if (undefinedLevel === true) { if (this.options.hierarchical.sortMethod === 'hubsize') { @@ -324,61 +321,34 @@ class LayoutEngine { } } + // check the distribution of the nodes per level. let distribution = this._getDistribution(); - // add offset to distribution - this._addOffsetsToDistribution(distribution); - - this._addChildNodeWidths(distribution); + // get the parent children relations. + this._generateMap(); // place the nodes on the canvas. this._placeNodesByHierarchy(distribution); - } - } - } + // Todo: condense the whitespace. + this._condenseHierarchy(); - _addChildNodeWidths(distribution) { - let levels = Object.keys(distribution); - for (let i = levels.length - 1; i > levels[0]; i--) { - for (let node in distribution[levels[i]].nodes) { - if (this.hierarchicalChildren[node] !== undefined) { - let parent = this.hierarchicalChildren[node].parents[0]; - this.hierarchicalParents[parent].amount += 1; - } + // shift to center so gravity does not have to do much + this._shiftToCenter(); } } } /** - * center align the nodes in the hierarchy for quicker display. - * @param distribution + * TODO: implement. Clear whitespace after positioning. * @private */ - _addOffsetsToDistribution(distribution) { - let maxDistances = 0; - // get the maximum amount of distances between nodes over all levels - for (let level in distribution) { - if (distribution.hasOwnProperty(level)) { - if (maxDistances < distribution[level].amount) { - maxDistances = distribution[level].amount; - } - } - } - // o---o---o : 3 nodes, 2 disances. hence -1 - maxDistances -= 1; + _condenseHierarchy() { - // set the distances for all levels but normalize on the first level (0) - var zeroLevelDistance = distribution[0].amount - 1 - maxDistances; - for (let level in distribution) { - if (distribution.hasOwnProperty(level)) { - var distances = distribution[level].amount - 1 - zeroLevelDistance; - distribution[level].distance = ((maxDistances - distances) * 0.5) * this.nodeSpacing; - } - } } + /** * This function places the nodes on the canvas based on the hierarchial distribution. * @@ -391,25 +361,17 @@ class LayoutEngine { // start placing all the level 0 nodes first. Then recursively position their branches. for (let level in distribution) { if (distribution.hasOwnProperty(level)) { - for (nodeId in distribution[level].nodes) { - if (distribution[level].nodes.hasOwnProperty(nodeId)) { - - node = distribution[level].nodes[nodeId]; - - if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { - if (node.x === undefined) {node.x = distribution[level].distance;} - - // 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;} - // 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); - } - + // sort nodes in level by position: + let nodeArray = Object.keys(distribution[level]); + this._sortNodeArray(nodeArray) + + for (let i = 0; i < nodeArray.length; i++) { + nodeId = nodeArray[i]; + node = distribution[level][nodeId]; + if (this.positionedNodes[nodeId] === undefined) { + this._setPositionForHierarchy(node, this.nodeSpacing * i) this.positionedNodes[nodeId] = true; - this._placeBranchNodes(node.edges,node.id,distribution,level); + this._placeBranchNodes(nodeId, level); } } } @@ -442,10 +404,9 @@ class LayoutEngine { node.options.fixed.x = true; } if (distribution[level] === undefined) { - distribution[level] = {amount: 0, nodes: {}, distance: 0}; + distribution[level] = {}; } - distribution[level].amount += 1; - distribution[level].nodes[nodeId] = node; + distribution[level][nodeId] = node; } } return distribution; @@ -521,7 +482,7 @@ class LayoutEngine { else { childNode = node.edges[i].to; } - this._setLevelByHubsize(level + 1, childNode); + this._setLevelByHubsize(level + 1, childNode, node.id); } } @@ -548,7 +509,7 @@ class LayoutEngine { // get the minimum level for (nodeId in this.body.nodes) { if (this.body.nodes.hasOwnProperty(nodeId)) { - minLevel = this.hierarchicalLevels[nodeId] < minLevel ? this.hierarchicalLevels[nodeId] : minLevel; + minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel); } } @@ -573,11 +534,6 @@ class LayoutEngine { if (this.hierarchicalLevels[node.id] !== undefined) return; - // set the references. - if (parentId !== undefined) { - this._updateReferences(parentId, node.id); - } - let childNode; this.hierarchicalLevels[node.id] = level; @@ -600,18 +556,48 @@ class LayoutEngine { * @param childNodeId * @private */ - _updateReferences(parentNodeId, childNodeId) { - if (this.hierarchicalParents[parentNodeId] === undefined) { - this.hierarchicalParents[parentNodeId] = {children:[], width:0, amount:0}; - } - this.hierarchicalParents[parentNodeId].children.push(childNodeId); - if (this.hierarchicalChildren[childNodeId] === undefined) { - this.hierarchicalChildren[childNodeId] = {parents:[], width:0, amount:0}; + _generateMap() { + let fillInRelations = (parentNode, childNode) => { + if (this.hierarchicalLevels[childNode.id] > this.hierarchicalLevels[parentNode.id]) { + let parentNodeId = parentNode.id; + let childNodeId = childNode.id; + if (this.hierarchicalParents[parentNodeId] === undefined) { + this.hierarchicalParents[parentNodeId] = {children: [], amount: 0}; + } + this.hierarchicalParents[parentNodeId].children.push(childNodeId); + if (this.hierarchicalChildren[childNodeId] === undefined) { + this.hierarchicalChildren[childNodeId] = {parents: [], amount: 0}; + } + this.hierarchicalChildren[childNodeId].parents.push(parentNodeId); + } } - this.hierarchicalChildren[childNodeId].parents.push(parentNodeId); + this._crawlNetwork(fillInRelations); } + _crawlNetwork(callback = function() {}) { + let progress = {}; + let crawler = (node) => { + if (progress[node.id] === undefined) { + progress[node.id] = true; + let childNode; + for (let i = 0; i < node.edges.length; i++) { + if (node.edges[i].toId === node.id) {childNode = node.edges[i].from;} + else {childNode = node.edges[i].to;} + + if (node.id !== childNode.id) { + callback(node, childNode); + crawler(childNode); + } + } + } + } + + for (let i = 0; i < this.body.nodeIndices.length; i++) { + let node = this.body.nodes[this.body.nodeIndices[i]]; + crawler(node); + } + } /** @@ -624,45 +610,170 @@ class LayoutEngine { * @param parentLevel * @private */ - _placeBranchNodes(edges, parentId, distribution, parentLevel) { - for (let i = 0; i < edges.length; i++) { - let childNode = undefined; - let parentNode = undefined; - if (edges[i].toId === parentId) { - childNode = edges[i].from; - parentNode = edges[i].to; + _placeBranchNodes(parentId, parentLevel) { + if (this.hierarchicalParents[parentId] === undefined) { + return; + } + + // get a list of childNodes + let childNodes = []; + for (let i = 0; i < this.hierarchicalParents[parentId].children.length; i++) { + childNodes.push(this.body.nodes[this.hierarchicalParents[parentId].children[i]]); + } + + // use the positions to order the nodes. + this._sortNodeArray(childNodes); + + // position the childNodes + for (let i = 0; i < childNodes.length; i++) { + let childNode = childNodes[i]; + let childNodeLevel = this.hierarchicalLevels[childNode.id]; + // check if the childnode is below the parent node and if it has already been positioned. + if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) { + // get the amount of space required for this node. If parent the width is based on the amount of children. + let pos; + + // we get the X or Y values we need and store them in pos and previousPos. The get and set make sure we get X or Y + if (i === 0) {pos = this._getPositionForHierarchy(this.body.nodes[parentId]);} + else {pos = this._getPositionForHierarchy(childNodes[i-1]) + this.nodeSpacing;} + this._setPositionForHierarchy(childNode, pos); + + // if overlap has been detected, we shift the branch + if (this.lastNodeOnLevel[childNodeLevel] !== undefined) { + let previousPos = this._getPositionForHierarchy(this.body.nodes[this.lastNodeOnLevel[childNodeLevel]]); + if (pos - previousPos < this.nodeSpacing) { + let diff = (previousPos + this.nodeSpacing) - pos; + let sharedParent = this._findCommonParent(this.lastNodeOnLevel[childNodeLevel], childNode.id); + this._shiftBlock(sharedParent.withChild, diff); + } + } + + // store change in position. + this.lastNodeOnLevel[childNodeLevel] = childNode.id; + + this.positionedNodes[childNode.id] = true; + + this._placeBranchNodes(childNode.id, childNodeLevel); } else { - childNode = edges[i].to; - parentNode = edges[i].from; + return } - let childNodeLevel = this.hierarchicalLevels[childNode.id]; + } - if (this.positionedNodes[childNode.id] === undefined) { - // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here. - if (childNodeLevel > parentLevel) { - if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { - if (childNode.x === undefined) { - childNode.x = Math.max(distribution[childNodeLevel].distance); - } - distribution[childNodeLevel].distance = childNode.x + this.nodeSpacing; - this.positionedNodes[childNode.id] = true; - } - else { - if (childNode.y === undefined) { - childNode.y = Math.max(distribution[childNodeLevel].distance) - } - distribution[childNodeLevel].distance = childNode.y + this.nodeSpacing; - } - this.positionedNodes[childNode.id] = true; + // center the parent nodes. + let minPos = 1e9; + let maxPos = -1e9; + for (let i = 0; i < childNodes.length; i++) { + let childNodeId = childNodes[i].id; + minPos = Math.min(minPos, this._getPositionForHierarchy(this.body.nodes[childNodeId])); + maxPos = Math.max(maxPos, this._getPositionForHierarchy(this.body.nodes[childNodeId])); + } + this._setPositionForHierarchy(this.body.nodes[parentId], 0.5 * (minPos + maxPos)); + } + + + /** + * Shift a branch a certain distance + * @param parentId + * @param diff + * @private + */ + _shiftBlock(parentId, diff) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + this.body.nodes[parentId].x += diff; + } + else { + this.body.nodes[parentId].y += diff; + } + if (this.hierarchicalParents[parentId] !== undefined) { + for (let i = 0; i < this.hierarchicalParents[parentId].children.length; i++) { + this._shiftBlock(this.hierarchicalParents[parentId].children[i], diff); + } + } + } - if (childNode.edges.length > 1) { - this._placeBranchNodes(childNode.edges, childNode.id, distribution, childNodeLevel); + + /** + * Find a common parent between branches. + * @param childA + * @param childB + * @returns {{foundParent, withChild}} + * @private + */ + _findCommonParent(childA,childB) { + let parents = {} + let iterateParents = (parents,child) => { + if (this.hierarchicalChildren[child] !== undefined) { + for (let i = 0; i < this.hierarchicalChildren[child].parents.length; i++) { + let parent = this.hierarchicalChildren[child].parents[i]; + parents[parent] = true; + iterateParents(parents, parent) + } + } + } + let findParent = (parents, child) => { + if (this.hierarchicalChildren[child] !== undefined) { + for (let i = 0; i < this.hierarchicalChildren[child].parents.length; i++) { + let parent = this.hierarchicalChildren[child].parents[i]; + if (parents[parent] !== undefined) { + return {foundParent:parent, withChild:child}; } + return findParent(parents, parent); } } + return {foundParent:null, withChild:child}; + } + + iterateParents(parents, childA); + return findParent(parents, childB) + } + + /** + * Abstract the getting of the position so we won't have to repeat the check for direction all the time + * @param node + * @param position + * @private + */ + _setPositionForHierarchy(node, position) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + node.x = position; + } + else { + node.y = position; + } + } + + /** + * Abstract the getting of the position of a node so we do not have to repeat the direction check all the time. + * @param node + * @returns {number|*} + * @private + */ + _getPositionForHierarchy(node) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + return node.x; + } + else { + return node.y; } } + + /** + * Use the x or y value to sort the array, allowing users to specify order. + * @param nodeArray + * @private + */ + _sortNodeArray(nodeArray) { + if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') { + nodeArray.sort(function (a,b) {return a.x - b.x;}) + } + else { + nodeArray.sort(function (a,b) {return a.y - b.y;}) + } + } + + + } export default LayoutEngine; \ No newline at end of file diff --git a/test/networkTest.html b/test/networkTest.html index 33e05940..f3cdbdfe 100644 --- a/test/networkTest.html +++ b/test/networkTest.html @@ -12,6 +12,8 @@ } + + @@ -35,6 +37,10 @@ nodes: JSON.parse('[{"id":"king"},{"id":"10:98:25"},{"id":"11:28:e8"},{"id":"11:28:ea"},{"id":"11:28:f6"},{"id":"11:28:fa"},{"id":"11:28:fd"},{"id":"11:29:01"},{"id":"11:29:05"},{"id":"11:29:07"},{"id":"11:29:11"},{"id":"11:29:14"},{"id":"11:29:15"},{"id":"11:29:1b"},{"id":"11:29:1c"},{"id":"11:29:1f"},{"id":"11:29:20"},{"id":"11:a0:bf"},{"id":"11:a0:c0"},{"id":"11:a0:c1"},{"id":"11:a0:c3"},{"id":"11:a0:c4"},{"id":"11:a0:c5"},{"id":"11:a0:c6"},{"id":"11:a0:c7"},{"id":"11:a0:c8"},{"id":"11:a0:c9"},{"id":"11:a0:cb"},{"id":"11:a0:cc"},{"id":"11:a0:ce"},{"id":"11:a0:d0"},{"id":"11:a0:d1"},{"id":"11:a0:d2"},{"id":"11:a0:d3"},{"id":"11:a0:d4"},{"id":"11:a0:d6"},{"id":"11:a0:d7"},{"id":"11:a0:d8"},{"id":"11:a0:d9"},{"id":"11:a0:da"},{"id":"11:a0:db"},{"id":"11:a0:dc"},{"id":"11:a0:dd"},{"id":"11:a0:de"},{"id":"11:a0:df"},{"id":"11:a0:e1"},{"id":"11:a0:e2"},{"id":"11:a0:e4"},{"id":"11:a0:e5"},{"id":"11:a0:e6"},{"id":"11:a0:e7"},{"id":"11:a0:e9"},{"id":"11:a0:ea"},{"id":"11:a0:ed"},{"id":"11:a0:ee"},{"id":"11:a0:ef"},{"id":"11:a0:f1"},{"id":"11:a0:f2"},{"id":"11:a0:f4"},{"id":"11:a0:f5"},{"id":"11:a0:f6"},{"id":"11:a0:f7"},{"id":"11:a0:f8"},{"id":"11:a0:f9"},{"id":"11:a0:fa"},{"id":"11:a0:fb"},{"id":"11:a0:fc"},{"id":"11:a0:fd"},{"id":"11:a0:fe"},{"id":"11:a0:ff"},{"id":"11:a1:00"},{"id":"11:a1:02"},{"id":"11:a1:04"},{"id":"11:a1:07"},{"id":"11:a1:09"},{"id":"11:a1:0a"},{"id":"11:a1:0b"},{"id":"11:a1:0c"},{"id":"11:a1:0d"},{"id":"11:a1:0e"},{"id":"11:a1:0f"},{"id":"11:a1:10"},{"id":"11:a1:11"},{"id":"11:a1:13"},{"id":"11:a1:16"},{"id":"11:a1:18"},{"id":"11:a1:19"},{"id":"11:a1:1a"},{"id":"11:a1:1d"},{"id":"11:a1:1e"},{"id":"11:a1:20"},{"id":"11:a1:21"},{"id":"11:a1:23"},{"id":"11:a1:24"},{"id":"11:a1:26"},{"id":"11:a1:27"},{"id":"11:a1:29"},{"id":"11:a1:2a"},{"id":"11:a1:2c"},{"id":"11:a1:2e"},{"id":"11:a1:2f"},{"id":"11:a1:31"},{"id":"11:a1:32"},{"id":"11:a1:34"},{"id":"11:a1:35"},{"id":"11:a1:36"},{"id":"11:a1:38"},{"id":"11:a1:39"},{"id":"11:a1:3a"},{"id":"11:a1:3c"},{"id":"11:a1:3e"},{"id":"11:a1:40"},{"id":"11:a1:44"},{"id":"11:a1:45"},{"id":"11:a1:46"},{"id":"11:a1:49"},{"id":"11:a1:4b"},{"id":"11:a1:4c"},{"id":"11:a1:4d"},{"id":"11:a1:4e"},{"id":"11:a1:4f"},{"id":"11:a1:50"},{"id":"11:a1:52"},{"id":"11:a1:53"},{"id":"11:a1:56"},{"id":"11:a1:58"},{"id":"11:a1:5a"},{"id":"11:a1:5b"},{"id":"11:a1:5c"},{"id":"11:a1:5d"},{"id":"11:a1:5e"},{"id":"11:a1:5f"},{"id":"11:a1:60"},{"id":"11:a1:61"},{"id":"11:a1:62"},{"id":"11:a1:63"},{"id":"11:a1:64"},{"id":"11:a1:65"},{"id":"11:a1:67"},{"id":"11:a1:68"},{"id":"11:a1:69"},{"id":"11:a1:6a"},{"id":"11:a1:6b"},{"id":"11:a1:6c"},{"id":"11:a1:6e"},{"id":"11:a1:6f"},{"id":"11:a1:70"},{"id":"11:a1:71"},{"id":"11:a1:72"},{"id":"11:a1:73"},{"id":"11:a1:75"},{"id":"11:a1:77"},{"id":"11:a1:78"},{"id":"11:a1:79"},{"id":"11:a1:7a"},{"id":"11:a1:7b"},{"id":"11:a1:7c"},{"id":"11:a1:7d"},{"id":"11:a1:80"},{"id":"11:a1:83"},{"id":"11:a1:84"},{"id":"11:a1:85"},{"id":"11:a1:86"},{"id":"11:a1:87"},{"id":"11:a1:88"},{"id":"11:a1:8a"},{"id":"11:a1:8b"},{"id":"11:a1:8c"},{"id":"11:a1:8e"},{"id":"11:a1:8f"},{"id":"11:a1:90"},{"id":"11:a1:91"},{"id":"11:a1:92"},{"id":"11:a1:93"},{"id":"11:a1:94"},{"id":"11:a1:95"},{"id":"11:a1:96"},{"id":"11:a1:98"},{"id":"11:a1:99"},{"id":"11:a1:9a"},{"id":"11:a1:9b"},{"id":"11:a1:9e"},{"id":"11:a1:9f"},{"id":"11:a1:a0"},{"id":"11:a1:a1"},{"id":"11:a1:a2"},{"id":"11:a1:a3"},{"id":"11:a1:a4"},{"id":"11:a1:a7"},{"id":"11:a1:a9"},{"id":"11:a1:aa"},{"id":"11:a1:ab"},{"id":"11:a1:ac"},{"id":"11:a1:ad"},{"id":"11:a1:ae"},{"id":"11:a1:af"},{"id":"11:a1:b1"},{"id":"11:a1:b3"},{"id":"11:a1:b7"},{"id":"11:a1:b8"},{"id":"11:a1:b9"},{"id":"11:a1:ba"},{"id":"11:a1:bb"},{"id":"11:a1:bc"},{"id":"11:a1:bd"},{"id":"11:a1:be"},{"id":"11:a1:bf"},{"id":"11:a1:c0"},{"id":"11:a1:c1"},{"id":"11:a1:c3"},{"id":"11:a1:c4"},{"id":"11:a1:c5"},{"id":"11:a1:c6"},{"id":"11:a1:c7"},{"id":"11:a1:c9"},{"id":"11:a1:ca"},{"id":"11:a1:cb"},{"id":"11:a1:cd"},{"id":"11:a1:ce"},{"id":"11:a1:cf"},{"id":"11:a1:d1"},{"id":"11:a1:d2"},{"id":"11:a1:d3"},{"id":"11:a1:d4"},{"id":"11:a1:d6"},{"id":"11:a1:d7"},{"id":"11:a1:d8"},{"id":"11:a1:da"},{"id":"11:a1:db"},{"id":"11:a1:dc"},{"id":"11:a1:dd"},{"id":"11:a1:de"},{"id":"11:a1:df"},{"id":"11:a1:e0"},{"id":"11:a1:e1"},{"id":"11:a1:e2"},{"id":"11:a1:e3"},{"id":"11:a1:e4"},{"id":"11:a1:e6"},{"id":"11:a1:e7"},{"id":"11:a1:e8"},{"id":"11:a1:e9"},{"id":"11:a1:ea"},{"id":"11:a1:ee"},{"id":"11:a1:ef"},{"id":"11:a1:f0"},{"id":"11:a1:f3"},{"id":"11:a1:f4"},{"id":"11:a1:f5"},{"id":"11:a1:f6"},{"id":"11:a1:f7"},{"id":"11:a1:f9"},{"id":"11:a1:fa"},{"id":"11:a1:fb"},{"id":"11:a1:fc"},{"id":"11:a1:fd"},{"id":"11:a1:ff"},{"id":"11:a2:01"},{"id":"11:a2:02"},{"id":"11:a2:03"},{"id":"11:a2:06"},{"id":"11:a2:09"},{"id":"11:a2:0a"},{"id":"11:a2:0c"},{"id":"11:a2:0f"},{"id":"11:a2:10"},{"id":"11:a2:11"},{"id":"11:a2:12"},{"id":"11:a2:13"},{"id":"11:a2:14"},{"id":"11:a2:15"},{"id":"11:a2:17"},{"id":"11:a2:1b"},{"id":"11:a2:1c"},{"id":"11:a2:1f"},{"id":"11:a2:20"},{"id":"11:a2:21"},{"id":"11:a2:22"},{"id":"11:a2:24"},{"id":"11:a2:28"},{"id":"11:a2:29"},{"id":"11:a2:2a"},{"id":"11:a2:2e"},{"id":"11:a2:33"},{"id":"11:a2:35"},{"id":"11:a2:36"},{"id":"11:a2:37"},{"id":"11:a2:38"},{"id":"11:a2:3a"},{"id":"11:a2:3c"},{"id":"11:a2:3e"},{"id":"11:a2:3f"},{"id":"11:a2:40"},{"id":"11:a2:41"},{"id":"11:a2:44"},{"id":"11:a2:48"},{"id":"11:a2:49"},{"id":"11:a2:4b"},{"id":"11:a2:4c"},{"id":"11:a2:4d"},{"id":"11:a2:4e"},{"id":"11:a2:51"},{"id":"11:a2:52"},{"id":"11:a2:55"},{"id":"11:a2:56"},{"id":"11:a2:57"},{"id":"11:a2:58"},{"id":"11:a2:5b"},{"id":"11:a2:5e"},{"id":"11:a2:5f"},{"id":"11:a2:60"},{"id":"11:a2:61"},{"id":"11:a2:65"},{"id":"11:a2:66"},{"id":"11:a2:6a"},{"id":"11:a2:6b"},{"id":"11:a2:6c"},{"id":"11:a2:6d"},{"id":"11:a2:6e"},{"id":"11:a2:6f"},{"id":"11:a2:71"},{"id":"11:a2:ab"},{"id":"11:a2:b1"},{"id":"11:a2:b9"},{"id":"11:a2:cf"},{"id":"11:a2:da"},{"id":"11:a3:2b"},{"id":"11:a3:3e"},{"id":"11:a3:4b"},{"id":"11:a3:8e"},{"id":"11:a4:15"},{"id":"26:82:72"},{"id":"11:28:f0"},{"id":"11:29:16"},{"id":"11:a0:f0"},{"id":"11:a1:7f"},{"id":"11:a1:89"},{"id":"11:a1:9d"},{"id":"11:a1:b2"},{"id":"11:a1:b4"},{"id":"11:a1:b5"},{"id":"11:a1:cc"},{"id":"11:a1:d5"},{"id":"11:a1:fe"},{"id":"11:a2:1e"},{"id":"11:a2:2c"},{"id":"11:a2:68"},{"id":"40:7f:0d"}]'), edges: JSON.parse('[{"from":"26:82:72","to":"king"},{"from":"26:82:72","to":"10:98:25"},{"from":"11:a2:52","to":"11:28:e8"},{"from":"11:a2:ab","to":"11:28:ea"},{"from":"11:a2:b9","to":"11:28:f6"},{"from":"11:a3:2b","to":"11:28:fa"},{"from":"11:a0:c7","to":"11:28:fd"},{"from":"11:a3:3e","to":"11:29:01"},{"from":"11:a0:e7","to":"11:29:05"},{"from":"11:a2:20","to":"11:29:07"},{"from":"11:a3:3e","to":"11:29:11"},{"from":"11:a0:d0","to":"11:29:14"},{"from":"11:a3:3e","to":"11:29:15"},{"from":"11:a2:15","to":"11:29:1b"},{"from":"11:a1:bd","to":"11:29:1c"},{"from":"11:a0:dd","to":"11:29:1f"},{"from":"11:a1:69","to":"11:29:20"},{"from":"11:a3:3e","to":"11:a0:bf"},{"from":"11:a1:0f","to":"11:a0:c0"},{"from":"11:a0:c7","to":"11:a0:c1"},{"from":"11:a0:f6","to":"11:a0:c3"},{"from":"11:a2:b9","to":"11:a0:c4"},{"from":"11:a3:4b","to":"11:a0:c5"},{"from":"11:a0:f4","to":"11:a0:c6"},{"from":"king","to":"11:a0:c7"},{"from":"11:a0:e7","to":"11:a0:c8"},{"from":"11:a0:e7","to":"11:a0:c9"},{"from":"11:a0:d7","to":"11:a0:cb"},{"from":"11:a0:d7","to":"11:a0:cc"},{"from":"11:a2:55","to":"11:a0:ce"},{"from":"10:98:25","to":"11:a0:d0"},{"from":"11:a3:2b","to":"11:a0:d1"},{"from":"11:a1:10","to":"11:a0:d2"},{"from":"11:a0:f6","to":"11:a0:d3"},{"from":"11:a0:f8","to":"11:a0:d4"},{"from":"11:a0:c7","to":"11:a0:d6"},{"from":"11:a2:6f","to":"11:a0:d7"},{"from":"11:a0:f4","to":"11:a0:d8"},{"from":"11:a0:f4","to":"11:a0:d9"},{"from":"11:a1:0f","to":"11:a0:da"},{"from":"11:a0:d6","to":"11:a0:db"},{"from":"11:a1:07","to":"11:a0:dc"},{"from":"11:a3:3e","to":"11:a0:dd"},{"from":"11:a2:51","to":"11:a0:de"},{"from":"11:a0:d7","to":"11:a0:df"},{"from":"11:a2:b1","to":"11:a0:e1"},{"from":"11:a0:ff","to":"11:a0:e2"},{"from":"11:a3:8e","to":"11:a0:e4"},{"from":"11:a1:b8","to":"11:a0:e5"},{"from":"11:a2:ab","to":"11:a0:e6"},{"from":"26:82:72","to":"11:a0:e7"},{"from":"11:a1:00","to":"11:a0:e9"},{"from":"11:a3:8e","to":"11:a0:ea"},{"from":"11:a1:69","to":"11:a0:ed"},{"from":"10:98:25","to":"11:a0:ee"},{"from":"11:a4:15","to":"11:a0:ef"},{"from":"11:a2:56","to":"11:a0:f1"},{"from":"11:a1:c9","to":"11:a0:f2"},{"from":"11:a1:16","to":"11:a0:f4"},{"from":"11:a1:6a","to":"11:a0:f5"},{"from":"11:a0:d7","to":"11:a0:f6"},{"from":"11:a2:b9","to":"11:a0:f7"},{"from":"11:a3:2b","to":"11:a0:f8"},{"from":"11:a2:b9","to":"11:a0:f9"},{"from":"11:a3:4b","to":"11:a0:fa"},{"from":"26:82:72","to":"11:a0:fb"},{"from":"11:a1:69","to":"11:a0:fc"},{"from":"11:a0:c7","to":"11:a0:fd"},{"from":"11:a2:cf","to":"11:a0:fe"},{"from":"11:a3:2b","to":"11:a0:ff"},{"from":"11:a2:b9","to":"11:a1:00"},{"from":"11:a2:33","to":"11:a1:02"},{"from":"11:a0:cb","to":"11:a1:04"},{"from":"11:a0:e7","to":"11:a1:07"},{"from":"11:a2:da","to":"11:a1:09"},{"from":"11:a0:f4","to":"11:a1:0a"},{"from":"11:a2:b9","to":"11:a1:0b"},{"from":"11:29:1f","to":"11:a1:0c"},{"from":"11:a1:00","to":"11:a1:0d"},{"from":"11:a0:c5","to":"11:a1:0e"},{"from":"11:a3:4b","to":"11:a1:0f"},{"from":"king","to":"11:a1:10"},{"from":"11:a2:b1","to":"11:a1:11"},{"from":"11:a3:2b","to":"11:a1:13"},{"from":"11:a2:da","to":"11:a1:16"},{"from":"26:82:72","to":"11:a1:18"},{"from":"11:a1:a1","to":"11:a1:19"},{"from":"11:a1:f7","to":"11:a1:1a"},{"from":"11:a2:ab","to":"11:a1:1d"},{"from":"11:a2:b1","to":"11:a1:1e"},{"from":"11:a3:2b","to":"11:a1:20"},{"from":"11:a1:86","to":"11:a1:21"},{"from":"11:a1:86","to":"11:a1:23"},{"from":"11:a1:2e","to":"11:a1:24"},{"from":"11:a2:71","to":"11:a1:26"},{"from":"11:a3:2b","to":"11:a1:27"},{"from":"king","to":"11:a1:29"},{"from":"11:a3:2b","to":"11:a1:2a"},{"from":"11:a3:3e","to":"11:a1:2c"},{"from":"king","to":"11:a1:2e"},{"from":"11:a3:3e","to":"11:a1:2f"},{"from":"king","to":"11:a1:31"},{"from":"king","to":"11:a1:32"},{"from":"11:a3:4b","to":"11:a1:34"},{"from":"11:a1:ff","to":"11:a1:35"},{"from":"11:a3:2b","to":"11:a1:36"},{"from":"11:a1:10","to":"11:a1:38"},{"from":"11:a2:b1","to":"11:a1:39"},{"from":"11:a3:2b","to":"11:a1:3a"},{"from":"11:29:05","to":"11:a1:3c"},{"from":"11:a1:bd","to":"11:a1:3e"},{"from":"11:a1:87","to":"11:a1:40"},{"from":"11:a4:15","to":"11:a1:44"},{"from":"11:a4:15","to":"11:a1:45"},{"from":"11:a2:cf","to":"11:a1:46"},{"from":"11:a0:dd","to":"11:a1:49"},{"from":"11:a3:4b","to":"11:a1:4b"},{"from":"26:82:72","to":"11:a1:4c"},{"from":"11:a2:ab","to":"11:a1:4d"},{"from":"11:a1:6a","to":"11:a1:4e"},{"from":"11:a2:ab","to":"11:a1:4f"},{"from":"11:a4:15","to":"11:a1:50"},{"from":"11:a2:cf","to":"11:a1:52"},{"from":"11:a1:b8","to":"11:a1:53"},{"from":"11:a2:52","to":"11:a1:56"},{"from":"11:a3:4b","to":"11:a1:58"},{"from":"11:a2:5b","to":"11:a1:5a"},{"from":"11:a2:ab","to":"11:a1:5b"},{"from":"11:a3:8e","to":"11:a1:5c"},{"from":"king","to":"11:a1:5d"},{"from":"26:82:72","to":"11:a1:5e"},{"from":"11:a2:38","to":"11:a1:5f"},{"from":"11:a2:b1","to":"11:a1:60"},{"from":"10:98:25","to":"11:a1:61"},{"from":"11:a2:56","to":"11:a1:62"},{"from":"11:a2:48","to":"11:a1:63"},{"from":"11:a0:dd","to":"11:a1:64"},{"from":"11:a1:35","to":"11:a1:65"},{"from":"11:a2:ab","to":"11:a1:67"},{"from":"11:a1:bd","to":"11:a1:68"},{"from":"11:a1:3c","to":"11:a1:69"},{"from":"11:a2:cf","to":"11:a1:6a"},{"from":"11:a1:00","to":"11:a1:6b"},{"from":"11:a1:07","to":"11:a1:6c"},{"from":"11:a2:56","to":"11:a1:6e"},{"from":"king","to":"11:a1:6f"},{"from":"king","to":"11:a1:70"},{"from":"11:a3:3e","to":"11:a1:71"},{"from":"11:a1:6a","to":"11:a1:72"},{"from":"11:a2:b9","to":"11:a1:73"},{"from":"11:a1:a1","to":"11:a1:75"},{"from":"11:a2:cf","to":"11:a1:77"},{"from":"11:a4:15","to":"11:a1:78"},{"from":"11:a1:0a","to":"11:a1:79"},{"from":"11:a3:4b","to":"11:a1:7a"},{"from":"11:a0:f6","to":"11:a1:7b"},{"from":"26:82:72","to":"11:a1:7c"},{"from":"11:a1:79","to":"11:a1:7d"},{"from":"11:a1:c9","to":"11:a1:80"},{"from":"11:a1:5d","to":"11:a1:83"},{"from":"26:82:72","to":"11:a1:84"},{"from":"11:a2:cf","to":"11:a1:85"},{"from":"11:a2:b1","to":"11:a1:86"},{"from":"11:a1:af","to":"11:a1:87"},{"from":"11:a2:b9","to":"11:a1:88"},{"from":"11:a2:20","to":"11:a1:8a"},{"from":"11:a0:f4","to":"11:a1:8b"},{"from":"11:a2:ab","to":"11:a1:8c"},{"from":"11:a2:da","to":"11:a1:8e"},{"from":"11:a2:cf","to":"11:a1:8f"},{"from":"11:a4:15","to":"11:a1:90"},{"from":"11:a4:15","to":"11:a1:91"},{"from":"26:82:72","to":"11:a1:92"},{"from":"10:98:25","to":"11:a1:93"},{"from":"11:a0:e7","to":"11:a1:94"},{"from":"11:a3:3e","to":"11:a1:95"},{"from":"26:82:72","to":"11:a1:96"},{"from":"11:a2:cf","to":"11:a1:98"},{"from":"11:a1:bd","to":"11:a1:99"},{"from":"11:a4:15","to":"11:a1:9a"},{"from":"11:a4:15","to":"11:a1:9b"},{"from":"11:a0:e7","to":"11:a1:9e"},{"from":"11:a2:b9","to":"11:a1:9f"},{"from":"11:a1:38","to":"11:a1:a0"},{"from":"11:a1:00","to":"11:a1:a1"},{"from":"11:a0:f4","to":"11:a1:a2"},{"from":"king","to":"11:a1:a3"},{"from":"11:a2:ab","to":"11:a1:a4"},{"from":"11:a2:56","to":"11:a1:a7"},{"from":"11:a2:5b","to":"11:a1:a9"},{"from":"11:a1:69","to":"11:a1:aa"},{"from":"11:a1:35","to":"11:a1:ab"},{"from":"11:a0:e7","to":"11:a1:ac"},{"from":"11:a0:f6","to":"11:a1:ad"},{"from":"11:a0:cb","to":"11:a1:ae"},{"from":"11:a2:4b","to":"11:a1:af"},{"from":"11:a2:ab","to":"11:a1:b1"},{"from":"11:a0:cb","to":"11:a1:b3"},{"from":"10:98:25","to":"11:a1:b7"},{"from":"11:a2:ab","to":"11:a1:b8"},{"from":"11:a1:0a","to":"11:a1:b9"},{"from":"11:a0:d0","to":"11:a1:ba"},{"from":"11:a0:e7","to":"11:a1:bb"},{"from":"11:a2:da","to":"11:a1:bc"},{"from":"11:a1:93","to":"11:a1:bd"},{"from":"11:a2:5b","to":"11:a1:be"},{"from":"11:a2:20","to":"11:a1:bf"},{"from":"11:a2:20","to":"11:a1:c0"},{"from":"26:82:72","to":"11:a1:c1"},{"from":"11:a1:3c","to":"11:a1:c3"},{"from":"king","to":"11:a1:c4"},{"from":"11:a3:3e","to":"11:a1:c5"},{"from":"11:a2:20","to":"11:a1:c6"},{"from":"11:a2:56","to":"11:a1:c7"},{"from":"11:a1:35","to":"11:a1:c9"},{"from":"11:a3:3e","to":"11:a1:ca"},{"from":"11:a0:ed","to":"11:a1:cb"},{"from":"11:a0:f6","to":"11:a1:cd"},{"from":"11:a0:f6","to":"11:a1:ce"},{"from":"11:a1:3c","to":"11:a1:cf"},{"from":"11:a1:ac","to":"11:a1:d1"},{"from":"11:a2:20","to":"11:a1:d2"},{"from":"11:a3:2b","to":"11:a1:d3"},{"from":"11:a1:f7","to":"11:a1:d4"},{"from":"11:a2:da","to":"11:a1:d6"},{"from":"11:a2:ab","to":"11:a1:d7"},{"from":"10:98:25","to":"11:a1:d8"},{"from":"11:a2:b9","to":"11:a1:da"},{"from":"11:a2:b1","to":"11:a1:db"},{"from":"11:a3:3e","to":"11:a1:dc"},{"from":"11:a1:ff","to":"11:a1:dd"},{"from":"11:a1:f7","to":"11:a1:de"},{"from":"11:a4:15","to":"11:a1:df"},{"from":"11:a0:d7","to":"11:a1:e0"},{"from":"11:a3:4b","to":"11:a1:e1"},{"from":"11:a2:b9","to":"11:a1:e2"},{"from":"11:a3:3e","to":"11:a1:e3"},{"from":"11:a3:4b","to":"11:a1:e4"},{"from":"11:a1:f7","to":"11:a1:e6"},{"from":"11:a3:2b","to":"11:a1:e7"},{"from":"11:a3:3e","to":"11:a1:e8"},{"from":"11:a3:8e","to":"11:a1:e9"},{"from":"11:a3:8e","to":"11:a1:ea"},{"from":"11:a1:3c","to":"11:a1:ee"},{"from":"11:a2:b9","to":"11:a1:ef"},{"from":"11:a1:d1","to":"11:a1:f0"},{"from":"11:a3:2b","to":"11:a1:f3"},{"from":"11:a2:12","to":"11:a1:f4"},{"from":"11:a1:f7","to":"11:a1:f5"},{"from":"11:a1:ff","to":"11:a1:f6"},{"from":"11:a2:b1","to":"11:a1:f7"},{"from":"11:a2:b1","to":"11:a1:f9"},{"from":"11:a2:b1","to":"11:a1:fa"},{"from":"11:a1:3c","to":"11:a1:fb"},{"from":"11:a1:31","to":"11:a1:fc"},{"from":"11:a3:4b","to":"11:a1:fd"},{"from":"26:82:72","to":"11:a1:ff"},{"from":"11:a3:3e","to":"11:a2:01"},{"from":"11:a0:c7","to":"11:a2:02"},{"from":"11:a1:56","to":"11:a2:03"},{"from":"11:a2:cf","to":"11:a2:06"},{"from":"11:a2:b1","to":"11:a2:09"},{"from":"11:a2:b1","to":"11:a2:0a"},{"from":"11:a2:ab","to":"11:a2:0c"},{"from":"11:a2:33","to":"11:a2:0f"},{"from":"11:a2:6e","to":"11:a2:10"},{"from":"11:a0:d0","to":"11:a2:11"},{"from":"11:29:05","to":"11:a2:12"},{"from":"11:a1:69","to":"11:a2:13"},{"from":"11:a2:b1","to":"11:a2:14"},{"from":"11:a0:c7","to":"11:a2:15"},{"from":"11:29:07","to":"11:a2:17"},{"from":"11:a2:b1","to":"11:a2:1b"},{"from":"11:a1:2e","to":"11:a2:1c"},{"from":"11:a0:c7","to":"11:a2:1f"},{"from":"11:a2:2e","to":"11:a2:20"},{"from":"11:a1:f7","to":"11:a2:21"},{"from":"11:a1:00","to":"11:a2:22"},{"from":"11:a3:4b","to":"11:a2:24"},{"from":"11:a1:f7","to":"11:a2:28"},{"from":"11:a0:e7","to":"11:a2:29"},{"from":"11:a1:f7","to":"11:a2:2a"},{"from":"11:a1:93","to":"11:a2:2e"},{"from":"11:a2:71","to":"11:a2:33"},{"from":"11:a2:71","to":"11:a2:35"},{"from":"11:a1:f7","to":"11:a2:36"},{"from":"11:a2:da","to":"11:a2:37"},{"from":"10:98:25","to":"11:a2:38"},{"from":"10:98:25","to":"11:a2:3a"},{"from":"11:a1:3c","to":"11:a2:3c"},{"from":"11:a0:e7","to":"11:a2:3e"},{"from":"11:a1:f7","to":"11:a2:3f"},{"from":"11:a1:af","to":"11:a2:40"},{"from":"11:a2:71","to":"11:a2:41"},{"from":"26:82:72","to":"11:a2:44"},{"from":"26:82:72","to":"11:a2:48"},{"from":"11:a1:31","to":"11:a2:49"},{"from":"11:a0:f4","to":"11:a2:4b"},{"from":"11:a0:c7","to":"11:a2:4c"},{"from":"11:a2:3f","to":"11:a2:4d"},{"from":"11:a2:52","to":"11:a2:4e"},{"from":"11:a2:b9","to":"11:a2:51"},{"from":"11:a1:d8","to":"11:a2:52"},{"from":"11:a0:ed","to":"11:a2:55"},{"from":"11:a1:3e","to":"11:a2:56"},{"from":"11:a1:87","to":"11:a2:57"},{"from":"11:a2:cf","to":"11:a2:58"},{"from":"11:a2:56","to":"11:a2:5b"},{"from":"11:a2:b1","to":"11:a2:5e"},{"from":"11:a1:69","to":"11:a2:5f"},{"from":"11:a2:b9","to":"11:a2:60"},{"from":"king","to":"11:a2:61"},{"from":"11:a1:f7","to":"11:a2:65"},{"from":"11:a0:d0","to":"11:a2:66"},{"from":"11:a0:f4","to":"11:a2:6a"},{"from":"11:a1:35","to":"11:a2:6b"},{"from":"11:a1:0a","to":"11:a2:6c"},{"from":"11:a2:b9","to":"11:a2:6d"},{"from":"11:a2:ab","to":"11:a2:6e"},{"from":"11:a1:ff","to":"11:a2:6f"},{"from":"11:a1:f7","to":"11:a2:71"},{"from":"11:a4:15","to":"11:a2:ab"},{"from":"11:a3:3e","to":"11:a2:b1"},{"from":"11:a3:2b","to":"11:a2:b9"},{"from":"11:a3:4b","to":"11:a2:cf"},{"from":"11:a3:4b","to":"11:a2:da"},{"from":"11:a3:3e","to":"11:a3:2b"},{"from":"king","to":"11:a3:3e"},{"from":"11:a1:00","to":"11:a3:4b"},{"from":"11:a3:3e","to":"11:a3:8e"},{"from":"11:a2:cf","to":"11:a4:15"},{"from":"11:a0:ff","to":"11:28:f0"},{"from":"11:a2:68","to":"11:29:16"},{"from":"11:a2:68","to":"11:a0:f0"},{"from":"11:a1:9d","to":"11:a1:7f"},{"from":"11:a1:38","to":"11:a1:89"},{"from":"11:a1:cc","to":"11:a1:9d"},{"from":"11:a1:cc","to":"11:a1:b2"},{"from":"11:a2:68","to":"11:a1:b4"},{"from":"11:a1:9d","to":"11:a1:b5"},{"from":"11:a0:f0","to":"11:a1:cc"},{"from":"11:a0:f0","to":"11:a1:d5"},{"from":"11:a0:f0","to":"11:a1:fe"},{"from":"11:a0:f0","to":"11:a2:1e"},{"from":"11:a1:16","to":"11:a2:2c"},{"from":"11:29:1c","to":"11:a2:68"},{"from":"26:82:72","to":"40:7f:0d"}]') }; + + for (var i = 0 ; i < data.nodes.length; i++) { + data.nodes[i].label = data.nodes[i].id + } // create a network var status = document.getElementById('status'); var container = document.getElementById('mynetwork'); @@ -45,7 +51,7 @@ sortMethod: "directed" } }, - physics: false, //{stabilization:false}, + physics: false,//{stabilization:false}, configure:"layout, physics" }; network = new vis.Network(container, data, options);