Browse Source

Succesfully mixed universes into graph. Universes work. Graphics needed

css_transitions
Alex de Mulder 11 years ago
parent
commit
0c64bd1bc3
6 changed files with 457 additions and 456 deletions
  1. +1
    -1
      Jakefile.js
  2. +209
    -209
      dist/vis.js
  3. +32
    -94
      src/graph/Graph.js
  4. +180
    -0
      src/graph/UniverseMixin.js
  5. +35
    -2
      src/graph/cluster.js
  6. +0
    -150
      src/graph/universe.js

+ 1
- 1
Jakefile.js View File

@ -83,7 +83,7 @@ task('build', {async: true}, function () {
'./src/graph/Popup.js', './src/graph/Popup.js',
'./src/graph/Groups.js', './src/graph/Groups.js',
'./src/graph/Images.js', './src/graph/Images.js',
'./src/graph/Universe.js',
'./src/graph/UniverseMixin.js',
'./src/graph/Cluster.js', './src/graph/Cluster.js',
'./src/graph/Graph.js', './src/graph/Graph.js',

+ 209
- 209
dist/vis.js View File

@ -4,8 +4,8 @@
* *
* A dynamic, browser-based visualization library. * A dynamic, browser-based visualization library.
* *
* @version @@version
* @date @@date
* @version 0.4.0-SNAPSHOT
* @date 2014-01-17
* *
* @license * @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com * Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -10529,155 +10529,185 @@ Images.prototype.load = function(url) {
}; };
var UniverseMixin = {
_putDataInUniverse : function() {
this.universe["activePockets"][this._universe()].nodes = this.nodes;
this.universe["activePockets"][this._universe()].edges = this.edges;
this.universe["activePockets"][this._universe()].nodeIndices = this.nodeIndices;
},
_switchToUniverse : function(universeID) {
this.nodeIndices = this.universe["activePockets"][universeID]["nodeIndices"];
this.nodes = this.universe["activePockets"][universeID]["nodes"];
this.edges = this.universe["activePockets"][universeID]["edges"];
},
function Universe() {
this.universe = {};
this.activeUniverse = ["default"];
this.universe["activePockets"] = {};
this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]] = {"nodes":{},"edges":{},"nodeIndices":[]};
this.universe["frozenPockets"] = {};
this.universe["draw"] = {};
_loadActiveUniverse : function() {
this._switchToUniverse(this._universe());
},
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields
}
_universe : function() {
return this.activeUniverse[this.activeUniverse.length-1];
},
_previousUniverse : function() {
if (this.activeUniverse.length > 1) {
return this.activeUniverse[this.activeUniverse.length-2];
}
else {
throw new TypeError('there are not enough universes in the this.activeUniverse array.');
return "";
}
},
Universe.prototype._putDataInUniverse = function() {
this.universe["activePockets"][this._universe()].nodes = this.nodes;
this.universe["activePockets"][this._universe()].edges = this.edges;
this.universe["activePockets"][this._universe()].nodeIndices = this.nodeIndices;
};
_setActiveUniverse : function(newID) {
this.activeUniverse.push(newID);
},
Universe.prototype._switchToUniverse = function(universeID) {
this.nodeIndices = this.universe["activePockets"][universeID]["nodeIndices"];
this.nodes = this.universe["activePockets"][universeID]["nodes"];
this.edges = this.universe["activePockets"][universeID]["edges"];
};
_forgetLastUniverse : function() {
this.activeUniverse.pop();
},
Universe.prototype._loadActiveUniverse = function() {
this._switchToUniverse(this._universe());
};
_createNewUniverse : function(newID) {
this.universe["activePockets"][newID] = {"nodes":{ },"edges":{ },"nodeIndices":[]}
},
Universe.prototype._universe = function() {
return this.activeUniverse[this.activeUniverse.length-1];
};
_deleteActiveUniverse : function(universeID) {
delete this.universe["activePockets"][universeID];
},
Universe.prototype._previousUniverse = function() {
if (this.activeUniverse.length > 1) {
return this.activeUniverse[this.activeUniverse.length-2];
}
else {
throw new TypeError('there are not enough universes in the this.activeUniverse array.');
return "";
}
};
_deleteFrozenUniverse : function(universeID) {
delete this.universe["frozenPockets"][universeID];
},
Universe.prototype._setActiveUniverse = function(newID) {
this.activeUniverse.push(newID);
};
_freezeUniverse : function(universeID) {
this.universe["frozenPockets"][universeID] = this.universe["activePockets"][universeID];
this._deleteActiveUniverse(universeID);
},
Universe.prototype._forgetLastUniverse = function() {
this.activeUniverse.pop();
};
_activateUniverse : function(universeID) {
this.universe["activePockets"][universeID] = this.universe["frozenPockets"][universeID];
this._deleteFrozenUniverse(universeID);
},
Universe.prototype._createNewUniverse = function(newID) {
this.universe["activePockets"][newID] = {"nodes":{},"edges":{},"nodeIndices":[]}
};
_mergeThisWithFrozen : function(universeID) {
for (var nodeID in this.nodes) {
if (this.nodes.hasOwnProperty(nodeID)) {
this.universe["frozenPockets"][universeID]["nodes"][nodeID] = this.nodes[nodeID];
}
}
Universe.prototype._deleteActiveUniverse = function(universeID) {
delete this.universe["activePockets"][universeID];
};
for (var edgeID in this.edges) {
if (this.edges.hasOwnProperty(edgeID)) {
this.universe["frozenPockets"][universeID]["edges"][edgeID] = this.edges[edgeID];
}
}
Universe.prototype._deleteFrozenUniverse = function(universeID) {
delete this.universe["frozenPockets"][universeID];
};
for (var i = 0; i < this.nodeIndices.length; i++) {
this.universe["frozenPockets"][universeID]["nodeIndices"].push(this.nodeIndices[i]);
}
},
Universe.prototype._freezeUniverse = function(universeID) {
this.universe["frozenPockets"][universeID] = this.universe["activePockets"][universeID];
this._deleteActiveUniverse(universeID);
};
_collapseThisToSingleCluster : function() {
this.clusterToFit(1,false);
},
Universe.prototype._activateUniverse = function(universeID) {
this.universe["activePockets"][universeID] = this.universe["frozenPockets"][universeID];
this._deleteFrozenUniverse(universeID);
};
Universe.prototype._mergeThisWithFrozen = function(universeID) {
for (var nodeID in this.nodes) {
if (this.nodes.hasOwnProperty(nodeID)) {
this.universe["frozenPockets"][universeID]["nodes"][nodeID] = this.nodes[nodeID];
_addUniverse : function(node) {
var universe = this._universe();
if (this.universe['activePockets'][universe]["nodes"].hasOwnProperty(node.id)) {
console.log("the node is part of the active universe");
} }
}
for (var edgeID in this.edges) {
if (this.edges.hasOwnProperty(edgeID)) {
this.universe["frozenPockets"][universeID]["edges"][edgeID] = this.edges[edgeID];
else {
console.log("I dont konw what the fuck happened!!");
} }
}
for (var i = 0; i < this.nodeIndices.length; i++) {
this.universe["frozenPockets"][universeID]["edges"][nodeIndices].push(this.nodeIndices[i]);
}
};
Universe.prototype._collapseThisToSingleCluster = function() {
this.clusterToFit(1,false);
};
delete this.nodes[node.id];
this._freezeUniverse(universe);
this._createNewUniverse(node.id);
Universe.prototype._addUniverse = function(node) {
var universe = this._universe();
if (this.universe['activePockets'][universe]["nodes"].hasOwnProperty(node.id)) {
console.log("the node is part of the active universe");
}
else {
console.log("I dont konw what the fuck happened!!");
}
delete this.nodes[node.id];
this._setActiveUniverse(node.id);
this._switchToUniverse(this._universe());
this._freezeUniverse(universe);
this._createNewUniverse(node.id);
this.nodes[node.id] = node;
//this.universe["draw"][node.id] = new Node(node.nodeProperties,node.imagelist,node.grouplist,this.constants);
},
this._setActiveUniverse(node.id);
this._switchToUniverse(this._universe());
_collapseUniverse : function() {
var universe = this._universe();
this.nodes[node.id] = node;
//this.universe["draw"][node.id] = new Node(node.nodeProperties,node.imagelist,node.grouplist,this.constants);
};
if (universe != "default") {
var isMovingBeforeClustering = this.moving;
Universe.prototype._collapseUniverse = function() {
var universe = this._universe();
var previousUniverse = this._previousUniverse();
if (universe != "default") {
var isMovingBeforeClustering = this.moving;
this._collapseThisToSingleCluster();
var previousUniverse = this._previousUniverse();
this._mergeThisWithFrozen(previousUniverse);
this._collapseThisToSingleCluster();
this._deleteActiveUniverse(universe);
this._mergeThisWithFrozen(previousUniverse);
this._activateUniverse(previousUniverse);
this._deleteActiveUniverse(universe);
this._switchToUniverse(previousUniverse);
this._activateUniverse(previousUniverse);
this._forgetLastUniverse();
this._switchToUniverse(previousUniverse);
this._updateNodeIndexList();
this._forgetLastUniverse();
// if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
if (this.moving != isMovingBeforeClustering) {
this.start();
}
}
},
this._updateNodeIndexList();
_doInAllActiveUniverses : function(runFunction,args) {
if (args === undefined) {
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction]();
}
}
}
else {
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction](args);
}
}
}
this._loadActiveUniverse();
},
// if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
if (this.moving != isMovingBeforeClustering) {
this.start();
_doInAllFrozenUniverses : function(runFunction,args) {
if (args === undefined) {
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction]();
}
}
} }
else {
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction](args);
}
}
}
this._loadActiveUniverse();
},
_doInAllUniverses : function(runFunction,argument) {
this._doInAllActiveUniverses(runFunction,argument);
this._doInAllFrozenUniverses(runFunction,argument);
} }
}; };
Universe.prototype._doInAllActiveUniverses = function(runFunction,arguments) {
}
/** /**
* @constructor Cluster * @constructor Cluster
* Contains the cluster properties for the graph object * Contains the cluster properties for the graph object
@ -10689,16 +10719,49 @@ function Cluster() {
} }
/** /**
* This function can be called to open up a specific cluster.
* This function clusters until the maxNumberOfNodes has been reached
*
* @param {Number} maxNumberOfNodes
* @param {Boolean} reposition
*/
Cluster.prototype.clusterToFit = function(maxNumberOfNodes, reposition) {
var numberOfNodes = this.nodeIndices.length;
var maxLevels = 15;
var level = 0;
// we first cluster the hubs, then we pull in the outliers, repeat
while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
if (level % 5 == 0) {
console.log("Aggregating Hubs @ level: ",level,". Threshold:", this.hubThreshold,"clusterSession",this.clusterSession);
this.forceAggregateHubs();
}
else {
console.log("Pulling in Outliers @ level: ",level,"clusterSession",this.clusterSession);
this.increaseClusterLevel();
}
numberOfNodes = this.nodeIndices.length;
level += 1;
}
// after the clustering we reposition the nodes to reduce the initial chaos
if (level > 1 && reposition == true) {
this.repositionNodes();
}
};
/**
* This function can be called to open up a specific cluster. It is only called by
* It will unpack the cluster back one level. * It will unpack the cluster back one level.
* *
* @param node | Node object: cluster to open. * @param node | Node object: cluster to open.
*/ */
Cluster.prototype.openCluster = function(node) { Cluster.prototype.openCluster = function(node) {
var isMovingBeforeClustering = this.moving;
if (node.clusterSize > 15) { if (node.clusterSize > 15) {
this._addUniverse(node); this._addUniverse(node);
} }
var isMovingBeforeClustering = this.moving;
this._expandClusterNode(node,false,true); this._expandClusterNode(node,false,true);
@ -11694,7 +11757,7 @@ function Graph (container, data, options) {
Cluster.call(this); Cluster.call(this);
// call the universe constructor // call the universe constructor
Universe.call(this);
this._loadUniverse(); // would be fantastic if multiple in heritance just worked!
var graph = this; var graph = this;
this.freezeSimulation = false;// freeze the simulation this.freezeSimulation = false;// freeze the simulation
@ -11788,47 +11851,12 @@ function Graph (container, data, options) {
} }
// add the universe functionality to this
Graph.prototype = Object.create(Universe.prototype);
/** /**
* We add the functionality of the cluster object to the graph object * We add the functionality of the cluster object to the graph object
* @type {Cluster.prototype} * @type {Cluster.prototype}
*/ */
Graph.prototype = Object.create(Cluster.prototype); Graph.prototype = Object.create(Cluster.prototype);
/**
* This function clusters until the maxNumberOfNodes has been reached
*
* @param {Number} maxNumberOfNodes
* @param {Boolean} reposition
*/
Graph.prototype.clusterToFit = function(maxNumberOfNodes, reposition) {
var numberOfNodes = this.nodeIndices.length;
var maxLevels = 15;
var level = 0;
// we first cluster the hubs, then we pull in the outliers, repeat
while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
if (level % 5 == 0) {
console.log("Aggregating Hubs @ level: ",level,". Threshold:", this.hubThreshold,"clusterSession",this.clusterSession);
this.forceAggregateHubs();
}
else {
console.log("Pulling in Outliers @ level: ",level,"clusterSession",this.clusterSession);
this.increaseClusterLevel();
}
numberOfNodes = this.nodeIndices.length;
level += 1;
}
// after the clustering we reposition the nodes to reduce the initial chaos
if (level > 1 && reposition == true) {
this.repositionNodes();
}
};
/** /**
* This function zooms out to fit all data on screen based on amount of nodes * This function zooms out to fit all data on screen based on amount of nodes
*/ */
@ -11851,7 +11879,7 @@ Graph.prototype.zoomToFit = function() {
* @private * @private
*/ */
Graph.prototype._updateNodeIndexList = function() { Graph.prototype._updateNodeIndexList = function() {
var universe = this.activeUniverse[this.activeUniverse.length-1];
var universe = this._universe();
this.universe["activePockets"][universe]["nodeIndices"] = []; this.universe["activePockets"][universe]["nodeIndices"] = [];
this.nodeIndices = this.universe["activePockets"][universe]["nodeIndices"]; this.nodeIndices = this.universe["activePockets"][universe]["nodeIndices"];
for (var idx in this.nodes) { for (var idx in this.nodes) {
@ -12045,7 +12073,7 @@ Graph.prototype._create = function () {
this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); this.hammer.on('mousewheel',me._onMouseWheel.bind(me) );
this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF
this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) );
/*
this.mouseTrap = mouseTrap; this.mouseTrap = mouseTrap;
this.mouseTrap.bind("=",this.decreaseClusterLevel.bind(me)); this.mouseTrap.bind("=",this.decreaseClusterLevel.bind(me));
this.mouseTrap.bind("-",this.increaseClusterLevel.bind(me)); this.mouseTrap.bind("-",this.increaseClusterLevel.bind(me));
@ -12053,7 +12081,7 @@ Graph.prototype._create = function () {
this.mouseTrap.bind("h",this.updateClustersDefault.bind(me)); this.mouseTrap.bind("h",this.updateClustersDefault.bind(me));
this.mouseTrap.bind("c",this._collapseUniverse.bind(me)); this.mouseTrap.bind("c",this._collapseUniverse.bind(me));
this.mouseTrap.bind("f",this.toggleFreeze.bind(me)); this.mouseTrap.bind("f",this.toggleFreeze.bind(me));
*/
// add the frame to the container element // add the frame to the container element
this.containerElement.appendChild(this.frame); this.containerElement.appendChild(this.frame);
}; };
@ -13134,41 +13162,8 @@ Graph.prototype._redraw = function() {
ctx.translate(this.translation.x, this.translation.y); ctx.translate(this.translation.x, this.translation.y);
ctx.scale(this.scale, this.scale); ctx.scale(this.scale, this.scale);
// this._drawEdges(ctx);
// this._drawNodes(ctx);
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this.edges = this.universe["activePockets"][universe]["edges"];
this._drawEdges(ctx);
}
}
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this.edges = this.universe["frozenPockets"][universe]["edges"];
this._drawEdges(ctx);
}
}
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this.nodes = this.universe["activePockets"][universe]["nodes"];
this._drawNodes(ctx);
}
}
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this.nodes = this.universe["frozenPockets"][universe]["nodes"];
this._drawNodes(ctx);
}
}
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"];
this.nodes = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodes"];
this.edges = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["edges"];
this._doInAllUniverses("_drawEdges",ctx);
this._doInAllUniverses("_drawNodes",ctx);
// restore original scaling and translation // restore original scaling and translation
ctx.restore(); ctx.restore();
@ -13379,7 +13374,8 @@ Graph.prototype._calculateForces = function(nodes,edges) {
var gravity = 0.08; var gravity = 0.08;
for (i = 0; i < this.nodeIndices.length; i++) { for (i = 0; i < this.nodeIndices.length; i++) {
node = nodes[this.nodeIndices[i]]; node = nodes[this.nodeIndices[i]];
if (this.activeUniverse[this.activeUniverse.length-1] == "default") {
// gravity does not apply when we are in a pocket universe
if (this._universe() == "default") {
dx = -node.x + centerPos.x; dx = -node.x + centerPos.x;
dy = -node.y + centerPos.y; dy = -node.y + centerPos.y;
@ -13584,6 +13580,9 @@ Graph.prototype._discreteStepNodes = function() {
nodes[id].discreteStep(interval); nodes[id].discreteStep(interval);
} }
} }
var vmin = this.constants.minVelocity;
this.moving = this._isMoving(vmin);
}; };
/** /**
@ -13592,25 +13591,8 @@ Graph.prototype._discreteStepNodes = function() {
Graph.prototype.start = function() { Graph.prototype.start = function() {
if (!this.freezeSimulation) { if (!this.freezeSimulation) {
if (this.moving) { if (this.moving) {
var vmin = this.constants.minVelocity;
/*
this._calculateForces();
this._discreteStepNodes();
this.moving = this._isMoving(vmin);
*/
//console.log("no",this.nodes)
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this._calculateForces();
this._discreteStepNodes();
this.moving = this._isMoving(vmin);
}
}
this._loadActiveUniverse();
this._doInAllActiveUniverses("_calculateForces");
this._doInAllActiveUniverses("_discreteStepNodes");
} }
if (this.moving) { if (this.moving) {
@ -13665,6 +13647,24 @@ Graph.prototype.toggleFreeze = function() {
} }
}; };
Graph.prototype._loadUniverse = function() {
this.universe = {};
this.activeUniverse = ["default"];
this.universe["activePockets"] = {};
this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]] = {"nodes":{},"edges":{},"nodeIndices":[]};
this.universe["frozenPockets"] = {};
this.universe["draw"] = {};
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields
for (var mixinFunction in UniverseMixin) {
if (UniverseMixin.hasOwnProperty(mixinFunction)) {
Graph.prototype[mixinFunction] = UniverseMixin[mixinFunction];
}
}
};
/** /**
* vis.js module exports * vis.js module exports
*/ */

