Browse Source

fantastic clustering in network woohoo, added point labels for bargraphs in graph2d

flowchartTest
Alex de Mulder 10 years ago
parent
commit
a9b7485b86
18 changed files with 27297 additions and 28601 deletions
  1. +26689
    -27401
      dist/vis.js
  2. +1
    -1
      dist/vis.map
  3. +14
    -14
      dist/vis.min.js
  4. +1
    -0
      examples/graph2d/19_labels.html
  5. +102
    -0
      examples/network/39_newClustering.html
  6. +10
    -7
      lib/network/Edge.js
  7. +41
    -35
      lib/network/Network.js
  8. +11
    -156
      lib/network/Node.js
  9. +392
    -961
      lib/network/mixins/ClusterMixin.js
  10. +6
    -6
      lib/network/mixins/SelectionMixin.js
  11. +1
    -1
      lib/network/mixins/physics/HierarchialRepulsionMixin.js
  12. +3
    -14
      lib/network/mixins/physics/PhysicsMixin.js
  13. +17
    -0
      lib/network/modules/ClusterEngine.js
  14. +0
    -0
      lib/network/modules/clustering/backend.js
  15. +0
    -0
      lib/network/modules/clustering/public.js
  16. +0
    -0
      lib/network/modules/clustering/support.js
  17. +4
    -2
      lib/timeline/component/graph2d_types/bar.js
  18. +5
    -3
      lib/util.js

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


+ 1
- 1
dist/vis.map
File diff suppressed because it is too large
View File


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


+ 1
- 0
examples/graph2d/19_labels.html View File

@ -57,6 +57,7 @@
var options = {
start: '2014-06-10',
end: '2014-06-18',
style:'bar'
};
var graph2d = new vis.Graph2d(container, dataset, options);
</script>

+ 102
- 0
examples/network/39_newClustering.html View File

@ -0,0 +1,102 @@
<!doctype html>
<html>
<head>
<title>Network | Basic usage</title>
<script type="text/javascript" src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
<style type="text/css">
#mynetwork {
width: 400px;
height: 400px;
border: 1px solid lightgray;
}
</style>
</head>
<body>
<div id="mynetwork"></div>
<script type="text/javascript">
// create an array with nodes
var nodes = [
{id: 1, label: 'Node 1'},
{id: 2, label: 'Node 2'},
{id: 3, label: 'Node 3'},
{id: 4, label: 'Node 4'},
{id: 5, label: 'Node 5'},
{id: 6, label: 'Node 6', cid:1},
{id: 7, label: 'Node 7', cid:1},
{id: 8, label: 'Node 8', cid:1},
{id: 9, label: 'Node 9', cid:1},
{id: 10, label: 'Node 10', cid:1}
];
// create an array with edges
var edges = [
{from: 1, to: 2},
{from: 1, to: 3},
{from: 10, to: 4},
{from: 2, to: 5},
{from: 6, to: 2},
{from: 7, to: 5},
{from: 8, to: 6},
{from: 9, to: 7},
{from: 10, to: 9}
];
// create a network
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {clustering:true};
var network = new vis.Network(container, data, options);
var clusterOptions = {
joinCondition:function(parentOptions,childOptions) {
return true;
},
processClusterProperties: function (properties, childNodes, childEdges) {
return properties;
},
clusterNodeProperties: {id:'bla', borderWidth:8},
}
var clusterOptionsByData = {
joinCondition:function(childOptions) {
return childOptions.cid == 1;
},
processClusterProperties: function (properties, childNodes, childEdges) {
return properties;
},
clusterNodeProperties: {id:'bla', borderWidth:8},
}
// network.clusterByNodeData(clusterOptionsByData)
network.clusterOutliers({clusterNodeProperties: {borderWidth:8}})
// network.clusterByConnection(2, clusterOptions);
// network.clusterByConnection(9, {
// joinCondition:function(parentOptions,childOptions) {return true;},
// processProperties:function (properties, childNodes, childEdges) {
// return properties;
// },
// clusterNodeProperties: {id:'bla2', label:"bla2", borderWidth:8}
// });
network.on("select", function(params) {
if (params.nodes.length == 1) {
if (params.nodes[0].indexOf("cluster") != -1) {
network.openCluster(params.nodes[0])
}
}
})
// network.openCluster('bla');
// network.openCluster('bla2');
</script>
</body>
</html>

