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.
### 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

+ 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>
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>
@ -1353,12 +1355,6 @@ var options = {
<td>Default length of a gap in pixels on a dashed line.
Only applicable when the line style is <code>dash-line</code>.</td>
</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>
<td>inheritColor</td>

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

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

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

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

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

@ -26,7 +26,7 @@
// create some 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: 4, style: 'line', width: 1, 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 = {
stabilize: false,
edges: {
length: 120,
width: 2,
style: 'arrow',
color: 'gray'
@ -79,6 +78,7 @@
}
}
},
physics: {barnesHut:{springLength:200}}, // this is the correct way to set the length of the springs
groups: {
black: {
// defaults for nodes in this group

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

@ -45,9 +45,7 @@
nodes: {
shape: 'box'
},
edges: {
length: 180
},
physics: {barnesHut:{springLength:150}}, // this is the correct way to set the length of the springs
stabilize: false
};
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 y = - mynetwork.clientHeight / 2 + 50;
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
var container = document.getElementById('mynetwork');

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

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

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

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

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

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

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

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

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

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

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

@ -77,10 +77,8 @@
};
var options = {
edges: {
},
stabilize: false,
configurePhysics:true
stabilize: false,
configurePhysics:true
};
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
* example for the color
*/
function Edge (properties, network, constants) {
function Edge (properties, network, networkConstants) {
if (!network) {
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
this.id = undefined;
this.fromId = undefined;
this.toId = undefined;
this.style = constants.edges.style;
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.length = constants.physics.springLength;
this.customLength = false;
this.selected = 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.to = null; // a node
@ -57,18 +50,10 @@ function Edge (properties, network, constants) {
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.lengthFixed = false;
this.setProperties(properties, constants);
this.setProperties(properties);
this.controlNodesEnabled = false;
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} constants and object with default, global properties
*/
Edge.prototype.setProperties = function(properties, constants) {
Edge.prototype.setProperties = function(properties) {
if (!properties) {
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.to !== undefined) {this.toId = properties.to;}
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 (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.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.length !== undefined) {this.length = properties.length;
this.customLength = true;}
if (properties.length !== undefined) {this.physics.springLength = properties.length;}
// 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) {
this.options.inheritColor = false;
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 {
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.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
switch (this.style) {
switch (this.options.style) {
case 'line': this.draw = this._drawLine; break;
case 'arrow': this.draw = this._drawArrow; break;
case 'arrow-center': this.draw = this._drawArrowCenter; break;
@ -223,9 +187,9 @@ Edge.prototype.getValue = function() {
*/
Edge.prototype.setValueRange = function(min, max) {
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() {
var colorObj = this.color;
if (this.inheritColor == "to") {
var colorObj = this.options.color;
if (this.options.inheritColor == "to") {
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 = {
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
var point;
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 midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY};
@ -318,7 +282,7 @@ Edge.prototype._drawLine = function(ctx) {
}
else {
var x, y;
var radius = this.length / 4;
var radius = this.physics.springLength / 4;
var node = this.from;
if (!node.width) {
node.resize(ctx);
@ -345,14 +309,14 @@ Edge.prototype._drawLine = function(ctx) {
*/
Edge.prototype._getLineWidth = function() {
if (this.selected == true) {
return Math.min(this.widthSelected, this.widthMax)*this.networkScaleInv;
return Math.min(this.widthSelected, this.options.widthMax)*this.networkScaleInv;
}
else {
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 {
return this.width*this.networkScaleInv;
return this.options.width*this.networkScaleInv;
}
}
};
@ -360,8 +324,8 @@ Edge.prototype._getLineWidth = function() {
Edge.prototype._getViaCoordinates = function () {
var xVia = 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 dy = Math.abs(this.from.y - this.to.y);
@ -531,8 +495,8 @@ Edge.prototype._line = function (ctx) {
// draw a straight line
ctx.beginPath();
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();
if (via.x == null) {
ctx.lineTo(this.to.x, this.to.y);
@ -587,17 +551,17 @@ Edge.prototype._label = function (ctx, text, x, y) {
if (text) {
// TODO: cache the calculated size
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 height = this.fontSize;
var height = this.options.fontSize;
var left = x - width / 2;
var top = y - height / 2;
ctx.fillRect(left, top, width, height);
// draw text
ctx.fillStyle = this.fontColor || "black";
ctx.fillStyle = this.options.fontColor || "black";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(text, left, top);
@ -615,9 +579,9 @@ Edge.prototype._label = function (ctx, text, x, y) {
*/
Edge.prototype._drawDashLine = function(ctx) {
// 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();
@ -626,8 +590,8 @@ Edge.prototype._drawDashLine = function(ctx) {
if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) {
// configure the dash pattern
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 {
pattern = [5,5];
@ -660,15 +624,15 @@ Edge.prototype._drawDashLine = function(ctx) {
// draw dashed line
ctx.beginPath();
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,
[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,
[this.dash.length,this.dash.gap]);
[this.options.dash.length,this.options.dash.gap]);
}
else //If all else fails draw a line
{
@ -681,7 +645,7 @@ Edge.prototype._drawDashLine = function(ctx) {
// draw label
if (this.label) {
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 midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY};
@ -733,9 +697,9 @@ Edge.prototype._pointOnCircle = function (x, y, radius, percentage) {
Edge.prototype._drawArrowCenter = function(ctx) {
var point;
// 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();
if (this.from != this.to) {
@ -743,9 +707,9 @@ Edge.prototype._drawArrowCenter = function(ctx) {
var via = this._line(ctx);
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
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 midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY};
@ -766,7 +730,7 @@ Edge.prototype._drawArrowCenter = function(ctx) {
else {
// draw circle
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;
if (!node.width) {
node.resize(ctx);
@ -783,7 +747,7 @@ Edge.prototype._drawArrowCenter = function(ctx) {
// draw all arrows
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);
ctx.arrow(point.x, point.y, angle, length);
ctx.fill();
@ -808,9 +772,9 @@ Edge.prototype._drawArrowCenter = function(ctx) {
*/
Edge.prototype._drawArrow = function(ctx) {
// 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();
@ -828,14 +792,14 @@ Edge.prototype._drawArrow = function(ctx) {
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
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;
}
else if (this.smoothCurves.enabled == true) {
else if (this.options.smoothCurves.enabled == true) {
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));
dx = (this.to.x - via.x);
dy = (this.to.y - via.y);
@ -845,7 +809,7 @@ Edge.prototype._drawArrow = function(ctx) {
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
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;
yTo = (1 - toBorderPoint) * via.y + toBorderPoint * this.to.y;
}
@ -856,7 +820,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.beginPath();
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);
}
else {
@ -865,7 +829,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.stroke();
// 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.fill();
ctx.stroke();
@ -873,7 +837,7 @@ Edge.prototype._drawArrow = function(ctx) {
// draw label
if (this.label) {
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 midpointY = 0.5*(0.5*(this.from.y + via.y) + 0.5*(this.to.y + via.y));
point = {x:midpointX, y:midpointY};
@ -888,7 +852,7 @@ Edge.prototype._drawArrow = function(ctx) {
// draw circle
var node = this.from;
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) {
node.resize(ctx);
}
@ -916,7 +880,7 @@ Edge.prototype._drawArrow = function(ctx) {
ctx.stroke();
// 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.fill();
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
if (this.from != this.to) {
if (this.smoothCurves.enabled == true) {
if (this.options.smoothCurves.enabled == true) {
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;
yVia = this.via.y;
}
@ -977,7 +941,7 @@ Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is
}
else {
var x, y, dx, dy;
var radius = this.length / 4;
var radius = this.physics.springLength / 4;
var node = this.from;
if (!node.width) {
node.resize(ctx);
@ -1168,14 +1132,14 @@ Edge.prototype.getControlNodePositions = function(ctx) {
var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
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;
}
else if (this.smoothCurves.enabled == true) {
else if (this.options.smoothCurves.enabled == true) {
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));
dx = (this.to.x - via.x);
dy = (this.to.y - via.y);
@ -1185,7 +1149,7 @@ Edge.prototype.getControlNodePositions = function(ctx) {
var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
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;
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
this.containerElement = container;
this.width = '100%';
this.height = '100%';
// render and calculation settings
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.physicsDiscreteStepsize = 0.50; // discrete stepsize of the simulation
this.stabilize = true; // stabilize before displaying the network
this.selectable = 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};
// set constant values
this.constants = {
this.defaultOptions = {
nodes: {
mass: 1,
radiusMin: 10,
radiusMax: 30,
radius: 10,
@ -191,6 +186,7 @@ function Network (container, data, options) {
dynamicSmoothCurves: true,
maxVelocity: 30,
minVelocity: 0.1, // px/s
stabilize: true, // stabilize before displaying the network
stabilizationIterations: 1000, // maximum number of iteration to stabilize
labels:{
add:"Add Node",
@ -225,8 +221,13 @@ function Network (container, data, options) {
zoomable: true,
hover: false,
hideEdgesOnDrag: false,
hideNodesOnDrag: false
hideNodesOnDrag: false,
width : '100%',
height : '100%',
selectable: true
};
this.constants = util.extend({}, this.defaultOptions);
this.hoverObj = {nodes:{},edges:{}};
this.controlNodesActive = false;
@ -329,7 +330,7 @@ function Network (container, data, options) {
}
else {
// 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);
}
}
@ -546,7 +547,7 @@ Network.prototype.setData = function(data, disableStart) {
this._putDataInSector();
if (!disableStart) {
// find a stable position or start animating to a stable position
if (this.stabilize) {
if (this.constants.stabilize) {
var me = this;
setTimeout(function() {me._stabilize(); me.start();},0)
}
@ -564,72 +565,17 @@ Network.prototype.setData = function(data, disableStart) {
Network.prototype.setOptions = function (options) {
if (options) {
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.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) {
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) {
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;
}
else if (options.dataManipulation !== undefined) {
this.constants.dataManipulation.enabled = false;
}
// TODO: work out these options and document them
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 (util.isString(options.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;}
}
}
// 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) {
for (prop in options.nodes) {
if (options.nodes.hasOwnProperty(prop)) {
this.constants.nodes[prop] = options.nodes[prop];
}
}
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) {
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.
// load the force calculation functions, grouped under the physics system.
this._loadPhysicsSystem();
@ -816,7 +677,7 @@ Network.prototype.setOptions = function (options) {
// bind keys. If disabled, this will not do anything;
this._createKeyBinds();
this.setSize(this.width, this.height);
this.setSize(this.constants.width, this.constants.height);
this.moving = true;
this.start();
@ -1767,7 +1628,7 @@ Network.prototype._updateValueRange = function(obj) {
* chart will be resized too.
*/
Network.prototype.redraw = function() {
this.setSize(this.width, this.height);
this.setSize(this.constants.width, this.constants.height);
this._redraw();
};
@ -2267,7 +2128,7 @@ Network.prototype._configureSmoothCurves = function(disableStart) {
// cleanup unused support nodes
for (var nodeId in this.sectors['support']['nodes']) {
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];
}
}
@ -2278,7 +2139,6 @@ Network.prototype._configureSmoothCurves = function(disableStart) {
this.sectors['support']['nodes'] = {};
for (var edgeId in this.edges) {
if (this.edges.hasOwnProperty(edgeId)) {
this.edges[edgeId].smooth = false;
this.edges[edgeId].via = null;
}
}
@ -2305,7 +2165,6 @@ Network.prototype._createBezierNodes = function() {
if (this.edges.hasOwnProperty(edgeId)) {
var edge = this.edges[edgeId];
if (edge.via == null) {
edge.smooth = true;
var nodeId = "edgeId:".concat(edge.id);
this.sectors['support']['nodes'][nodeId] = new Node(
{id:nodeId,

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

@ -25,7 +25,10 @@ var util = require('../util');
* 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.hover = false;
@ -33,33 +36,20 @@ function Node(properties, imagelist, grouplist, constants) {
this.dynamicEdges = [];
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.color = constants.nodes.color;
// set defaults for the properties
this.id = undefined;
this.shape = constants.nodes.shape;
this.image = constants.nodes.image;
this.x = null;
this.y = null;
this.xFixed = false;
this.yFixed = false;
this.horizontalAlignLeft = 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.radiusMin = constants.nodes.radiusMin;
this.radiusMax = constants.nodes.radiusMax;
this.level = -1;
this.preassignedLevel = false;
this.borderWidth = constants.nodes.borderWidth;
this.borderWidthSelected = constants.nodes.borderWidthSelected;
this.imagelist = imagelist;
@ -70,9 +60,7 @@ function Node(properties, imagelist, grouplist, constants) {
this.fy = 0.0; // external force y
this.vx = 0.0; // velocity x
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};
@ -82,10 +70,10 @@ function Node(properties, imagelist, grouplist, constants) {
this.resetCluster();
this.dynamicEdgesLength = 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;
// variables to tell the node about the network.
@ -145,21 +133,21 @@ Node.prototype.setProperties = function(properties, constants) {
if (!properties) {
return;
}
var fields = ['borderWidth','borderWidthSelected','shape','image','radius','fontColor',
'fontSize','fontFace','group','mass'
];
util.selectiveDeepExtend(fields, this.options, properties);
this.originalLabel = undefined;
// basic properties
if (properties.id !== undefined) {this.id = properties.id;}
if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;}
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.y !== undefined) {this.y = properties.y;}
if (properties.value !== undefined) {this.value = properties.value;}
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
if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;}
@ -169,30 +157,25 @@ Node.prototype.setProperties = function(properties, constants) {
if (this.id === undefined) {
throw "Node must have an id";
}
// console.log(this.options);
// 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) {
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) {
this.imageObj = this.imagelist.load(this.image);
this.imageObj = this.imagelist.load(this.options.image);
}
else {
throw "No imagelist provided";
@ -203,13 +186,14 @@ Node.prototype.setProperties = function(properties, constants) {
this.yFixed = this.yFixed || (properties.y !== undefined && !properties.allowedToMoveY);
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
switch (this.shape) {
switch (this.options.shape) {
case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break;
case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; 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);
}
switch (this.shape) {
switch (this.options.shape) {
case 'circle':
case 'dot':
return this.radius + borderWidth;
return this.options.radius+ borderWidth;
case 'ellipse':
var a = this.width / 2;
@ -345,14 +329,14 @@ Node.prototype._addForce = function(fx, fy) {
Node.prototype.discreteStep = function(interval) {
if (!this.xFixed) {
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.x += this.vx * interval; // position
}
if (!this.yFixed) {
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.y += this.vy * interval; // position
}
@ -368,7 +352,7 @@ Node.prototype.discreteStep = function(interval) {
Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
if (!this.xFixed) {
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 = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx;
this.x += this.vx * interval; // position
@ -379,7 +363,7 @@ Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
if (!this.yFixed) {
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 = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy;
this.y += this.vy * interval; // position
@ -445,14 +429,14 @@ Node.prototype.getDistance = function(x, y) {
Node.prototype.setValueRange = function(min, max) {
if (!this.radiusFixed && this.value !== undefined) {
if (max == min) {
this.radius = (this.radiusMin + this.radiusMax) / 2;
this.options.radius= (this.options.radiusMin + this.options.radiusMax) / 2;
}
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
var width, height;
if (this.value) {
this.radius = this.baseRadiusValue;
this.options.radius= this.baseRadiusValue;
var scale = this.imageObj.height / this.imageObj.width;
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 {
width = 0;
@ -513,7 +497,7 @@ Node.prototype._resizeImage = function (ctx) {
if (this.width > 0 && this.height > 0) {
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.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;
}
}
@ -562,7 +546,7 @@ Node.prototype._resizeBox = function (ctx) {
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.growthIndicator = this.width - (textSize.width + 2 * margin);
// this.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;
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
if (this.clusterSize > 1) {
@ -585,16 +569,16 @@ Node.prototype._drawBox = function (ctx) {
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.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.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
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.stroke();
@ -613,7 +597,7 @@ Node.prototype._resizeDatabase = function (ctx) {
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.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;
}
};
@ -624,10 +608,10 @@ Node.prototype._drawDatabase = function (ctx) {
this.top = this.y - this.height / 2;
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
if (this.clusterSize > 1) {
@ -642,7 +626,7 @@ Node.prototype._drawDatabase = function (ctx) {
ctx.lineWidth *= this.networkScaleInv;
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.fill();
ctx.stroke();
@ -656,7 +640,7 @@ Node.prototype._resizeCircle = function (ctx) {
var margin = 5;
var textSize = this.getTextSize(ctx);
var diameter = Math.max(textSize.width, textSize.height) + 2 * margin;
this.radius = diameter / 2;
this.options.radius= diameter / 2;
this.width = diameter;
this.height = diameter;
@ -664,8 +648,8 @@ Node.prototype._resizeCircle = function (ctx) {
// scaling used for clustering
// this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
// this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
this.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;
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
if (this.clusterSize > 1) {
@ -686,15 +670,15 @@ Node.prototype._drawCircle = function (ctx) {
ctx.lineWidth *= this.networkScaleInv;
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.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
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.stroke();
@ -715,7 +699,7 @@ Node.prototype._resizeEllipse = function (ctx) {
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.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;
}
};
@ -726,10 +710,10 @@ Node.prototype._drawEllipse = function (ctx) {
this.top = this.y - this.height / 2;
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
if (this.clusterSize > 1) {
@ -744,7 +728,7 @@ Node.prototype._drawEllipse = function (ctx) {
ctx.lineWidth *= this.networkScaleInv;
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.fill();
@ -774,15 +758,15 @@ Node.prototype._drawStar = function (ctx) {
Node.prototype._resizeShape = function (ctx) {
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.height = size;
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.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;
}
};
@ -794,8 +778,8 @@ Node.prototype._drawShape = function (ctx, shape) {
this.top = this.y - this.height / 2;
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;
// choose draw method depending on the shape
@ -807,23 +791,22 @@ Node.prototype._drawShape = function (ctx, shape) {
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
if (this.clusterSize > 1) {
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
ctx.lineWidth = Math.min(this.width,ctx.lineWidth);
ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth);
ctx[shape](this.x, this.y, this.options.radius+ radiusMultiplier * ctx.lineWidth);
ctx.stroke();
}
ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
ctx.lineWidth *= this.networkScaleInv;
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.stroke();
@ -842,7 +825,7 @@ Node.prototype._resizeText = function (ctx) {
// scaling used for clustering
this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
this.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);
}
};
@ -857,15 +840,15 @@ Node.prototype._drawText = function (ctx) {
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.textBaseline = baseline || "middle";
var lines = text.split('\n');
var lineCount = lines.length;
var fontSize = (this.fontSize + 4);
var fontSize = (Number(this.options.fontSize) + 4);
var yLine = y + (1 - lineCount) / 2 * fontSize;
if (labelUnderNode == true) {
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) {
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'),
height = (this.fontSize + 4) * lines.length,
height = (Number(this.options.fontSize) + 4) * lines.length,
width = 0;
for (var i = 0, iMax = lines.length; i < iMax; i++) {
@ -971,11 +954,11 @@ Node.prototype.clearVelocity = function() {
*/
Node.prototype.updateVelocity = function(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;
//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;

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

@ -367,9 +367,9 @@ exports._expelChildFromParent = function(parentNode, containedNodeId, recursive,
this._validateEdges(parentNode);
// 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.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;
// 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
var parentNode = edge.from;
var childNode = edge.to;
if (edge.to.mass > edge.from.mass) {
if (edge.to.options.mass > edge.from.options.mass) {
parentNode = edge.to;
childNode = edge.from;
}
@ -508,7 +508,7 @@ exports._forceClustersByZoom = function() {
// group to the largest node
if (childNode.id != parentNode.id) {
if (parentNode.mass > childNode.mass) {
if (parentNode.options.mass > childNode.options.mass) {
this._addToCluster(parentNode,childNode,true);
}
else {
@ -677,11 +677,11 @@ exports._addToCluster = function(parentNode, childNode, force) {
delete this.nodes[childNode.id];
// update the properties of the child and parent
var massBefore = parentNode.mass;
var massBefore = parentNode.options.mass;
childNode.clusterSession = this.clusterSession;
parentNode.mass += childNode.mass;
parentNode.options.mass += childNode.options.mass;
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.
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++) {
var node = this.nodes[this.nodeIndices[i]];
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();
if (node.xFixed == false) {node.x = radius * Math.cos(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 data = {id:node.id,
label: node.label,
group: node.group,
shape: node.shape,
group: node.options.group,
shape: node.options.shape,
color: {
background:node.color.background,
border:node.color.border,
background:node.options.color.background,
border:node.options.color.border,
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) {

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

@ -18,11 +18,13 @@ exports._calculateNodeForces = function() {
// place the nodes one by one recursively
for (var i = 0; i < nodeCount; i++) {
node = nodes[nodeIndices[i]];
if (node.options.mass > 0) {
// 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();
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 fy = dy * gravityForce;
node.fx += fx;
@ -76,7 +78,7 @@ exports._getForceContribution = function(parentBranch,node) {
distance = 0.5*Math.random();
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 fy = dy * gravityForce;
node.fx += fx;
@ -107,10 +109,12 @@ exports._formBarnesHutTree = function(nodes,nodeIndices) {
for (var i = 0; i < nodeCount; i++) {
var x = nodes[nodeIndices[i]].x;
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
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
for (i = 0; i < nodeCount; i++) {
node = nodes[nodeIndices[i]];
this._placeInTree(barnesHutTree.root,node);
if (node.options.mass > 0) {
this._placeInTree(barnesHutTree.root,node);
}
}
// make global
@ -161,13 +167,13 @@ exports._formBarnesHutTree = function(nodes,nodeIndices) {
* @private
*/
exports._updateBranchMass = function(parentBranch, node) {
var totalMass = parentBranch.mass + node.mass;
var totalMass = parentBranch.mass + node.options.mass;
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.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.mass = totalMass;

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

@ -84,7 +84,7 @@ exports._calculateHierarchicalSpringForces = function () {
if (edge.connected) {
// only calculate forces if nodes are in the same sector
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
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) {
// only calculate forces if nodes are in the same sector
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
edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;
@ -257,7 +257,7 @@ exports._calculateSpringForcesWithSupport = function () {
var node2 = edge.via;
var node3 = edge.from;
edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
edgeLength = edge.physics.springLength;
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;
};
/**
* 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
* @param {Object} a

Loading…
Cancel
Save