+ 32
- 94
src/graph/Graph.js View File

@ -88,7 +88,7 @@ function Graph (container, data, options) {
Cluster.call(this); Cluster.call(this);
// call the universe constructor // call the universe constructor
Universe.call(this);
this._loadUniverse(); // would be fantastic if multiple in heritance just worked!
var graph = this; var graph = this;
this.freezeSimulation = false;// freeze the simulation this.freezeSimulation = false;// freeze the simulation
@ -182,47 +182,12 @@ function Graph (container, data, options) {
} }
// add the universe functionality to this
Graph.prototype = Object.create(Universe.prototype);
/** /**
* We add the functionality of the cluster object to the graph object * We add the functionality of the cluster object to the graph object
* @type {Cluster.prototype} * @type {Cluster.prototype}
*/ */
Graph.prototype = Object.create(Cluster.prototype); Graph.prototype = Object.create(Cluster.prototype);
/**
* This function clusters until the maxNumberOfNodes has been reached
*
* @param {Number} maxNumberOfNodes
* @param {Boolean} reposition
*/
Graph.prototype.clusterToFit = function(maxNumberOfNodes, reposition) {
var numberOfNodes = this.nodeIndices.length;
var maxLevels = 15;
var level = 0;
// we first cluster the hubs, then we pull in the outliers, repeat
while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
if (level % 5 == 0) {
console.log("Aggregating Hubs @ level: ",level,". Threshold:", this.hubThreshold,"clusterSession",this.clusterSession);
this.forceAggregateHubs();
}
else {
console.log("Pulling in Outliers @ level: ",level,"clusterSession",this.clusterSession);
this.increaseClusterLevel();
}
numberOfNodes = this.nodeIndices.length;
level += 1;
}
// after the clustering we reposition the nodes to reduce the initial chaos
if (level > 1 && reposition == true) {
this.repositionNodes();
}
};
/** /**
* This function zooms out to fit all data on screen based on amount of nodes * This function zooms out to fit all data on screen based on amount of nodes
*/ */
@ -245,7 +210,7 @@ Graph.prototype.zoomToFit = function() {
* @private * @private
*/ */
Graph.prototype._updateNodeIndexList = function() { Graph.prototype._updateNodeIndexList = function() {
var universe = this.activeUniverse[this.activeUniverse.length-1];
var universe = this._universe();
this.universe["activePockets"][universe]["nodeIndices"] = []; this.universe["activePockets"][universe]["nodeIndices"] = [];
this.nodeIndices = this.universe["activePockets"][universe]["nodeIndices"]; this.nodeIndices = this.universe["activePockets"][universe]["nodeIndices"];
for (var idx in this.nodes) { for (var idx in this.nodes) {
@ -439,7 +404,7 @@ Graph.prototype._create = function () {
this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); this.hammer.on('mousewheel',me._onMouseWheel.bind(me) );
this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF
this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) );
/*
this.mouseTrap = mouseTrap; this.mouseTrap = mouseTrap;
this.mouseTrap.bind("=",this.decreaseClusterLevel.bind(me)); this.mouseTrap.bind("=",this.decreaseClusterLevel.bind(me));
this.mouseTrap.bind("-",this.increaseClusterLevel.bind(me)); this.mouseTrap.bind("-",this.increaseClusterLevel.bind(me));
@ -447,7 +412,7 @@ Graph.prototype._create = function () {
this.mouseTrap.bind("h",this.updateClustersDefault.bind(me)); this.mouseTrap.bind("h",this.updateClustersDefault.bind(me));
this.mouseTrap.bind("c",this._collapseUniverse.bind(me)); this.mouseTrap.bind("c",this._collapseUniverse.bind(me));
this.mouseTrap.bind("f",this.toggleFreeze.bind(me)); this.mouseTrap.bind("f",this.toggleFreeze.bind(me));
*/
// add the frame to the container element // add the frame to the container element
this.containerElement.appendChild(this.frame); this.containerElement.appendChild(this.frame);
}; };
@ -1528,41 +1493,8 @@ Graph.prototype._redraw = function() {
ctx.translate(this.translation.x, this.translation.y); ctx.translate(this.translation.x, this.translation.y);
ctx.scale(this.scale, this.scale); ctx.scale(this.scale, this.scale);
// this._drawEdges(ctx);
// this._drawNodes(ctx);
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this.edges = this.universe["activePockets"][universe]["edges"];
this._drawEdges(ctx);
}
}
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this.edges = this.universe["frozenPockets"][universe]["edges"];
this._drawEdges(ctx);
}
}
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this.nodes = this.universe["activePockets"][universe]["nodes"];
this._drawNodes(ctx);
}
}
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this.nodes = this.universe["frozenPockets"][universe]["nodes"];
this._drawNodes(ctx);
}
}
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"];
this.nodes = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodes"];
this.edges = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["edges"];
this._doInAllUniverses("_drawEdges",ctx);
this._doInAllUniverses("_drawNodes",ctx);
// restore original scaling and translation // restore original scaling and translation
ctx.restore(); ctx.restore();
@ -1773,7 +1705,8 @@ Graph.prototype._calculateForces = function(nodes,edges) {
var gravity = 0.08; var gravity = 0.08;
for (i = 0; i < this.nodeIndices.length; i++) { for (i = 0; i < this.nodeIndices.length; i++) {
node = nodes[this.nodeIndices[i]]; node = nodes[this.nodeIndices[i]];
if (this.activeUniverse[this.activeUniverse.length-1] == "default") {
// gravity does not apply when we are in a pocket universe
if (this._universe() == "default") {
dx = -node.x + centerPos.x; dx = -node.x + centerPos.x;
dy = -node.y + centerPos.y; dy = -node.y + centerPos.y;
@ -1978,6 +1911,9 @@ Graph.prototype._discreteStepNodes = function() {
nodes[id].discreteStep(interval); nodes[id].discreteStep(interval);
} }
} }
var vmin = this.constants.minVelocity;
this.moving = this._isMoving(vmin);
}; };
/** /**
@ -1986,25 +1922,8 @@ Graph.prototype._discreteStepNodes = function() {
Graph.prototype.start = function() { Graph.prototype.start = function() {
if (!this.freezeSimulation) { if (!this.freezeSimulation) {
if (this.moving) { if (this.moving) {
var vmin = this.constants.minVelocity;
/*
this._calculateForces();
this._discreteStepNodes();
this.moving = this._isMoving(vmin);
*/
//console.log("no",this.nodes)
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this._calculateForces();
this._discreteStepNodes();
this.moving = this._isMoving(vmin);
}
}
this._loadActiveUniverse();
this._doInAllActiveUniverses("_calculateForces");
this._doInAllActiveUniverses("_discreteStepNodes");
} }
if (this.moving) { if (this.moving) {
@ -2058,3 +1977,22 @@ Graph.prototype.toggleFreeze = function() {
this.start(); this.start();
} }
}; };
Graph.prototype._loadUniverse = function() {
this.universe = {};
this.activeUniverse = ["default"];
this.universe["activePockets"] = {};
this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]] = {"nodes":{},"edges":{},"nodeIndices":[]};
this.universe["frozenPockets"] = {};
this.universe["draw"] = {};
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields
for (var mixinFunction in UniverseMixin) {
if (UniverseMixin.hasOwnProperty(mixinFunction)) {
Graph.prototype[mixinFunction] = UniverseMixin[mixinFunction];
}
}
};

