@ -1,31 +1,31 @@
var Emitter = require ( 'emitter-component' ) ;
var Hammer = require ( '../module/hammer' ) ;
var keycharm = require ( 'keycharm' ) ;
var util = require ( '../util' ) ;
var hammerUtil = require ( '../hammerUtil' ) ;
var DataSet = require ( '../DataSet' ) ;
var DataView = require ( '../DataView' ) ;
var dotparser = require ( './dotparser' ) ;
var gephiParser = require ( './gephiParser' ) ;
var Groups = require ( './Groups' ) ;
var Images = require ( './Images' ) ;
var Node = require ( './Node' ) ;
var Edge = require ( './Edge' ) ;
var Node = require ( './modules/components/nodes/ NodeMain ' ) ;
var Edge = require ( './modules/components/edges/ EdgeMain ' ) ;
var Popup = require ( './Popup' ) ;
var MixinLoader = require ( './mixins/MixinLoader' ) ;
var Activator = require ( '../shared/Activator' ) ;
var locales = require ( './locales' ) ;
// Load custom shapes into CanvasRenderingContext2D
require ( './shapes' ) ;
import { PhysicsEngine } from './modules/PhysicsEngine'
import { ClusterEngine } from './modules/Clustering'
import { CanvasRenderer } from './modules/CanvasRenderer'
import { Canvas } from './modules/Canvas'
import { View } from './modules/View'
import { InteractionHandler } from './modules/InteractionHandler'
import { SelectionHandler } from "./modules/SelectionHandler"
import NodesHandler from './modules/NodesHandler' ;
import EdgesHandler from './modules/EdgesHandler' ;
import PhysicsEngine from './modules/PhysicsEngine' ;
import ClusterEngine from './modules/Clustering' ;
import CanvasRenderer from './modules/CanvasRenderer' ;
import Canvas from './modules/Canvas' ;
import View from './modules/View' ;
import InteractionHandler from './modules/InteractionHandler' ;
import SelectionHandler from "./modules/SelectionHandler" ;
import LayoutEngine from "./modules/LayoutEngine" ;
/ * *
* @ constructor Network
@ -43,96 +43,8 @@ function Network (container, data, options) {
throw new SyntaxError ( 'Constructor must be called with the new operator' ) ;
}
this . _initializeMixinLoaders ( ) ;
// render and calculation settings
this . initializing = true ;
this . triggerFunctions = { add : null , edit : null , editEdge : null , connect : null , del : null } ;
var customScalingFunction = function ( min , max , total , value ) {
if ( max == min ) {
return 0.5 ;
}
else {
var scale = 1 / ( max - min ) ;
return Math . max ( 0 , ( value - min ) * scale ) ;
}
} ;
// set constant values
this . defaultOptions = {
nodes : {
customScalingFunction : customScalingFunction ,
mass : 1 ,
radiusMin : 10 ,
radiusMax : 30 ,
radius : 10 ,
shape : 'ellipse' ,
image : undefined ,
widthMin : 16 , // px
widthMax : 64 , // px
fontColor : 'black' ,
fontSize : 14 , // px
fontFace : 'verdana' ,
fontFill : undefined ,
fontStrokeWidth : 0 , // px
fontStrokeColor : '#ffffff' ,
fontDrawThreshold : 3 ,
scaleFontWithValue : false ,
fontSizeMin : 14 ,
fontSizeMax : 30 ,
fontSizeMaxVisible : 30 ,
value : 1 ,
level : - 1 ,
color : {
border : '#2B7CE9' ,
background : '#97C2FC' ,
highlight : {
border : '#2B7CE9' ,
background : '#D2E5FF'
} ,
hover : {
border : '#2B7CE9' ,
background : '#D2E5FF'
}
} ,
group : undefined ,
borderWidth : 1 ,
borderWidthSelected : undefined
} ,
edges : {
customScalingFunction : customScalingFunction ,
widthMin : 1 , //
widthMax : 15 , //
width : 1 ,
widthSelectionMultiplier : 2 ,
hoverWidth : 1.5 ,
value : 1 ,
style : 'line' ,
color : {
color : '#848484' ,
highlight : '#848484' ,
hover : '#848484'
} ,
opacity : 1.0 ,
fontColor : '#343434' ,
fontSize : 14 , // px
fontFace : 'arial' ,
fontFill : 'white' ,
fontStrokeWidth : 0 , // px
fontStrokeColor : 'white' ,
labelAlignment : 'horizontal' ,
arrowScaleFactor : 1 ,
dash : {
length : 10 ,
gap : 5 ,
altLength : undefined
} ,
inheritColor : "from" , // to, from, false, true (== from)
useGradients : false // release in 4.0
} ,
this . remainingOptions = {
dataManipulation : {
enabled : false ,
initiallyVisible : false
@ -144,43 +56,10 @@ function Network (container, data, options) {
direction : "UD" , // UD, DU, LR, RL
layout : "hubsize" // hubsize, directed
} ,
interaction : {
dragNodes : true ,
dragView : true ,
zoomView : true ,
hoverEnabled : false ,
showNavigationIcons : false ,
tooltip : {
delay : 300 ,
fontColor : 'black' ,
fontSize : 14 , // px
fontFace : 'verdana' ,
color : {
border : '#666' ,
background : '#FFFFC6'
}
} ,
keyboard : {
enabled : false ,
speed : { x : 10 , y : 10 , zoom : 0.02 } ,
bindToWindow : true
}
} ,
selection : {
enabled : true ,
selectConnectedEdges : true
} ,
smoothCurves : {
enabled : true ,
dynamic : true ,
type : "continuous" ,
roundness : 0.5
} ,
locale : 'en' ,
locales : locales ,
useDefaultGroups : true
} ;
this . constants = util . extend ( { } , this . defaultOptions ) ;
// containers for nodes and edges
this . body = {
@ -223,121 +102,67 @@ function Network (container, data, options) {
}
} ;
// modules
this . canvas = new Canvas ( this . body ) ;
this . selectionHandler = new SelectionHandler ( this . body , this . canvas ) ;
this . interactionHandler = new InteractionHandler ( this . body , this . canvas , this . selectionHandler ) ;
this . view = new View ( this . body , this . canvas ) ;
this . renderer = new CanvasRenderer ( this . body , this . canvas ) ;
this . clustering = new ClusterEngine ( this . body ) ;
this . physics = new PhysicsEngine ( this . body ) ;
// todo think of good comment for this set
var groups = new Groups ( ) ; // object with groups
var images = new Images ( ( ) => this . body . emitter . emit ( "_requestRedraw" ) ) ; // object with images
// create the DOM elements
this . canvas . create ( ) ;
// data handling modules
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 ) ; // TODO: layout engine for initial positioning and hierarchical positioning
this . clustering = new ClusterEngine ( this . body ) ; // clustering api
this . hoverObj = { nodes : { } , edges : { } } ;
this . controlNodesActive = false ;
this . navigationHammers = [ ] ;
this . manipulationHammers = [ ] ;
// Node variables
var me = this ;
this . groups = new Groups ( ) ; // object with groups
this . images = new Images ( ) ; // object with images
this . images . setOnloadCallback ( function ( status ) {
me . _requestRedraw ( ) ;
} ) ;
this . nodesHandler = new NodesHandler ( this . body , images , groups , this . layoutEngine ) ; // Handle adding, deleting and updating of nodes as well as global options
this . edgesHandler = new EdgesHandler ( this . body , images , groups ) ; // Handle adding, deleting and updating of edges as well as global options
// keyboard navigation variables
this . xIncrement = 0 ;
this . yIncrement = 0 ;
this . zoomIncrement = 0 ;
// loading all the mixins:
// load the force calculation functions, grouped under the physics system.
//this._loadPhysicsSystem();
// create a frame and canvas
// load the cluster system. (mandatory, even when not using the cluster system, there are function calls to it)
// load the selection system. (mandatory, required by Network)
this . _loadSelectionSystem ( ) ;
// load the selection system. (mandatory, required by Network)
//this._loadHierarchySystem();
// apply options
this . setOptions ( options ) ;
// position and scale variables and objects
this . pointerPosition = { "x" : 0 , "y" : 0 } ; // coordinates of the bottom right of the canvas. they will be set during _redraw
this . scale = 1 ; // defining the global scale variable in the constructor
// 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 ) => {
var t0 = new Date ( ) . valueOf ( ) ;
// update shortcut lists
this . _updateNodeIndexList ( ) ;
this . physics . _updateCalculationNodes ( ) ;
// update values
this . _updateValueRange ( this . body . nodes ) ;
this . _updateValueRange ( this . body . edges ) ;
// update edges
this . _reconnectEdges ( ) ;
this . edgesHandler . createBezierNodes ( params ) ;
this . _markAllEdgesAsDirty ( ) ;
// start simulation (can be called safely, even if already running)
this . body . emitter . emit ( "startSimulation" ) ;
console . log ( "_dataChanged took:" , new Date ( ) . valueOf ( ) - t0 ) ;
} )
// create event listeners used to subscribe on the DataSets of the nodes and edges
this . nodesListeners = {
'add' : function ( event , params ) {
me . _addNodes ( params . items ) ;
me . start ( ) ;
} ,
'update' : function ( event , params ) {
me . _updateNodes ( params . items , params . data ) ;
me . start ( ) ;
} ,
'remove' : function ( event , params ) {
me . _removeNodes ( params . items ) ;
me . start ( ) ;
}
} ;
this . edgesListeners = {
'add' : function ( event , params ) {
me . _addEdges ( params . items ) ;
me . start ( ) ;
} ,
'update' : function ( event , params ) {
me . _updateEdges ( params . items ) ;
me . start ( ) ;
} ,
'remove' : function ( event , params ) {
me . _removeEdges ( params . items ) ;
me . start ( ) ;
}
} ;
// this is called when options of EXISTING nodes or edges have changed.
this . body . emitter . on ( "_dataUpdated" , ( ) => {
var t0 = new Date ( ) . valueOf ( ) ;
// update values
this . _updateValueRange ( this . body . nodes ) ;
this . _updateValueRange ( this . body . edges ) ;
// update edges
this . _reconnectEdges ( ) ;
this . edgesHandler . createBezierNodes ( params ) ;
this . _markAllEdgesAsDirty ( ) ;
// start simulation (can be called safely, even if already running)
this . body . emitter . emit ( "startSimulation" ) ;
console . log ( "_dataUpdated took:" , new Date ( ) . valueOf ( ) - t0 ) ;
} ) ;
// create the DOM elements
this . canvas . create ( ) ;
// properties for the animation
this . moving = true ;
this . renderTimer = undefined ; // Scheduling function. Is definded in this.start();
// apply options
this . setOptions ( options ) ;
// load data (the disable start variable will be the same as the enabled clustering)
this . setData ( data , this . constants . hierarchicalLayout . enabled ) ;
this . setData ( data ) ;
// hierarchical layout
if ( this . constants . hierarchicalLayout . enabled == true ) {
this . _setupHierarchicalLayout ( ) ;
}
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 . constants . stabilize == false ) {
this . zoomExtent ( { duration : 0 } , true , this . constants . clustering . enabled ) ;
}
}
if ( this . constants . stabilize == false ) {
this . initializing = false ;
}
var me = this ;
// this event will trigger a rebuilding of the cache of colors, nodes etc.
this . on ( "_dataChanged" , function ( ) {
me . _updateNodeIndexList ( ) ;
me . physics . _updateCalculationNodes ( ) ;
me . _markAllEdgesAsDirty ( ) ;
if ( me . initializing !== true ) {
me . moving = true ;
me . start ( ) ;
}
} )
this . on ( "_newEdgesCreated" , this . _createBezierNodes . bind ( this ) ) ;
//this.on("stabilizationIterationsDone", function () {me.initializing = false; me.start();}.bind(this));
}
// Extend Network with an Emitter mixin
@ -352,9 +177,6 @@ Network.prototype._createEdge = function(properties) {
return new Edge ( properties , this . body , this . constants )
}
/ * *
* Update the this . body . nodeIndices with the most recent node index list
* @ private
@ -376,10 +198,10 @@ Network.prototype._updateNodeIndexList = function() {
* { Options } [ options ] Object with options
* @ param { Boolean } [ disableStart ] | optional : disable the calling of the start function .
* /
Network . prototype . setData = function ( data , disableStart ) {
if ( disableStart === undefined ) {
disableStart = false ;
}
Network . prototype . setData = function ( data ) {
// reset the physics engine.
this . body . emitter . emit ( "resetPhysics" ) ;
this . body . emitter . emit ( "_resetData" ) ;
// unselect all to ensure no selections from old data are carried over.
this . selectionHandler . unselectAll ( ) ;
@ -393,9 +215,9 @@ Network.prototype.setData = function(data, disableStart) {
}
// clean up in case there is anyone in an active mode of the manipulation. This is the same option as bound to the escape button.
if ( this . constants . dataManipulation . enabled == true ) {
this . _createManipulatorBar ( ) ;
}
//if (this.constants.dataManipulation.enabled == true) {
// this._createManipulatorBar();
//}
// set options
this . setOptions ( data && data . options ) ;
@ -417,23 +239,12 @@ Network.prototype.setData = function(data, disableStart) {
}
}
else {
this . _setNodes ( data && data . nodes ) ;
this . _s etE dges( data && data . edges ) ;
this . nodesHandler . setData ( data && data . nodes ) ;
this . edgesHandler . setData ( data && data . edges ) ;
}
if ( disableStart == false ) {
if ( this . constants . hierarchicalLayout . enabled == true ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
else {
// find a stable position or start animating to a stable position
this . body . emitter . emit ( "stabilize" ) ;
}
}
else {
this . initializing = false ;
}
// find a stable position or start animating to a stable position
this . body . emitter . emit ( "initPhysics" ) ;
} ;
/ * *
@ -442,41 +253,38 @@ Network.prototype.setData = function(data, disableStart) {
* /
Network . prototype . setOptions = function ( options ) {
if ( options ) {
var prop ;
var fields = [ 'nodes' , 'edges' , 'smoothCurves' , 'hierarchicalLayout' , 'navigation' ,
'keyboard' , 'dataManipulation' , 'onAdd' , 'onEdit' , 'onEditEdge' , 'onConnect' , 'onDelete' , 'clickToUse'
] ;
//var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','navigation',
// 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse'
//];
// extend all but the values in fields
util . selectiveNotDeepExtend ( fields , this . constants , options ) ;
util . selectiveNotDeepExtend ( [ 'color' ] , this . constants . nodes , options . nodes ) ;
util . selectiveNotDeepExtend ( [ 'color' , 'length' ] , this . constants . edges , options . edges ) ;
//util.selectiveNotDeepExtend(fields,this.constants, options);
//util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes);
//util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges);
this . groups . useDefaultGroups = this . constants . useDefaultGroups ;
//this.groups.useDefaultGroups = this.constants.useDefaultGroups;
this . nodesHandler . setOptions ( options . nodes ) ;
this . edgesHandler . setOptions ( options . edges ) ;
this . physics . setOptions ( options . physics ) ;
this . canvas . setOptions ( options . canvas ) ;
this . renderer . setOptions ( options . rendering ) ;
this . view . setOptions ( options . view ) ;
this . interactionHandler . setOptions ( options . interaction ) ;
this . selectionHandler . setOptions ( options . selection ) ;
this . layoutEngine . setOptions ( options . layout ) ;
//this.clustering.setOptions(options.clustering);
//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 . 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 ; }
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 . dataManipulation ) {
this . editMode = this . constants . dataManipulation . initiallyVisible ;
}
//if (options.dataManipulation) {
// this.editMode = this.constants.dataManipulation.initiallyVisible;
//}
// TODO: work out these options and document them
@ -554,76 +362,11 @@ Network.prototype.setOptions = function (options) {
this . body . emitter . emit ( "activate" ) ;
}
this . _markAllEdgesAsDirty ( ) ;
this . canvas . setSize ( ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
if ( this . initializing !== true ) {
this . moving = true ;
this . start ( ) ;
}
}
} ;
/ * *
* Binding the keys for keyboard navigation . These functions are defined in the NavigationMixin
* @ private
* /
Network . prototype . _createKeyBinds = function ( ) {
return ;
//var me = this;
//if (this.keycharm !== undefined) {
// this.keycharm.destroy();
//}
//
//if (this.constants.keyboard.bindToWindow == true) {
// this.keycharm = keycharm({container: window, preventDefault: false});
//}
//else {
// this.keycharm = keycharm({container: this.frame, preventDefault: false});
//}
//
//this.keycharm.reset();
//
//if (this.constants.keyboard.enabled && this.isActive()) {
// this.keycharm.bind("up", this._moveUp.bind(me) , "keydown");
// this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup");
// this.keycharm.bind("down", this._moveDown.bind(me) , "keydown");
// this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup");
// this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown");
// this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup");
// this.keycharm.bind("right",this._moveRight.bind(me), "keydown");
// this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup");
// this.keycharm.bind("=", this._zoomIn.bind(me), "keydown");
// this.keycharm.bind("=", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown");
// this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown");
// this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("-", this._zoomOut.bind(me), "keydown");
// this.keycharm.bind("-", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("[", this._zoomIn.bind(me), "keydown");
// this.keycharm.bind("[", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("]", this._zoomOut.bind(me), "keydown");
// this.keycharm.bind("]", this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown");
// this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup");
// this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown");
// this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup");
//}
//
//if (this.constants.dataManipulation.enabled == true) {
// this.keycharm.bind("esc",this._createManipulatorBar.bind(me));
// this.keycharm.bind("delete",this._deleteSelected.bind(me));
//}
} ;
/ * *
* Cleans up all bindings of the network , removing it fully from the memory IF the variable is set to null after calling this function .
* var network = new vis . Network ( . . ) ;
@ -631,31 +374,15 @@ Network.prototype._createKeyBinds = function() {
* network = null ;
* /
Network . prototype . destroy = function ( ) {
this . start = function ( ) { } ;
this . redraw = function ( ) { } ;
this . renderTimer = false ;
// cleanup physicsConfiguration if it exists
this . _cleanupPhysicsConfiguration ( ) ;
// remove keybindings
this . keycharm . reset ( ) ;
// clear hammer bindings
this . hammer . destroy ( ) ;
this . body . emitter . emit ( "destroy" ) ;
// clear events
this . off ( ) ;
this . body . emitter . off ( ) ;
this . _recursiveDOMDelete ( this . containerElement ) ;
// remove the container and everything inside it recursively
this . util . recursiveDOMDelete ( this . body . container ) ;
} ;
Network . prototype . _recursiveDOMDelete = function ( DOMobject ) {
while ( DOMobject . hasChildNodes ( ) == true ) {
this . _recursiveDOMDelete ( DOMobject . firstChild ) ;
DOMobject . removeChild ( DOMobject . firstChild ) ;
}
} ;
/ * *
* Check if there is an element on the given position in the network
@ -784,113 +511,6 @@ Network.prototype._checkHidePopup = function (pointer) {
} ;
/ * *
* Set a data set with nodes for the network
* @ param { Array | DataSet | DataView } nodes The data containing the nodes .
* @ private
* /
Network . prototype . _setNodes = function ( nodes ) {
var oldNodesData = this . body . data . nodes ;
if ( nodes instanceof DataSet || nodes instanceof DataView ) {
this . body . data . nodes = nodes ;
}
else if ( Array . isArray ( nodes ) ) {
this . body . data . nodes = new DataSet ( ) ;
this . body . data . nodes . add ( nodes ) ;
}
else if ( ! nodes ) {
this . body . data . nodes = new DataSet ( ) ;
}
else {
throw new TypeError ( 'Array or DataSet expected' ) ;
}
if ( oldNodesData ) {
// unsubscribe from old dataset
util . forEach ( this . nodesListeners , function ( callback , event ) {
oldNodesData . off ( event , callback ) ;
} ) ;
}
// remove drawn nodes
this . body . nodes = { } ;
if ( this . body . data . nodes ) {
// subscribe to new dataset
var me = this ;
util . forEach ( this . nodesListeners , function ( callback , event ) {
me . body . data . nodes . on ( event , callback ) ;
} ) ;
// draw all new nodes
var ids = this . body . data . nodes . getIds ( ) ;
this . _addNodes ( ids ) ;
}
this . _updateSelection ( ) ;
} ;
/ * *
* Add nodes
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _addNodes = function ( ids ) {
var id ;
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
id = ids [ i ] ;
var data = this . body . data . nodes . get ( id ) ;
var node = new Node ( data , this . images , this . groups , this . constants ) ;
this . body . nodes [ id ] = node ; // note: this may replace an existing node
if ( ( node . xFixed == false || node . yFixed == false ) && ( node . x === null || node . y === null ) ) {
var radius = 10 * 0.1 * ids . length + 10 ;
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 ) ; }
}
this . moving = true ;
}
this . _updateNodeIndexList ( ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
this . physics . _updateCalculationNodes ( ) ;
this . _reconnectEdges ( ) ;
this . _updateValueRange ( this . body . nodes ) ;
} ;
/ * *
* Update existing nodes , or create them when not yet existing
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _updateNodes = function ( ids , changedData ) {
var nodes = this . body . nodes ;
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
var id = ids [ i ] ;
var node = nodes [ id ] ;
var data = changedData [ i ] ;
if ( node ) {
// update node
node . setProperties ( data , this . constants ) ;
}
else {
// create node
node = new Node ( properties , this . images , this . groups , this . constants ) ;
nodes [ id ] = node ;
}
}
this . moving = true ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
this . _updateNodeIndexList ( ) ;
this . _updateValueRange ( nodes ) ;
this . _markAllEdgesAsDirty ( ) ;
} ;
Network . prototype . _markAllEdgesAsDirty = function ( ) {
@ -899,190 +519,8 @@ Network.prototype._markAllEdgesAsDirty = function() {
}
}
/ * *
* Remove existing nodes . If nodes do not exist , the method will just ignore it .
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _removeNodes = function ( ids ) {
var nodes = this . body . nodes ;
// remove from selection
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
if ( this . selectionObj . nodes [ ids [ i ] ] !== undefined ) {
this . body . nodes [ ids [ i ] ] . unselect ( ) ;
this . _removeFromSelection ( this . body . nodes [ ids [ i ] ] ) ;
}
}
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
var id = ids [ i ] ;
delete nodes [ id ] ;
}
this . _updateNodeIndexList ( ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
this . physics . _updateCalculationNodes ( ) ;
this . _reconnectEdges ( ) ;
this . _updateSelection ( ) ;
this . _updateValueRange ( nodes ) ;
} ;
/ * *
* Load edges by reading the data table
* @ param { Array | DataSet | DataView } edges The data containing the edges .
* @ private
* @ private
* /
Network . prototype . _setEdges = function ( edges ) {
var oldEdgesData = this . body . data . edges ;
if ( edges instanceof DataSet || edges instanceof DataView ) {
this . body . data . edges = edges ;
}
else if ( Array . isArray ( edges ) ) {
this . body . data . edges = new DataSet ( ) ;
this . body . data . edges . add ( edges ) ;
}
else if ( ! edges ) {
this . body . data . edges = new DataSet ( ) ;
}
else {
throw new TypeError ( 'Array or DataSet expected' ) ;
}
if ( oldEdgesData ) {
// unsubscribe from old dataset
util . forEach ( this . edgesListeners , function ( callback , event ) {
oldEdgesData . off ( event , callback ) ;
} ) ;
}
// remove drawn edges
this . body . edges = { } ;
if ( this . body . data . edges ) {
// subscribe to new dataset
var me = this ;
util . forEach ( this . edgesListeners , function ( callback , event ) {
me . body . data . edges . on ( event , callback ) ;
} ) ;
// draw all new nodes
var ids = this . body . data . edges . getIds ( ) ;
this . _addEdges ( ids ) ;
}
this . _reconnectEdges ( ) ;
} ;
/ * *
* Add edges
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _addEdges = function ( ids ) {
var edges = this . body . edges ,
edgesData = this . body . data . edges ;
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
var id = ids [ i ] ;
var oldEdge = edges [ id ] ;
if ( oldEdge ) {
oldEdge . disconnect ( ) ;
}
var data = edgesData . get ( id , { "showInternalIds" : true } ) ;
edges [ id ] = new Edge ( data , this . body , this . constants ) ;
}
this . moving = true ;
this . _updateValueRange ( edges ) ;
this . _createBezierNodes ( ) ;
this . physics . _updateCalculationNodes ( ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
} ;
/ * *
* Update existing edges , or create them when not yet existing
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _updateEdges = function ( ids ) {
var edges = this . body . edges ;
var edgesData = this . body . data . edges ;
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
var id = ids [ i ] ;
var data = edgesData . get ( id ) ;
var edge = edges [ id ] ;
if ( edge ) {
// update edge
edge . disconnect ( ) ;
edge . setProperties ( data ) ;
edge . connect ( ) ;
}
else {
// create edge
edge = new Edge ( data , this . body , this . constants ) ;
this . body . edges [ id ] = edge ;
}
}
this . _createBezierNodes ( ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
this . moving = true ;
this . _updateValueRange ( edges ) ;
} ;
/ * *
* Remove existing edges . Non existing ids will be ignored
* @ param { Number [ ] | String [ ] } ids
* @ private
* /
Network . prototype . _removeEdges = function ( ids ) {
var edges = this . body . edges ;
// remove from selection
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
if ( this . selectionObj . edges [ ids [ i ] ] !== undefined ) {
edges [ ids [ i ] ] . unselect ( ) ;
this . _removeFromSelection ( edges [ ids [ i ] ] ) ;
}
}
for ( var i = 0 , len = ids . length ; i < len ; i ++ ) {
var id = ids [ i ] ;
var edge = edges [ id ] ;
if ( edge ) {
if ( edge . via != null ) {
delete this . body . supportNodes [ edge . via . id ] ;
}
edge . disconnect ( ) ;
delete edges [ id ] ;
}
}
this . moving = true ;
this . _updateValueRange ( edges ) ;
if ( this . constants . hierarchicalLayout . enabled == true && this . initializing == false ) {
this . _resetLevels ( ) ;
this . _setupHierarchicalLayout ( ) ;
}
this . physics . _updateCalculationNodes ( ) ;
} ;
/ * *
* Reconnect all edges
* @ private
@ -1273,37 +711,6 @@ Network.prototype._configureSmoothCurves = function(disableStart = true) {
} ;
/ * *
* Bezier curves require an anchor point to calculate the smooth flow . These points are nodes . These nodes are invisible but
* are used for the force calculation .
*
* @ private
* /
Network . prototype . _createBezierNodes = function ( specificEdges = this . body . edges ) {
if ( this . constants . smoothCurves . enabled == true && this . constants . smoothCurves . dynamic == true ) {
for ( var edgeId in specificEdges ) {
if ( specificEdges . hasOwnProperty ( edgeId ) ) {
var edge = specificEdges [ edgeId ] ;
if ( edge . via == null ) {
var nodeId = "edgeId:" . concat ( edge . id ) ;
var node = new Node (
{ id : nodeId ,
mass : 1 ,
shape : 'circle' ,
image : "" ,
internalMultiplier : 1
} , { } , { } , this . constants ) ;
this . body . supportNodes [ nodeId ] = node ;
edge . via = node ;
edge . via . parentEdgeId = edge . id ;
edge . positionBezierNode ( ) ;
}
}
}
this . _updateNodeIndexList ( ) ;
}
} ;
/ * *
* load the functions that load the mixins into the prototype .
*