Browse Source

fixed bounding box bug, added function filter to configuration system

flowchartTest
Alex de Mulder 9 years ago
parent
commit
ccbdd46cc4
20 changed files with 3724 additions and 3491 deletions
  1. +3510
    -3391
      dist/vis.js
  2. +10
    -10
      docs/graph2d/graph2d.html
  3. +10
    -3
      docs/network/configure.html
  4. +1
    -1
      docs/network/physics.html
  5. +3
    -0
      lib/network/modules/CanvasRenderer.js
  6. +1
    -1
      lib/network/modules/PhysicsEngine.js
  7. +6
    -0
      lib/network/modules/components/Node.js
  8. +10
    -4
      lib/network/modules/components/nodes/shapes/Box.js
  9. +8
    -0
      lib/network/modules/components/nodes/shapes/Circle.js
  10. +7
    -4
      lib/network/modules/components/nodes/shapes/CircularImage.js
  11. +11
    -4
      lib/network/modules/components/nodes/shapes/Database.js
  12. +12
    -9
      lib/network/modules/components/nodes/shapes/Ellipse.js
  13. +3
    -1
      lib/network/modules/components/nodes/shapes/Empty.js
  14. +9
    -2
      lib/network/modules/components/nodes/shapes/Icon.js
  15. +14
    -4
      lib/network/modules/components/nodes/shapes/Image.js
  16. +7
    -0
      lib/network/modules/components/nodes/shapes/Text.js
  17. +5
    -0
      lib/network/modules/components/nodes/util/CircleImageBase.js
  18. +14
    -4
      lib/network/modules/components/nodes/util/ShapeBase.js
  19. +4
    -4
      lib/network/options.js
  20. +79
    -49
      lib/shared/ConfigurationSystem.js

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


+ 10
- 10
docs/graph2d/graph2d.html View File

@ -10,8 +10,8 @@
<title>vis.js - A dynamic, browser based visualization library.</title>
<!-- Bootstrap core CSS -->
<link href="./css/bootstrap.css" rel="stylesheet">
<link href="./css/newdocs.css" rel="stylesheet">
<link href="../css/bootstrap.css" rel="stylesheet">
<link href="../css/newdocs.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
@ -20,11 +20,11 @@
<![endif]-->
<link href="./css/prettify.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="./js/googleAnalytics.js"></script>
<script type="text/javascript" src="./js/prettify/prettify.js"></script>
<link href="../css/prettify.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../js/googleAnalytics.js"></script>
<script type="text/javascript" src="../js/prettify/prettify.js"></script>
<script src="./js/smooth-scroll.min.js"></script>
<script src="../js/smooth-scroll.min.js"></script>
<script language="JavaScript">
smoothScroll.init();
</script>
@ -72,7 +72,7 @@
}
</script>
<script type="text/javascript" src="./js/toggleTable.js"></script>
<script type="text/javascript" src="../js/toggleTable.js"></script>
</head>
<body onload="prettyPrint();">
@ -1362,7 +1362,7 @@ Graph2d.off('rangechanged', onChange);
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="./js/jquery.min.js"></script>
<script src="./js/bootstrap.min.js"></script>
<script src="../js/jquery.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<script src="./js/ie10-viewport-bug-workaround.js"></script>
<script src="../js/ie10-viewport-bug-workaround.js"></script>

+ 10
- 3
docs/network/configure.html View File

