Browse Source

fixed destroy!

flowchartTest
Alex de Mulder 9 years ago
parent
commit
6b770a3158
10 changed files with 12642 additions and 12432 deletions
  1. +12448
    -12335
      dist/vis.js
  2. +14
    -14
      examples/network/02_random_nodes.html
  3. +79
    -45
      lib/network/Network.js
  4. +8
    -1
      lib/network/modules/Canvas.js
  5. +34
    -21
      lib/network/modules/CanvasRenderer.js
  6. +13
    -3
      lib/network/modules/EdgesHandler.js
  7. +9
    -0
      lib/network/modules/InteractionHandler.js
  8. +5
    -1
      lib/network/modules/LayoutEngine.js
  9. +17
    -9
      lib/network/modules/NodesHandler.js
  10. +15
    -3
      lib/network/modules/PhysicsEngine.js

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


+ 14
- 14
examples/network/02_random_nodes.html View File

@ -88,15 +88,17 @@
network = new vis.Network(container, data, options); network = new vis.Network(container, data, options);
// add event listeners // add event listeners
network.on('select', function(params) {
document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes;
});
network.on('stabilized', function (params) {
document.getElementById('stabilization').innerHTML = 'Stabilization took ' + params.iterations + ' iterations.';
});
network.on('startStabilization', function (params) {
document.getElementById('stabilization').innerHTML = 'Stabilizing...';
});
// network.on('select', function(params) {
// document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes;
// });
// network.on('stabilized', function (params) {
// document.getElementById('stabilization').innerHTML = 'Stabilization took ' + params.iterations + ' iterations.';
// });
// network.on('startStabilization', function (params) {
// document.getElementById('stabilization').innerHTML = 'Stabilizing...';
// });
// setTimeout(destroy,500);
} }
@ -104,11 +106,9 @@
<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-61231638-1', 'auto');ga('send', 'pageview');</script></head> <script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-61231638-1', 'auto');ga('send', 'pageview');</script></head>
<body onload="draw();"> <body onload="draw();">
<form onsubmit="draw(); return false;">
<label for="nodeCount">Number of nodes:</label>
<input id="nodeCount" type="text" value="25" style="width: 50px;">
<input type="submit" value="Go">
</form>
<label for="nodeCount">Number of nodes:</label>
<input id="nodeCount" type="text" value="25" style="width: 50px;">
<input type="submit" value="Go" onclick="draw()">
<br> <br>

+ 79
- 45
lib/network/Network.js View File