+ 180
- 0
src/graph/UniverseMixin.js View File

@ -0,0 +1,180 @@
var UniverseMixin = {
_putDataInUniverse : function() {
this.universe["activePockets"][this._universe()].nodes = this.nodes;
this.universe["activePockets"][this._universe()].edges = this.edges;
this.universe["activePockets"][this._universe()].nodeIndices = this.nodeIndices;
},
_switchToUniverse : function(universeID) {
this.nodeIndices = this.universe["activePockets"][universeID]["nodeIndices"];
this.nodes = this.universe["activePockets"][universeID]["nodes"];
this.edges = this.universe["activePockets"][universeID]["edges"];
},
_loadActiveUniverse : function() {
this._switchToUniverse(this._universe());
},
_universe : function() {
return this.activeUniverse[this.activeUniverse.length-1];
},
_previousUniverse : function() {
if (this.activeUniverse.length > 1) {
return this.activeUniverse[this.activeUniverse.length-2];
}
else {
throw new TypeError('there are not enough universes in the this.activeUniverse array.');
return "";
}
},
_setActiveUniverse : function(newID) {
this.activeUniverse.push(newID);
},
_forgetLastUniverse : function() {
this.activeUniverse.pop();
},
_createNewUniverse : function(newID) {
this.universe["activePockets"][newID] = {"nodes":{ },"edges":{ },"nodeIndices":[]}
},
_deleteActiveUniverse : function(universeID) {
delete this.universe["activePockets"][universeID];
},
_deleteFrozenUniverse : function(universeID) {
delete this.universe["frozenPockets"][universeID];
},
_freezeUniverse : function(universeID) {
this.universe["frozenPockets"][universeID] = this.universe["activePockets"][universeID];
this._deleteActiveUniverse(universeID);
},
_activateUniverse : function(universeID) {
this.universe["activePockets"][universeID] = this.universe["frozenPockets"][universeID];
this._deleteFrozenUniverse(universeID);
},
_mergeThisWithFrozen : function(universeID) {
for (var nodeID in this.nodes) {
if (this.nodes.hasOwnProperty(nodeID)) {
this.universe["frozenPockets"][universeID]["nodes"][nodeID] = this.nodes[nodeID];
}
}
for (var edgeID in this.edges) {
if (this.edges.hasOwnProperty(edgeID)) {
this.universe["frozenPockets"][universeID]["edges"][edgeID] = this.edges[edgeID];
}
}
for (var i = 0; i < this.nodeIndices.length; i++) {
this.universe["frozenPockets"][universeID]["nodeIndices"].push(this.nodeIndices[i]);
}
},
_collapseThisToSingleCluster : function() {
this.clusterToFit(1,false);
},
_addUniverse : function(node) {
var universe = this._universe();
if (this.universe['activePockets'][universe]["nodes"].hasOwnProperty(node.id)) {
console.log("the node is part of the active universe");
}
else {
console.log("I dont konw what the fuck happened!!");
}
delete this.nodes[node.id];
this._freezeUniverse(universe);
this._createNewUniverse(node.id);
this._setActiveUniverse(node.id);
this._switchToUniverse(this._universe());
this.nodes[node.id] = node;
//this.universe["draw"][node.id] = new Node(node.nodeProperties,node.imagelist,node.grouplist,this.constants);
},
_collapseUniverse : function() {
var universe = this._universe();
if (universe != "default") {
var isMovingBeforeClustering = this.moving;
var previousUniverse = this._previousUniverse();
this._collapseThisToSingleCluster();
this._mergeThisWithFrozen(previousUniverse);
this._deleteActiveUniverse(universe);
this._activateUniverse(previousUniverse);
this._switchToUniverse(previousUniverse);
this._forgetLastUniverse();
this._updateNodeIndexList();
// if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
if (this.moving != isMovingBeforeClustering) {
this.start();
}
}
},
_doInAllActiveUniverses : function(runFunction,args) {
if (args === undefined) {
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction]();
}
}
}
else {
for (var universe in this.universe["activePockets"]) {
if (this.universe["activePockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction](args);
}
}
}
this._loadActiveUniverse();
},
_doInAllFrozenUniverses : function(runFunction,args) {
if (args === undefined) {
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction]();
}
}
}
else {
for (var universe in this.universe["frozenPockets"]) {
if (this.universe["frozenPockets"].hasOwnProperty(universe)) {
this._switchToUniverse(universe);
this[runFunction](args);
}
}
}
this._loadActiveUniverse();
},
_doInAllUniverses : function(runFunction,argument) {
this._doInAllActiveUniverses(runFunction,argument);
this._doInAllFrozenUniverses(runFunction,argument);
}
};

