Browse Source

- Fixed mass = 0 for nodes.

- Revamped the options system. You can globally set options (network.setOptions) to update
settings of nodes and edges that have not been specifically defined by the individual nodes and edges.
- Disabled inheritColor when color information is set on an edge.
- Tweaked examples.
- Removed the global length property for edges. The edgelength is part of the physics system. Therefore, you have to change
the springLength of the physics system to change the edge length. Individual edge lengths can still be defined.
- Removed global edge length definition form examples.
v3_develop
Alex de Mulder 10 years ago
parent
commit
06bf7c265b
24 changed files with 24317 additions and 24656 deletions
  1. +10
    -1
      HISTORY.md
  2. +23995
    -24146
      dist/vis.js
  3. +2
    -6
      docs/network.html
  4. +1
    -2
      examples/network/02_random_nodes.html
  5. +4
    -9
      examples/network/06_groups.html
  6. +1
    -1
      examples/network/10_multiline_text.html
  7. +1
    -1
      examples/network/11_custom_style.html
  8. +1
    -3
      examples/network/13_dashed_lines.html
  9. +5
    -5
      examples/network/17_network_info.html
  10. +1
    -3
      examples/network/18_fully_random_nodes_clustering.html
  11. +0
    -11
      examples/network/19_scale_free_graph_clustering.html
  12. +0
    -14
      examples/network/20_navigation.html
  13. +0
    -3
      examples/network/21_data_manipulation.html
  14. +0
    -2
      examples/network/23_hierarchical_layout.html
  15. +2
    -4
      examples/network/25_physics_configuration.html
  16. +88
    -124
      lib/network/Edge.js
  17. +42
    -183
      lib/network/Network.js
  18. +90
    -107
      lib/network/Node.js
  19. +8
    -8
      lib/network/mixins/ClusterMixin.js
  20. +6
    -6
      lib/network/mixins/ManipulationMixin.js
  21. +20
    -14
      lib/network/mixins/physics/BarnesHutMixin.js
  22. +1
    -1
      lib/network/mixins/physics/HierarchialRepulsionMixin.js
  23. +2
    -2
      lib/network/mixins/physics/PhysicsMixin.js
  24. +37
    -0
      lib/util.js

+ 10
- 1
HISTORY.md View File

@ -19,7 +19,16 @@ http://visjs.org
- Fixed items in groups sometimes being displayed but not positioned correctly. - Fixed items in groups sometimes being displayed but not positioned correctly.
### Network
- Fixed mass = 0 for nodes.
- Revamped the options system. You can globally set options (network.setOptions) to update
settings of nodes and edges that have not been specifically defined by the individual nodes and edges.
- Disabled inheritColor when color information is set on an edge.
- Tweaked examples.
- Removed the global length property for edges. The edgelength is part of the physics system. Therefore, you have to change
the springLength of the physics system to change the edge length. Individual edge lengths can still be defined.
- Removed global edge length definition form examples.
## 2014-07-22, version 3.1.0 ## 2014-07-22, version 3.1.0

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


+ 2
- 6
docs/network.html View File

@ -1261,6 +1261,8 @@ var options = {
<p> <p>
Edges can be configured with different length and styling. To configure edges, provide an object named <code>edges</code> in the <code>options</code> for the Network. Edges can be configured with different length and styling. To configure edges, provide an object named <code>edges</code> in the <code>options</code> for the Network.
Because the length of an edge is a property of the physics simulation, you can change the length of the edge by changing the springLength in your selected physics solver.
To change the edge length of individual edges, you can use the <code>length</code> property in the <a href="Edges">edge definition</a>.
</p> </p>
<p> <p>
@ -1353,12 +1355,6 @@ var options = {
<td>Default length of a gap in pixels on a dashed line. <td>Default length of a gap in pixels on a dashed line.
Only applicable when the line style is <code>dash-line</code>.</td> Only applicable when the line style is <code>dash-line</code>.</td>
</tr> </tr>
<tr>
<td>length</td>
<td>number</td>
<td>physics.[method].springLength</td>
<td>The resting length of the edge when modeled as a spring. By default the springLength determined by the physics is used. By using this setting you can make certain edges have different resting lengths.</td>
</tr>
<tr> <tr>
<td>inheritColor</td> <td>inheritColor</td>

+ 1
- 2
examples/network/02_random_nodes.html View File

@ -31,8 +31,7 @@
for (var i = 0; i < nodeCount; i++) { for (var i = 0; i < nodeCount; i++) {
nodes.push({ nodes.push({
id: i, id: i,
label: String(i),
radius:300
label: String(i)
}); });
connectionCount[i] = 0; connectionCount[i] = 0;

+ 4
- 9
examples/network/06_groups.html View File

@ -64,8 +64,7 @@
edges.push({ edges.push({
from: from + nodeOffset, from: from + nodeOffset,
to: to + nodeOffset, to: to + nodeOffset,
length: len,
color: color
length: len
}); });
connectionCount[from]++; connectionCount[from]++;
connectionCount[to]++; connectionCount[to]++;
@ -85,8 +84,7 @@
edges.push({ edges.push({
from: from + nodeOffset, from: from + nodeOffset,
to: to + nodeOffset, to: to + nodeOffset,
length: len,
color: color
length: len
}); });
connectionCount[from]++; connectionCount[from]++;
connectionCount[to]++; connectionCount[to]++;
@ -112,8 +110,7 @@
edges.push({ edges.push({
from: from, from: from,
to: to, to: to,
length: len,
color: color
length: len
}); });
} }
@ -135,9 +132,7 @@
nodes: { nodes: {
shape: 'dot' shape: 'dot'
}, },
edges: {
length: 50
}
physics: {barnesHut:{springLength: 200}}
}; };
network = new vis.Network(container, data, options); network = new vis.Network(container, data, options);
} }

+ 1
- 1
examples/network/10_multiline_text.html View File