@ -116,7 +116,7 @@ var options = {
network.setOptions(options);
</pre>
<p>As shown above, alternative to supplying an object, you can supply a <code>String</code>, <code>Array</code> or
<p>As shown above, alternative to supplying an object, you can supply a <code>String</code>, <code>Array</code>, <code>Function</code> or
<code>Boolean</code>. These will do the same as the filter option described below.</p>
<table class="moduleTable">
<tr class="header">
@ -134,12 +134,19 @@ network.setOptions(options);
</tr>
<tr>
<td>filter</td>
<td class="mid">String or Array or Boolean</td>
<td class="mid">String, Array, Boolean, Function</td>
<td class="mid"><code>true</code></td>
<td>When a boolean, true gives you all options, false will not show any. If a string is supplied, any
combination of the following is allowed: nodes, edges, layout, interaction, manipulation, physics,
selection, renderer. Feel free to come up with a fun seperating character. Finally, when supplied an
array of strings, any of the previously mentioned fields are accepted.
array of strings, any of the previously mentioned fields are accepted. <br><br>
When supplying a function, you receive two arguments. The option and the path of the option within the options object. If it returns true, the options will be shown in the configurator. Example:
<pre class="code">
function (option, path) {
return path.indexOf('physics') !== -1;
}
</pre>
This only shows the physics options.
</td>
</tr>
<tr>

+ 1
- 1
docs/network/physics.html View File

@ -154,7 +154,7 @@ network.setOptions(options);
by them and makes use of the barnesHut implementation in vis. The main differences are the central gravity model,
which is here distance independent, and the repulsion being linear instead of quadratic. Finally, all node masses have a
multiplier based on the amount of connected edges plus one.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.gravitationalConstant</td> <td class="mid">Number</td> <td class="mid"><code>-800</code></td> <td>This is similar to the barnesHut method except that the falloff is linear instead of quadratic. The connectivity is also taken into account as a factor of the mass. If you want the repulsion to be stronger, decrease the value (so -1000, -2000).</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.gravitationalConstant</td> <td class="mid">Number</td> <td class="mid"><code>-50</code></td> <td>This is similar to the barnesHut method except that the falloff is linear instead of quadratic. The connectivity is also taken into account as a factor of the mass. If you want the repulsion to be stronger, decrease the value (so -1000, -2000).</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.centralGravity</td> <td class="mid">Number</td> <td class="mid"><code>0.01</code></td> <td>There is a central gravity attractor to pull the entire network back to the center. This is not dependent on distance.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.springLength</td> <td class="mid">Number</td> <td class="mid"><code>100</code></td> <td>The edges are modelled as springs. This springLength here is the the rest length of the spring.</td></tr>
<tr parent="forceAtlas2Based" class="hidden"><td class="indent">forceAtlas2Based.springConstant</td> <td class="mid">Number</td> <td class="mid"><code>0.08</code></td> <td>This is how 'sturdy' the springs are. Higher values mean stronger springs.</td></tr>

+ 3
- 0
lib/network/modules/CanvasRenderer.js View File

@ -229,6 +229,9 @@ class CanvasRenderer {
else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
node.draw(ctx);
}
else {
node.updateBoundingBox(ctx);
}
}
}

+ 1
- 1
lib/network/modules/PhysicsEngine.js View File

