@ -4,8 +4,8 @@
*
* A dynamic , browser - based visualization library .
*
* @ version @ @ version
* @ date @ @ date
* @ version 0.6 .0 - SNAPSHOT
* @ date 2014 - 03 - 03
*
* @ license
* Copyright ( C ) 2011 - 2014 Almende B . V , http : //almende.com
@ -2350,6 +2350,380 @@ DataView.prototype._trigger = DataSet.prototype._trigger;
DataView . prototype . subscribe = DataView . prototype . on ;
DataView . prototype . unsubscribe = DataView . prototype . off ;
/ * *
* Created by Alex on 2 / 27 / 14.
* /
function SvgAxis ( range , mainId , constants ) {
this . svgId = mainId ;
this . range = range ;
this . constants = constants ;
this . duration = this . range . end - this . range . start ; // in milliseconds
this . minColumnWidth = 100 ;
this . _drawElements ( ) ;
this . _update ( ) ;
}
SvgAxis . prototype . _drawElements = function ( ) {
d3 . select ( this . svgId )
. append ( "rect" )
. attr ( "id" , "bars" )
. attr ( "x" , 0 )
. attr ( "y" , 0 )
. attr ( "width" , this . constants . width )
. attr ( "height" , this . constants . barHeight )
. style ( "stroke" , "rgb(6,120,155)" ) ;
this . leftText = d3 . select ( this . svgId )
. append ( "text" )
. attr ( "x" , 5 )
. attr ( "y" , 20 )
. attr ( "font-size" , 14 )
. text ( moment ( this . range . start ) ) ;
this . rightText = d3 . select ( this . svgId )
. append ( "text" )
. attr ( "y" , 20 )
. attr ( "font-size" , 14 )
. text ( moment ( this . range . end ) )
this . rightText . attr ( "x" , this . constants . width - 5 - this . rightText . node ( ) . getBBox ( ) . width ) ;
this . dateLabels = { } ;
this . markerLines = { } ;
}
SvgAxis . prototype . _createMarkerLine = function ( index ) {
this . markerLines [ index ] = { svg : d3 . select ( "svg#main" ) . append ( "line" )
. attr ( 'y1' , 0 )
. attr ( 'y2' , this . constants . height )
. style ( "stroke" , "rgb(220,220,220)" )
}
}
SvgAxis . prototype . _createDateLabel = function ( index ) {
this . dateLabels [ index ] = { svg : d3 . select ( this . svgId )
. append ( "text" )
. attr ( "font-size" , 12 )
, active : false } ;
}
SvgAxis . prototype . _update = function ( ) {
this . duration = this . range . end - this . range . start ; // in milliseconds
this . leftText . text ( moment ( this . range . start ) . format ( "DD-MM-YYYY HH:mm:ss" ) )
this . rightText . text ( moment ( this . range . end ) . format ( "DD-MM-YYYY" ) )
this . rightText . attr ( "x" , this . constants . width - 5 - this . rightText . node ( ) . getBBox ( ) . width ) ;
this . msPerPixel = this . duration / this . constants . width ;
this . columnDuration = this . minColumnWidth * this . msPerPixel ;
var milliSecondScale = [ 1 , 10 , 50 , 100 , 250 , 500 ] ;
var secondScale = [ 1 , 5 , 15 , 30 ] ;
var minuteScale = [ 1 , 5 , 15 , 30 ] ;
var hourScale = [ 1 , 3 , 6 , 12 ] ;
var dayScale = [ 1 , 2 , 3 , 5 , 10 , 15 ] ;
var monthScale = [ 1 , 2 , 3 , 4 , 5 , 6 ] ;
var yearScale = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 15 , 20 , 25 , 50 , 75 , 100 , 150 , 250 , 500 , 1000 ] ;
var multipliers = [ 1 , 1000 , 60000 , 3600000 , 24 * 3600000 , 30 * 24 * 3600000 , 365 * 24 * 3600000 ] ;
var scales = [ milliSecondScale , secondScale , minuteScale , hourScale , dayScale , monthScale , yearScale ]
var formats = [ "SSS" , "mm:ss" , "hh:mm:ss" , "DD HH:mm" , "DD-MM" , "MM-YYYY" , "YYYY" ]
var indices = this . _getAppropriateScale ( scales , multipliers ) ;
var scale = scales [ indices [ 0 ] ] [ indices [ 1 ] ] * multipliers [ indices [ 0 ] ] ;
var dateCorrection = ( this . range . start . valueOf ( ) % scale ) + 3600000 ;
for ( var i = 0 ; i < 30 ; i ++ ) {
var date = this . range . start + i * scale - dateCorrection ;
if ( ( ( i + 1 ) * scale - dateCorrection ) / this . msPerPixel > this . constants . width + 200 ) {
if ( this . dateLabels . hasOwnProperty ( i ) ) {
this . dateLabels [ i ] . svg . remove ( ) ;
delete this . dateLabels [ i ]
}
if ( this . markerLines . hasOwnProperty ( i ) ) {
this . markerLines [ i ] . svg . remove ( ) ;
delete this . markerLines [ i ]
}
}
else {
if ( ! this . dateLabels . hasOwnProperty ( i ) ) {
this . _createDateLabel ( i ) ;
}
if ( ! this . markerLines . hasOwnProperty ( i ) ) {
this . _createMarkerLine ( i ) ;
}
this . dateLabels [ i ] . svg . text ( moment ( date ) . format ( formats [ indices [ 0 ] ] ) )
. attr ( "x" , ( i * scale - dateCorrection ) / this . msPerPixel )
. attr ( "y" , 50 )
this . markerLines [ i ] . svg . attr ( "x1" , ( i * scale - dateCorrection ) / this . msPerPixel )
. attr ( "x2" , ( i * scale - dateCorrection ) / this . msPerPixel )
}
}
}
SvgAxis . prototype . _getAppropriateScale = function ( scales , multipliers ) {
for ( var i = 0 ; i < scales . length ; i ++ ) {
for ( var j = 0 ; j < scales [ i ] . length ; j ++ ) {
if ( scales [ i ] [ j ] * multipliers [ i ] > this . columnDuration ) {
return [ i , j ]
}
}
}
}
/ * *
* @ constructor SvgTimeline
* Create a graph visualization , displaying nodes and edges .
*
* @ param { Element } container The DOM element in which the Graph will
* be created . Normally a div element .
* @ param { Object } items An object containing parameters
* { Array } nodes
* { Array } edges
* @ param { Object } options Options
* /
function SvgTimeline ( container , items , options ) {
this . constants = {
width : 1400 ,
height : 400 ,
barHeight : 60
}
var now = moment ( ) . hours ( 0 ) . minutes ( 0 ) . seconds ( 0 ) . milliseconds ( 0 ) ;
this . range = {
start : now . clone ( ) . add ( 'days' , - 3 ) . valueOf ( ) ,
end : now . clone ( ) . add ( 'days' , 4 ) . valueOf ( )
}
this . items = { } ;
this . sortedItems = [ ] ;
this . activeItems = { } ;
this . sortedActiveItems = [ ] ;
this . _createItems ( items ) ;
this . container = container ;
this . _createSVG ( ) ;
this . axis = new SvgAxis ( this . range , "svg#main" , this . constants ) ;
var me = this ;
this . hammer = Hammer ( document . getElementById ( "main" ) , {
prevent_default : true
} ) ;
this . hammer . on ( 'tap' , me . _onTap . bind ( me ) ) ;
this . hammer . on ( 'doubletap' , me . _onDoubleTap . bind ( me ) ) ;
this . hammer . on ( 'hold' , me . _onHold . bind ( me ) ) ;
this . hammer . on ( 'pinch' , me . _onPinch . bind ( me ) ) ;
this . hammer . on ( 'touch' , me . _onTouch . bind ( me ) ) ;
this . hammer . on ( 'dragstart' , me . _onDragStart . bind ( me ) ) ;
this . hammer . on ( 'drag' , me . _onDrag . bind ( me ) ) ;
this . hammer . on ( 'dragend' , me . _onDragEnd . bind ( me ) ) ;
this . hammer . on ( 'release' , me . _onRelease . bind ( me ) ) ;
this . hammer . on ( 'mousewheel' , me . _onMouseWheel . bind ( me ) ) ;
this . hammer . on ( 'DOMMouseScroll' , me . _onMouseWheel . bind ( me ) ) ; // for FF
this . hammer . on ( 'mousemove' , me . _onMouseMoveTitle . bind ( me ) ) ;
//this._drawLines();
this . _update ( ) ;
}
SvgTimeline . prototype . _createSVG = function ( ) {
d3 . select ( "div#visualization" )
. append ( "svg" ) . attr ( "id" , "main" )
. attr ( "width" , this . constants . width )
. attr ( "height" , this . constants . height )
. attr ( "style" , "border:1px solid black" )
} ;
SvgTimeline . prototype . _createItems = function ( items ) {
for ( var i = 0 ; i < items . length ; i ++ ) {
this . items [ items [ i ] . id ] = new Item ( items [ i ] , this . constants ) ;
this . sortedItems . push ( this . items [ items [ i ] . id ] ) ;
}
this . _sortItems ( this . sortedItems ) ;
}
SvgTimeline . prototype . _sortItems = function ( items ) {
items . sort ( function ( a , b ) { return a . start - b . start } ) ;
}
SvgTimeline . prototype . _getPointer = function ( touch ) {
return {
x : touch . pageX ,
y : touch . pageY
} ;
} ;
SvgTimeline . prototype . _onTap = function ( ) { } ;
SvgTimeline . prototype . _onDoubleTap = function ( ) { } ;
SvgTimeline . prototype . _onHold = function ( ) { } ;
SvgTimeline . prototype . _onPinch = function ( ) { } ;
SvgTimeline . prototype . _onTouch = function ( event ) { } ;
SvgTimeline . prototype . _onDragStart = function ( event ) {
this . initialDragPos = this . _getPointer ( event . gesture . center ) ;
} ;
SvgTimeline . prototype . _onDrag = function ( event ) {
var pointer = this . _getPointer ( event . gesture . center ) ;
var diffX = pointer . x - this . initialDragPos . x ;
// var diffY = pointer.y - this.initialDragPos.y;
this . initialDragPos = pointer ;
this . range . start -= diffX * this . axis . msPerPixel ;
this . range . end -= diffX * this . axis . msPerPixel ;
this . _update ( ) ;
} ;
SvgTimeline . prototype . _onDragEnd = function ( ) { } ;
SvgTimeline . prototype . _onRelease = function ( ) { } ;
SvgTimeline . prototype . _onMouseWheel = function ( event ) {
var delta = 0 ;
if ( event . wheelDelta ) { /* IE/Opera. */
delta = event . wheelDelta / 120 ;
}
else if ( event . detail ) { /* Mozilla case. */
// In Mozilla, sign of delta is different than in IE.
// Also, delta is multiple of 3.
delta = - event . detail / 3 ;
}
if ( delta ) {
var pointer = { x : event . x , y : event . y }
var center = this . range . start + this . axis . duration * 0.5 ;
var zoomSpeed = 0.1 ;
var scrollSpeed = 0.1 ;
this . range . start = center - 0.5 * ( this . axis . duration * ( 1 - delta * zoomSpeed ) ) ;
this . range . end = this . range . start + ( this . axis . duration * ( 1 - delta * zoomSpeed ) ) ;
var diffX = delta * ( pointer . x - 0.5 * this . constants . width ) ;
// var diffY = pointer.y - this.initialDragPos.y;
this . range . start -= diffX * this . axis . msPerPixel * scrollSpeed ;
this . range . end -= diffX * this . axis . msPerPixel * scrollSpeed ;
this . _update ( ) ;
}
} ;
SvgTimeline . prototype . _onMouseMoveTitle = function ( ) { } ;
SvgTimeline . prototype . _update = function ( ) {
this . axis . _update ( ) ;
this . _getActiveItems ( ) ;
this . _updateItems ( ) ;
} ;
SvgTimeline . prototype . _getActiveItems = function ( ) {
// reset all currently active items to inactive
for ( var itemId in this . activeItems ) {
if ( this . activeItems . hasOwnProperty ( itemId ) ) {
this . activeItems [ itemId ] . active = false ;
}
}
this . sortedActiveItems = [ ]
var rangeStart = this . range . start - 200 * this . axis . msPerPixel
var rangeEnd = ( this . range . end + 200 * this . axis . msPerPixel )
for ( var itemId in this . items ) {
if ( this . items . hasOwnProperty ( itemId ) ) {
if ( this . items [ itemId ] . start >= rangeStart && this . items [ itemId ] . start < rangeEnd ||
this . items [ itemId ] . end >= rangeStart && this . items [ itemId ] . end < rangeEnd ) {
if ( this . items [ itemId ] . active == false ) {
this . activeItems [ itemId ] = this . items [ itemId ] ;
}
this . activeItems [ itemId ] . active = true ;
this . sortedActiveItems . push ( this . activeItems [ itemId ] ) ;
}
}
}
this . _sortItems ( this . sortedActiveItems ) ;
// cleanup
for ( var itemId in this . activeItems ) {
if ( this . activeItems . hasOwnProperty ( itemId ) ) {
if ( this . activeItems [ itemId ] . active == false ) {
this . activeItems [ itemId ] . svg . remove ( ) ;
this . activeItems [ itemId ] . svg = null ;
this . activeItems [ itemId ] . svgLine . remove ( ) ;
this . activeItems [ itemId ] . svgLine = null ;
delete this . activeItems [ itemId ] ;
}
}
}
} ;
SvgTimeline . prototype . _updateItems = function ( ) {
for ( var i = 0 ; i < this . sortedActiveItems . length ; i ++ ) {
var item = this . sortedActiveItems [ i ] ;
if ( item . svg == null ) {
// item.svg = d3.select("svg#main")
// .append("rect")
// .attr("class","item")
// .style("stroke", "rgb(6,120,155)")
// .style("fill", "rgb(6,120,155)");
item . svg = d3 . select ( "svg#main" )
. append ( "foreignObject" )
item . svgContent = item . svg . append ( "xhtml:body" )
. style ( "font" , "14px 'Helvetica Neue'" )
. style ( "background-color" , "#ff00ff" )
. html ( "<h1>An HTML Foreign Object in SVG</h1><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu enim quam. Quisque nisi risus, sagittis quis tempor nec, aliquam eget neque. Nulla bibendum semper lorem non ullamcorper. Nulla non ligula lorem. Praesent porttitor, tellus nec suscipit aliquam, enim elit posuere lorem, at laoreet enim ligula sed tortor. Ut sodales, urna a aliquam semper, nibh diam gravida sapien, sit amet fermentum purus lacus eget massa. Donec ac arcu vel magna consequat pretium et vel ligula. Donec sit amet erat elit. Vivamus eu metus eget est hendrerit rutrum. Curabitur vitae orci et leo interdum egestas ut sit amet dui. In varius enim ut sem posuere in tristique metus ultrices.<p>Integer mollis massa at orci porta vestibulum. Pellentesque dignissim turpis ut tortor ultricies condimentum et quis nibh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer euismod lorem vulputate dui pharetra luctus. Sed vulputate, nunc quis porttitor scelerisque, dui est varius ipsum, eu blandit mauris nibh pellentesque tortor. Vivamus ultricies ante eget ipsum pulvinar ac tempor turpis mollis. Morbi tortor orci, euismod vel sagittis ac, lobortis nec est. Quisque euismod venenatis felis at dapibus. Vestibulum dignissim nulla ut nisi tristique porttitor. Proin et nunc id arcu cursus dapibus non quis libero. Nunc ligula mi, bibendum non mattis nec, luctus id neque. Suspendisse ut eros lacus. Praesent eget lacus eget risus congue vestibulum. Morbi tincidunt pulvinar lacus sed faucibus. Phasellus sed vestibulum sapien." ) ;
if ( item . end == 0 ) {
item . svgLine = d3 . select ( "svg#main" )
. append ( "line" )
. attr ( "y1" , this . constants . barHeight )
. style ( "stroke" , "rgb(200,200,255)" )
. style ( "stroke-width" , 3 )
}
}
item . svg . attr ( 'width' , item . getLength ( this . axis . msPerPixel ) )
. attr ( "x" , this . _getXforItem ( item ) )
. attr ( "y" , this . _getYforItem ( item , i ) )
. attr ( 'height' , 25 )
if ( item . end == 0 ) {
item . svgLine . attr ( 'y2' , item . y )
. attr ( 'x1' , item . timeX )
. attr ( 'x2' , item . timeX )
}
}
} ;
SvgTimeline . prototype . _getXforItem = function ( item ) {
item . timeX = ( item . start - this . range . start ) / this . axis . msPerPixel ;
if ( item . end == 0 ) {
item . drawX = item . timeX - item . width * 0.5 ;
}
else {
item . drawX = item . timeX ;
}
return item . drawX ;
}
SvgTimeline . prototype . _getYforItem = function ( item , index ) {
var bounds = 10 ;
var startIndex = Math . max ( 0 , index - bounds ) ;
item . level = 0 ;
for ( var i = startIndex ; i < index ; i ++ ) {
var item2 = this . sortedActiveItems [ i ] ;
if ( item . drawX <= ( item2 . drawX + item2 . width + 5 ) && item2 . level == item . level ) {
item . level += 1 ;
}
}
item . y = 100 + 50 * item . level ;
return item . y ;
}
/ * *
* @ constructor TimeStep
* The class TimeStep is an iterator for dates . You provide a start date and an
@ -10445,6 +10819,7 @@ function Edge (properties, graph, constants) {
this . width = constants . edges . width ;
this . value = undefined ;
this . length = constants . physics . springLength ;
this . customLength = false ;
this . selected = false ;
this . smooth = constants . smoothCurves ;
@ -10500,7 +10875,8 @@ Edge.prototype.setProperties = function(properties, constants) {
if ( properties . title !== undefined ) { this . title = properties . title ; }
if ( properties . width !== undefined ) { this . width = properties . width ; }
if ( properties . value !== undefined ) { this . value = properties . value ; }
if ( properties . length !== undefined ) { this . length = properties . length ; }
if ( properties . length !== undefined ) { this . length = properties . length ;
this . customLength = true ; }
// Added to support dashed lines
// David Jordan
@ -10644,7 +11020,7 @@ Edge.prototype._drawLine = function(ctx) {
ctx . lineWidth = this . _getLineWidth ( ) ;
var point ;
if ( this . from != this . to + 9 ) {
if ( this . from != this . to ) {
// draw line
this . _line ( ctx ) ;
@ -11388,6 +11764,50 @@ var physicsMixin = {
} ,
/ * *
* This loads the node force solver based on the barnes hut or repulsion algorithm
*
* @ private
* /
_loadSelectedForceSolver : function ( ) {
// this overloads the this._calculateNodeForces
if ( this . constants . physics . barnesHut . enabled == true ) {
this . _clearMixin ( repulsionMixin ) ;
this . _clearMixin ( hierarchalRepulsionMixin ) ;
this . constants . physics . centralGravity = this . constants . physics . barnesHut . centralGravity ;
this . constants . physics . springLength = this . constants . physics . barnesHut . springLength ;
this . constants . physics . springConstant = this . constants . physics . barnesHut . springConstant ;
this . constants . physics . damping = this . constants . physics . barnesHut . damping ;
this . _loadMixin ( barnesHutMixin ) ;
}
else if ( this . constants . physics . hierarchicalRepulsion . enabled == true ) {
this . _clearMixin ( barnesHutMixin ) ;
this . _clearMixin ( repulsionMixin ) ;
this . constants . physics . centralGravity = this . constants . physics . hierarchicalRepulsion . centralGravity ;
this . constants . physics . springLength = this . constants . physics . hierarchicalRepulsion . springLength ;
this . constants . physics . springConstant = this . constants . physics . hierarchicalRepulsion . springConstant ;
this . constants . physics . damping = this . constants . physics . hierarchicalRepulsion . damping ;
this . _loadMixin ( hierarchalRepulsionMixin ) ;
}
else {
this . _clearMixin ( barnesHutMixin ) ;
this . _clearMixin ( hierarchalRepulsionMixin ) ;
this . barnesHutTree = undefined ;
this . constants . physics . centralGravity = this . constants . physics . repulsion . centralGravity ;
this . constants . physics . springLength = this . constants . physics . repulsion . springLength ;
this . constants . physics . springConstant = this . constants . physics . repulsion . springConstant ;
this . constants . physics . damping = this . constants . physics . repulsion . damping ;
this . _loadMixin ( repulsionMixin ) ;
}
} ,
/ * *
* Before calculating the forces , we check if we need to cluster to keep up performance and we check
* if there is more than one node . If it is just one node , we dont calculate anything .
@ -11526,7 +11946,7 @@ var physicsMixin = {
if ( edge . connected ) {
// only calculate forces if nodes are in the same sector
if ( this . nodes . hasOwnProperty ( edge . toId ) && this . nodes . hasOwnProperty ( edge . fromId ) ) {
edgeLength = edge . length ;
edgeLength = edge . customLength ? edge . length : this . constants . physics . springL ength;
// this implies that the edges between big clusters are longer
edgeLength += ( edge . to . clusterSize + edge . from . clusterSize - 2 ) * this . constants . clustering . edgeGrowth ;
@ -11575,7 +11995,7 @@ var physicsMixin = {
var node2 = edge . via ;
var node3 = edge . from ;
edgeLength = edge . length ;
edgeLength = edge . customLength ? edge . length : this . constants . physics . springL ength;
combinedClusterSize = node1 . clusterSize + node3 . clusterSize - 2 ;
@ -11608,6 +12028,10 @@ var physicsMixin = {
springForce = this . constants . physics . springConstant * ( edgeLength - length ) / length ;
if ( length == 0 ) {
length = 0.01 ;
}
fx = dx * springForce ;
fy = dy * springForce ;
@ -11615,8 +12039,242 @@ var physicsMixin = {
node1 . fy += fy ;
node2 . fx -= fx ;
node2 . fy -= fy ;
} ,
/ * *
* Load the HTML for the physics config and bind it
* @ private
* /
_loadPhysicsConfiguration : function ( ) {
if ( this . physicsConfiguration === undefined ) {
this . physicsConfiguration = document . createElement ( 'div' ) ;
this . physicsConfiguration . className = "PhysicsConfiguration" ;
this . physicsConfiguration . innerHTML = '' +
'<table><tr><td><b>Simulation Mode:</b></td></tr>' +
'<tr>' +
'<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod1" value="BH" checked="checked">Barnes Hut</td>' +
'<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod2" value="R">Repulsion</td>' +
'<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod3" value="H">Hierarchical</td>' +
'</tr>' +
'</table>' +
'<table id="graph_BH_table" style="display:none">' +
'<tr><td><b>Barnes Hut</b></td></tr>' +
'<tr>' +
'<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="500" max="20000" value="2000" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="-2000" id="graph_BH_gc_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="0.3" step="0.05" style="width:300px" id="graph_BH_cg"></td><td>3</td><td><input value="0.03" id="graph_BH_cg_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="100" step="1" style="width:300px" id="graph_BH_sl"></td><td>500</td><td><input value="100" id="graph_BH_sl_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="0.05" step="0.005" style="width:300px" id="graph_BH_sc"></td><td>0.5</td><td><input value="0.05" id="graph_BH_sc_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="0.09" step="0.005" style="width:300px" id="graph_BH_damp"></td><td>0.3</td><td><input value="0.09" id="graph_BH_damp_value" style="width:60px"></td>' +
'</tr>' +
'</table>' +
'<table id="graph_R_table" style="display:none">' +
'<tr><td><b>Repulsion</b></td></tr>' +
'<tr>' +
'<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="100" step="1" style="width:300px" id="graph_R_nd"></td><td width="50px">300</td><td><input value="100" id="graph_R_nd_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="0.1" step="0.05" style="width:300px" id="graph_R_cg"></td><td>3</td><td><input value="0.01" id="graph_R_cg_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="200" step="1" style="width:300px" id="graph_R_sl"></td><td>500</td><td><input value="200" id="graph_R_sl_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="0.05" step="0.005" style="width:300px" id="graph_R_sc"></td><td>0.5</td><td><input value="0.05" id="graph_R_sc_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="0.09" step="0.005" style="width:300px" id="graph_R_damp"></td><td>0.3</td><td><input value="0.09" id="graph_R_damp_value" style="width:60px"></td>' +
'</tr>' +
'</table>' +
'<table id="graph_H_table" style="display:none">' +
'<tr><td width="150"><b>Hierarchical</b></td></tr>' +
'<tr>' +
'<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="60" step="1" style="width:300px" id="graph_H_nd"></td><td width="50px">300</td><td><input value="60" id="graph_H_nd_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="0" step="0.05" style="width:300px" id="graph_H_cg"></td><td>3</td><td><input value="0" id="graph_H_cg_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="100" step="1" style="width:300px" id="graph_H_sl"></td><td>500</td><td><input value="100" id="graph_H_sl_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="0.01" step="0.005" style="width:300px" id="graph_H_sc"></td><td>0.5</td><td><input value="0.01" id="graph_H_sc_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="0.09" step="0.005" style="width:300px" id="graph_H_damp"></td><td>0.3</td><td><input value="0.09" id="graph_H_damp_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">direction</td><td>1</td><td><input type="range" min="0" max="3" value="0" step="1" style="width:300px" id="graph_H_direction"></td><td>4</td><td><input value="LR" id="graph_H_direction_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">levelSeparation</td><td>1</td><td><input type="range" min="0" max="500" value="150" step="1" style="width:300px" id="graph_H_levsep"></td><td>500</td><td><input value="150" id="graph_H_levsep_value" style="width:60px"></td>' +
'</tr>' +
'<tr>' +
'<td width="150px">nodeSpacing</td><td>1</td><td><input type="range" min="0" max="500" value="100" step="1" style="width:300px" id="graph_H_nspac"></td><td>500</td><td><input value="100" id="graph_H_nspac_value" style="width:60px"></td>' +
'</tr>' +
'</table>'
this . containerElement . parentElement . insertBefore ( this . physicsConfiguration , this . containerElement ) ;
var hierarchicalLayoutDirections = [ "LR" , "RL" , "UD" , "DU" ] ;
var rangeElement ;
rangeElement = document . getElementById ( 'graph_BH_gc' ) ;
rangeElement . innerHTML = this . constants . physics . barnesHut . gravitationalConstant ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_BH_gc' , - 1 , "physics_barnesHut_gravitationalConstant" ) ;
rangeElement = document . getElementById ( 'graph_BH_cg' ) ;
rangeElement . innerHTML = this . constants . physics . barnesHut . centralGravity ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_BH_cg' , 1 , "physics_centralGravity" ) ;
rangeElement = document . getElementById ( 'graph_BH_sc' ) ;
rangeElement . innerHTML = this . constants . physics . barnesHut . springConstant ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_BH_sc' , 1 , "physics_springConstant" ) ;
rangeElement = document . getElementById ( 'graph_BH_sl' ) ;
rangeElement . innerHTML = this . constants . physics . barnesHut . springLength ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_BH_sl' , 1 , "physics_springLength" ) ;
rangeElement = document . getElementById ( 'graph_BH_damp' ) ;
rangeElement . innerHTML = this . constants . physics . barnesHut . damping ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_BH_damp' , 1 , "physics_damping" ) ;
rangeElement = document . getElementById ( 'graph_R_nd' ) ;
rangeElement . innerHTML = this . constants . physics . repulsion . nodeDistance ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_R_nd' , 1 , "physics_repulsion_nodeDistance" ) ;
rangeElement = document . getElementById ( 'graph_R_cg' ) ;
rangeElement . innerHTML = this . constants . physics . repulsion . centralGravity ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_R_cg' , 1 , "physics_centralGravity" ) ;
rangeElement = document . getElementById ( 'graph_R_sc' ) ;
rangeElement . innerHTML = this . constants . physics . repulsion . springConstant ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_R_sc' , 1 , "physics_springConstant" ) ;
rangeElement = document . getElementById ( 'graph_R_sl' ) ;
rangeElement . innerHTML = this . constants . physics . repulsion . springLength ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_R_sl' , 1 , "physics_springLength" ) ;
rangeElement = document . getElementById ( 'graph_R_damp' ) ;
rangeElement . innerHTML = this . constants . physics . repulsion . damping ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_R_damp' , 1 , "physics_damping" ) ;
rangeElement = document . getElementById ( 'graph_H_nd' ) ;
rangeElement . innerHTML = this . constants . physics . hierarchicalRepulsion . nodeDistance ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_nd' , 1 , "physics_hierarchicalRepulsion_nodeDistance" ) ;
rangeElement = document . getElementById ( 'graph_H_cg' ) ;
rangeElement . innerHTML = this . constants . physics . hierarchicalRepulsion . centralGravity ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_cg' , 1 , "physics_centralGravity" ) ;
rangeElement = document . getElementById ( 'graph_H_sc' ) ;
rangeElement . innerHTML = this . constants . physics . hierarchicalRepulsion . springConstant ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_sc' , 1 , "physics_springConstant" ) ;
rangeElement = document . getElementById ( 'graph_H_sl' ) ;
rangeElement . innerHTML = this . constants . physics . hierarchicalRepulsion . springLength ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_sl' , 1 , "physics_springLength" ) ;
rangeElement = document . getElementById ( 'graph_H_damp' ) ;
rangeElement . innerHTML = this . constants . physics . hierarchicalRepulsion . damping ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_damp' , 1 , "physics_damping" ) ;
rangeElement = document . getElementById ( 'graph_H_direction' ) ;
rangeElement . innerHTML = hierarchicalLayoutDirections . indexOf ( this . constants . hierarchicalLayout . direction ) ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_direction' , hierarchicalLayoutDirections , "hierarchicalLayout_direction" ) ;
rangeElement = document . getElementById ( 'graph_H_levsep' ) ;
rangeElement . innerHTML = this . constants . hierarchicalLayout . levelSeparation ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_levsep' , 1 , "hierarchicalLayout_levelSeparation" ) ;
rangeElement = document . getElementById ( 'graph_H_nspac' ) ;
rangeElement . innerHTML = this . constants . hierarchicalLayout . nodeSpacing ;
rangeElement . onchange = showValueOfRange . bind ( this , 'graph_H_nspac' , 1 , "hierarchicalLayout_nodeSpacing" ) ;
var radioButton1 = document . getElementById ( "graph_physicsMethod1" ) ;
var radioButton2 = document . getElementById ( "graph_physicsMethod2" ) ;
var radioButton3 = document . getElementById ( "graph_physicsMethod3" ) ;
radioButton2 . checked = true ;
if ( this . constants . physics . barnesHut . enabled ) {
radioButton1 . checked = true ;
}
if ( this . constants . hierarchicalLayout . enabled ) {
radioButton3 . checked = true ;
}
switchConfigurations . apply ( this ) ;
radioButton1 . onchange = switchConfigurations . bind ( this ) ;
radioButton2 . onchange = switchConfigurations . bind ( this ) ;
radioButton3 . onchange = switchConfigurations . bind ( this ) ;
}
} ,
_overWriteGraphConstants : function ( constantsVariableName , value ) {
var nameArray = constantsVariableName . split ( "_" ) ;
if ( nameArray . length == 1 ) {
this . constants [ nameArray [ 0 ] ] = value ;
}
else if ( nameArray . length == 2 ) {
this . constants [ nameArray [ 0 ] ] [ nameArray [ 1 ] ] = value ;
}
else if ( nameArray . length == 3 ) {
this . constants [ nameArray [ 0 ] ] [ nameArray [ 1 ] ] [ nameArray [ 2 ] ] = value ;
}
}
}
function switchConfigurations ( ) {
var ids = [ "graph_BH_table" , "graph_R_table" , "graph_H_table" ]
var radioButton = document . querySelector ( 'input[name="graph_physicsMethod"]:checked' ) . value ;
var tableId = "graph_" + radioButton + "_table" ;
var table = document . getElementById ( tableId ) ;
table . style . display = "block" ;
for ( var i = 0 ; i < ids . length ; i ++ ) {
if ( ids [ i ] != tableId ) {
table = document . getElementById ( ids [ i ] ) ;
table . style . display = "none" ;
}
}
this . _restoreNodes ( ) ;
if ( radioButton == "R" ) {
this . constants . hierarchicalLayout . enabled = false ;
this . constants . physics . hierarchicalRepulsion . enabeled = false ;
this . constants . physics . barnesHut . enabled = false ;
}
else if ( radioButton == "H" ) {
this . constants . hierarchicalLayout . enabled = true ;
this . constants . physics . hierarchicalRepulsion . enabeled = true ;
this . constants . physics . barnesHut . enabled = false ;
this . _setupHierarchicalLayout ( ) ;
}
else {
this . constants . hierarchicalLayout . enabled = false ;
this . constants . physics . hierarchicalRepulsion . enabeled = false ;
this . constants . physics . barnesHut . enabled = true ;
}
this . _loadSelectedForceSolver ( ) ;
this . moving = true ;
this . start ( ) ;
}
function showValueOfRange ( id , map , constantsVariableName ) {
var valueId = id + "_value" ;
var rangeValue = document . getElementById ( id ) . value ;
if ( constantsVariableName == "hierarchicalLayout_direction" ||
constantsVariableName == "hierarchicalLayout_levelSeparation" ||
constantsVariableName == "hierarchicalLayout_nodeSpacing" ) {
this . _setupHierarchicalLayout ( ) ;
}
if ( map instanceof Array ) {
document . getElementById ( valueId ) . value = map [ parseInt ( rangeValue ) ] ;
this . _overWriteGraphConstants ( constantsVariableName , map [ parseInt ( rangeValue ) ] ) ;
}
else {
document . getElementById ( valueId ) . value = map * parseFloat ( rangeValue ) ;
this . _overWriteGraphConstants ( constantsVariableName , map * parseFloat ( rangeValue ) ) ;
}
this . moving = true ;
this . start ( ) ;
} ;
/ * *
* Created by Alex on 2 / 10 / 14.
* /
@ -11643,7 +12301,7 @@ var hierarchalRepulsionMixin = {
// repulsing forces between nodes
var nodeDistance = this . constants . physics . repulsion . nodeDistance ;
var nodeDistance = this . constants . physics . hie rarchicalR epulsion. nodeDistance ;
var minimumDistance = nodeDistance ;
// we loop from i over all but the last entree in the array
@ -12397,7 +13055,24 @@ var HierarchicalLayoutMixin = {
}
}
}
} ,
/ * *
* Unfix nodes
*
* @ private
* /
_restoreNodes : function ( ) {
for ( nodeId in this . nodes ) {
if ( this . nodes . hasOwnProperty ( nodeId ) ) {
this . nodes [ nodeId ] . xFixed = false ;
this . nodes [ nodeId ] . yFixed = false ;
}
}
}
} ;
/ * *
* Created by Alex on 2 / 4 / 14.
@ -14930,6 +15605,7 @@ var SelectionMixin = {
this . _unselectAll ( ) ;
}
}
this . emit ( "click" , this . getSelection ( ) ) ;
this . _redraw ( ) ;
} ,
@ -14948,6 +15624,7 @@ var SelectionMixin = {
"y" : this . _canvasToY ( pointer . y ) } ;
this . openCluster ( node ) ;
}
this . emit ( "doubleClick" , this . getSelection ( ) ) ;
} ,
@ -15302,51 +15979,12 @@ var graphMixinLoaders = {
_loadPhysicsSystem : function ( ) {
this . _loadMixin ( physicsMixin ) ;
this . _loadSelectedForceSolver ( ) ;
} ,
/ * *
* This loads the node force solver based on the barnes hut or repulsion algorithm
*
* @ private
* /
_loadSelectedForceSolver : function ( ) {
// this overloads the this._calculateNodeForces
if ( this . constants . physics . barnesHut . enabled == true ) {
this . _clearMixin ( repulsionMixin ) ;
this . _clearMixin ( hierarchalRepulsionMixin ) ;
this . constants . physics . centralGravity = this . constants . physics . barnesHut . centralGravity ;
this . constants . physics . springLength = this . constants . physics . barnesHut . springLength ;
this . constants . physics . springConstant = this . constants . physics . barnesHut . springConstant ;
this . constants . physics . damping = this . constants . physics . barnesHut . damping ;
this . _loadMixin ( barnesHutMixin ) ;
}
else if ( this . constants . physics . hierarchicalRepulsion . enabled == true ) {
this . _clearMixin ( barnesHutMixin ) ;
this . _clearMixin ( repulsionMixin ) ;
this . constants . physics . centralGravity = this . constants . physics . hierarchicalRepulsion . centralGravity ;
this . constants . physics . springLength = this . constants . physics . hierarchicalRepulsion . springLength ;
this . constants . physics . springConstant = this . constants . physics . hierarchicalRepulsion . springConstant ;
this . constants . physics . damping = this . constants . physics . hierarchicalRepulsion . damping ;
this . _loadMixin ( hierarchalRepulsionMixin ) ;
if ( this . constants . configurePhysics == true ) {
this . _loadPhysicsConfiguration ( ) ;
}
else {
this . _clearMixin ( barnesHutMixin ) ;
this . _clearMixin ( hierarchalRepulsionMixin ) ;
this . barnesHutTree = undefined ;
} ,
this . constants . physics . centralGravity = this . constants . physics . repulsion . centralGravity ;
this . constants . physics . springLength = this . constants . physics . repulsion . springLength ;
this . constants . physics . springConstant = this . constants . physics . repulsion . springConstant ;
this . constants . physics . damping = this . constants . physics . repulsion . damping ;
this . _loadMixin ( repulsionMixin ) ;
}
} ,
/ * *
@ -15573,6 +16211,7 @@ function Graph (container, data, options) {
altLength : undefined
}
} ,
configurePhysics : false ,
physics : {
barnesHut : {
enabled : true ,
@ -15971,6 +16610,7 @@ Graph.prototype.setOptions = function (options) {
if ( options . stabilize !== undefined ) { this . stabilize = options . stabilize ; }
if ( options . selectable !== undefined ) { this . selectable = options . selectable ; }
if ( options . smoothCurves !== undefined ) { this . constants . smoothCurves = options . smoothCurves ; }
if ( options . configurePhysics !== undefined ) { this . constants . configurePhysics = options . configurePhysics ; }
if ( options . onAdd ) {
this . triggerFunctions . add = options . onAdd ;