cytoscape-automove
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -7,3 +7,3 @@ ;(function(){ 'use strict'; | ||
// - a selector that matches the nodes | ||
// - a collection or array of nodes (very good for performance) | ||
// - a collection of nodes (very good for performance) | ||
nodesMatching: function( node ){ return false; }, | ||
@@ -16,4 +16,17 @@ | ||
// - 'viewport' => keeps the node body within the viewport | ||
// - 'drag' => matching nodes are effectively dragged along | ||
reposition: 'mean', | ||
// for `reposition: 'mean'`, specify nodes that should be ignored in the mean calculation | ||
// - a function that returns true for nodes to be ignored | ||
// - a selector that matches the nodes to be ignored | ||
// - a collection of nodes to be ignored (very good for performance) | ||
meanIgnores: function( node ){ return false; }, | ||
// for `reposition: 'drag'`, specify nodes that when dragged cause the matched nodes to move along | ||
// - a function that returns true for nodes to be listened to for drag events | ||
// - a selector that matches the nodes to be listened to for drag events | ||
// - a collection of nodes to be ignored (very good for performance) | ||
dragWith: function( node ){ return false; }, | ||
// specify when the repositioning should occur by specifying a function that | ||
@@ -27,2 +40,3 @@ // calls update() when reposition updates should occur | ||
// - reposition: 'viewport' | ||
// - reposition: 'drag' | ||
// - default/undefined => on a position event for any node (not as efficient...) | ||
@@ -39,2 +53,3 @@ when: undefined | ||
var isFunction = function( x ){ return typeof x === typeofFn; }; | ||
var isCollection = function( x ){ return isObject( x ) && isFunction( x.collection ) }; | ||
@@ -54,9 +69,29 @@ // Object.assign() polyfill | ||
var eleMatchesSpec = function( ele, spec ){ | ||
if( ele == null || ele.removed() ){ | ||
return false; | ||
} else if( isString( spec ) ){ | ||
return ele.is( spec ); | ||
var eleExists = function( ele ){ | ||
return ele != null && !ele.removed(); | ||
}; | ||
var elesHasEle = function( eles, ele ){ | ||
if( eles.has != undefined ){ // 3.x | ||
elesHasEle = function( eles, ele ){ return eles.has( ele ); }; | ||
} else { // 2.x | ||
elesHasEle = function( eles, ele ){ return eles.intersection( ele ).length > 0; }; | ||
} | ||
return elesHasEle( eles, ele ); | ||
}; | ||
var getEleMatchesSpecFn = function( spec ){ | ||
if( isString( spec ) ){ | ||
return function( ele ){ | ||
return ele.is( spec ); | ||
}; | ||
} else if( isFunction( spec ) ){ | ||
return spec; | ||
} else if( isCollection( spec ) ){ | ||
return function( ele ){ | ||
return elesHasEle( spec, ele ); | ||
}; | ||
} else { | ||
return spec( ele ); | ||
throw new Error('Can not create match function for spec', spec); | ||
} | ||
@@ -101,36 +136,56 @@ }; | ||
var getRepositioner = function( spec, cy ){ | ||
if( spec === 'mean' ){ | ||
return meanNeighborhoodPosition; | ||
} else if( spec === 'viewport' ){ | ||
var getRepositioner = function( rule, cy ){ | ||
var r = rule.reposition; | ||
if( r === 'mean' ){ | ||
return meanNeighborhoodPosition( getEleMatchesSpecFn( rule.meanIgnores ) ); | ||
} else if( r === 'viewport' ){ | ||
return viewportPosition( cy ); | ||
} else if( isObject( spec ) ){ | ||
return boxPosition( spec ); | ||
} else if( r === 'drag' ){ | ||
return dragAlong( rule ); | ||
} else if( isObject( r ) ){ | ||
return boxPosition( r ); | ||
} else { | ||
return spec; | ||
return r; | ||
} | ||
}; | ||
var meanNeighborhoodPosition = function( node ){ | ||
var nhood = node.neighborhood(); | ||
var avgPos = { x: 0, y: 0 }; | ||
var nhoodSize = 0; | ||
var dragAlong = function( rule ){ | ||
return function( node ){ | ||
var pos = node.position(); | ||
var delta = rule.delta; | ||
for( var i = 0; i < nhood.length; i++ ){ | ||
var nhoodEle = nhood[i]; | ||
if( rule.delta != null && !node.same( rule.grabbedNode ) ){ | ||
return { | ||
x: pos.x + delta.x, | ||
y: pos.y + delta.y | ||
} | ||
} | ||
}; | ||
}; | ||
if( nhoodEle.isNode() ){ | ||
var pos = nhoodEle.position(); | ||
var meanNeighborhoodPosition = function( ignore ){ | ||
return function( node ){ | ||
var nhood = node.neighborhood(); | ||
var avgPos = { x: 0, y: 0 }; | ||
var nhoodSize = 0; | ||
avgPos.x += pos.x; | ||
avgPos.y += pos.y; | ||
for( var i = 0; i < nhood.length; i++ ){ | ||
var nhoodEle = nhood[i]; | ||
nhoodSize++; | ||
if( nhoodEle.isNode() && !ignore( nhoodEle ) ){ | ||
var pos = nhoodEle.position(); | ||
avgPos.x += pos.x; | ||
avgPos.y += pos.y; | ||
nhoodSize++; | ||
} | ||
} | ||
} | ||
avgPos.x /= nhoodSize; | ||
avgPos.y /= nhoodSize; | ||
avgPos.x /= nhoodSize; | ||
avgPos.y /= nhoodSize; | ||
return avgPos; | ||
return avgPos; | ||
}; | ||
}; | ||
@@ -183,3 +238,3 @@ | ||
if( movedNode.neighborhood().some( matches ) ){ | ||
if( movedNode.closedNeighborhood().some( matches ) ){ | ||
update( cy, [ rule ] ); | ||
@@ -201,2 +256,42 @@ } | ||
var dragListener = function( rule ){ | ||
return function( update, cy ){ | ||
bindOnRule( rule, cy, 'grab', 'node', function(){ | ||
var node = this; | ||
if( rule.dragWithMatches( node ) ){ | ||
var p = node.position(); | ||
rule.grabbedNode = node; | ||
rule.p1 = { x: p.x, y: p.y }; | ||
rule.delta = { x: 0, y: 0 }; | ||
} | ||
}); | ||
bindOnRule( rule, cy, 'drag', 'node', function(){ | ||
var node = this; | ||
if( node.same( rule.grabbedNode ) ){ | ||
var d = rule.delta; | ||
var p1 = rule.p1; | ||
var p = node.position(); | ||
var p2 = { x: p.x, y: p.y }; | ||
d.x = p2.x - p1.x; | ||
d.y = p2.y - p1.y; | ||
rule.p1 = p2; | ||
update( cy, [ rule ] ); | ||
} | ||
}); | ||
bindOnRule( rule, cy, 'free', 'node', function(){ | ||
rule.grabbedNode = null; | ||
rule.delta = null; | ||
rule.p1 = null; | ||
}); | ||
}; | ||
}; | ||
var matchingNodesListener = function( rule ){ | ||
@@ -217,2 +312,4 @@ return function( update, cy ){ | ||
return meanListener( rule ); | ||
} else if( rule.reposition === 'drag' ){ | ||
return dragListener( rule ); | ||
} else if( | ||
@@ -232,14 +329,21 @@ isObject( rule.reposition ) | ||
rule.getNewPos = getRepositioner( rule.reposition, cy ); | ||
rule.getNewPos = getRepositioner( rule, cy ); | ||
rule.listener = getListener( cy, rule ); | ||
var nodesAreCollection = isObject( rule.nodesMatching ) && isFunction( rule.nodesMatching.collection ); | ||
var nodesAreCollection = isCollection( rule.nodesMatching ); | ||
if( nodesAreCollection ){ | ||
rule.nodes = rule.nodesMatching; | ||
rule.matches = function( ele ){ return ele != null && rule.nodes.intersection( ele ).length > 0; }; | ||
rule.matches = function( ele ){ return eleExists( ele ) && elesHasEle( rule.nodes, ele ); }; | ||
} else { | ||
rule.matches = function( ele ){ return eleMatchesSpec( ele, rule.nodesMatching ); }; | ||
var matches = getEleMatchesSpecFn( rule.nodesMatching ); | ||
rule.matches = function( ele ){ return eleExists( ele ) && matches( ele ) }; | ||
} | ||
if( rule.dragWith != null ){ | ||
rule.dragWithMatches = getEleMatchesSpecFn( rule.dragWith ); | ||
} | ||
rule.listener( function(){ | ||
@@ -295,3 +399,3 @@ update( cy, [ rule ] ); | ||
var newPos = rule.getNewPos( node ); | ||
var newPosIsDiff = pos.x !== newPos.x || pos.y !== newPos.y; | ||
var newPosIsDiff = newPos != null && ( pos.x !== newPos.x || pos.y !== newPos.y ); | ||
@@ -298,0 +402,0 @@ if( newPosIsDiff ){ // only update on diff for perf |
{ | ||
"name": "cytoscape-automove", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "An extension for Cytoscape.js that automatically updates node positions based on specified rules", | ||
@@ -5,0 +5,0 @@ "main": "cytoscape-automove.js", |
@@ -58,3 +58,3 @@ cytoscape-automove | ||
// - a selector that matches the nodes | ||
// - a collection or array of nodes (very good for performance) | ||
// - a collection of nodes (very good for performance) | ||
nodesMatching: function( node ){ return false; }, | ||
@@ -67,4 +67,17 @@ | ||
// - 'viewport' => keeps the node body within the viewport | ||
// - 'drag' => matching nodes are effectively dragged along | ||
reposition: 'mean', | ||
// for `reposition: 'mean'`, specify nodes that should be ignored in the mean calculation | ||
// - a function that returns true for nodes to be ignored | ||
// - a selector that matches the nodes to be ignored | ||
// - a collection of nodes to be ignored (very good for performance) | ||
meanIgnores: function( node ){ return false; }, | ||
// for `reposition: 'drag'`, specify nodes that when dragged cause the matched nodes to move along (i.e. the master nodes) | ||
// - a function that returns true for nodes to be listened to for drag events | ||
// - a selector that matches the nodes to be listened to for drag events | ||
// - a collection of nodes to be listened to for drag events (very good for performance) | ||
dragWith: function( node ){ return false; }, | ||
// specify when the repositioning should occur by specifying a function that | ||
@@ -78,2 +91,3 @@ // calls update() when reposition updates should occur | ||
// - reposition: 'viewport' | ||
// - reposition: 'drag' | ||
// - default/undefined => on a position event for any node (not as efficient...) | ||
@@ -80,0 +94,0 @@ when: undefined |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
25686
477
133