Browse Source

- Fixed bug where a network that has frozen physics would resume redrawing after setData, setOptions etc.

- Added option to bypass default groups. If more groups are specified in the nodes than there are in the groups, loop over supplied groups instead of default.
- Added two new static smooth curves modes: curveCW and curve CCW.
- Added request redraw for certain internal processes to reduce number of draw calls.
v3_develop
Alex de Mulder 9 years ago
parent
commit
805ef8d43e
10 changed files with 4444 additions and 4250 deletions
  1. +3
    -0
      HISTORY.md
  2. +4284
    -4197
      dist/vis.js
  3. +6
    -4
      examples/network/06_groups.html
  4. +17
    -4
      examples/network/26_staticSmoothCurves.html
  5. +2
    -0
      examples/network/27_world_cup_network.html
  6. +26
    -9
      lib/network/Edge.js
  7. +50
    -19
      lib/network/Groups.js
  8. +53
    -14
      lib/network/Network.js
  9. +1
    -1
      lib/network/Node.js
  10. +2
    -2
      lib/network/mixins/SelectionMixin.js

+ 3
- 0
HISTORY.md View File

@ -8,6 +8,9 @@ http://visjs.org
- (added gradient coloring for lines, but set for release in 4.0 due to required refactoring of options)
- Fixed bug where a network that has frozen physics would resume redrawing after setData, setOptions etc.
- Added option to bypass default groups. If more groups are specified in the nodes than there are in the groups, loop over supplied groups instead of default.
- Added two new static smooth curves modes: curveCW and curve CCW.
- Added request redraw for certain internal processes to reduce number of draw calls.
### Timeline

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


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

@ -141,9 +141,11 @@
var options = {
stabilize: false,
nodes: {
shape: 'dot'
shape: 'dot',
radius:30,
borderWidth:2
},
physics: {barnesHut:{springLength: 200}}
physics: {barnesHut:{springLength: 100}}
};
network = new vis.Network(container, data, options);
}
@ -154,9 +156,9 @@
<body onload="draw()">
<form onsubmit= "javascript: draw(); return false;">
Number of groups:
<input type="text" value="6" id="groupCount" style="width: 50px;">
<input type="text" value="23" id="groupCount" style="width: 50px;">
Number of nodes per group:
<input type="text" value="7" id="nodeCount" style="width: 50px;">
<input type="text" value="1" id="nodeCount" style="width: 50px;">
<input type="submit" value="Go">
</form>
<br>

+ 17
- 4
examples/network/26_staticSmoothCurves.html View File