+ 35
- 2
src/graph/cluster.js View File

@ -9,16 +9,49 @@ function Cluster() {
} }
/** /**
* This function can be called to open up a specific cluster.
* This function clusters until the maxNumberOfNodes has been reached
*
* @param {Number} maxNumberOfNodes
* @param {Boolean} reposition
*/
Cluster.prototype.clusterToFit = function(maxNumberOfNodes, reposition) {
var numberOfNodes = this.nodeIndices.length;
var maxLevels = 15;
var level = 0;
// we first cluster the hubs, then we pull in the outliers, repeat
while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
if (level % 5 == 0) {
console.log("Aggregating Hubs @ level: ",level,". Threshold:", this.hubThreshold,"clusterSession",this.clusterSession);
this.forceAggregateHubs();
}
else {
console.log("Pulling in Outliers @ level: ",level,"clusterSession",this.clusterSession);
this.increaseClusterLevel();
}
numberOfNodes = this.nodeIndices.length;
level += 1;
}
// after the clustering we reposition the nodes to reduce the initial chaos
if (level > 1 && reposition == true) {
this.repositionNodes();
}
};
/**
* This function can be called to open up a specific cluster. It is only called by
* It will unpack the cluster back one level. * It will unpack the cluster back one level.
* *
* @param node | Node object: cluster to open. * @param node | Node object: cluster to open.
*/ */
Cluster.prototype.openCluster = function(node) { Cluster.prototype.openCluster = function(node) {
var isMovingBeforeClustering = this.moving;
if (node.clusterSize > 15) { if (node.clusterSize > 15) {
this._addUniverse(node); this._addUniverse(node);
} }
var isMovingBeforeClustering = this.moving;
this._expandClusterNode(node,false,true); this._expandClusterNode(node,false,true);

+ 0
- 150
src/graph/universe.js View File

@ -1,150 +0,0 @@
function Universe() {
this.universe = {};
this.activeUniverse = ["default"];
this.universe["activePockets"] = {};
this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]] = {"nodes":{},"edges":{},"nodeIndices":[]};
this.universe["frozenPockets"] = {};
this.universe["draw"] = {};
this.nodeIndices = this.universe["activePockets"][this.activeUniverse[this.activeUniverse.length-1]]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields
}
Universe.prototype._putDataInUniverse = function() {
this.universe["activePockets"][this._universe()].nodes = this.nodes;
this.universe["activePockets"][this._universe()].edges = this.edges;
this.universe["activePockets"][this._universe()].nodeIndices = this.nodeIndices;
};
Universe.prototype._switchToUniverse = function(universeID) {
this.nodeIndices = this.universe["activePockets"][universeID]["nodeIndices"];
this.nodes = this.universe["activePockets"][universeID]["nodes"];
this.edges = this.universe["activePockets"][universeID]["edges"];
};
Universe.prototype._loadActiveUniverse = function() {
this._switchToUniverse(this._universe());
};
Universe.prototype._universe = function() {
return this.activeUniverse[this.activeUniverse.length-1];
};
Universe.prototype._previousUniverse = function() {
if (this.activeUniverse.length > 1) {
return this.activeUniverse[this.activeUniverse.length-2];
}
else {
throw new TypeError('there are not enough universes in the this.activeUniverse array.');
return "";
}
};
Universe.prototype._setActiveUniverse = function(newID) {
this.activeUniverse.push(newID);
};
Universe.prototype._forgetLastUniverse = function() {
this.activeUniverse.pop();
};
Universe.prototype._createNewUniverse = function(newID) {
this.universe["activePockets"][newID] = {"nodes":{},"edges":{},"nodeIndices":[]}
};
Universe.prototype._deleteActiveUniverse = function(universeID) {
delete this.universe["activePockets"][universeID];
};
Universe.prototype._deleteFrozenUniverse = function(universeID) {
delete this.universe["frozenPockets"][universeID];
};
Universe.prototype._freezeUniverse = function(universeID) {
this.universe["frozenPockets"][universeID] = this.universe["activePockets"][universeID];
this._deleteActiveUniverse(universeID);
};
Universe.prototype._activateUniverse = function(universeID) {
this.universe["activePockets"][universeID] = this.universe["frozenPockets"][universeID];
this._deleteFrozenUniverse(universeID);
};
Universe.prototype._mergeThisWithFrozen = function(universeID) {
for (var nodeID in this.nodes) {
if (this.nodes.hasOwnProperty(nodeID)) {
this.universe["frozenPockets"][universeID]["nodes"][nodeID] = this.nodes[nodeID];
}
}
for (var edgeID in this.edges) {
if (this.edges.hasOwnProperty(edgeID)) {
this.universe["frozenPockets"][universeID]["edges"][edgeID] = this.edges[edgeID];
}
}
for (var i = 0; i < this.nodeIndices.length; i++) {
this.universe["frozenPockets"][universeID]["edges"][nodeIndices].push(this.nodeIndices[i]);
}
};
Universe.prototype._collapseThisToSingleCluster = function() {
this.clusterToFit(1,false);
};
Universe.prototype._addUniverse = function(node) {
var universe = this._universe();
if (this.universe['activePockets'][universe]["nodes"].hasOwnProperty(node.id)) {
console.log("the node is part of the active universe");
}
else {
console.log("I dont konw what the fuck happened!!");
}
delete this.nodes[node.id];
this._freezeUniverse(universe);
this._createNewUniverse(node.id);
this._setActiveUniverse(node.id);
this._switchToUniverse(this._universe());
this.nodes[node.id] = node;
//this.universe["draw"][node.id] = new Node(node.nodeProperties,node.imagelist,node.grouplist,this.constants);
};
Universe.prototype._collapseUniverse = function() {
var universe = this._universe();
if (universe != "default") {
var isMovingBeforeClustering = this.moving;
var previousUniverse = this._previousUniverse();
this._collapseThisToSingleCluster();
this._mergeThisWithFrozen(previousUniverse);
this._deleteActiveUniverse(universe);
this._activateUniverse(previousUniverse);
this._switchToUniverse(previousUniverse);
this._forgetLastUniverse();
this._updateNodeIndexList();
// if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
if (this.moving != isMovingBeforeClustering) {
this.start();
}
}
};
Universe.prototype._doInAllActiveUniverses = function(runFunction,arguments) {
}

Loading…
Cancel
Save