+ 10
- 7
lib/network/Edge.js View File

@ -23,6 +23,7 @@ function Edge (properties, network, networkConstants) {
var fields = ['edges','physics'];
var constants = util.selectiveBridgeObject(fields,networkConstants);
this.options = constants.edges;
this.physics = constants.physics;
this.options['smoothCurves'] = networkConstants['smoothCurves'];
@ -46,13 +47,13 @@ function Edge (properties, network, networkConstants) {
this.to = null; // a node
this.via = null; // a temp node
this.fromBackup = null; // used to clean up after reconnect
this.toBackup = null;; // used to clean up after reconnect
this.fromBackup = null; // used to clean up after reconnect (used for manipulation)
this.toBackup = null; // used to clean up after reconnect (used for manipulation)
// we use this to be able to reconnect the edge to a cluster if its node is put into a cluster
// by storing the original information we can revert to the original connection when the cluser is opened.
this.originalFromId = [];
this.originalToId = [];
this.fromArray = [];
this.toArray = [];
this.connected = false;
@ -76,10 +77,11 @@ Edge.prototype.setProperties = function(properties) {
if (!properties) {
return;
}
this.properties = properties;
var fields = ['style','fontSize','fontFace','fontColor','fontFill','fontStrokeWidth','fontStrokeColor','width',
'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash','inheritColor','labelAlignment', 'opacity',
'customScalingFunction','useGradients'
'customScalingFunction','useGradients','value'
];
util.selectiveDeepExtend(fields, this.options, properties);
@ -135,9 +137,9 @@ Edge.prototype.connect = function () {
this.from = this.network.nodes[this.fromId] || null;
this.to = this.network.nodes[this.toId] || null;
this.connected = (this.from && this.to);
this.connected = (this.from !== null && this.to !== null);
if (this.connected) {
if (this.connected === true) {
this.from.attachEdge(this);
this.to.attachEdge(this);
}
@ -259,6 +261,7 @@ Edge.prototype._getColor = function(ctx) {
}
if (this.colorDirty === true) {
if (this.options.inheritColor == "to") {
colorObj = {
highlight: this.to.options.color.highlight.border,

+ 41
- 35
lib/network/Network.js View File

@ -85,6 +85,7 @@ function Network (container, data, options) {
fontSizeMin: 14,
fontSizeMax: 30,
fontSizeMaxVisible: 30,
value: 1,
level: -1,
color: {
border: '#2B7CE9',
@ -109,6 +110,7 @@ function Network (container, data, options) {
width: 1,
widthSelectionMultiplier: 2,
hoverWidth: 1.5,
value:1,
style: 'line',
color: {
color:'#848484',
@ -164,26 +166,33 @@ function Network (container, data, options) {
springConstant: null
},
clustering: { // Per Node in Cluster = PNiC
enabled: false, // (Boolean) | global on/off switch for clustering.
initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold.
clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes
reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this
chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains).
clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered.
sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector.
screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node.
fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px).
maxFontSize: 1000,
forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster).
distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster).
edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength.
nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster.
height: 1, // (px PNiC) | growth of the height 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.
activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open.
clusterLevelDifference: 2, // used for normalization of the cluster levels
clusterByZoom: true // enable clustering through zooming in and out
enabled: false // (Boolean) | global on/off switch for clustering.
//
//initialMaxNodes: 100, // (# nodes) | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold.
//clusterThreshold:500, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes
//reduceToNodes:300, // (# nodes) | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this
//chainThreshold: 0.4, // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains).
//clusterEdgeThreshold: 20, // (px) | edge length threshold. if smaller, this node is clustered.
//sectorThreshold: 100, // (# nodes in cluster) | cluster size threshold. If larger, expanding in own sector.
//screenSizeThreshold: 0.2, // (% of canvas) | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node.
//fontSizeMultiplier: 4.0, // (px PNiC) | how much the cluster font size grows per node in cluster (in px).
//maxFontSize: 1000,
//forceAmplification: 0.1, // (multiplier PNiC) | factor of increase fo the repulsion force of a cluster (per node in cluster).
//distanceAmplification: 0.1, // (multiplier PNiC) | factor how much the repulsion distance of a cluster increases (per node in cluster).
//edgeGrowth: 20, // (px PNiC) | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength.
//nodeScaling: {width: 1, // (px PNiC) | growth of the width per node in cluster.
// height: 1, // (px PNiC) | growth of the height 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.
//activeAreaBoxSize: 80, // (px) | box area around the curser where clusters are popped open.
//clusterLevelDifference: 2, // used for normalization of the cluster levels
//clusterByZoom: true // enable clustering through zooming in and out
},
navigation: {
enabled: false
@ -583,11 +592,7 @@ Network.prototype.zoomExtent = function(options, initialZoom, disableStart) {
*/
Network.prototype._updateNodeIndexList = function() {
this._clearNodeIndexList();
for (var idx in this.nodes) {
if (this.nodes.hasOwnProperty(idx)) {
this.nodeIndices.push(idx);
}
}
this.nodeIndices = Object.keys(this.nodes);
};
@ -1288,7 +1293,6 @@ Network.prototype._zoom = function(scale, pointer) {
this._setScale(scale);
this._setTranslation(tx, ty);
this.updateClustersDefault();
if (preScaleDragPointer != null) {
var postScaleDragPointer = this.canvasToDOM(preScaleDragPointer);
@ -1483,7 +1487,7 @@ Network.prototype._checkShowPopup = function (pointer) {
for (id in edges) {
if (edges.hasOwnProperty(id)) {
var edge = edges[id];
if (edge.connected && (edge.getTitle() !== undefined) &&
if (edge.connected === true && (edge.getTitle() !== undefined) &&
edge.isOverlappingWith(obj)) {
overlappingEdges.push(id);
}
@ -1678,7 +1682,6 @@ Network.prototype._addNodes = function(ids) {
this._updateCalculationNodes();
this._reconnectEdges();
this._updateValueRange(this.nodes);
this.updateLabels();
};
/**
@ -1914,7 +1917,6 @@ Network.prototype._reconnectEdges = function() {
for (id in nodes) {
if (nodes.hasOwnProperty(id)) {
nodes[id].edges = [];
nodes[id].dynamicEdges = [];
}
}
@ -2035,7 +2037,7 @@ Network.prototype._redraw = function(hidden, requested) {
}
}
// this._doInSupportSector("_drawNodes",ctx,true);
//this._doInSupportSector("_drawNodes",ctx,true);
// this._drawTree(ctx,"#F00F0F");
// restore original scaling and translation
@ -2215,7 +2217,7 @@ Network.prototype._drawEdges = function(ctx) {
if (edges.hasOwnProperty(id)) {
var edge = edges[id];
edge.setScale(this.scale);
if (edge.connected) {
if (edge.connected === true) {
edges[id].draw(ctx);
}
}
@ -2442,6 +2444,7 @@ Network.prototype._animationStep = function() {
// check if the physics have settled
if (this.moving == true) {
var startTime = Date.now();
this._physicsTick();
var physicsTime = Date.now() - startTime;
@ -2595,11 +2598,14 @@ Network.prototype._configureSmoothCurves = function(disableStart) {
*
* @private
*/
Network.prototype._createBezierNodes = function() {
Network.prototype._createBezierNodes = function(specificEdges) {
if (specificEdges === undefined) {
specificEdges = this.edges;
}
if (this.constants.smoothCurves.enabled == true && this.constants.smoothCurves.dynamic == true) {
for (var edgeId in this.edges) {
if (this.edges.hasOwnProperty(edgeId)) {
var edge = this.edges[edgeId];
for (var edgeId in specificEdges) {
if (specificEdges.hasOwnProperty(edgeId)) {
var edge = specificEdges[edgeId];
if (edge.via == null) {
var nodeId = "edgeId:".concat(edge.id);
this.sectors['support']['nodes'][nodeId] = new Node(

+ 11
- 156
lib/network/Node.js View File

@ -33,8 +33,6 @@ function Node(properties, imagelist, grouplist, networkConstants) {
this.hover = false;
this.edges = []; // all edges connected to this node
this.dynamicEdges = [];
this.reroutedEdges = {};
// set defaults for the properties
this.id = undefined;
@ -72,15 +70,6 @@ function Node(properties, imagelist, grouplist, networkConstants) {
this.setProperties(properties, constants);
// creating the variables for clustering
this.resetCluster();
this.clusterSession = 0;
this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width;
this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height;
this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius;
this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements;
this.growthIndicator = 0;
// variables to tell the node about the network.
this.networkScaleInv = 1;
this.networkScale = 1;
@ -101,18 +90,6 @@ Node.prototype.revertPosition = function() {
}
/**
* (re)setting the clustering variables and objects
*/
Node.prototype.resetCluster = function() {
// clustering variables
this.formationScale = undefined; // this is used to determine when to open the cluster
this.clusterSize = 1; // this signifies the total amount of nodes in this cluster
this.containedNodes = {};
this.containedEdges = {};
this.clusterSessions = [];
};
/**
* Attach a edge to the node
* @param {Edge} edge
@ -121,9 +98,6 @@ Node.prototype.attachEdge = function(edge) {
if (this.edges.indexOf(edge) == -1) {
this.edges.push(edge);
}
if (this.dynamicEdges.indexOf(edge) == -1) {
this.dynamicEdges.push(edge);
}
};
/**
@ -135,10 +109,6 @@ Node.prototype.detachEdge = function(edge) {
if (index != -1) {
this.edges.splice(index, 1);
}
index = this.dynamicEdges.indexOf(edge);
if (index != -1) {
this.dynamicEdges.splice(index, 1);
}
};
@ -151,10 +121,12 @@ Node.prototype.setProperties = function(properties, constants) {
if (!properties) {
return;
}
this.properties = properties;
var fields = ['borderWidth','borderWidthSelected','shape','image','brokenImage','radius','fontColor',
'fontSize','fontFace','fontFill','fontStrokeWidth','fontStrokeColor','group','mass','fontDrawThreshold',
'scaleFontWithValue','fontSizeMaxVisible','customScalingFunction','iconFontFace', 'icon', 'iconColor', 'iconSize'
var fields = ['borderWidth', 'borderWidthSelected', 'shape', 'image', 'brokenImage', 'radius', 'fontColor',
'fontSize', 'fontFace', 'fontFill', 'fontStrokeWidth', 'fontStrokeColor', 'group', 'mass', 'fontDrawThreshold',
'scaleFontWithValue', 'fontSizeMaxVisible', 'customScalingFunction', 'iconFontFace', 'icon', 'iconColor', 'iconSize',
'value'
];
util.selectiveDeepExtend(fields, this.options, properties);
@ -424,6 +396,7 @@ Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
this.fy = 0;
this.vy = 0;
}
};
/**
@ -547,29 +520,11 @@ Node.prototype._resizeImage = function (ctx) {
}
this.width = width;
this.height = height;
this.growthIndicator = 0;
if (this.width > 0 && this.height > 0) {
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - width;
}
}
};
Node.prototype._drawImageAtPosition = function (ctx) {
if (this.imageObj.width != 0 ) {
// draw the shade
if (this.clusterSize > 1) {
var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0);
lineWidth *= this.networkScaleInv;
lineWidth = Math.min(0.2 * this.width,lineWidth);
ctx.globalAlpha = 0.5;
ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth);
}
// draw the image
ctx.globalAlpha = 1.0;
ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height);
@ -619,12 +574,6 @@ Node.prototype._resizeCircularImage = function (ctx) {
var diameter = this.options.radius * 2;
this.width = diameter;
this.height = diameter;
// scaling used for clustering
//this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
//this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.options.radius- 0.5*diameter;
this._swapToImageResizeWhenImageLoaded = true;
}
}
@ -678,12 +627,6 @@ Node.prototype._resizeBox = function (ctx) {
var textSize = this.getTextSize(ctx);
this.width = textSize.width + 2 * margin;
this.height = textSize.height + 2 * margin;
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.growthIndicator = this.width - (textSize.width + 2 * margin);
// this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
}
};
@ -693,22 +636,11 @@ Node.prototype._drawBox = function (ctx) {
this.left = this.x - this.width / 2;
this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.options.radius);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
@ -734,12 +666,6 @@ Node.prototype._resizeDatabase = function (ctx) {
var size = textSize.width + 2 * margin;
this.width = size;
this.height = size;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - size;
}
};
@ -748,22 +674,11 @@ Node.prototype._drawDatabase = function (ctx) {
this.left = this.x - this.width / 2;
this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
@ -790,32 +705,16 @@ Node.prototype._resizeCircle = function (ctx) {
this.width = diameter;
this.height = diameter;
// scaling used for clustering
// this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
// this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.options.radius- 0.5*diameter;
}
};
Node.prototype._drawRawCircle = function (ctx, x, y, radius) {
var clusterLineWidth = 2.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.circle(x, y, radius+2*ctx.lineWidth);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
@ -850,12 +749,6 @@ Node.prototype._resizeEllipse = function (ctx) {
this.width = this.height;
}
var defaultSize = this.width;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - defaultSize;
}
};
@ -864,22 +757,12 @@ Node.prototype._drawEllipse = function (ctx) {
this.left = this.x - this.width / 2;
this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
@ -923,12 +806,6 @@ Node.prototype._resizeShape = function (ctx) {
var size = 2 * this.options.radius;
this.width = size;
this.height = size;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - size;
}
};
@ -938,7 +815,6 @@ Node.prototype._drawShape = function (ctx, shape) {
this.left = this.x - this.width / 2;
this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var radiusMultiplier = 2;
@ -953,16 +829,7 @@ Node.prototype._drawShape = function (ctx, shape) {
}
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
@ -990,12 +857,6 @@ Node.prototype._resizeText = function (ctx) {
var textSize = this.getTextSize(ctx);
this.width = textSize.width + 2 * margin;
this.height = textSize.height + 2 * margin;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - (textSize.width + 2 * margin);
}
};
@ -1022,12 +883,6 @@ Node.prototype._resizeIcon = function (ctx) {
};
this.width = iconSize.width + 2 * margin;
this.height = iconSize.height + 2 * margin;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - (iconSize.width + 2 * margin);
}
};

+ 392
- 961
lib/network/mixins/ClusterMixin.js
File diff suppressed because it is too large
View File


+ 6
- 6
lib/network/mixins/SelectionMixin.js View File

@ -355,8 +355,8 @@ exports._clusterInSelection = function() {
* @private
*/
exports._selectConnectedEdges = function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
for (var i = 0; i < node.edges.length; i++) {
var edge = node.edges[i];
edge.select();
this._addToSelection(edge);
}
@ -369,8 +369,8 @@ exports._selectConnectedEdges = function(node) {
* @private
*/
exports._hoverConnectedEdges = function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
for (var i = 0; i < node.edges.length; i++) {
var edge = node.edges[i];
edge.hover = true;
this._addToHover(edge);
}
@ -384,8 +384,8 @@ exports._hoverConnectedEdges = function(node) {
* @private
*/
exports._unselectConnectedEdges = function(node) {
for (var i = 0; i < node.dynamicEdges.length; i++) {
var edge = node.dynamicEdges[i];
for (var i = 0; i < node.edges.length; i++) {
var edge = node.edges[i];
edge.unselect();
this._removeFromSelection(edge);
}

+ 1
- 1
lib/network/mixins/physics/HierarchialRepulsionMixin.js View File

@ -81,7 +81,7 @@ exports._calculateHierarchicalSpringForces = function () {
for (edgeId in edges) {
if (edges.hasOwnProperty(edgeId)) {
edge = edges[edgeId];
if (edge.connected) {
if (edge.connected === true) {
// only calculate forces if nodes are in the same sector
if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
edgeLength = edge.physics.springLength;

+ 3
- 14
lib/network/mixins/physics/PhysicsMixin.js View File

@ -71,11 +71,6 @@ exports._initializeForceCalculation = function () {
this.nodes[this.nodeIndices[0]]._setForce(0, 0);
}
else {
// if there are too many nodes on screen, we cluster without repositioning
if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) {
this.clusterToFit(this.constants.clustering.reduceToNodes, false);
}
// we now start the force calculation
this._calculateForces();
}
@ -202,12 +197,10 @@ exports._calculateSpringForces = function () {
for (edgeId in edges) {
if (edges.hasOwnProperty(edgeId)) {
edge = edges[edgeId];
if (edge.connected) {
if (edge.connected === true) {
// only calculate forces if nodes are in the same sector
if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
edgeLength = edge.physics.springLength;
// this implies that the edges between big clusters are longer
edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;
dx = (edge.from.x - edge.to.x);
dy = (edge.from.y - edge.to.y);
@ -242,14 +235,14 @@ exports._calculateSpringForces = function () {
* @private
*/
exports._calculateSpringForcesWithSupport = function () {
var edgeLength, edge, edgeId, combinedClusterSize;
var edgeLength, edge, edgeId;
var edges = this.edges;
// forces caused by the edges, modelled as springs
for (edgeId in edges) {
if (edges.hasOwnProperty(edgeId)) {
edge = edges[edgeId];
if (edge.connected) {
if (edge.connected === true) {
// only calculate forces if nodes are in the same sector
if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
if (edge.via != null) {
@ -259,10 +252,6 @@ exports._calculateSpringForcesWithSupport = function () {
edgeLength = edge.physics.springLength;
combinedClusterSize = node1.clusterSize + node3.clusterSize - 2;
// this implies that the edges between big clusters are longer
edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth;
this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
}

+ 17
- 0
lib/network/modules/ClusterEngine.js View File

@ -0,0 +1,17 @@
/**
* Created by Alex on 2/20/2015.
*/
var public = require("./clustering/public");
var support = require("./clustering/support");
var backend = require("./clustering/backend");
function ClusterEngine(network) {
this.network = network;
}
module.exports = clusterEngine

+ 0
- 0
lib/network/modules/clustering/backend.js View File


+ 0
- 0
lib/network/modules/clustering/public.js View File


+ 0
- 0
lib/network/modules/clustering/support.js View File


+ 4
- 2
lib/timeline/component/graph2d_types/bar.js View File

@ -58,7 +58,8 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
combinedData.push({
x: processedGroupData[groupIds[i]][j].x,
y: processedGroupData[groupIds[i]][j].y,
groupId: groupIds[i]
groupId: groupIds[i],
label: processedGroupData[groupIds[i]][j].label
});
barPoints += 1;
}
@ -114,7 +115,8 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', framework.svgElements, framework.svg);
// draw points
if (group.options.drawPoints.enabled == true) {
DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
Points.draw([combinedData[i]], group, framework, drawData.offset);
//DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
}
}
};

+ 5
- 3
lib/util.js View File

@ -225,22 +225,24 @@ exports.selectiveNotDeepExtend = function (props, a, b) {
* Deep extend an object a with the properties of object b
* @param {Object} a
* @param {Object} b
* @param {Boolean} protoExtend --> optional parameter. If true, the prototype values will also be extended.
* (ie. the options objects that inherit from others will also get the inherited options)
* @returns {Object}
*/
exports.deepExtend = function(a, b) {
exports.deepExtend = function(a, b, protoExtend) {
// TODO: add support for Arrays to deepExtend
if (Array.isArray(b)) {
throw new TypeError('Arrays are not supported by deepExtend');
}
for (var prop in b) {
if (b.hasOwnProperty(prop)) {
if (b.hasOwnProperty(prop) || protoExtend === true) {
if (b[prop] && b[prop].constructor === Object) {
if (a[prop] === undefined) {
a[prop] = {};
}
if (a[prop].constructor === Object) {
exports.deepExtend(a[prop], b[prop]);
exports.deepExtend(a[prop], b[prop], protoExtend);
}
else {
a[prop] = b[prop];

Loading…
Cancel
Save