@ -39,7 +39,7 @@ class PhysicsEngine {
},
forceAtlas2Based: {
theta: 0.5,
gravitationalConstant: -800,
gravitationalConstant: -50,
centralGravity: 0.01,
springConstant: 0.08,
springLength: 100,

+ 6
- 0
lib/network/modules/components/Node.js View File

@ -368,6 +368,12 @@ class Node {
this.shape.draw(ctx, this.x, this.y, this.selected, this.hover);
}
/**
* Update the bounding box of the shape
*/
updateBoundingBox() {
this.shape.updateBoundingBox(this.x,this.y);
}
/**
* Recalculate the size of this node in the given canvas

+ 10
- 4
lib/network/modules/components/nodes/shapes/Box.js View File

@ -43,12 +43,18 @@ class Box extends NodeBase {
ctx.stroke();
this.boundingBox.top = this.top;
this.updateBoundingBox(x,y);
this.labelModule.draw(ctx, x, y, selected);
}
updateBoundingBox(x,y) {
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
this.boundingBox.left = this.left;
this.boundingBox.right = this.left + this.width;
this.boundingBox.top = this.top;
this.boundingBox.bottom = this.top + this.height;
this.labelModule.draw(ctx, x, y, selected);
this.boundingBox.right = this.left + this.width;
}
distanceToBorder(ctx, angle) {

+ 8
- 0
lib/network/modules/components/nodes/shapes/Circle.js View File

@ -31,9 +31,17 @@ class Circle extends CircleImageBase {
this.boundingBox.right = x + this.options.size;
this.boundingBox.bottom = y + this.options.size;
this.updateBoundingBox(x,y);
this.labelModule.draw(ctx, x, y, selected);
}
updateBoundingBox(x,y) {
this.boundingBox.top = y - this.options.size;
this.boundingBox.left = x - this.options.size;
this.boundingBox.right = x + this.options.size;
this.boundingBox.bottom = y + this.options.size;
}
distanceToBorder(ctx, angle) {
this.resize(ctx);
var a = this.width / 2;

+ 7
- 4
lib/network/modules/components/nodes/shapes/CircularImage.js View File

@ -47,16 +47,19 @@ class CircularImage extends CircleImageBase {
ctx.restore();
this._drawImageLabel(ctx, x, y, selected);
this.updateBoundingBox(x,y);
}
updateBoundingBox(x,y) {
this.boundingBox.top = y - this.options.size;
this.boundingBox.left = x - this.options.size;
this.boundingBox.right = x + this.options.size;
this.boundingBox.bottom = y + this.options.size;
this._drawImageLabel(ctx, x, y, selected);
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
}

+ 11
- 4
lib/network/modules/components/nodes/shapes/Database.js View File

@ -42,14 +42,21 @@ class Database extends NodeBase {
ctx.stroke();
this.boundingBox.top = this.top;
this.boundingBox.left = this.left;
this.boundingBox.right = this.left + this.width;
this.boundingBox.bottom = this.top + this.height;
this.updateBoundingBox(x,y);
this.labelModule.draw(ctx, x, y, selected);
}
updateBoundingBox(x,y) {
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
this.boundingBox.left = this.left;
this.boundingBox.top = this.top;
this.boundingBox.bottom = this.top + this.height;
this.boundingBox.right = this.left + this.width;
}
distanceToBorder(ctx, angle) {
this.resize(ctx);
var a = this.width / 2;

+ 12
- 9
lib/network/modules/components/nodes/shapes/Ellipse.js View File

@ -21,8 +21,8 @@ class Ellipse extends NodeBase {
draw(ctx, x, y, selected, hover) {
this.resize(ctx, selected);
this.left = x - this.width / 2;
this.top = y - this.height / 2;
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
var borderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
@ -45,21 +45,24 @@ class Ellipse extends NodeBase {
ctx.stroke();
this.updateBoundingBox(x,y);
this.labelModule.draw(ctx, x, y, selected);
}
updateBoundingBox(x,y) {
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
this.boundingBox.left = this.left;
this.boundingBox.top = this.top;
this.boundingBox.bottom = this.top + this.height;
this.boundingBox.right = this.left + this.width;
this.labelModule.draw(ctx, x, y, selected);
}
distanceToBorder(ctx, angle) {
this.resize(ctx);
var a = this.width / 2;
var b = this.height / 2;
var a = this.width * 0.5;
var b = this.height * 0.5;
var w = (Math.sin(angle) * a);
var h = (Math.cos(angle) * b);
return a * b / Math.sqrt(w * w + h * h);

+ 3
- 1
lib/network/modules/components/nodes/shapes/Empty.js View File

@ -14,6 +14,8 @@ class Empty extends NodeBase {
draw() {}
distanceToBorder() {}
}
updateBoundingBox() {}}
export default Empty;

+ 9
- 2
lib/network/modules/components/nodes/shapes/Icon.js View File

@ -27,7 +27,15 @@ class Icon extends NodeBase {
this.top = y - this.height * 0.5;
this._icon(ctx, x, y, selected);
if (this.options.label !== undefined) {
var iconTextSpacing = 5;
this.labelModule.draw(ctx, x, y + this.height * 0.5 + iconTextSpacing, selected);
}
this.updateBoundingBox(x,y)
}
updateBoundingBox(x,y) {
this.boundingBox.top = y - this.options.icon.size * 0.5;
this.boundingBox.left = x - this.options.icon.size * 0.5;
this.boundingBox.right = x + this.options.icon.size * 0.5;
@ -35,10 +43,9 @@ class Icon extends NodeBase {
if (this.options.label !== undefined) {
var iconTextSpacing = 5;
this.labelModule.draw(ctx, x, y + this.height * 0.5 + iconTextSpacing, selected);
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
}
}

+ 14
- 4
lib/network/modules/components/nodes/shapes/Image.js View File

@ -19,15 +19,25 @@ class Image extends CircleImageBase {
this._drawImageAtPosition(ctx);
this._drawImageLabel(ctx, x, y, selected || hover);
this.updateBoundingBox(x,y);
}
updateBoundingBox(x,y) {
this.left = x - this.width / 2;
this.top = y - this.height / 2;
this.boundingBox.top = this.top;
this.boundingBox.left = this.left;
this.boundingBox.right = this.left + this.width;
this.boundingBox.bottom = this.top + this.height;
this._drawImageLabel(ctx, x, y, selected || hover);
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
if (this.options.label !== undefined) {
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
}
}
distanceToBorder(ctx, angle) {

+ 7
- 0
lib/network/modules/components/nodes/shapes/Text.js View File

@ -28,6 +28,13 @@ class Text extends NodeBase {
// disable shadows for other elements.
this.disableShadow(ctx);
this.updateBoundingBox(x,y);
}
updateBoundingBox(x,y) {
this.left = x - this.width / 2;
this.top = y - this.height / 2;
this.boundingBox.top = this.top;
this.boundingBox.left = this.left;
this.boundingBox.right = this.left + this.width;

+ 5
- 0
lib/network/modules/components/nodes/util/CircleImageBase.js View File

@ -3,6 +3,7 @@ import NodeBase from '../util/NodeBase'
class CircleImageBase extends NodeBase {
constructor(options, body, labelModule) {
super(options, body, labelModule);
this.labelOffset = 0;
}
_resizeImage() {
@ -77,6 +78,10 @@ class CircleImageBase extends NodeBase {
}
yLabel = y + offset;
if (this.options.label) {
this.labelOffset = offset;
}
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging');
}
}

+ 14
- 4
lib/network/modules/components/nodes/util/ShapeBase.js View File

@ -38,20 +38,30 @@ class ShapeBase extends NodeBase {
ctx.stroke();
if (this.options.label !== undefined) {
let yLabel = y + 0.5 * this.height + 3; // the + 3 is to offset it a bit below the node.
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging');
}
this.updateBoundingBox(x,y);
}
updateBoundingBox(x,y) {
this.boundingBox.top = y - this.options.size;
this.boundingBox.left = x - this.options.size;
this.boundingBox.right = x + this.options.size;
this.boundingBox.bottom = y + this.options.size;
if (this.options.label!== undefined) {
let yLabel = y + 0.5 * this.height + 3; // the + 3 is to offset it a bit below the node.
this.labelModule.draw(ctx, x, yLabel, selected, 'hanging');
if (this.options.label !== undefined) {
this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + 3);
}
}
}
export default ShapeBase;

+ 4
- 4
lib/network/options.js View File

@ -19,9 +19,9 @@ let any = 'any'
let allOptions = {
configure: {
enabled: {boolean},
filter: {boolean,string,array},
filter: {boolean,string,array,fn},
container: {dom},
__type__: {object,boolean,string,array}
__type__: {object,boolean,string,array,fn}
},
edges: {
arrows: {
@ -432,7 +432,7 @@ let configureOptions = {
},
forceAtlas2Based: {
//theta: [0.5, 0.1, 1, 0.05],
gravitationalConstant: [-800, -3000, 0, 50],
gravitationalConstant: [-800, -3000, 0, 1],
centralGravity: [0.01, 0, 1, 0.005],
springLength: [95, 0, 500, 5],
springConstant: [0.08, 0, 5, 0.005],
@ -454,7 +454,7 @@ let configureOptions = {
},
maxVelocity: [50, 0, 150, 1],
minVelocity: [0.1, 0.01, 0.5, 0.01],
solver: ['barnesHut', 'repulsion', 'hierarchicalRepulsion','forceAtlas2Based'],
solver: ['barnesHut', 'forceAtlas2Based', 'repulsion', 'hierarchicalRepulsion'],
timestep: [0.5, 0, 1, 0.05]
},
global: {

+ 79
- 49
lib/shared/ConfigurationSystem.js View File

@ -21,6 +21,7 @@ class ConfigurationSystem {
this.parent = parentModule;
this.changedOptions = [];
this.container = defaultContainer;
this.allowCreation = false;
this.options = {};
this.defaultOptions = {
@ -68,6 +69,10 @@ class ConfigurationSystem {
this.options.filter = true;
enabled = options;
}
else if (typeof options === 'function') {
this.options.filter = options;
enabled = true;
}
this.options.enabled = enabled;
}
this._clean();
@ -81,7 +86,7 @@ class ConfigurationSystem {
if (this.options.container !== undefined) {
this.container = this.options.container;
}
this._create(this.options.filter);
this._create();
}
}
@ -90,15 +95,27 @@ class ConfigurationSystem {
* @param {Boolean | String} config
* @private
*/
_create(config) {
_create() {
this._clean();
this.changedOptions = [];
let config = this.options.filter;
let counter = 0;
let show = false;
for (let option in this.configureOptions) {
if (this.configureOptions.hasOwnProperty(option)) {
if (config === true || config.indexOf(option) !== -1) {
let optionObj = this.configureOptions[option];
this.allowCreation = false;
show = false;
if (typeof config === 'function') {
show = config(option,[]);
show = show || this._handleObject(this.configureOptions[option], [option]);
}
else if (config === true || config.indexOf(option) !== -1) {
show = true;
}
if (show !== false) {
this.allowCreation = true;
// linebreak between categories
if (counter > 0) {
@ -108,8 +125,7 @@ class ConfigurationSystem {
this._makeHeader(option);
// get the suboptions
let path = [option];
this._handleObject(optionObj, path);
this._handleObject(this.configureOptions[option], [option]);
}
counter++;
}
@ -191,12 +207,14 @@ class ConfigurationSystem {
* @private
*/
_makeItem(path, ...domElements) {
let item = document.createElement('div');
item.className = 'vis-network-configuration item s' + path.length;
domElements.forEach((element) => {
item.appendChild(element);
});
this.domElements.push(item);
if (this.allowCreation === true) {
let item = document.createElement('div');
item.className = 'vis-network-configuration item s' + path.length;
domElements.forEach((element) => {
item.appendChild(element);
});
this.domElements.push(item);
}
}
@ -431,56 +449,68 @@ class ConfigurationSystem {
* @private
*/
_handleObject(obj, path = []) {
let show = false;
let config = this.options.filter;
let visibleInSet = false;
for (let subObj in obj) {
if (obj.hasOwnProperty(subObj)) {
let item = obj[subObj];
let newPath = util.copyAndExtendArray(path, subObj);
let value = this._getValue(newPath);
if (item instanceof Array) {
this._handleArray(item, value, newPath);
}
else if (typeof item === 'string') {
this._makeTextInput(item, value, newPath);
}
else if (typeof item === 'boolean') {
this._makeCheckbox(item, value, newPath);
show = false;
if (typeof config === 'function') {
show = config(subObj,path);
}
else if (item instanceof Object) {
// collapse the physics options that are not enabled
let draw = true;
if (path.indexOf('physics') !== -1) {
if (this.moduleOptions.physics.solver !== subObj) {
draw = false;
}
if (show !== false) {
visibleInSet = true;
let item = obj[subObj];
let newPath = util.copyAndExtendArray(path, subObj);
let value = this._getValue(newPath);
if (item instanceof Array) {
this._handleArray(item, value, newPath);
}
else if (typeof item === 'string') {
this._makeTextInput(item, value, newPath);
}
else if (typeof item === 'boolean') {
this._makeCheckbox(item, value, newPath);
}
else if (item instanceof Object) {
// collapse the physics options that are not enabled
let draw = true;
if (path.indexOf('physics') !== -1) {
if (this.moduleOptions.physics.solver !== subObj) {
draw = false;
}
}
if (draw === true) {
// initially collapse options with an disabled enabled option.
if (item.enabled !== undefined) {
let enabledPath = util.copyAndExtendArray(newPath, 'enabled');
let enabledValue = this._getValue(enabledPath);
if (enabledValue === true) {
let label = this._makeLabel(subObj, newPath, true);
this._makeItem(newPath, label);
this._handleObject(item, newPath);
if (draw === true) {
// initially collapse options with an disabled enabled option.
if (item.enabled !== undefined) {
let enabledPath = util.copyAndExtendArray(newPath, 'enabled');
let enabledValue = this._getValue(enabledPath);
if (enabledValue === true) {
let label = this._makeLabel(subObj, newPath, true);
this._makeItem(newPath, label);
visibleInSet = this._handleObject(item, newPath) || visibleInSet;
}
else {
this._makeCheckbox(item, enabledValue, newPath);
}
}
else {
this._makeCheckbox(item, enabledValue, newPath);
let label = this._makeLabel(subObj, newPath, true);
this._makeItem(newPath, label);
visibleInSet = this._handleObject(item, newPath) || visibleInSet;
}
}
else {
let label = this._makeLabel(subObj, newPath, true);
this._makeItem(newPath, label);
this._handleObject(item, newPath);
}
}
}
else {
console.error('dont know how to handle', item, subObj, newPath);
else {
console.error('dont know how to handle', item, subObj, newPath);
}
}
}
}
return visibleInSet;
}

Loading…
Cancel
Save