@ -32,19 +32,26 @@
Smooth curve type:
<select id="dropdownID">
<option value="continuous">continuous</option>
<option value="continuous" selected="selected">continuous</option>
<option value="discrete">discrete</option>
<option value="diagonalCross">diagonalCross</option>
<option value="straightCross">straightCross</option>
<option value="horizontal">horizontal</option>
<option value="vertical">vertical</option>
</select>
<option value="curvedCW">curvedCW</option>
<option value="curvedCCW">curvedCCW</option>
</select><br/>
Roundness (0..1): <input type="range" min="0" max="1" value="0.5" step="0.05" style="width:200px" id="roundnessSlider"> <input id="roundnessScreen" value="0.5"> (0.5 is max roundness for continuous, 1.0 for the others)
<div id="mynetwork"></div>
<script type="text/javascript">
var dropdown = document.getElementById("dropdownID");
dropdown.onchange = update;
var roundnessSlider = document.getElementById("roundnessSlider");
roundnessSlider.onchange = update;
var roundnessScreen = document.getElementById("roundnessScreen");
// create an array with nodes
var nodes = [
{id: 1, label: 'Node 1'},
@ -53,7 +60,7 @@ dropdown.onchange = update;
// create an array with edges
var edges = [
{from: 1, to: 2}
{from: 1, to: 2, style:"arrow"}
];
// create a network
@ -68,8 +75,14 @@ dropdown.onchange = update;
function update() {
var type = dropdown.value;
network.setOptions({smoothCurves:{type:type}});
var roundness = roundnessSlider.value;
roundnessScreen.value = roundness;
var options = {smoothCurves:{type:type, roundness:roundness}}
network.setOptions(options);
}
update();
</script>
</body>

+ 2
- 0
examples/network/27_world_cup_network.html View File

@ -39,6 +39,8 @@ Smooth curve type:
<option value="straightCross">straightCross</option>
<option value="horizontal">horizontal</option>
<option value="vertical">vertical</option>
<option value="curvedCW">curvedCW</option>
<option value="curvedCCW">curvedCCW</option>
</select><br/>
inheritColor option:
<select id="inheritColor">

+ 26
- 9
lib/network/Edge.js View File

@ -368,7 +368,6 @@ Edge.prototype._getViaCoordinates = function () {
var yVia = null;
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);
if (type == 'discrete' || type == 'diagonalCross') {
@ -461,17 +460,39 @@ Edge.prototype._getViaCoordinates = function () {
yVia = this.to.y + (1 - factor) * dy;
}
}
else if (type == 'curvedCW') {
var dx = this.to.x - this.from.x;
var dy = this.from.y - this.to.y;
var radius = Math.sqrt(dx*dx + dy*dy);
var pi = Math.PI;
var originalAngle = Math.atan2(dy,dx);
var myAngle = (originalAngle + ((factor * 0.5) + 0.5) * pi) % (2 * pi);
xVia = this.from.x + (factor*0.5 + 0.5)*radius*Math.sin(myAngle);
yVia = this.from.y + (factor*0.5 + 0.5)*radius*Math.cos(myAngle);
}
else if (type == 'curvedCCW') {
var dx = this.to.x - this.from.x;
var dy = this.from.y - this.to.y;
var radius = Math.sqrt(dx*dx + dy*dy);
var pi = Math.PI;
var originalAngle = Math.atan2(dy,dx);
var myAngle = (originalAngle + ((-factor * 0.5) + 0.5) * pi) % (2 * pi);
xVia = this.from.x + (factor*0.5 + 0.5)*radius*Math.sin(myAngle);
yVia = this.from.y + (factor*0.5 + 0.5)*radius*Math.cos(myAngle);
}
else { // continuous
if (Math.abs(this.from.x - this.to.x) < Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
// console.log(1)
xVia = this.from.x + factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
// console.log(2)
xVia = this.from.x - factor * dy;
yVia = this.from.y - factor * dy;
xVia = this.to.x > xVia ? this.to.x : xVia;
@ -479,13 +500,11 @@ Edge.prototype._getViaCoordinates = function () {
}
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
// console.log(3)
xVia = this.from.x + factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x < xVia ? this.to.x : xVia;
}
else if (this.from.x > this.to.x) {
// console.log(4, this.from.x, this.to.x)
xVia = this.from.x - factor * dy;
yVia = this.from.y + factor * dy;
xVia = this.to.x > xVia ? this.to.x : xVia;
@ -495,13 +514,11 @@ Edge.prototype._getViaCoordinates = function () {
else if (Math.abs(this.from.x - this.to.x) > Math.abs(this.from.y - this.to.y)) {
if (this.from.y > this.to.y) {
if (this.from.x < this.to.x) {
// console.log(5)
xVia = this.from.x + factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
// console.log(6)
xVia = this.from.x - factor * dx;
yVia = this.from.y - factor * dx;
yVia = this.to.y > yVia ? this.to.y : yVia;
@ -509,13 +526,11 @@ Edge.prototype._getViaCoordinates = function () {
}
else if (this.from.y < this.to.y) {
if (this.from.x < this.to.x) {
// console.log(7)
xVia = this.from.x + factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
}
else if (this.from.x > this.to.x) {
// console.log(8)
xVia = this.from.x - factor * dx;
yVia = this.from.y + factor * dx;
yVia = this.to.y < yVia ? this.to.y : yVia;
@ -551,6 +566,8 @@ Edge.prototype._line = function (ctx) {
// this.via.y = via.y;
ctx.quadraticCurveTo(via.x,via.y,this.to.x, this.to.y);
ctx.stroke();
//ctx.circle(via.x,via.y,2)
//ctx.stroke();
return via;
}
}

+ 50
- 19
lib/network/Groups.js View File

@ -7,6 +7,9 @@ var util = require('../util');
function Groups() {
this.clear();
this.defaultIndex = 0;
this.groupsArray = [];
this.groupIndex = 0;
this.useDefaultGroups = true;
}
@ -14,16 +17,33 @@ function Groups() {
* default constants for group colors
*/
Groups.DEFAULT = [
{border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue
{border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // yellow
{border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // red
{border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // green
{border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // magenta
{border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // purple
{border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // orange
{border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue
{border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // pink
{border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}} // mint
{border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // 0: blue
{border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // 1: yellow
{border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // 2: red
{border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // 3: green
{border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // 4: magenta
{border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // 5: purple
{border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // 6: orange
{border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // 7: darkblue
{border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // 8: pink
{border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}}, // 9: mint
{border: "#990000", background: "#EE0000", highlight: {border: "#BB0000", background: "#FF3333"}, hover: {border: "#BB0000", background: "#FF3333"}}, // 10:bright red
{border: "#01AA01", background: "#22FF22", highlight: {border: "#33DD33", background: "#AAFFAA"}, hover: {border: "#22FF22", background: "#66FF66"}}, // 11:bright GREEN
{border: "#97C2FC", background: "#2B7CE9", highlight: {border: "#D2E5FF", background: "#2B7CE9"}, hover: {border: "#D2E5FF", background: "#2B7CE9"}}, // 12: blue
{border: "#FFFF00", background: "#FFA500", highlight: {border: "#FFFFA3", background: "#FFA500"}, hover: {border: "#FFFFA3", background: "#FFA500"}}, // 13: yellow
//{border: "#FB7E81", background: "#FA0A10", highlight: {border: "#FFAFB1", background: "#FA0A10"}, hover: {border: "#FFAFB1", background: "#FA0A10"}}, // 14: red
{border: "#7BE141", background: "#41A906", highlight: {border: "#A1EC76", background: "#41A906"}, hover: {border: "#A1EC76", background: "#41A906"}}, // 15: green
{border: "#EB7DF4", background: "#E129F0", highlight: {border: "#F0B3F5", background: "#E129F0"}, hover: {border: "#F0B3F5", background: "#E129F0"}}, // 16: magenta
{border: "#AD85E4", background: "#7C29F0", highlight: {border: "#D3BDF0", background: "#7C29F0"}, hover: {border: "#D3BDF0", background: "#7C29F0"}}, // 17: purple
{border: "#FFA807", background: "#C37F00", highlight: {border: "#FFCA66", background: "#C37F00"}, hover: {border: "#FFCA66", background: "#C37F00"}}, // 18: orange
{border: "#6E6EFD", background: "#4220FB", highlight: {border: "#9B9BFD", background: "#4220FB"}, hover: {border: "#9B9BFD", background: "#4220FB"}}, // 19: darkblue
{border: "#FFC0CB", background: "#FD5A77", highlight: {border: "#FFD1D9", background: "#FD5A77"}, hover: {border: "#FFD1D9", background: "#FD5A77"}}, // 20: pink
{border: "#C2FABC", background: "#4AD63A", highlight: {border: "#E6FFE3", background: "#4AD63A"}, hover: {border: "#E6FFE3", background: "#4AD63A"}}, // 21:mint
{border: "#EE0000", background: "#990000", highlight: {border: "#FF3333", background: "#BB0000"}, hover: {border: "#FF3333", background: "#BB0000"}}, // 22:bright red
{border: "#22FF22", background: "#01AA01", highlight: {border: "#AAFFAA", background: "#33DD33"}, hover: {border: "#66FF66", background: "#22FF22"}}, // 23:bright GREEN
];
@ -54,12 +74,22 @@ Groups.prototype.clear = function () {
Groups.prototype.get = function (groupname) {
var group = this.groups[groupname];
if (group == undefined) {
// create new group
var index = this.defaultIndex % Groups.DEFAULT.length;
this.defaultIndex++;
group = {};
group.color = Groups.DEFAULT[index];
this.groups[groupname] = group;
if (this.useDefaultGroups === false && this.groupsArray.length > 0) {
// create new group
var index = this.groupIndex % this.groupsArray.length;
this.groupIndex++;
group = {};
group.color = this.groups[this.groupsArray[index]];
this.groups[groupname] = group;
}
else {
// create new group
var index = this.defaultIndex % Groups.DEFAULT.length;
this.defaultIndex++;
group = {};
group.color = Groups.DEFAULT[index];
this.groups[groupname] = group;
}
}
return group;
@ -67,13 +97,14 @@ Groups.prototype.get = function (groupname) {
/**
* Add a custom group style
* @param {String} groupname
* @param {String} groupName
* @param {Object} style An object containing borderColor,
* backgroundColor, etc.
* @return {Object} group The created group object
*/
Groups.prototype.add = function (groupname, style) {
this.groups[groupname] = style;
Groups.prototype.add = function (groupName, style) {
this.groups[groupName] = style;
this.groupsArray.push(groupName);
return style;
};

+ 53
- 14
lib/network/Network.js View File

@ -236,7 +236,8 @@ function Network (container, data, options) {
hideNodesOnDrag: false,
width : '100%',
height : '100%',
selectable: true
selectable: true,
useDefaultGroups: true
};
this.constants = util.extend({}, this.defaultOptions);
this.pixelRatio = 1;
@ -258,13 +259,14 @@ function Network (container, data, options) {
this.lockedOnNodeId = null;
this.lockedOnNodeOffset = null;
this.touchTime = 0;
this.redrawRequested = false;
// Node variables
var network = this;
this.groups = new Groups(); // object with groups
this.images = new Images(); // object with images
this.images.setOnloadCallback(function (status) {
network._redraw();
network._requestRedraw();
});
// keyboard navigation variables
@ -676,6 +678,7 @@ Network.prototype.setOptions = function (options) {
util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes);
util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges);
this.groups.useDefaultGroups = this.constants.useDefaultGroups;
if (options.physics) {
util.mergeOptions(this.constants.physics, options.physics,'barnesHut');
util.mergeOptions(this.constants.physics, options.physics,'repulsion');
@ -1971,7 +1974,23 @@ Network.prototype.redraw = function() {
* @param hidden | used to get the first estimate of the node sizes. only the nodes are drawn after which they are quickly drawn over.
* @private
*/
Network.prototype._redraw = function(hidden) {
Network.prototype._requestRedraw = function(hidden) {
if (this.redrawRequested !== true) {
this.redrawRequested = true;
if (this.requiresTimeout === true) {
window.setTimeout(this._redraw.bind(this, hidden),0);
}
else {
window.requestAnimationFrame(this._redraw.bind(this, hidden, true));
}
}
};
Network.prototype._redraw = function(hidden, requested) {
if (hidden === undefined) {
hidden = false;
}
this.redrawRequested = false;
var ctx = this.frame.canvas.getContext('2d');
ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
@ -1995,7 +2014,7 @@ Network.prototype._redraw = function(hidden) {
"y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight)
};
if (!(hidden == true)) {
if (hidden === false) {
this._doInAllSectors("_drawAllSectorNodes", ctx);
if (this.drag.dragging == false || this.drag.dragging === undefined || this.constants.hideEdgesOnDrag == false) {
this._doInAllSectors("_drawEdges", ctx);
@ -2006,7 +2025,7 @@ Network.prototype._redraw = function(hidden) {
this._doInAllSectors("_drawNodes",ctx,false);
}
if (!(hidden == true)) {
if (hidden === false) {
if (this.controlNodesActive == true) {
this._doInAllSectors("_drawControlNodes", ctx);
}
@ -2018,10 +2037,10 @@ Network.prototype._redraw = function(hidden) {
// restore original scaling and translation
ctx.restore();
if (hidden == true) {
if (hidden === true) {
ctx.clearRect(0, 0, w, h);
}
};
}
/**
* Set the translation of the network
@ -2227,10 +2246,6 @@ Network.prototype._stabilize = function() {
var count = 0;
while (this.moving && count < this.constants.stabilizationIterations) {
this._physicsTick();
// TODO: cleanup
//if (count % 100 == 0) {
// console.log("stabilizationIterations",count);
//}
count++;
}
@ -2412,6 +2427,11 @@ Network.prototype._animationStep = function() {
// reset the timer so a new scheduled animation step can be set
this.timer = undefined;
if (this.requiresTimeout == true) {
// this schedules a new animation step
this.start();
}
// handle the keyboad movement
this._handleNavigation();
@ -2436,8 +2456,10 @@ Network.prototype._animationStep = function() {
this._redraw();
this.renderTime = Date.now() - renderStartTime;
// this schedules a new animation step
this.start();
if (this.requiresTimeout == false) {
// this schedules a new animation step
this.start();
}
};
if (typeof window !== 'undefined') {
@ -2463,7 +2485,7 @@ Network.prototype.start = function() {
}
}
else {
this._redraw();
this._requestRedraw();
// this check is to ensure that the network does not emit these events if it was already stabilized and setOptions is called (setting moving to true and calling start())
if (this.stabilizationIterations > 1) {
// trigger the "stabilized" event.
@ -2914,4 +2936,21 @@ Network.prototype.getConnectedNodes = function(nodeId) {
return nodeList;
}
Network.prototype.getEdgesFromNode = function(nodeId) {
var edgesList = [];
if (this.nodes[nodeId] !== undefined) {
var node = this.nodes[nodeId];
for (var i = 0; i < node.edges.length; i++) {
edgesList.push(node.edges[i].id);
}
}
return edgesList;
}
Network.prototype.generateColorObject = function(color) {
return util.parseColor(color);
}
module.exports = Network;

+ 1
- 1
lib/network/Node.js View File

@ -78,7 +78,7 @@ function Node(properties, imagelist, grouplist, networkConstants) {
this.clusterSizeWidthFactor = networkConstants.clustering.nodeScaling.width;
this.clusterSizeHeightFactor = networkConstants.clustering.nodeScaling.height;
this.clusterSizeRadiusFactor = networkConstants.clustering.nodeScaling.radius;
this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements;
this.maxNodeSizeIncrements = networkConstants.clustering.maxNodeSizeIncrements;
this.growthIndicator = 0;
// variables to tell the node about the network.

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

@ -512,7 +512,7 @@ exports._handleTap = function(pointer) {
canvas: {x: this._XconvertDOMtoCanvas(pointer.x), y: this._YconvertDOMtoCanvas(pointer.y)}
}
this.emit("click", properties);
this._redraw();
this._requestRedraw();
};
@ -556,7 +556,7 @@ exports._handleOnHold = function(pointer) {
this._selectObject(edge,true);
}
}
this._redraw();
this._requestRedraw();
};

Loading…
Cancel
Save