@ -39,7 +39,7 @@ import allOptions from './modules/components/AllOptions.js';
* {Array} edges * {Array} edges
* @param {Object} options Options * @param {Object} options Options
*/ */
function Network (container, data, options) {
function Network(container, data, options) {
if (!(this instanceof Network)) { if (!(this instanceof Network)) {
throw new SyntaxError('Constructor must be called with the new operator'); throw new SyntaxError('Constructor must be called with the new operator');
} }
@ -61,35 +61,35 @@ function Network (container, data, options) {
nodes: null, // A DataSet or DataView nodes: null, // A DataSet or DataView
edges: null // A DataSet or DataView edges: null // A DataSet or DataView
}, },
functions:{
createNode: () => {},
createEdge: () => {},
getPointer: () => {}
functions: {
createNode: function() {},
createEdge: function() {},
getPointer: function() {}
}, },
emitter: { emitter: {
on: this.on.bind(this),
off: this.off.bind(this),
on: this.on.bind(this),
off: this.off.bind(this),
emit: this.emit.bind(this), emit: this.emit.bind(this),
once: this.once.bind(this) once: this.once.bind(this)
}, },
eventListeners: { eventListeners: {
onTap: function() {},
onTouch: function() {},
onDoubleTap: function() {},
onHold: function() {},
onDragStart: function() {},
onDrag: function() {},
onDragEnd: function() {},
onTap: function() {},
onTouch: function() {},
onDoubleTap: function() {},
onHold: function() {},
onDragStart: function() {},
onDrag: function() {},
onDragEnd: function() {},
onMouseWheel: function() {}, onMouseWheel: function() {},
onPinch: function() {},
onMouseMove: function() {},
onRelease: function() {},
onContext: function() {}
onPinch: function() {},
onMouseMove: function() {},
onRelease: function() {},
onContext: function() {}
}, },
container: container, container: container,
view: { view: {
scale:1,
translation:{x:0,y:0}
scale: 1,
translation: {x: 0, y: 0}
} }
}; };
@ -97,20 +97,20 @@ function Network (container, data, options) {
this.bindEventListeners(); this.bindEventListeners();
// setting up all modules // setting up all modules
var images = new Images(() => this.body.emitter.emit("_requestRedraw")); // object with images
this.groups = new Groups(); // object with groups
this.canvas = new Canvas(this.body); // DOM handler
this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
this.clustering = new ClusterEngine(this.body); // clustering api
this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler); // data manipulation system
this.nodesHandler = new NodesHandler(this.body, images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
this.edgesHandler = new EdgesHandler(this.body, images, this.groups); // Handle adding, deleting and updating of edges as well as global options
this.images = new Images(() => this.body.emitter.emit("_requestRedraw")); // object with images
this.groups = new Groups(); // object with groups
this.canvas = new Canvas(this.body); // DOM handler
this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
this.clustering = new ClusterEngine(this.body); // clustering api
this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler); // data manipulation system
this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
this.configurationSystem = new ConfigurationSystem(this); this.configurationSystem = new ConfigurationSystem(this);
@ -136,7 +136,7 @@ Emitter(Network.prototype);
Network.prototype.setOptions = function (options) { Network.prototype.setOptions = function (options) {
if (options !== undefined) { if (options !== undefined) {
let errorFound = Validator.validate(options,allOptions);
let errorFound = Validator.validate(options, allOptions);
if (errorFound === true) { if (errorFound === true) {
options = {}; options = {};
console.log('%cErrors have been found in the supplied options object. None of the options will be used.', printStyle); console.log('%cErrors have been found in the supplied options object. None of the options will be used.', printStyle);
@ -192,7 +192,7 @@ Network.prototype.setOptions = function (options) {
* Update the this.body.nodeIndices with the most recent node index list * Update the this.body.nodeIndices with the most recent node index list
* @private * @private
*/ */
Network.prototype._updateVisibleIndices = function() {
Network.prototype._updateVisibleIndices = function () {
let nodes = this.body.nodes; let nodes = this.body.nodes;
let edges = this.body.edges; let edges = this.body.edges;
this.body.nodeIndices = []; this.body.nodeIndices = [];
@ -215,7 +215,11 @@ Network.prototype._updateVisibleIndices = function() {
} }
}; };
Network.prototype.bindEventListeners = function() {
/**
* Bind all events
*/
Network.prototype.bindEventListeners = function () {
// this event will trigger a rebuilding of the cache everything. Used when nodes or edges have been added or removed. // this event will trigger a rebuilding of the cache everything. Used when nodes or edges have been added or removed.
this.body.emitter.on("_dataChanged", (params) => { this.body.emitter.on("_dataChanged", (params) => {
// update shortcut lists // update shortcut lists
@ -236,6 +240,7 @@ Network.prototype.bindEventListeners = function() {
}); });
} }
/** /**
* Set nodes and edges, and optionally options as well. * Set nodes and edges, and optionally options as well.
* *
@ -247,7 +252,7 @@ Network.prototype.bindEventListeners = function() {
* {Options} [options] Object with options * {Options} [options] Object with options
* @param {Boolean} [disableStart] | optional: disable the calling of the start function. * @param {Boolean} [disableStart] | optional: disable the calling of the start function.
*/ */
Network.prototype.setData = function(data) {
Network.prototype.setData = function (data) {
// reset the physics engine. // reset the physics engine.
this.body.emitter.emit("resetPhysics"); this.body.emitter.emit("resetPhysics");
this.body.emitter.emit("_resetData"); this.body.emitter.emit("_resetData");
@ -257,7 +262,7 @@ Network.prototype.setData = function(data) {
if (data && data.dot && (data.nodes || data.edges)) { if (data && data.dot && (data.nodes || data.edges)) {
throw new SyntaxError('Data must contain either parameter "dot" or ' + throw new SyntaxError('Data must contain either parameter "dot" or ' +
' parameter pair "nodes" and "edges", but not both.');
' parameter pair "nodes" and "edges", but not both.');
} }
// set options // set options
@ -265,7 +270,7 @@ Network.prototype.setData = function(data) {
// set all data // set all data
if (data && data.dot) { if (data && data.dot) {
// parse DOT file // parse DOT file
if(data && data.dot) {
if (data && data.dot) {
var dotData = dotparser.DOTToGraph(data.dot); var dotData = dotparser.DOTToGraph(data.dot);
this.setData(dotData); this.setData(dotData);
return; return;
@ -273,7 +278,7 @@ Network.prototype.setData = function(data) {
} }
else if (data && data.gephi) { else if (data && data.gephi) {
// parse DOT file // parse DOT file
if(data && data.gephi) {
if (data && data.gephi) {
var gephiData = gephiParser.parseGephi(data.gephi); var gephiData = gephiParser.parseGephi(data.gephi);
this.setData(gephiData); this.setData(gephiData);
return; return;
@ -298,16 +303,45 @@ Network.prototype.setData = function(data) {
* network.destroy(); * network.destroy();
* network = null; * network = null;
*/ */
Network.prototype.destroy = function() {
Network.prototype.destroy = function () {
this.body.emitter.emit("destroy"); this.body.emitter.emit("destroy");
// clear events // clear events
this.body.emitter.off(); this.body.emitter.off();
this.off(); this.off();
// delete modules
delete this.groups;
delete this.canvas;
delete this.selectionHandler;
delete this.interactionHandler;
delete this.view;
delete this.renderer;
delete this.physics;
delete this.layoutEngine;
delete this.clustering;
delete this.manipulation;
delete this.nodesHandler;
delete this.edgesHandler;
delete this.configurationSystem;
delete this.images;
// delete emitter bindings
delete this.body.emitter.emit;
delete this.body.emitter.on;
delete this.body.emitter.off;
delete this.body.emitter.once;
delete this.body.emitter;
for (var nodeId in this.body.nodes) {
delete this.body.nodes[nodeId];
}
for (var edgeId in this.body.edges) {
delete this.body.edges[edgeId];
}
// remove the container and everything inside it recursively // remove the container and everything inside it recursively
util.recursiveDOMDelete(this.body.container); util.recursiveDOMDelete(this.body.container);
}; };
@ -319,7 +353,7 @@ Network.prototype.destroy = function() {
* setValueRange(min, max). * setValueRange(min, max).
* @private * @private
*/ */
Network.prototype._updateValueRange = function(obj) {
Network.prototype._updateValueRange = function (obj) {
var id; var id;
// determine the range of the objects // determine the range of the objects

+ 8
- 1
lib/network/modules/Canvas.js View File

@ -22,6 +22,10 @@ class Canvas {
} }
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
}
bindEventListeners() {
// bind the events // bind the events
this.body.emitter.once("resize", (obj) => { this.body.emitter.once("resize", (obj) => {
if (obj.width !== 0) { if (obj.width !== 0) {
@ -31,7 +35,10 @@ class Canvas {
this.body.view.translation.y = obj.height * 0.5; this.body.view.translation.y = obj.height * 0.5;
} }
}); });
this.body.emitter.on("destroy", () => this.hammer.destroy());
this.body.emitter.on("destroy", () => {
this.hammerFrame.destroy();
this.hammer.destroy();
});
// automatically adapt to a changing size of the browser. // automatically adapt to a changing size of the browser.
window.onresize = () => {this.setSize(); this.body.emitter.emit("_redraw");}; window.onresize = () => {this.setSize(); this.body.emitter.emit("_redraw");};

+ 34
- 21
lib/network/modules/CanvasRenderer.js View File

@ -20,7 +20,18 @@ class CanvasRenderer {
this.allowRedrawRequests = true; this.allowRedrawRequests = true;
this.dragging = false; this.dragging = false;
this.options = {};
this.defaultOptions = {
hideEdgesOnDrag: false,
hideNodesOnDrag: false
}
util.extend(this.options, this.defaultOptions);
this._determineBrowserMethod();
this.bindEventListeners();
}
bindEventListeners() {
this.body.emitter.on("dragStart", () => { this.body.emitter.on("dragStart", () => {
this.dragging = true; this.dragging = true;
}); });
@ -42,15 +53,18 @@ class CanvasRenderer {
this.renderRequests -= 1; this.renderRequests -= 1;
this.renderingActive = this.renderRequests > 0; this.renderingActive = this.renderRequests > 0;
}); });
this.body.emitter.on('destroy', () => {
this.renderRequests = 0;
this.renderingActive = false;
if (this.requiresTimeout === true) {
clearTimeout(this.renderTimer);
}
else {
cancelAnimationFrame(this.renderTimer);
}
this.body.emitter.off();
});
this.options = {};
this.defaultOptions = {
hideEdgesOnDrag: false,
hideNodesOnDrag: false
}
util.extend(this.options, this.defaultOptions);
this._determineBrowserMethod();
} }
setOptions(options) { setOptions(options) {
@ -70,25 +84,24 @@ class CanvasRenderer {
} }
} }
} }
else {
}
} }
_renderStep() { _renderStep() {
// reset the renderTimer so a new scheduled animation step can be set
this.renderTimer = undefined;
if (this.renderingActive === true) {
// reset the renderTimer so a new scheduled animation step can be set
this.renderTimer = undefined;
if (this.requiresTimeout === true) {
// this schedules a new simulation step
this._startRendering();
}
if (this.requiresTimeout === true) {
// this schedules a new simulation step
this._startRendering();
}
this._redraw();
this._redraw();
if (this.requiresTimeout === false) {
// this schedules a new simulation step
this._startRendering();
if (this.requiresTimeout === false) {
// this schedules a new simulation step
this._startRendering();
}
} }
} }

+ 13
- 3
lib/network/modules/EdgesHandler.js View File

@ -15,9 +15,9 @@ class EdgesHandler {
this.body.functions.createEdge = this.create.bind(this); this.body.functions.createEdge = this.create.bind(this);
this.edgesListeners = { this.edgesListeners = {
'add': (event, params) => {this.add(params.items);},
'update': (event, params) => {this.update(params.items);},
'remove': (event, params) => {this.remove(params.items);}
add: (event, params) => {this.add(params.items);},
update: (event, params) => {this.update(params.items);},
remove: (event, params) => {this.remove(params.items);}
}; };
this.options = {}; this.options = {};
@ -93,7 +93,10 @@ class EdgesHandler {
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
}
bindEventListeners() {
// this allows external modules to force all dynamic curves to turn static. // this allows external modules to force all dynamic curves to turn static.
this.body.emitter.on("_forceDisableDynamicCurves", (type) => { this.body.emitter.on("_forceDisableDynamicCurves", (type) => {
let emitChange = false; let emitChange = false;
@ -134,6 +137,13 @@ class EdgesHandler {
// refresh the edges. Used when reverting from hierarchical layout // refresh the edges. Used when reverting from hierarchical layout
this.body.emitter.on("refreshEdges", this.refresh.bind(this)); this.body.emitter.on("refreshEdges", this.refresh.bind(this));
this.body.emitter.on("refresh", this.refresh.bind(this)); this.body.emitter.on("refresh", this.refresh.bind(this));
this.body.emitter.on("destroy", () => {
delete this.body.functions.createEdge;
delete this.edgesListeners.add;
delete this.edgesListeners.update;
delete this.edgesListeners.remove;
delete this.edgesListeners;
});
} }

+ 9
- 0
lib/network/modules/InteractionHandler.js View File

@ -49,6 +49,15 @@ class InteractionHandler {
} }
} }
util.extend(this.options,this.defaultOptions); util.extend(this.options,this.defaultOptions);
this.bindEventListeners()
}
bindEventListeners() {
this.body.emitter.on('destroy', () => {
clearTimeout(this.popupTimer);
delete this.body.functions.getPointer;
})
} }
setOptions(options) { setOptions(options) {

+ 5
- 1
lib/network/modules/LayoutEngine.js View File

@ -22,13 +22,17 @@ class LayoutEngine {
this.hierarchicalLevels = {}; this.hierarchicalLevels = {};
this.bindEventListeners();
}
bindEventListeners() {
this.body.emitter.on('_dataChanged', () => { this.body.emitter.on('_dataChanged', () => {
this.setupHierarchicalLayout(); this.setupHierarchicalLayout();
}) })
this.body.emitter.on('_resetHierarchicalLayout', () => { this.body.emitter.on('_resetHierarchicalLayout', () => {
this.setupHierarchicalLayout(); this.setupHierarchicalLayout();
this.body.emitter.emit('fit',{duration:0}); this.body.emitter.emit('fit',{duration:0});
})
});
} }
setOptions(options, allOptions) { setOptions(options, allOptions) {

+ 17
- 9
lib/network/modules/NodesHandler.js View File

@ -16,17 +16,11 @@ class NodesHandler {
this.body.functions.createNode = this.create.bind(this); this.body.functions.createNode = this.create.bind(this);
this.nodesListeners = { this.nodesListeners = {
'add': (event, params) => {this.add(params.items);},
'update': (event, params) => {this.update(params.items, params.data);},
'remove': (event, params) => {this.remove(params.items);}
add: (event, params) => {this.add(params.items);},
update: (event, params) => {this.update(params.items, params.data);},
remove: (event, params) => {this.remove(params.items);}
}; };
// refresh the nodes. Used when reverting from hierarchical layout
this.body.emitter.on('refreshNodes', this.refresh.bind(this));
this.body.emitter.on('refresh', this.refresh.bind(this));
this.options = {}; this.options = {};
this.defaultOptions = { this.defaultOptions = {
borderWidth: 1, borderWidth: 1,
@ -105,6 +99,20 @@ class NodesHandler {
}; };
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
}
bindEventListeners() {
// refresh the nodes. Used when reverting from hierarchical layout
this.body.emitter.on('refreshNodes', this.refresh.bind(this));
this.body.emitter.on('refresh', this.refresh.bind(this));
this.body.emitter.on("destroy", () => {
delete this.body.functions.createNode;
delete this.nodesListeners.add;
delete this.nodesListeners.update;
delete this.nodesListeners.remove;
delete this.nodesListeners;
});
} }
setOptions(options) { setOptions(options) {

+ 15
- 3
lib/network/modules/PhysicsEngine.js View File

@ -63,6 +63,10 @@ class PhysicsEngine {
} }
util.extend(this.options, this.defaultOptions); util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
}
bindEventListeners() {
this.body.emitter.on('initPhysics', () => {this.initPhysics();}); this.body.emitter.on('initPhysics', () => {this.initPhysics();});
this.body.emitter.on('resetPhysics', () => {this.stopSimulation(); this.ready = false;}); this.body.emitter.on('resetPhysics', () => {this.stopSimulation(); this.ready = false;});
this.body.emitter.on('disablePhysics', () => {this.physicsEnabled = false; this.stopSimulation();}); this.body.emitter.on('disablePhysics', () => {this.physicsEnabled = false; this.stopSimulation();});
@ -78,6 +82,10 @@ class PhysicsEngine {
} }
}) })
this.body.emitter.on('stopSimulation', () => {this.stopSimulation();}); this.body.emitter.on('stopSimulation', () => {this.stopSimulation();});
this.body.emitter.on('destroy', () => {
this.stopSimulation(false);
this.body.emitter.off();
});
} }
setOptions(options) { setOptions(options) {
@ -157,13 +165,17 @@ class PhysicsEngine {
/** /**
* Stop the simulation, force stabilization. * Stop the simulation, force stabilization.
*/ */
stopSimulation() {
stopSimulation(emit = true) {
this.stabilized = true; this.stabilized = true;
this._emitStabilized();
if (emit === true) {
this._emitStabilized();
}
if (this.viewFunction !== undefined) { if (this.viewFunction !== undefined) {
this.body.emitter.off('initRedraw', this.viewFunction); this.body.emitter.off('initRedraw', this.viewFunction);
this.viewFunction = undefined; this.viewFunction = undefined;
this.body.emitter.emit('_stopRendering');
if (emit === true) {
this.body.emitter.emit('_stopRendering');
}
} }
} }

Loading…
Cancel
Save