Browse Source

fixed few (but not all clustering issues)

v3_develop
Alex de Mulder 9 years ago
parent
commit
4cb8f20679
3 changed files with 27240 additions and 27188 deletions
  1. +27188
    -27162
      dist/vis.js
  2. +6
    -2
      lib/network/Network.js
  3. +46
    -24
      lib/network/mixins/ClusterMixin.js

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


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

@ -164,7 +164,8 @@ function Network (container, data, options) {
radius: 1}, // (px PNiC) | growth of the radius per node in cluster. radius: 1}, // (px PNiC) | growth of the radius per node in cluster.
maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster. maxNodeSizeIncrements: 600, // (# increments) | max growth of the width per node in cluster.
activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open. activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open.
clusterLevelDifference: 2
clusterLevelDifference: 2,
clusterByZoom: true // enable clustering through zooming in and out
}, },
navigation: { navigation: {
enabled: false enabled: false
@ -873,7 +874,10 @@ Network.prototype._createKeyBinds = function() {
this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown");
this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup");
} }
this.keycharm.bind("1",this.increaseClusterLevel.bind(me), "keydown");
this.keycharm.bind("2",this.decreaseClusterLevel.bind(me), "keydown");
this.keycharm.bind("3",this.forceAggregateHubs.bind(me,true),"keydown");
this.keycharm.bind("4",this.normalizeClusterLevels.bind(me), "keydown");
if (this.constants.dataManipulation.enabled == true) { if (this.constants.dataManipulation.enabled == true) {
this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); this.keycharm.bind("esc",this._createManipulatorBar.bind(me));
this.keycharm.bind("delete",this._deleteSelected.bind(me)); this.keycharm.bind("delete",this._deleteSelected.bind(me));

+ 46
- 24
lib/network/mixins/ClusterMixin.js View File

@ -32,22 +32,24 @@ exports.startWithClustering = function() {
exports.clusterToFit = function(maxNumberOfNodes, reposition) { exports.clusterToFit = function(maxNumberOfNodes, reposition) {
var numberOfNodes = this.nodeIndices.length; var numberOfNodes = this.nodeIndices.length;
var maxLevels = 50;
var maxLevels = 2;
var level = 0; var level = 0;
// we first cluster the hubs, then we pull in the outliers, repeat // we first cluster the hubs, then we pull in the outliers, repeat
while (numberOfNodes > maxNumberOfNodes && level < maxLevels) { while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
if (level % 3 == 0) {
this.forceAggregateHubs(true);
this.normalizeClusterLevels();
console.log("Performing clustering:", level, numberOfNodes, this.clusterSession);
if (level % 3 == 0.0) {
//this.forceAggregateHubs(true);
//this.normalizeClusterLevels();
} }
else { else {
this.increaseClusterLevel(); // this also includes a cluster normalization
//this.increaseClusterLevel(); // this also includes a cluster normalization
} }
//this.forceAggregateHubs(true);
numberOfNodes = this.nodeIndices.length; numberOfNodes = this.nodeIndices.length;
level += 1; level += 1;
} }
console.log("finished")
// after the clustering we reposition the nodes to reduce the initial chaos // after the clustering we reposition the nodes to reduce the initial chaos
if (level > 0 && reposition == true) { if (level > 0 && reposition == true) {
@ -98,7 +100,7 @@ exports.openCluster = function(node) {
* This calls the updateClustes with default arguments * This calls the updateClustes with default arguments
*/ */
exports.updateClustersDefault = function() { exports.updateClustersDefault = function() {
if (this.constants.clustering.enabled == true) {
if (this.constants.clustering.enabled == true && this.constants.clustering.clusterByZoom == true) {
this.updateClusters(0,false,false); this.updateClusters(0,false,false);
} }
}; };
@ -224,7 +226,7 @@ exports._aggregateHubs = function(force) {
/** /**
* This function is fired by keypress. It forces hubs to form.
* This function forces hubs to form.
* *
*/ */
exports.forceAggregateHubs = function(doNotStart) { exports.forceAggregateHubs = function(doNotStart) {
@ -235,6 +237,7 @@ exports.forceAggregateHubs = function(doNotStart) {
// update the index list, dynamic edges and labels // update the index list, dynamic edges and labels
this._updateNodeIndexList(); this._updateNodeIndexList();
this._updateCalculationNodes();
this._updateDynamicEdges(); this._updateDynamicEdges();
this.updateLabels(); this.updateLabels();
@ -347,7 +350,7 @@ exports._expandClusterNode = function(parentNode, recursive, force, openAll) {
* @private * @private
*/ */
exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) { exports._expelChildFromParent = function(parentNode, containedNodeId, recursive, force, openAll) {
var childNode = parentNode.containedNodes[containedNodeId];
var childNode = parentNode.containedNodes[containedNodeId]
// if child node has been added on smaller scale than current, kick out // if child node has been added on smaller scale than current, kick out
if (childNode.formationScale < this.scale || force == true) { if (childNode.formationScale < this.scale || force == true) {
@ -502,10 +505,10 @@ exports._forceClustersByZoom = function() {
var childNode = this.nodes[nodeId]; var childNode = this.nodes[nodeId];
// the edges can be swallowed by another decrease // the edges can be swallowed by another decrease
if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) { if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) {
var edge = childNode.dynamicEdges[0]; var edge = childNode.dynamicEdges[0];
var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId]; var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId];
// group to the largest node // group to the largest node
if (childNode.id != parentNode.id) { if (childNode.id != parentNode.id) {
if (parentNode.options.mass > childNode.options.mass) { if (parentNode.options.mass > childNode.options.mass) {
@ -585,9 +588,14 @@ exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSize
if (absorptionSizeOffset === undefined) { if (absorptionSizeOffset === undefined) {
absorptionSizeOffset = 0; absorptionSizeOffset = 0;
} }
if (hubNode.dynamicEdgesLength < 0) {
console.error(hubNode.dynamicEdgesLength, this.hubThreshold, onlyEqual)
}
// we decide if the node is a hub // we decide if the node is a hub
if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) || if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) ||
(hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) { (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) {
// initialize variables // initialize variables
var dx,dy,length; var dx,dy,length;
var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale; var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale;
@ -600,7 +608,7 @@ exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSize
edgesIdarray.push(hubNode.dynamicEdges[j].id); edgesIdarray.push(hubNode.dynamicEdges[j].id);
} }
// if the hub clustering is not forces, we check if one of the edges connected
// if the hub clustering is not forced, we check if one of the edges connected
// to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold
if (force == false) { if (force == false) {
allowCluster = false; allowCluster = false;
@ -625,17 +633,24 @@ exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSize
// start the clustering if allowed // start the clustering if allowed
if ((!force && allowCluster) || force) { if ((!force && allowCluster) || force) {
// we loop over all edges INITIALLY connected to this hub
var children = [];
var childrenIds = {};
// we loop over all edges INITIALLY connected to this hub to get a list of the childNodes
for (j = 0; j < amountOfInitialEdges; j++) { for (j = 0; j < amountOfInitialEdges; j++) {
edge = this.edges[edgesIdarray[j]]; edge = this.edges[edgesIdarray[j]];
// the edge can be clustered by this function in a previous loop
if (edge !== undefined) {
var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId];
// we do not want hubs to merge with other hubs nor do we want to cluster itself.
if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) &&
(childNode.id != hubNode.id)) {
this._addToCluster(hubNode,childNode,force);
}
var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId];
if (childrenIds[childNode.id] === undefined) {
childrenIds[childNode.id] = true;
children.push(childNode);
}
}
for (j = 0; j < children.length; j++) {
var childNode = children[j];
// we do not want hubs to merge with other hubs nor do we want to cluster itself.
if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) &&
(childNode.id != hubNode.id)) {
this._addToCluster(hubNode,childNode,force);
} }
} }
} }
@ -655,14 +670,16 @@ exports._formClusterFromHub = function(hubNode, force, onlyEqual, absorptionSize
exports._addToCluster = function(parentNode, childNode, force) { exports._addToCluster = function(parentNode, childNode, force) {
// join child node in the parent node // join child node in the parent node
parentNode.containedNodes[childNode.id] = childNode; parentNode.containedNodes[childNode.id] = childNode;
//console.log(parentNode.id, childNode.id)
// manage all the edges connected to the child and parent nodes // manage all the edges connected to the child and parent nodes
for (var i = 0; i < childNode.dynamicEdges.length; i++) { for (var i = 0; i < childNode.dynamicEdges.length; i++) {
var edge = childNode.dynamicEdges[i]; var edge = childNode.dynamicEdges[i];
if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode
//console.log("COLLECT",parentNode.id, childNode.id, edge.toId, edge.fromId)
this._addToContainedEdges(parentNode,childNode,edge); this._addToContainedEdges(parentNode,childNode,edge);
} }
else { else {
//console.log("REWIRE",parentNode.id, childNode.id, edge.toId, edge.fromId)
this._connectEdgeToCluster(parentNode,childNode,edge); this._connectEdgeToCluster(parentNode,childNode,edge);
} }
} }
@ -690,7 +707,6 @@ exports._addToCluster = function(parentNode, childNode, force) {
// forced clusters only open from screen size and double tap // forced clusters only open from screen size and double tap
if (force == true) { if (force == true) {
// parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3);
parentNode.formationScale = 0; parentNode.formationScale = 0;
} }
else { else {
@ -739,6 +755,10 @@ exports._updateDynamicEdges = function() {
} }
} }
} }
if (node.dynamicEdgesLength < correction) {
console.error("overshoot", node.dynamicEdgesLength, correction)
}
node.dynamicEdgesLength -= correction; node.dynamicEdgesLength -= correction;
} }
}; };
@ -894,12 +914,14 @@ exports._connectEdgeBackToChild = function(parentNode, childNode) {
* @private * @private
*/ */
exports._validateEdges = function(parentNode) { exports._validateEdges = function(parentNode) {
var dynamicEdges = []
for (var i = 0; i < parentNode.dynamicEdges.length; i++) { for (var i = 0; i < parentNode.dynamicEdges.length; i++) {
var edge = parentNode.dynamicEdges[i]; var edge = parentNode.dynamicEdges[i];
if (parentNode.id != edge.toId && parentNode.id != edge.fromId) {
parentNode.dynamicEdges.splice(i,1);
if (parentNode.id == edge.toId || parentNode.id == edge.fromId) {
dynamicEdges.push(edge);
} }
} }
parentNode.dynamicEdges = dynamicEdges;
}; };

Loading…
Cancel
Save