@ -26,7 +26,7 @@
// create some edges // create some edges
var edges = [ var edges = [
{from: 1, to: 2, style: 'line', color: 'red', width: 3, length: 200},
{from: 1, to: 2, style: 'line', color: 'red', width: 3, length: 200}, // individual length definition is possible
{from: 1, to: 3, style: 'dash-line', width: 1, length: 200}, {from: 1, to: 3, style: 'dash-line', width: 1, length: 200},
{from: 1, to: 4, style: 'line', width: 1, length: 200}, {from: 1, to: 4, style: 'line', width: 1, length: 200},
{from: 1, to: 5, style: 'arrow', width: 3, length: 200} {from: 1, to: 5, style: 'arrow', width: 3, length: 200}

+ 1
- 1
examples/network/11_custom_style.html View File

@ -61,7 +61,6 @@
options = { options = {
stabilize: false, stabilize: false,
edges: { edges: {
length: 120,
width: 2, width: 2,
style: 'arrow', style: 'arrow',
color: 'gray' color: 'gray'
@ -79,6 +78,7 @@
} }
} }
}, },
physics: {barnesHut:{springLength:200}}, // this is the correct way to set the length of the springs
groups: { groups: {
black: { black: {
// defaults for nodes in this group // defaults for nodes in this group

+ 1
- 3
examples/network/13_dashed_lines.html View File

@ -45,9 +45,7 @@
nodes: { nodes: {
shape: 'box' shape: 'box'
}, },
edges: {
length: 180
},
physics: {barnesHut:{springLength:150}}, // this is the correct way to set the length of the springs
stabilize: false stabilize: false
}; };
var network = new vis.Network(container, data, options); var network = new vis.Network(container, data, options);

+ 5
- 5
examples/network/17_network_info.html View File

@ -96,11 +96,11 @@
var x = - mynetwork.clientWidth / 2 + 50; var x = - mynetwork.clientWidth / 2 + 50;
var y = - mynetwork.clientHeight / 2 + 50; var y = - mynetwork.clientHeight / 2 + 50;
var step = 70; var step = 70;
nodes.push({id: 1000, x: x, y: y, label: 'Internet', group: 'internet', value: 1});
nodes.push({id: 1001, x: x, y: y + step, label: 'Switch', group: 'switch', value: 1});
nodes.push({id: 1002, x: x, y: y + 2 * step, label: 'Server', group: 'server', value: 1});
nodes.push({id: 1003, x: x, y: y + 3 * step, label: 'Computer', group: 'desktop', value: 1});
nodes.push({id: 1004, x: x, y: y + 4 * step, label: 'Smartphone', group: 'mobile', value: 1});
nodes.push({id: 1000, x: x, y: y, label: 'Internet', group: 'internet', value: 1, mass:0});
nodes.push({id: 1001, x: x, y: y + step, label: 'Switch', group: 'switch', value: 1, mass:0});
nodes.push({id: 1002, x: x, y: y + 2 * step, label: 'Server', group: 'server', value: 1, mass:0});
nodes.push({id: 1003, x: x, y: y + 3 * step, label: 'Computer', group: 'desktop', value: 1, mass:0});
nodes.push({id: 1004, x: x, y: y + 4 * step, label: 'Smartphone', group: 'mobile', value: 1, mass:0});
// create a network // create a network
var container = document.getElementById('mynetwork'); var container = document.getElementById('mynetwork');

+ 1
- 3
examples/network/18_fully_random_nodes_clustering.html View File

@ -53,9 +53,7 @@
edges: edges edges: edges
}; };
var options = { var options = {
edges: {
length: 80
},
physics: {barnesHut:{springLength:120}}, // this is the correct way to set the length of the springs
clustering: { clustering: {
enabled: clusteringOn enabled: clusteringOn
}, },

+ 0
- 11
examples/network/19_scale_free_graph_clustering.html View File

@ -76,17 +76,6 @@
nodes: nodes, nodes: nodes,
edges: edges edges: edges
}; };
/*
var options = {
nodes: {
shape: 'circle'
},
edges: {
length: 50
},
stabilize: false
};
*/
var options = { var options = {
clustering: { clustering: {
enabled: clusteringOn, enabled: clusteringOn,

+ 0
- 14
examples/network/20_navigation.html View File

@ -94,21 +94,7 @@
nodes: nodes, nodes: nodes,
edges: edges edges: edges
}; };
/*
var options = {
nodes: {
shape: 'circle'
},
edges: {
length: 50
},
stabilize: false
};
*/
var options = { var options = {
edges: {
length: 50
},
stabilize: false, stabilize: false,
navigation: true, navigation: true,
keyboard: true keyboard: true

+ 0
- 3
examples/network/21_data_manipulation.html View File

@ -114,9 +114,6 @@
edges: edges edges: edges
}; };
var options = { var options = {
edges: {
length: 50
},
stabilize: false, stabilize: false,
dataManipulation: true, dataManipulation: true,
onAdd: function(data,callback) { onAdd: function(data,callback) {

+ 0
- 2
examples/network/23_hierarchical_layout.html View File

@ -79,8 +79,6 @@
}; };
var directionInput = document.getElementById("direction"); var directionInput = document.getElementById("direction");
var options = { var options = {
edges: {
},
stabilize: false, stabilize: false,
smoothCurves: false, smoothCurves: false,
hierarchicalLayout: { hierarchicalLayout: {

+ 2
- 4
examples/network/25_physics_configuration.html View File

@ -77,10 +77,8 @@
}; };
var options = { var options = {
edges: {
},
stabilize: false,
configurePhysics:true
stabilize: false,
configurePhysics:true
}; };
network = new vis.Network(container, data, options); network = new vis.Network(container, data, options);

+ 88
- 124
lib/network/Edge.js View File

@ -16,35 +16,28 @@ var Node = require('./Node');
* @param {Object} constants An object with default values for * @param {Object} constants An object with default values for
* example for the color * example for the color
*/ */
function Edge (properties, network, constants) {
function Edge (properties, network, networkConstants) {
if (!network) { if (!network) {
throw "No network provided"; throw "No network provided";
} }
this.network = network;
var fields = ['edges','physics'];
var constants = util.selectiveBridgeObject(fields,networkConstants);
this.options = constants.edges;
this.physics = constants.physics;
this.options['smoothCurves'] = networkConstants['smoothCurves'];
// initialize constants
this.widthMin = constants.edges.widthMin;
this.widthMax = constants.edges.widthMax;
this.network = network;
// initialize variables // initialize variables
this.id = undefined; this.id = undefined;
this.fromId = undefined; this.fromId = undefined;
this.toId = undefined; this.toId = undefined;
this.style = constants.edges.style;
this.title = undefined; this.title = undefined;
this.width = constants.edges.width;
this.widthSelectionMultiplier = constants.edges.widthSelectionMultiplier;
this.widthSelected = this.width * this.widthSelectionMultiplier;
this.hoverWidth = constants.edges.hoverWidth;
this.widthSelected = this.options.width * this.options.widthSelectionMultiplier;
this.value = undefined; this.value = undefined;
this.length = constants.physics.springLength;
this.customLength = false;
this.selected = false; this.selected = false;
this.hover = false; this.hover = false;
this.smoothCurves = constants.smoothCurves;
this.dynamicSmoothCurves = constants.dynamicSmoothCurves;
this.arrowScaleFactor = constants.edges.arrowScaleFactor;
this.inheritColor = constants.edges.inheritColor;
this.from = null; // a node this.from = null; // a node
this.to = null; // a node this.to = null; // a node
@ -57,18 +50,10 @@ function Edge (properties, network, constants) {
this.connected = false; this.connected = false;
// Added to support dashed lines
// David Jordan
// 2012-08-08
this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength
this.color = {color:constants.edges.color.color,
highlight:constants.edges.color.highlight,
hover:constants.edges.color.hover};
this.widthFixed = false; this.widthFixed = false;
this.lengthFixed = false; this.lengthFixed = false;
this.setProperties(properties, constants);
this.setProperties(properties);
this.controlNodesEnabled = false; this.controlNodesEnabled = false;
this.controlNodes = {from:null, to:null, positions:{}}; this.controlNodes = {from:null, to:null, positions:{}};
@ -80,62 +65,41 @@ function Edge (properties, network, constants) {
* @param {Object} properties an object with properties * @param {Object} properties an object with properties
* @param {Object} constants and object with default, global properties * @param {Object} constants and object with default, global properties
*/ */
Edge.prototype.setProperties = function(properties, constants) {
Edge.prototype.setProperties = function(properties) {
if (!properties) { if (!properties) {
return; return;
} }
var fields = ['style','fontSize','fontFace','fontColor','fontFill','width',
'widthSelectionMultiplier','hoverWidth','arrowScaleFactor','dash'
];
util.selectiveDeepExtend(fields, this.options, properties);
if (properties.from !== undefined) {this.fromId = properties.from;} if (properties.from !== undefined) {this.fromId = properties.from;}
if (properties.to !== undefined) {this.toId = properties.to;} if (properties.to !== undefined) {this.toId = properties.to;}
if (properties.id !== undefined) {this.id = properties.id;} if (properties.id !== undefined) {this.id = properties.id;}
if (properties.style !== undefined) {this.style = properties.style;}
if (properties.label !== undefined) {this.label = properties.label;} if (properties.label !== undefined) {this.label = properties.label;}
if (this.label) {
this.fontSize = constants.edges.fontSize;
this.fontFace = constants.edges.fontFace;
this.fontColor = constants.edges.fontColor;
this.fontFill = constants.edges.fontFill;
if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;}
if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;}
if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;}
if (properties.fontFill !== undefined) {this.fontFill = properties.fontFill;}
}
if (properties.title !== undefined) {this.title = properties.title;} if (properties.title !== undefined) {this.title = properties.title;}
if (properties.width !== undefined) {this.width = properties.width;}
if (properties.widthSelectionMultiplier !== undefined)
{this.widthSelectionMultiplier = properties.widthSelectionMultiplier;}
if (properties.hoverWidth !== undefined) {this.hoverWidth = properties.hoverWidth;}
if (properties.value !== undefined) {this.value = properties.value;} if (properties.value !== undefined) {this.value = properties.value;}
if (properties.length !== undefined) {this.length = properties.length;
this.customLength = true;}
if (properties.length !== undefined) {this.physics.springLength = properties.length;}
// scale the arrow // scale the arrow
if (properties.arrowScaleFactor !== undefined) {this.arrowScaleFactor = properties.arrowScaleFactor;}
if (properties.arrowScaleFactor !== undefined) {this.options.arrowScaleFactor = properties.arrowScaleFactor;}
if (properties.inheritColor !== undefined) {this.inheritColor = properties.inheritColor;}
// Added to support dashed lines
// David Jordan
// 2012-08-08
if (properties.dash) {
if (properties.dash.length !== undefined) {this.dash.length = properties.dash.length;}
if (properties.dash.gap !== undefined) {this.dash.gap = properties.dash.gap;}
if (properties.dash.altLength !== undefined) {this.dash.altLength = properties.dash.altLength;}
}
if (properties.inheritColor !== undefined) {this.options.inheritColor = properties.inheritColor;}
if (properties.color !== undefined) { if (properties.color !== undefined) {
this.options.inheritColor = false;
if (util.isString(properties.color)) { if (util.isString(properties.color)) {
this.color.color = properties.color;
this.color.highlight = properties.color;
this.options.color.color = properties.color;
this.options.color.highlight = properties.color;
} }
else { else {
if (properties.color.color !== undefined) {this.color.color = properties.color.color;}
if (properties.color.highlight !== undefined) {this.color.highlight = properties.color.highlight;}
if (properties.color.hover !== undefined) {this.color.hover = properties.color.hover;}
if (properties.color.color !== undefined) {this.options.color.color = properties.color.color;}
if (properties.color.highlight !== undefined) {this.options.color.highlight = properties.color.highlight;}
if (properties.color.hover !== undefined) {this.options.color.hover = properties.color.hover;}
} }
} }
@ -145,10 +109,10 @@ Edge.prototype.setProperties = function(properties, constants) {
this.widthFixed = this.widthFixed || (properties.width !== undefined); this.widthFixed = this.widthFixed || (properties.width !== undefined);
this.lengthFixed = this.lengthFixed || (properties.length !== undefined); this.lengthFixed = this.lengthFixed || (properties.length !== undefined);
this.widthSelected = this.width * this.widthSelectionMultiplier;
this.widthSelected = this.options.width* this.options.widthSelectionMultiplier;
// set draw method based on style // set draw method based on style
switch (this.style) {
switch (this.options.style) {
case 'line': this.draw = this._drawLine; break; case 'line': this.draw = this._drawLine; break;
case 'arrow': this.draw = this._drawArrow; break; case 'arrow': this.draw = this._drawArrow; break;
case 'arrow-center': this.draw = this._drawArrowCenter; break; case 'arrow-center': this.draw = this._drawArrowCenter; break;
@ -223,9 +187,9 @@ Edge.prototype.getValue = function() {
*/ */
Edge.prototype.setValueRange = function(min, max) { Edge.prototype.setValueRange = function(min, max) {
if (!this.widthFixed && this.value !== undefined) { if (!this.widthFixed && this.value !== undefined) {
var scale = (this.widthMax - this.widthMin) / (max - min);
this.width = (this.value - min) * scale + this.widthMin;
this.widthSelected = this.width * this.widthSelectionMultiplier;
var scale = (this.options.widthMax - this.options.widthMin) / (max - min);
this.options.width= (this.value - min) * scale + this.options.widthMin;
this.widthSelected = this.options.width* this.options.widthSelectionMultiplier;
} }
}; };
@ -264,19 +228,19 @@ Edge.prototype.isOverlappingWith = function(obj) {
}; };
Edge.prototype._getColor = function() { Edge.prototype._getColor = function() {
var colorObj = this.color;
if (this.inheritColor == "to") {
var colorObj = this.options.color;
if (this.options.inheritColor == "to") {
colorObj = { colorObj = {
highlight: this.to.color.highlight.border,
hover: this.to.color.hover.border,
color: this.to.color.border
highlight: this.to.options.color.highlight.border,
hover: this.to.options.color.hover.border,
color: this.to.options.color.border
}; };
} }
else if (this.inheritColor == "from" || this.inheritColor == true) {
else if (this.options.inheritColor == "from" || this.options.inheritColor == true) {
colorObj = { colorObj = {
highlight: this.from.color.highlight.border,
hover: this.from.color.hover.border,
color: this.from.color.border
highlight: this.from.options.color.highlight.border,
hover: this.from.options.color.hover.border,
color: this.from.options.color.border
}; };
} }
@ -305,7 +269,7 @@ Edge.prototype._drawLine = function(ctx) {
// draw label // draw label
var point; var point;
if (this.label) { if (this.label) {
if (this.smoothCurves.enabled == true && via != null) {
if (this.options.smoothCurves.enabled == true && via != null) {
var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x));
var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY}; point = {x:midpointX, y:midpointY};
@ -318,7 +282,7 @@ Edge.prototype._drawLine = function(ctx) {
} }
else { else {
var x, y; var x, y;
var radius = this.length / 4;
var radius = this.physics.springLength / 4;
var node = this.from; var node = this.from;
if (!node.width) { if (!node.width) {
node.resize(ctx); node.resize(ctx);
@ -345,14 +309,14 @@ Edge.prototype._drawLine = function(ctx) {
*/ */
Edge.prototype._getLineWidth = function() { Edge.prototype._getLineWidth = function() {
if (this.selected == true) { if (this.selected == true) {
return Math.min(this.widthSelected, this.widthMax)*this.networkScaleInv;
return Math.min(this.widthSelected, this.options.widthMax)*this.networkScaleInv;
} }
else { else {
if (this.hover == true) { if (this.hover == true) {
return Math.min(this.hoverWidth, this.widthMax)*this.networkScaleInv;
return Math.min(this.options.hoverWidth, this.options.widthMax)*this.networkScaleInv;
} }
else { else {
return this.width*this.networkScaleInv;
return this.options.width*this.networkScaleInv;
} }
} }
}; };
@ -360,8 +324,8 @@ Edge.prototype._getLineWidth = function() {
Edge.prototype._getViaCoordinates = function () { Edge.prototype._getViaCoordinates = function () {
var xVia = null; var xVia = null;
var yVia = null; var yVia = null;
var factor = this.smoothCurves.roundness;
var type = this.smoothCurves.type;
var factor = this.options.smoothCurves.roundness;
var type = this.options.smoothCurves.type;
var dx = Math.abs(this.from.x - this.to.x); var dx = Math.abs(this.from.x - this.to.x);
var dy = Math.abs(this.from.y - this.to.y); var dy = Math.abs(this.from.y - this.to.y);
@ -531,8 +495,8 @@ Edge.prototype._line = function (ctx) {
// draw a straight line // draw a straight line
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(this.from.x, this.from.y); ctx.moveTo(this.from.x, this.from.y);
if (this.smoothCurves.enabled == true) {
if (this.smoothCurves.dynamic == false) {
if (this.options.smoothCurves.enabled == true) {
if (this.options.smoothCurves.dynamic == false) {
var via = this._getViaCoordinates(); var via = this._getViaCoordinates();
if (via.x == null) { if (via.x == null) {
ctx.lineTo(this.to.x, this.to.y); ctx.lineTo(this.to.x, this.to.y);
@ -587,17 +551,17 @@ Edge.prototype._label = function (ctx, text, x, y) {
if (text) { if (text) {
// TODO: cache the calculated size // TODO: cache the calculated size
ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") + ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") +
this.fontSize + "px " + this.fontFace;
ctx.fillStyle = this.fontFill;
this.options.fontSize + "px " + this.options.fontFace;
ctx.fillStyle = this.options.fontFill;
var width = ctx.measureText(text).width; var width = ctx.measureText(text).width;
var height = this.fontSize;
var height = this.options.fontSize;
var left = x - width / 2; var left = x - width / 2;
var top = y - height / 2; var top = y - height / 2;
ctx.fillRect(left, top, width, height); ctx.fillRect(left, top, width, height);
// draw text // draw text
ctx.fillStyle = this.fontColor || "black";
ctx.fillStyle = this.options.fontColor || "black";
ctx.textAlign = "left"; ctx.textAlign = "left";
ctx.textBaseline = "top"; ctx.textBaseline = "top";
ctx.fillText(text, left, top); ctx.fillText(text, left, top);
@ -615,9 +579,9 @@ Edge.prototype._label = function (ctx, text, x, y) {
*/ */
Edge.prototype._drawDashLine = function(ctx) { Edge.prototype._drawDashLine = function(ctx) {
// set style // set style
if (this.selected == true) {ctx.strokeStyle = this.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.color.hover;}
else {ctx.strokeStyle = this.color.color;}
if (this.selected == true) {ctx.strokeStyle = this.options.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.options.color.hover;}
else {ctx.strokeStyle = this.options.color.color;}
ctx.lineWidth = this._getLineWidth(); ctx.lineWidth = this._getLineWidth();
@ -626,8 +590,8 @@ Edge.prototype._drawDashLine = function(ctx) {
if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) { if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) {
// configure the dash pattern // configure the dash pattern
var pattern = [0]; var pattern = [0];
if (this.dash.length !== undefined && this.dash.gap !== undefined) {
pattern = [this.dash.length,this.dash.gap];
if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) {
pattern = [this.options.dash.length,this.options.dash.gap];
} }
else { else {
pattern = [5,5]; pattern = [5,5];
@ -660,15 +624,15 @@ Edge.prototype._drawDashLine = function(ctx) {
// draw dashed line // draw dashed line
ctx.beginPath(); ctx.beginPath();
ctx.lineCap = 'round'; ctx.lineCap = 'round';
if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
if (this.options.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
{ {
ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
[this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]);
[this.options.dash.length,this.options.dash.gap,this.options.dash.altLength,this.options.dash.gap]);
} }
else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value
else if (this.options.dash.length !== undefined && this.options.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value
{ {
ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y, ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
[this.dash.length,this.dash.gap]);
[this.options.dash.length,this.options.dash.gap]);
} }
else //If all else fails draw a line else //If all else fails draw a line
{ {
@ -681,7 +645,7 @@ Edge.prototype._drawDashLine = function(ctx) {
// draw label // draw label
if (this.label) { if (this.label) {
var point; var point;
if (this.smoothCurves.enabled == true && via != null) {
if (this.options.smoothCurves.enabled == true && via != null) {
var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x));
var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY}; point = {x:midpointX, y:midpointY};
@ -733,9 +697,9 @@ Edge.prototype._pointOnCircle = function (x, y, radius, percentage) {
Edge.prototype._drawArrowCenter = function(ctx) { Edge.prototype._drawArrowCenter = function(ctx) {
var point; var point;
// set style // set style
if (this.selected == true) {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.color.hover; ctx.fillStyle = this.color.hover;}
else {ctx.strokeStyle = this.color.color; ctx.fillStyle = this.color.color;}
if (this.selected == true) {ctx.strokeStyle = this.options.color.highlight; ctx.fillStyle = this.options.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.options.color.hover; ctx.fillStyle = this.options.color.hover;}
else {ctx.strokeStyle = this.options.color.color; ctx.fillStyle = this.options.color.color;}
ctx.lineWidth = this._getLineWidth(); ctx.lineWidth = this._getLineWidth();
if (this.from != this.to) { if (this.from != this.to) {
@ -743,9 +707,9 @@ Edge.prototype._drawArrowCenter = function(ctx) {
var via = this._line(ctx); var via = this._line(ctx);
var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x)); var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
var length = (10 + 5 * this.width) * this.arrowScaleFactor;
var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor;
// draw an arrow halfway the line // draw an arrow halfway the line
if (this.smoothCurves.enabled == true && via != null) {
if (this.options.smoothCurves.enabled == true && via != null) {
var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x));
var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY}; point = {x:midpointX, y:midpointY};
@ -766,7 +730,7 @@ Edge.prototype._drawArrowCenter = function(ctx) {
else { else {
// draw circle // draw circle
var x, y; var x, y;
var radius = 0.25 * Math.max(100,this.length);
var radius = 0.25 * Math.max(100,this.physics.springLength);
var node = this.from; var node = this.from;
if (!node.width) { if (!node.width) {
node.resize(ctx); node.resize(ctx);
@ -783,7 +747,7 @@ Edge.prototype._drawArrowCenter = function(ctx) {
// draw all arrows // draw all arrows
var angle = 0.2 * Math.PI; var angle = 0.2 * Math.PI;
var length = (10 + 5 * this.width) * this.arrowScaleFactor;
var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor;
point = this._pointOnCircle(x, y, radius, 0.5); point = this._pointOnCircle(x, y, radius, 0.5);
ctx.arrow(point.x, point.y, angle, length); ctx.arrow(point.x, point.y, angle, length);
ctx.fill(); ctx.fill();
@ -808,9 +772,9 @@ Edge.prototype._drawArrowCenter = function(ctx) {
*/ */
Edge.prototype._drawArrow = function(ctx) { Edge.prototype._drawArrow = function(ctx) {
// set style // set style
if (this.selected == true) {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.color.hover; ctx.fillStyle = this.color.hover;}
else {ctx.strokeStyle = this.color.color; ctx.fillStyle = this.color.color;}
if (this.selected == true) {ctx.strokeStyle = this.options.color.highlight; ctx.fillStyle = this.options.color.highlight;}
else if (this.hover == true) {ctx.strokeStyle = this.options.color.hover; ctx.fillStyle = this.options.color.hover;}
else {ctx.strokeStyle = this.options.color.color; ctx.fillStyle = this.options.color.color;}
ctx.lineWidth = this._getLineWidth(); ctx.lineWidth = this._getLineWidth();
@ -828,14 +792,14 @@ Edge.prototype._drawArrow = function(ctx) {
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
var via; var via;
if (this.smoothCurves.dynamic == true && this.smoothCurves.enabled == true ) {
if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true ) {
via = this.via; via = this.via;
} }
else if (this.smoothCurves.enabled == true) {
else if (this.options.smoothCurves.enabled == true) {
via = this._getViaCoordinates(); via = this._getViaCoordinates();
} }
if (this.smoothCurves.enabled == true && via.x != null) {
if (this.options.smoothCurves.enabled == true && via.x != null) {
angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x)); angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x));
dx = (this.to.x - via.x); dx = (this.to.x - via.x);
dy = (this.to.y - via.y); dy = (this.to.y - via.y);
@ -845,7 +809,7 @@ Edge.prototype._drawArrow = function(ctx) {
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
var xTo,yTo; var xTo,yTo;
if (this.smoothCurves.enabled == true && via.x != null) {
if (this.options.smoothCurves.enabled == true && via.x != null) {
xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x; xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y; yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y;
} }
@ -856,7 +820,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(xFrom,yFrom); ctx.moveTo(xFrom,yFrom);
if (this.smoothCurves.enabled == true && via.x != null) {
if (this.options.smoothCurves.enabled == true && via.x != null) {
ctx.quadraticCurveTo(via.x,via.y,xTo, yTo); ctx.quadraticCurveTo(via.x,via.y,xTo, yTo);
} }
else { else {
@ -865,7 +829,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.stroke(); ctx.stroke();
// draw arrow at the end of the line // draw arrow at the end of the line
length = (10 + 5 * this.width) * this.arrowScaleFactor;
length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor;
ctx.arrow(xTo, yTo, angle, length); ctx.arrow(xTo, yTo, angle, length);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -873,7 +837,7 @@ Edge.prototype._drawArrow = function(ctx) {
// draw label // draw label
if (this.label) { if (this.label) {
var point; var point;
if (this.smoothCurves.enabled == true && via != null) {
if (this.options.smoothCurves.enabled == true && via != null) {
var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x)); var midpointX = 0.5*(0.5*(this.from.x + via.x) + 0.5*(this.to.x + via.x));
var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y)); var midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY}; point = {x:midpointX, y:midpointY};
@ -888,7 +852,7 @@ Edge.prototype._drawArrow = function(ctx) {
// draw circle // draw circle
var node = this.from; var node = this.from;
var x, y, arrow; var x, y, arrow;
var radius = 0.25 * Math.max(100,this.length);
var radius = 0.25 * Math.max(100,this.physics.springLength);
if (!node.width) { if (!node.width) {
node.resize(ctx); node.resize(ctx);
} }
@ -916,7 +880,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.stroke(); ctx.stroke();
// draw all arrows // draw all arrows
var length = (10 + 5 * this.width) * this.arrowScaleFactor;
var length = (10 + 5 * this.options.width) * this.options.arrowScaleFactor;
ctx.arrow(arrow.x, arrow.y, arrow.angle, length); ctx.arrow(arrow.x, arrow.y, arrow.angle, length);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -945,9 +909,9 @@ Edge.prototype._drawArrow = function(ctx) {
*/ */
Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
if (this.from != this.to) { if (this.from != this.to) {
if (this.smoothCurves.enabled == true) {
if (this.options.smoothCurves.enabled == true) {
var xVia, yVia; var xVia, yVia;
if (this.smoothCurves.enabled == true && this.smoothCurves.dynamic == true) {
if (this.options.smoothCurves.enabled == true && this.options.smoothCurves.dynamic == true) {
xVia = this.via.x; xVia = this.via.x;
yVia = this.via.y; yVia = this.via.y;
} }
@ -977,7 +941,7 @@ Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is
} }
else { else {
var x, y, dx, dy; var x, y, dx, dy;
var radius = this.length / 4;
var radius = this.physics.springLength / 4;
var node = this.from; var node = this.from;
if (!node.width) { if (!node.width) {
node.resize(ctx); node.resize(ctx);
@ -1168,14 +1132,14 @@ Edge.prototype.getControlNodePositions = function(ctx) {
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y; var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
var via; var via;
if (this.smoothCurves.dynamic == true && this.smoothCurves.enabled == true) {
if (this.options.smoothCurves.dynamic == true && this.options.smoothCurves.enabled == true) {
via = this.via; via = this.via;
} }
else if (this.smoothCurves.enabled == true) {
else if (this.options.smoothCurves.enabled == true) {
via = this._getViaCoordinates(); via = this._getViaCoordinates();
} }
if (this.smoothCurves.enabled == true && via.x != null) {
if (this.options.smoothCurves.enabled == true && via.x != null) {
angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x)); angle = Math.atan2((this.to.y - via.y), (this.to.x - via.x));
dx = (this.to.x - via.x); dx = (this.to.x - via.x);
dy = (this.to.y - via.y); dy = (this.to.y - via.y);
@ -1185,7 +1149,7 @@ Edge.prototype.getControlNodePositions = function(ctx) {
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength; var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
var xTo,yTo; var xTo,yTo;
if (this.smoothCurves.enabled == true && via.x != null) {
if (this.options.smoothCurves.enabled == true && via.x != null) {
xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x; xTo = (1 - toBorderPoint) * via.x + toBorderPoint * this.to.x;
yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y; yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y;
} }

+ 42
- 183
lib/network/Network.js View File

@ -37,8 +37,6 @@ function Network (container, data, options) {
// create variables and set default values // create variables and set default values
this.containerElement = container; this.containerElement = container;
this.width = '100%';
this.height = '100%';
// render and calculation settings // render and calculation settings
this.renderRefreshRate = 60; // hz (fps) this.renderRefreshRate = 60; // hz (fps)
@ -47,17 +45,14 @@ function Network (container, data, options) {
this.maxPhysicsTicksPerRender = 3; // max amount of physics ticks per render step. this.maxPhysicsTicksPerRender = 3; // max amount of physics ticks per render step.
this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation this.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation
this.stabilize = true; // stabilize before displaying the network
this.selectable = true;
this.initializing = true; this.initializing = true;
// these functions are triggered when the dataset is edited
this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null}; this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null};
// set constant values // set constant values
this.constants = {
this.defaultOptions = {
nodes: { nodes: {
mass: 1,
radiusMin: 10, radiusMin: 10,
radiusMax: 30, radiusMax: 30,
radius: 10, radius: 10,
@ -191,6 +186,7 @@ function Network (container, data, options) {
dynamicSmoothCurves: true, dynamicSmoothCurves: true,
maxVelocity: 30, maxVelocity: 30,
minVelocity: 0.1, // px/s minVelocity: 0.1, // px/s
stabilize: true, // stabilize before displaying the network
stabilizationIterations: 1000, // maximum number of iteration to stabilize stabilizationIterations: 1000, // maximum number of iteration to stabilize
labels:{ labels:{
add:"Add Node", add:"Add Node",
@ -225,8 +221,13 @@ function Network (container, data, options) {
zoomable: true, zoomable: true,
hover: false, hover: false,
hideEdgesOnDrag: false, hideEdgesOnDrag: false,
hideNodesOnDrag: false
hideNodesOnDrag: false,
width : '100%',
height : '100%',
selectable: true
}; };
this.constants = util.extend({}, this.defaultOptions);
this.hoverObj = {nodes:{},edges:{}}; this.hoverObj = {nodes:{},edges:{}};
this.controlNodesActive = false; this.controlNodesActive = false;
@ -329,7 +330,7 @@ function Network (container, data, options) {
} }
else { else {
// zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here. // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here.
if (this.stabilize == false) {
if (this.constants.stabilize == false) {
this.zoomExtent(true,this.constants.clustering.enabled); this.zoomExtent(true,this.constants.clustering.enabled);
} }
} }
@ -546,7 +547,7 @@ Network.prototype.setData = function(data, disableStart) {
this._putDataInSector(); this._putDataInSector();
if (!disableStart) { if (!disableStart) {
// find a stable position or start animating to a stable position // find a stable position or start animating to a stable position
if (this.stabilize) {
if (this.constants.stabilize) {
var me = this; var me = this;
setTimeout(function() {me._stabilize(); me.start();},0) setTimeout(function() {me._stabilize(); me.start();},0)
} }
@ -564,72 +565,17 @@ Network.prototype.setData = function(data, disableStart) {
Network.prototype.setOptions = function (options) { Network.prototype.setOptions = function (options) {
if (options) { if (options) {
var prop; var prop;
// retrieve parameter values
if (options.width !== undefined) {this.width = options.width;}
if (options.height !== undefined) {this.height = options.height;}
if (options.stabilize !== undefined) {this.stabilize = options.stabilize;}
if (options.selectable !== undefined) {this.selectable = options.selectable;}
if (options.freezeForStabilization !== undefined) {this.constants.freezeForStabilization = options.freezeForStabilization;}
if (options.configurePhysics !== undefined){this.constants.configurePhysics = options.configurePhysics;}
if (options.stabilizationIterations !== undefined) {this.constants.stabilizationIterations = options.stabilizationIterations;}
if (options.dragNetwork !== undefined) {this.constants.dragNetwork = options.dragNetwork;}
if (options.dragNodes !== undefined) {this.constants.dragNodes = options.dragNodes;}
if (options.zoomable !== undefined) {this.constants.zoomable = options.zoomable;}
if (options.hover !== undefined) {this.constants.hover = options.hover;}
if (options.hideEdgesOnDrag !== undefined) {this.constants.hideEdgesOnDrag = options.hideEdgesOnDrag;}
if (options.hideNodesOnDrag !== undefined) {this.constants.hideNodesOnDrag = options.hideNodesOnDrag;}
// TODO: deprecated since version 3.0.0. Cleanup some day
if (options.dragGraph !== undefined) {
throw new Error('Option dragGraph is renamed to dragNetwork');
}
if (options.labels !== undefined) {
for (prop in options.labels) {
if (options.labels.hasOwnProperty(prop)) {
this.constants.labels[prop] = options.labels[prop];
}
}
}
if (options.onAdd) {
this.triggerFunctions.add = options.onAdd;
}
if (options.onEdit) {
this.triggerFunctions.edit = options.onEdit;
}
if (options.onEditEdge) {
this.triggerFunctions.editEdge = options.onEditEdge;
}
if (options.onConnect) {
this.triggerFunctions.connect = options.onConnect;
}
if (options.onDelete) {
this.triggerFunctions.del = options.onDelete;
}
var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','clustering','navigation','keyboard','dataManipulation',
'onAdd','onEdit','onEditEdge','onConnect','onDelete'
];
util.selectiveNotDeepExtend(fields,this.constants, options);
util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes);
util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges);
if (options.physics) { if (options.physics) {
if (options.physics.barnesHut) {
this.constants.physics.barnesHut.enabled = true;
for (prop in options.physics.barnesHut) {
if (options.physics.barnesHut.hasOwnProperty(prop)) {
this.constants.physics.barnesHut[prop] = options.physics.barnesHut[prop];
}
}
}
if (options.physics.repulsion) {
this.constants.physics.barnesHut.enabled = false;
for (prop in options.physics.repulsion) {
if (options.physics.repulsion.hasOwnProperty(prop)) {
this.constants.physics.repulsion[prop] = options.physics.repulsion[prop];
}
}
}
util.mergeOptions(this.constants.physics, options.physics,'barnesHut');
util.mergeOptions(this.constants.physics, options.physics,'repulsion');
if (options.physics.hierarchicalRepulsion) { if (options.physics.hierarchicalRepulsion) {
this.constants.hierarchicalLayout.enabled = true; this.constants.hierarchicalLayout.enabled = true;
@ -642,92 +588,28 @@ Network.prototype.setOptions = function (options) {
} }
} }
} }
console.log(this.triggerFunctions)
if (options.onAdd) {this.triggerFunctions.add = options.onAdd;}
if (options.onEdit) {this.triggerFunctions.edit = options.onEdit;}
if (options.onEditEdge) {this.triggerFunctions.editEdge = options.onEditEdge;}
if (options.onConnect) {this.triggerFunctions.connect = options.onConnect;}
if (options.onDelete) {this.triggerFunctions.del = options.onDelete;}
if (options.smoothCurves !== undefined) {
if (typeof options.smoothCurves == 'boolean') {
this.constants.smoothCurves.enabled = options.smoothCurves;
}
else {
this.constants.smoothCurves.enabled = true;
for (prop in options.smoothCurves) {
if (options.smoothCurves.hasOwnProperty(prop)) {
this.constants.smoothCurves[prop] = options.smoothCurves[prop];
}
}
}
}
util.mergeOptions(this.constants, options,'smoothCurves');
util.mergeOptions(this.constants, options,'hierarchicalLayout');
util.mergeOptions(this.constants, options,'clustering');
util.mergeOptions(this.constants, options,'navigation');
util.mergeOptions(this.constants, options,'keyboard');
util.mergeOptions(this.constants, options,'dataManipulation');
if (options.hierarchicalLayout) {
this.constants.hierarchicalLayout.enabled = true;
for (prop in options.hierarchicalLayout) {
if (options.hierarchicalLayout.hasOwnProperty(prop)) {
this.constants.hierarchicalLayout[prop] = options.hierarchicalLayout[prop];
}
}
}
else if (options.hierarchicalLayout !== undefined) {
this.constants.hierarchicalLayout.enabled = false;
}
if (options.clustering) {
this.constants.clustering.enabled = true;
for (prop in options.clustering) {
if (options.clustering.hasOwnProperty(prop)) {
this.constants.clustering[prop] = options.clustering[prop];
}
}
}
else if (options.clustering !== undefined) {
this.constants.clustering.enabled = false;
}
if (options.navigation) {
this.constants.navigation.enabled = true;
for (prop in options.navigation) {
if (options.navigation.hasOwnProperty(prop)) {
this.constants.navigation[prop] = options.navigation[prop];
}
}
}
else if (options.navigation !== undefined) {
this.constants.navigation.enabled = false;
}
if (options.keyboard) {
this.constants.keyboard.enabled = true;
for (prop in options.keyboard) {
if (options.keyboard.hasOwnProperty(prop)) {
this.constants.keyboard[prop] = options.keyboard[prop];
}
}
}
else if (options.keyboard !== undefined) {
this.constants.keyboard.enabled = false;
}
if (options.dataManipulation) { if (options.dataManipulation) {
this.constants.dataManipulation.enabled = true;
for (prop in options.dataManipulation) {
if (options.dataManipulation.hasOwnProperty(prop)) {
this.constants.dataManipulation[prop] = options.dataManipulation[prop];
}
}
this.editMode = this.constants.dataManipulation.initiallyVisible; this.editMode = this.constants.dataManipulation.initiallyVisible;
} }
else if (options.dataManipulation !== undefined) {
this.constants.dataManipulation.enabled = false;
}
// TODO: work out these options and document them // TODO: work out these options and document them
if (options.edges) { if (options.edges) {
for (prop in options.edges) {
if (options.edges.hasOwnProperty(prop)) {
if (typeof options.edges[prop] != "object") {
this.constants.edges[prop] = options.edges[prop];
}
}
}
if (options.edges.color !== undefined) { if (options.edges.color !== undefined) {
if (util.isString(options.edges.color)) { if (util.isString(options.edges.color)) {
this.constants.edges.color = {}; this.constants.edges.color = {};
@ -748,38 +630,18 @@ Network.prototype.setOptions = function (options) {
else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;} else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;}
} }
} }
// Added to support dashed lines
// David Jordan
// 2012-08-08
if (options.edges.dash) {
if (options.edges.dash.length !== undefined) {
this.constants.edges.dash.length = options.edges.dash.length;
}
if (options.edges.dash.gap !== undefined) {
this.constants.edges.dash.gap = options.edges.dash.gap;
}
if (options.edges.dash.altLength !== undefined) {
this.constants.edges.dash.altLength = options.edges.dash.altLength;
}
}
} }
if (options.nodes) { if (options.nodes) {
for (prop in options.nodes) {
if (options.nodes.hasOwnProperty(prop)) {
this.constants.nodes[prop] = options.nodes[prop];
}
}
if (options.nodes.color) { if (options.nodes.color) {
this.constants.nodes.color = util.parseColor(options.nodes.color);
var newColorObj = util.parseColor(options.nodes.color);
this.constants.nodes.color.background = newColorObj.background;
this.constants.nodes.color.border = newColorObj.border;
this.constants.nodes.color.highlight.background = newColorObj.highlight.background;
this.constants.nodes.color.highlight.border = newColorObj.highlight.border;
this.constants.nodes.color.hover.background = newColorObj.hover.background;
this.constants.nodes.color.hover.border = newColorObj.hover.border;
} }
/*
if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin;
if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax;
*/
} }
if (options.groups) { if (options.groups) {
for (var groupname in options.groups) { for (var groupname in options.groups) {
@ -802,7 +664,6 @@ Network.prototype.setOptions = function (options) {
} }
} }
// (Re)loading the mixins that can be enabled or disabled in the options. // (Re)loading the mixins that can be enabled or disabled in the options.
// load the force calculation functions, grouped under the physics system. // load the force calculation functions, grouped under the physics system.
this._loadPhysicsSystem(); this._loadPhysicsSystem();
@ -816,7 +677,7 @@ Network.prototype.setOptions = function (options) {
// bind keys. If disabled, this will not do anything; // bind keys. If disabled, this will not do anything;
this._createKeyBinds(); this._createKeyBinds();
this.setSize(this.width, this.height);
this.setSize(this.constants.width, this.constants.height);
this.moving = true; this.moving = true;
this.start(); this.start();
@ -1767,7 +1628,7 @@ Network.prototype._updateValueRange = function(obj) {
* chart will be resized too. * chart will be resized too.
*/ */
Network.prototype.redraw = function() { Network.prototype.redraw = function() {
this.setSize(this.width, this.height);
this.setSize(this.constants.width, this.constants.height);
this._redraw(); this._redraw();
}; };
@ -2267,7 +2128,7 @@ Network.prototype._configureSmoothCurves = function(disableStart) {
// cleanup unused support nodes // cleanup unused support nodes
for (var nodeId in this.sectors['support']['nodes']) { for (var nodeId in this.sectors['support']['nodes']) {
if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) { if (this.sectors['support']['nodes'].hasOwnProperty(nodeId)) {
if (this.edges[this.sectors['support']['nodes'][nodeId]] === undefined) {
if (this.edges[this.sectors['support']['nodes'][nodeId].parentEdgeId] === undefined) {
delete this.sectors['support']['nodes'][nodeId]; delete this.sectors['support']['nodes'][nodeId];
} }
} }
@ -2278,7 +2139,6 @@ Network.prototype._configureSmoothCurves = function(disableStart) {
this.sectors['support']['nodes'] = {}; this.sectors['support']['nodes'] = {};
for (var edgeId in this.edges) { for (var edgeId in this.edges) {
if (this.edges.hasOwnProperty(edgeId)) { if (this.edges.hasOwnProperty(edgeId)) {
this.edges[edgeId].smooth = false;
this.edges[edgeId].via = null; this.edges[edgeId].via = null;
} }
} }
@ -2305,7 +2165,6 @@ Network.prototype._createBezierNodes = function() {
if (this.edges.hasOwnProperty(edgeId)) { if (this.edges.hasOwnProperty(edgeId)) {
var edge = this.edges[edgeId]; var edge = this.edges[edgeId];
if (edge.via == null) { if (edge.via == null) {
edge.smooth = true;
var nodeId = "edgeId:".concat(edge.id); var nodeId = "edgeId:".concat(edge.id);
this.sectors['support']['nodes'][nodeId] = new Node( this.sectors['support']['nodes'][nodeId] = new Node(
{id:nodeId, {id:nodeId,

+ 90
- 107
lib/network/Node.js View File

@ -25,7 +25,10 @@ var util = require('../util');
* example for the color * example for the color
* *
*/ */
function Node(properties, imagelist, grouplist, constants) {
function Node(properties, imagelist, grouplist, networkConstants) {
var constants = util.selectiveBridgeObject(['nodes'],networkConstants);
this.options = constants.nodes;
this.selected = false; this.selected = false;
this.hover = false; this.hover = false;
@ -33,33 +36,20 @@ function Node(properties, imagelist, grouplist, constants) {
this.dynamicEdges = []; this.dynamicEdges = [];
this.reroutedEdges = {}; this.reroutedEdges = {};
this.group = constants.nodes.group;
this.fontSize = Number(constants.nodes.fontSize);
this.fontFace = constants.nodes.fontFace;
this.fontColor = constants.nodes.fontColor;
this.fontDrawThreshold = 3; this.fontDrawThreshold = 3;
this.color = constants.nodes.color;
// set defaults for the properties // set defaults for the properties
this.id = undefined; this.id = undefined;
this.shape = constants.nodes.shape;
this.image = constants.nodes.image;
this.x = null; this.x = null;
this.y = null; this.y = null;
this.xFixed = false; this.xFixed = false;
this.yFixed = false; this.yFixed = false;
this.horizontalAlignLeft = true; // these are for the navigation controls this.horizontalAlignLeft = true; // these are for the navigation controls
this.verticalAlignTop = true; // these are for the navigation controls this.verticalAlignTop = true; // these are for the navigation controls
this.radius = constants.nodes.radius;
this.baseRadiusValue = constants.nodes.radius;
this.baseRadiusValue = networkConstants.nodes.radius;
this.radiusFixed = false; this.radiusFixed = false;
this.radiusMin = constants.nodes.radiusMin;
this.radiusMax = constants.nodes.radiusMax;
this.level = -1; this.level = -1;
this.preassignedLevel = false; this.preassignedLevel = false;
this.borderWidth = constants.nodes.borderWidth;
this.borderWidthSelected = constants.nodes.borderWidthSelected;
this.imagelist = imagelist; this.imagelist = imagelist;
@ -70,9 +60,7 @@ function Node(properties, imagelist, grouplist, constants) {
this.fy = 0.0; // external force y this.fy = 0.0; // external force y
this.vx = 0.0; // velocity x this.vx = 0.0; // velocity x
this.vy = 0.0; // velocity y this.vy = 0.0; // velocity y
this.minForce = constants.minForce;
this.damping = constants.physics.damping;
this.mass = 1; // kg
this.damping = networkConstants.physics.damping; // written every time gravity is calculated
this.fixedData = {x:null,y:null}; this.fixedData = {x:null,y:null};
@ -82,10 +70,10 @@ function Node(properties, imagelist, grouplist, constants) {
this.resetCluster(); this.resetCluster();
this.dynamicEdgesLength = 0; this.dynamicEdgesLength = 0;
this.clusterSession = 0; this.clusterSession = 0;
this.clusterSizeWidthFactor = constants.clustering.nodeScaling.width;
this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height;
this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius;
this.maxNodeSizeIncrements = constants.clustering.maxNodeSizeIncrements;
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; this.growthIndicator = 0;
// variables to tell the node about the network. // variables to tell the node about the network.
@ -145,21 +133,21 @@ Node.prototype.setProperties = function(properties, constants) {
if (!properties) { if (!properties) {
return; return;
} }
var fields = ['borderWidth','borderWidthSelected','shape','image','radius','fontColor',
'fontSize','fontFace','group','mass'
];
util.selectiveDeepExtend(fields, this.options, properties);
this.originalLabel = undefined; this.originalLabel = undefined;
// basic properties // basic properties
if (properties.id !== undefined) {this.id = properties.id;} if (properties.id !== undefined) {this.id = properties.id;}
if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;} if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;}
if (properties.title !== undefined) {this.title = properties.title;} if (properties.title !== undefined) {this.title = properties.title;}
if (properties.group !== undefined) {this.group = properties.group;}
if (properties.x !== undefined) {this.x = properties.x;} if (properties.x !== undefined) {this.x = properties.x;}
if (properties.y !== undefined) {this.y = properties.y;} if (properties.y !== undefined) {this.y = properties.y;}
if (properties.value !== undefined) {this.value = properties.value;} if (properties.value !== undefined) {this.value = properties.value;}
if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;} if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;}
if (properties.borderWidth !== undefined) {this.borderWidth = properties.borderWidth;}
if (properties.borderWidthSelected !== undefined) {this.borderWidthSelected = properties.borderWidthSelected;}
// physics
if (properties.mass !== undefined) {this.mass = properties.mass;}
// navigation controls properties // navigation controls properties
if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;} if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;}
@ -169,30 +157,25 @@ Node.prototype.setProperties = function(properties, constants) {
if (this.id === undefined) { if (this.id === undefined) {
throw "Node must have an id"; throw "Node must have an id";
} }
// console.log(this.options);
// copy group properties // copy group properties
if (this.group !== undefined && this.group != "") {
var groupObj = this.grouplist.get(this.group);
if (this.options.group !== undefined && this.options.group != "") {
var groupObj = this.grouplist.get(this.options.group);
for (var prop in groupObj) { for (var prop in groupObj) {
if (groupObj.hasOwnProperty(prop)) { if (groupObj.hasOwnProperty(prop)) {
this[prop] = groupObj[prop];
this.options[prop] = groupObj[prop];
} }
} }
} }
// individual shape properties
if (properties.shape !== undefined) {this.shape = properties.shape;}
if (properties.image !== undefined) {this.image = properties.image;}
if (properties.radius !== undefined) {this.radius = properties.radius; this.baseRadiusValue = this.radius;}
if (properties.color !== undefined) {this.color = util.parseColor(properties.color);}
if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;}
if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;}
if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;}
// individual shape properties
if (properties.radius !== undefined) {this.baseRadiusValue = this.options.radius;}
if (properties.color !== undefined) {this.options.color = util.parseColor(properties.color);}
if (this.image !== undefined && this.image != "") {
if (this.options.image!== undefined && this.options.image!= "") {
if (this.imagelist) { if (this.imagelist) {
this.imageObj = this.imagelist.load(this.image);
this.imageObj = this.imagelist.load(this.options.image);
} }
else { else {
throw "No imagelist provided"; throw "No imagelist provided";
@ -203,13 +186,14 @@ Node.prototype.setProperties = function(properties, constants) {
this.yFixed = this.yFixed || (properties.y !== undefined && !properties.allowedToMoveY); this.yFixed = this.yFixed || (properties.y !== undefined && !properties.allowedToMoveY);
this.radiusFixed = this.radiusFixed || (properties.radius !== undefined); this.radiusFixed = this.radiusFixed || (properties.radius !== undefined);
if (this.shape == 'image') {
this.radiusMin = constants.nodes.widthMin;
this.radiusMax = constants.nodes.widthMax;
if (this.options.shape == 'image') {
this.options.radiusMin = constants.nodes.widthMin;
this.options.radiusMax = constants.nodes.widthMax;
} }
// choose draw method depending on the shape // choose draw method depending on the shape
switch (this.shape) {
switch (this.options.shape) {
case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break; case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break;
case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break; case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break;
case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break; case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break;
@ -283,10 +267,10 @@ Node.prototype.distanceToBorder = function (ctx, angle) {
this.resize(ctx); this.resize(ctx);
} }
switch (this.shape) {
switch (this.options.shape) {
case 'circle': case 'circle':
case 'dot': case 'dot':
return this.radius + borderWidth;
return this.options.radius+ borderWidth;
case 'ellipse': case 'ellipse':
var a = this.width / 2; var a = this.width / 2;
@ -345,14 +329,14 @@ Node.prototype._addForce = function(fx, fy) {
Node.prototype.discreteStep = function(interval) { Node.prototype.discreteStep = function(interval) {
if (!this.xFixed) { if (!this.xFixed) {
var dx = this.damping * this.vx; // damping force var dx = this.damping * this.vx; // damping force
var ax = (this.fx - dx) / this.mass; // acceleration
var ax = (this.fx - dx) / this.options.mass; // acceleration
this.vx += ax * interval; // velocity this.vx += ax * interval; // velocity
this.x += this.vx * interval; // position this.x += this.vx * interval; // position
} }
if (!this.yFixed) { if (!this.yFixed) {
var dy = this.damping * this.vy; // damping force var dy = this.damping * this.vy; // damping force
var ay = (this.fy - dy) / this.mass; // acceleration
var ay = (this.fy - dy) / this.options.mass; // acceleration
this.vy += ay * interval; // velocity this.vy += ay * interval; // velocity
this.y += this.vy * interval; // position this.y += this.vy * interval; // position
} }
@ -368,7 +352,7 @@ Node.prototype.discreteStep = function(interval) {
Node.prototype.discreteStepLimited = function(interval, maxVelocity) { Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
if (!this.xFixed) { if (!this.xFixed) {
var dx = this.damping * this.vx; // damping force var dx = this.damping * this.vx; // damping force
var ax = (this.fx - dx) / this.mass; // acceleration
var ax = (this.fx - dx) / this.options.mass; // acceleration
this.vx += ax * interval; // velocity this.vx += ax * interval; // velocity
this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx; this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx;
this.x += this.vx * interval; // position this.x += this.vx * interval; // position
@ -379,7 +363,7 @@ Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
if (!this.yFixed) { if (!this.yFixed) {
var dy = this.damping * this.vy; // damping force var dy = this.damping * this.vy; // damping force
var ay = (this.fy - dy) / this.mass; // acceleration
var ay = (this.fy - dy) / this.options.mass; // acceleration
this.vy += ay * interval; // velocity this.vy += ay * interval; // velocity
this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy; this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy;
this.y += this.vy * interval; // position this.y += this.vy * interval; // position
@ -445,14 +429,14 @@ Node.prototype.getDistance = function(x, y) {
Node.prototype.setValueRange = function(min, max) { Node.prototype.setValueRange = function(min, max) {
if (!this.radiusFixed && this.value !== undefined) { if (!this.radiusFixed && this.value !== undefined) {
if (max == min) { if (max == min) {
this.radius = (this.radiusMin + this.radiusMax) / 2;
this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2;
} }
else { else {
var scale = (this.radiusMax - this.radiusMin) / (max - min);
this.radius = (this.value - min) * scale + this.radiusMin;
var scale = (this.options.radiusMax - this.options.radiusMin) / (max - min);
this.options.radius= (this.value - min) * scale + this.options.radiusMin;
} }
} }
this.baseRadiusValue = this.radius;
this.baseRadiusValue = this.options.radius;
}; };
/** /**
@ -491,11 +475,11 @@ Node.prototype._resizeImage = function (ctx) {
if (!this.width || !this.height) { // undefined or 0 if (!this.width || !this.height) { // undefined or 0
var width, height; var width, height;
if (this.value) { if (this.value) {
this.radius = this.baseRadiusValue;
this.options.radius= this.baseRadiusValue;
var scale = this.imageObj.height / this.imageObj.width; var scale = this.imageObj.height / this.imageObj.width;
if (scale !== undefined) { if (scale !== undefined) {
width = this.radius || this.imageObj.width;
height = this.radius * scale || this.imageObj.height;
width = this.options.radius|| this.imageObj.width;
height = this.options.radius* scale || this.imageObj.height;
} }
else { else {
width = 0; width = 0;
@ -513,7 +497,7 @@ Node.prototype._resizeImage = function (ctx) {
if (this.width > 0 && this.height > 0) { if (this.width > 0 && this.height > 0) {
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - width; this.growthIndicator = this.width - width;
} }
} }
@ -562,7 +546,7 @@ Node.prototype._resizeBox = function (ctx) {
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; 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.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.growthIndicator = this.width - (textSize.width + 2 * margin); this.growthIndicator = this.width - (textSize.width + 2 * margin);
// this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
// this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
} }
}; };
@ -574,10 +558,10 @@ Node.prototype._drawBox = function (ctx) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5; var clusterLineWidth = 2.5;
var borderWidth = this.borderWidth;
var selectionLineWidth = this.borderWidthSelected || 2 * this.borderWidth;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border // draw the outer border
if (this.clusterSize > 1) { if (this.clusterSize > 1) {
@ -585,16 +569,16 @@ Node.prototype._drawBox = function (ctx) {
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); 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.radius);
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.stroke();
} }
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background;
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.options.color.background;
ctx.roundRect(this.left, this.top, this.width, this.height, this.radius);
ctx.roundRect(this.left, this.top, this.width, this.height, this.options.radius);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -613,7 +597,7 @@ Node.prototype._resizeDatabase = function (ctx) {
// scaling used for clustering // scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - size; this.growthIndicator = this.width - size;
} }
}; };
@ -624,10 +608,10 @@ Node.prototype._drawDatabase = function (ctx) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5; var clusterLineWidth = 2.5;
var borderWidth = this.borderWidth;
var selectionLineWidth = this.borderWidthSelected || 2 * this.borderWidth;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border // draw the outer border
if (this.clusterSize > 1) { if (this.clusterSize > 1) {
@ -642,7 +626,7 @@ Node.prototype._drawDatabase = function (ctx) {
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background;
ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height); ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -656,7 +640,7 @@ Node.prototype._resizeCircle = function (ctx) {
var margin = 5; var margin = 5;
var textSize = this.getTextSize(ctx); var textSize = this.getTextSize(ctx);
var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; var diameter = Math.max(textSize.width, textSize.height) + 2 * margin;
this.radius = diameter / 2;
this.options.radius= diameter / 2;
this.width = diameter; this.width = diameter;
this.height = diameter; this.height = diameter;
@ -664,8 +648,8 @@ Node.prototype._resizeCircle = function (ctx) {
// scaling used for clustering // scaling used for clustering
// this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor; // 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.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.radius - 0.5*diameter;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.options.radius- 0.5*diameter;
} }
}; };
@ -675,10 +659,10 @@ Node.prototype._drawCircle = function (ctx) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5; var clusterLineWidth = 2.5;
var borderWidth = this.borderWidth;
var selectionLineWidth = this.borderWidthSelected || 2 * this.borderWidth;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border // draw the outer border
if (this.clusterSize > 1) { if (this.clusterSize > 1) {
@ -686,15 +670,15 @@ Node.prototype._drawCircle = function (ctx) {
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.circle(this.x, this.y, this.radius+2*ctx.lineWidth);
ctx.circle(this.x, this.y, this.options.radius+2*ctx.lineWidth);
ctx.stroke(); ctx.stroke();
} }
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
ctx.circle(this.x, this.y, this.radius);
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(this.x, this.y, this.options.radius);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -715,7 +699,7 @@ Node.prototype._resizeEllipse = function (ctx) {
// scaling used for clustering // scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.options.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - defaultSize; this.growthIndicator = this.width - defaultSize;
} }
}; };
@ -726,10 +710,10 @@ Node.prototype._drawEllipse = function (ctx) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5; var clusterLineWidth = 2.5;
var borderWidth = this.borderWidth;
var selectionLineWidth = this.borderWidthSelected || 2 * this.borderWidth;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border // draw the outer border
if (this.clusterSize > 1) { if (this.clusterSize > 1) {
@ -744,7 +728,7 @@ Node.prototype._drawEllipse = function (ctx) {
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background;
ctx.ellipse(this.left, this.top, this.width, this.height); ctx.ellipse(this.left, this.top, this.width, this.height);
ctx.fill(); ctx.fill();
@ -774,15 +758,15 @@ Node.prototype._drawStar = function (ctx) {
Node.prototype._resizeShape = function (ctx) { Node.prototype._resizeShape = function (ctx) {
if (!this.width) { if (!this.width) {
this.radius = this.baseRadiusValue;
var size = 2 * this.radius;
this.options.radius= this.baseRadiusValue;
var size = 2 * this.options.radius;
this.width = size; this.width = size;
this.height = size; this.height = size;
// scaling used for clustering // scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - size; this.growthIndicator = this.width - size;
} }
}; };
@ -794,8 +778,8 @@ Node.prototype._drawShape = function (ctx, shape) {
this.top = this.y - this.height / 2; this.top = this.y - this.height / 2;
var clusterLineWidth = 2.5; var clusterLineWidth = 2.5;
var borderWidth = this.borderWidth;
var selectionLineWidth = this.borderWidthSelected || 2 * this.borderWidth;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
var radiusMultiplier = 2; var radiusMultiplier = 2;
// choose draw method depending on the shape // choose draw method depending on the shape
@ -807,23 +791,22 @@ Node.prototype._drawShape = function (ctx, shape) {
case 'star': radiusMultiplier = 4; break; case 'star': radiusMultiplier = 4; break;
} }
ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
ctx.strokeStyle = this.selected ? this.options.color.highlight.border : this.hover ? this.options.color.hover.border : this.options.color.border;
// draw the outer border // draw the outer border
if (this.clusterSize > 1) { if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth);
ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth);
ctx.stroke(); ctx.stroke();
} }
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0); ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv; ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth); ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
ctx[shape](this.x, this.y, this.radius);
ctx.fillStyle = this.selected ? this.options.color.highlight.background : this.hover ? this.options.color.hover.background : this.options.color.background;
ctx[shape](this.x, this.y, this.options.radius);
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
@ -842,7 +825,7 @@ Node.prototype._resizeText = function (ctx) {
// scaling used for clustering // scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor; this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor; this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.options.radius+= Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
this.growthIndicator = this.width - (textSize.width + 2 * margin); this.growthIndicator = this.width - (textSize.width + 2 * margin);
} }
}; };
@ -857,15 +840,15 @@ Node.prototype._drawText = function (ctx) {
Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) { Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNode) {
if (text && this.fontSize * this.networkScale > this.fontDrawThreshold) {
ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
ctx.fillStyle = this.fontColor || "black";
if (text && Number(this.options.fontSize) * this.networkScale > this.fontDrawThreshold) {
ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace;
ctx.fillStyle = this.options.fontColor || "black";
ctx.textAlign = align || "center"; ctx.textAlign = align || "center";
ctx.textBaseline = baseline || "middle"; ctx.textBaseline = baseline || "middle";
var lines = text.split('\n'); var lines = text.split('\n');
var lineCount = lines.length; var lineCount = lines.length;
var fontSize = (this.fontSize + 4);
var fontSize = (Number(this.options.fontSize) + 4);
var yLine = y + (1 - lineCount) / 2 * fontSize; var yLine = y + (1 - lineCount) / 2 * fontSize;
if (labelUnderNode == true) { if (labelUnderNode == true) {
yLine = y + (1 - lineCount) / (2 * fontSize); yLine = y + (1 - lineCount) / (2 * fontSize);
@ -881,10 +864,10 @@ Node.prototype._label = function (ctx, text, x, y, align, baseline, labelUnderNo
Node.prototype.getTextSize = function(ctx) { Node.prototype.getTextSize = function(ctx) {
if (this.label !== undefined) { if (this.label !== undefined) {
ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
ctx.font = (this.selected ? "bold " : "") + this.options.fontSize + "px " + this.options.fontFace;
var lines = this.label.split('\n'), var lines = this.label.split('\n'),
height = (this.fontSize + 4) * lines.length,
height = (Number(this.options.fontSize) + 4) * lines.length,
width = 0; width = 0;
for (var i = 0, iMax = lines.length; i < iMax; i++) { for (var i = 0, iMax = lines.length; i < iMax; i++) {
@ -971,11 +954,11 @@ Node.prototype.clearVelocity = function() {
*/ */
Node.prototype.updateVelocity = function(massBeforeClustering) { Node.prototype.updateVelocity = function(massBeforeClustering) {
var energyBefore = this.vx * this.vx * massBeforeClustering; var energyBefore = this.vx * this.vx * massBeforeClustering;
//this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
this.vx = Math.sqrt(energyBefore/this.mass);
//this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass);
this.vx = Math.sqrt(energyBefore/this.options.mass);
energyBefore = this.vy * this.vy * massBeforeClustering; energyBefore = this.vy * this.vy * massBeforeClustering;
//this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
this.vy = Math.sqrt(energyBefore/this.mass);
//this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.options.mass) : Math.sqrt(energyBefore/this.options.mass);
this.vy = Math.sqrt(energyBefore/this.options.mass);
}; };
module.exports = Node; module.exports = Node;

+ 8
- 8
lib/network/mixins/ClusterMixin.js View File

@ -367,9 +367,9 @@ exports._expelChildFromParent = function(parentNode, containedNodeId, recursive,
this._validateEdges(parentNode); this._validateEdges(parentNode);
// undo the changes from the clustering operation on the parent node // undo the changes from the clustering operation on the parent node
parentNode.mass -= childNode.mass;
parentNode.options.mass -= childNode.options.mass;
parentNode.clusterSize -= childNode.clusterSize; parentNode.clusterSize -= childNode.clusterSize;
parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length; parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length;
// place the child node near the parent, not at the exact same location to avoid chaos in the system // place the child node near the parent, not at the exact same location to avoid chaos in the system
@ -471,7 +471,7 @@ exports._formClustersByZoom = function() {
// first check which node is larger // first check which node is larger
var parentNode = edge.from; var parentNode = edge.from;
var childNode = edge.to; var childNode = edge.to;
if (edge.to.mass > edge.from.mass) {
if (edge.to.options.mass > edge.from.options.mass) {
parentNode = edge.to; parentNode = edge.to;
childNode = edge.from; childNode = edge.from;
} }
@ -508,7 +508,7 @@ exports._forceClustersByZoom = function() {
// group to the largest node // group to the largest node
if (childNode.id != parentNode.id) { if (childNode.id != parentNode.id) {
if (parentNode.mass > childNode.mass) {
if (parentNode.options.mass > childNode.options.mass) {
this._addToCluster(parentNode,childNode,true); this._addToCluster(parentNode,childNode,true);
} }
else { else {
@ -677,11 +677,11 @@ exports._addToCluster = function(parentNode, childNode, force) {
delete this.nodes[childNode.id]; delete this.nodes[childNode.id];
// update the properties of the child and parent // update the properties of the child and parent
var massBefore = parentNode.mass;
var massBefore = parentNode.options.mass;
childNode.clusterSession = this.clusterSession; childNode.clusterSession = this.clusterSession;
parentNode.mass += childNode.mass;
parentNode.options.mass += childNode.options.mass;
parentNode.clusterSize += childNode.clusterSize; parentNode.clusterSize += childNode.clusterSize;
parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
parentNode.options.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
// keep track of the clustersessions so we can open the cluster up as it has been formed. // keep track of the clustersessions so we can open the cluster up as it has been formed.
if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) { if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) {
@ -1043,7 +1043,7 @@ exports.repositionNodes = function() {
for (var i = 0; i < this.nodeIndices.length; i++) { for (var i = 0; i < this.nodeIndices.length; i++) {
var node = this.nodes[this.nodeIndices[i]]; var node = this.nodes[this.nodeIndices[i]];
if ((node.xFixed == false || node.yFixed == false)) { if ((node.xFixed == false || node.yFixed == false)) {
var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.mass);
var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.options.mass);
var angle = 2 * Math.PI * Math.random(); var angle = 2 * Math.PI * Math.random();
if (node.xFixed == false) {node.x = radius * Math.cos(angle);} if (node.xFixed == false) {node.x = radius * Math.cos(angle);}
if (node.yFixed == false) {node.y = radius * Math.sin(angle);} if (node.yFixed == false) {node.y = radius * Math.sin(angle);}

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

@ -504,14 +504,14 @@ exports._editNode = function() {
var node = this._getSelectedNode(); var node = this._getSelectedNode();
var data = {id:node.id, var data = {id:node.id,
label: node.label, label: node.label,
group: node.group,
shape: node.shape,
group: node.options.group,
shape: node.options.shape,
color: { color: {
background:node.color.background,
border:node.color.border,
background:node.options.color.background,
border:node.options.color.border,
highlight: { highlight: {
background:node.color.highlight.background,
border:node.color.highlight.border
background:node.options.color.highlight.background,
border:node.options.color.highlight.border
} }
}}; }};
if (this.triggerFunctions.edit.length == 2) { if (this.triggerFunctions.edit.length == 2) {

+ 20
- 14
lib/network/mixins/physics/BarnesHutMixin.js View File

@ -18,11 +18,13 @@ exports._calculateNodeForces = function() {
// place the nodes one by one recursively // place the nodes one by one recursively
for (var i = 0; i < nodeCount; i++) { for (var i = 0; i < nodeCount; i++) {
node = nodes[nodeIndices[i]]; node = nodes[nodeIndices[i]];
if (node.options.mass > 0) {
// starting with root is irrelevant, it never passes the BarnesHut condition // starting with root is irrelevant, it never passes the BarnesHut condition
this._getForceContribution(barnesHutTree.root.children.NW,node);
this._getForceContribution(barnesHutTree.root.children.NE,node);
this._getForceContribution(barnesHutTree.root.children.SW,node);
this._getForceContribution(barnesHutTree.root.children.SE,node);
this._getForceContribution(barnesHutTree.root.children.NW,node);
this._getForceContribution(barnesHutTree.root.children.NE,node);
this._getForceContribution(barnesHutTree.root.children.SW,node);
this._getForceContribution(barnesHutTree.root.children.SE,node);
}
} }
} }
}; };
@ -55,7 +57,7 @@ exports._getForceContribution = function(parentBranch,node) {
distance = 0.1*Math.random(); distance = 0.1*Math.random();
dx = distance; dx = distance;
} }
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance);
var fx = dx * gravityForce; var fx = dx * gravityForce;
var fy = dy * gravityForce; var fy = dy * gravityForce;
node.fx += fx; node.fx += fx;
@ -76,7 +78,7 @@ exports._getForceContribution = function(parentBranch,node) {
distance = 0.5*Math.random(); distance = 0.5*Math.random();
dx = distance; dx = distance;
} }
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.options.mass / (distance * distance * distance);
var fx = dx * gravityForce; var fx = dx * gravityForce;
var fy = dy * gravityForce; var fy = dy * gravityForce;
node.fx += fx; node.fx += fx;
@ -107,10 +109,12 @@ exports._formBarnesHutTree = function(nodes,nodeIndices) {
for (var i = 0; i < nodeCount; i++) { for (var i = 0; i < nodeCount; i++) {
var x = nodes[nodeIndices[i]].x; var x = nodes[nodeIndices[i]].x;
var y = nodes[nodeIndices[i]].y; var y = nodes[nodeIndices[i]].y;
if (x < minX) { minX = x; }
if (x > maxX) { maxX = x; }
if (y < minY) { minY = y; }
if (y > maxY) { maxY = y; }
if (nodes[nodeIndices[i]].options.mass > 0) {
if (x < minX) { minX = x; }
if (x > maxX) { maxX = x; }
if (y < minY) { minY = y; }
if (y > maxY) { maxY = y; }
}
} }
// make the range a square // make the range a square
var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
@ -145,7 +149,9 @@ exports._formBarnesHutTree = function(nodes,nodeIndices) {
// place the nodes one by one recursively // place the nodes one by one recursively
for (i = 0; i < nodeCount; i++) { for (i = 0; i < nodeCount; i++) {
node = nodes[nodeIndices[i]]; node = nodes[nodeIndices[i]];
this._placeInTree(barnesHutTree.root,node);
if (node.options.mass > 0) {
this._placeInTree(barnesHutTree.root,node);
}
} }
// make global // make global
@ -161,13 +167,13 @@ exports._formBarnesHutTree = function(nodes,nodeIndices) {
* @private * @private
*/ */
exports._updateBranchMass = function(parentBranch, node) { exports._updateBranchMass = function(parentBranch, node) {
var totalMass = parentBranch.mass + node.mass;
var totalMass = parentBranch.mass + node.options.mass;
var totalMassInv = 1/totalMass; var totalMassInv = 1/totalMass;
parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.mass;
parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
parentBranch.centerOfMass.x *= totalMassInv; parentBranch.centerOfMass.x *= totalMassInv;
parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.mass;
parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
parentBranch.centerOfMass.y *= totalMassInv; parentBranch.centerOfMass.y *= totalMassInv;
parentBranch.mass = totalMass; parentBranch.mass = totalMass;

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

@ -84,7 +84,7 @@ exports._calculateHierarchicalSpringForces = function () {
if (edge.connected) { if (edge.connected) {
// only calculate forces if nodes are in the same sector // only calculate forces if nodes are in the same sector
if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
edgeLength = edge.physics.springLength;
// this implies that the edges between big clusters are longer // this implies that the edges between big clusters are longer
edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;

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

@ -205,7 +205,7 @@ exports._calculateSpringForces = function () {
if (edge.connected) { if (edge.connected) {
// only calculate forces if nodes are in the same sector // only calculate forces if nodes are in the same sector
if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) { if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
edgeLength = edge.physics.springLength;
// this implies that the edges between big clusters are longer // this implies that the edges between big clusters are longer
edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth; edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;
@ -257,7 +257,7 @@ exports._calculateSpringForcesWithSupport = function () {
var node2 = edge.via; var node2 = edge.via;
var node3 = edge.from; var node3 = edge.from;
edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
edgeLength = edge.physics.springLength;
combinedClusterSize = node1.clusterSize + node3.clusterSize - 2; combinedClusterSize = node1.clusterSize + node3.clusterSize - 2;

+ 37
- 0
lib/util.js View File

@ -164,6 +164,43 @@ exports.selectiveDeepExtend = function (props, a, b) {
return a; return a;
}; };
/**
* Extend object a with selected properties of object b or a series of objects
* Only properties with defined values are copied
* @param {Array.<String>} props
* @param {Object} a
* @param {... Object} b
* @return {Object} a
*/
exports.selectiveNotDeepExtend = function (props, a, b) {
// 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 (props.indexOf(prop) == -1) {
if (b[prop] && b[prop].constructor === Object) {
if (a[prop] === undefined) {
a[prop] = {};
}
if (a[prop].constructor === Object) {
exports.deepExtend(a[prop], b[prop]);
}
else {
a[prop] = b[prop];
}
} else if (Array.isArray(b[prop])) {
throw new TypeError('Arrays are not supported by deepExtend');
} else {
a[prop] = b[prop];
}
}
}
}
return a;
};
/** /**
* Deep extend an object a with the properties of object b * Deep extend an object a with the properties of object b
* @param {Object} a * @param {Object} a

Loading…
Cancel
Save