Skip to content

Commit

Permalink
Update extension to allow functions for some options iVis-at-Bilkent/…
Browse files Browse the repository at this point in the history
  • Loading branch information
hasanbalci committed Jan 6, 2021
1 parent 3bfc61d commit 3f43c7c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 24 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@ var options = {
randomize: true, // use random node positions at beginning of layout

// Node repulsion (non overlapping) multiplier
nodeRepulsion: 4500,
nodeRepulsion: node => 4500,

// Ideal edge (non nested) length
idealEdgeLength: 50,
idealEdgeLength: edge => 50,

// Divisor to compute edge forces
edgeElasticity: 0.45,
edgeElasticity: edge => 0.45,

// Nesting factor (multiplier) to compute ideal edge length for nested edges
nestingFactor: 0.1,
Expand Down
45 changes: 36 additions & 9 deletions cytoscape-cosep.js
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,8 @@ CoSEPLayout.prototype.initSpringEmbedder = function () {

this.maxIterations = CoSEPConstants.PHASE1_MAX_ITERATIONS;

// Reassign this attribute by using new constant value
this.displacementThresholdPerNode = 3.0 * FDLayoutConstants.DEFAULT_EDGE_LENGTH / 100;
this.totalDisplacementThreshold = this.displacementThresholdPerNode * this.getAllNodes().length;

this.repulsionRange = this.calcRepulsionRange();
Expand Down Expand Up @@ -863,7 +865,7 @@ CoSEPLayout.prototype.secondPhaseInit = function () {
if (length == 0) return;

// Calculate spring forces
var springForce = this.springConstant * (length - idealLength);
var springForce = edge.edgeElasticity * (length - idealLength);

// Project force onto x and y axes
var springForceX = springForce * (edge.lengthX / length);
Expand Down Expand Up @@ -1601,15 +1603,23 @@ var defaults = {
// Include labels in node dimensions
nodeDimensionsIncludeLabels: false,
// Node repulsion (non overlapping) multiplier
nodeRepulsion: 4500,
nodeRepulsion: function nodeRepulsion(node) {
return 4500;
},
// Ideal edge (non nested) length
idealEdgeLength: 50,
idealEdgeLength: function idealEdgeLength(edge) {
return 50;
},
// Divisor to compute edge forces
edgeElasticity: 0.45,
edgeElasticity: function edgeElasticity(edge) {
return 0.45;
},
// Nesting factor (multiplier) to compute ideal edge length for nested edges
nestingFactor: 0.1,
// Gravity force (constant)
gravity: 0.25,
// For enabling tiling
tile: true,
// Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function)
tilingPaddingVertical: 10,
// Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function)
Expand All @@ -1629,9 +1639,6 @@ var defaults = {
* @param options
*/
var getUserOptions = function getUserOptions(options) {
if (options.nodeRepulsion != null) CoSEPConstants.DEFAULT_REPULSION_STRENGTH = CoSEConstants.DEFAULT_REPULSION_STRENGTH = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = options.nodeRepulsion;
if (options.idealEdgeLength != null) CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = options.idealEdgeLength;
if (options.edgeElasticity != null) CoSEPConstants.DEFAULT_SPRING_STRENGTH = CoSEConstants.DEFAULT_SPRING_STRENGTH = FDLayoutConstants.DEFAULT_SPRING_STRENGTH = options.edgeElasticity;
if (options.nestingFactor != null) CoSEPConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = CoSEConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = options.nestingFactor;
if (options.gravity != null) CoSEPConstants.DEFAULT_GRAVITY_STRENGTH = CoSEConstants.DEFAULT_GRAVITY_STRENGTH = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH = options.gravity;
if (options.gravityRange != null) CoSEPConstants.DEFAULT_GRAVITY_RANGE_FACTOR = CoSEConstants.DEFAULT_GRAVITY_RANGE_FACTOR = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR = options.gravityRange;
Expand Down Expand Up @@ -1733,6 +1740,8 @@ var Layout = function (_ContinuousLayout) {
this.processChildrenList(this.root, this.getTopMostNodes(nodes), cosepLayout);

// Adding edges to GraphManager
var idealLengthTotal = 0;
var edgeCount = 0;
for (var i = 0; i < edges.length; i++) {
var edge = edges[i];
var sourceNode = this.idToLNode[edge.data("source")];
Expand All @@ -1741,6 +1750,10 @@ var Layout = function (_ContinuousLayout) {
(function () {
var gmEdge = graphManager.add(cosepLayout.newEdge(), sourceNode, targetNode);
gmEdge.id = edge.id();
gmEdge.idealLength = optFn(_this2.options.idealEdgeLength, edge);
gmEdge.edgeElasticity = optFn(_this2.options.edgeElasticity, edge);
idealLengthTotal += gmEdge.idealLength;
edgeCount++;

/**
* Setting variables related to port constraints
Expand Down Expand Up @@ -1795,6 +1808,17 @@ var Layout = function (_ContinuousLayout) {
}
}

// We need to update the ideal edge length constant with the avg. ideal length value after processing edges
// in case there is no edge, use other options
if (this.options.idealEdgeLength != null) {
if (edges.length > 0) CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = idealLengthTotal / edgeCount;else if (!isFn(this.options.idealEdgeLength)) // in case there is no edge, but option gives a value to use
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = this.options.idealEdgeLength;else // in case there is no edge and we cannot get a value from option (because it's a function)
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = 50;
// we need to update these constant values based on the ideal edge length constant
CoSEPConstants.MIN_REPULSION_DIST = CoSEConstants.MIN_REPULSION_DIST = FDLayoutConstants.MIN_REPULSION_DIST = FDLayoutConstants.DEFAULT_EDGE_LENGTH / 10.0;
CoSEPConstants.DEFAULT_RADIAL_SEPARATION = CoSEConstants.DEFAULT_RADIAL_SEPARATION = FDLayoutConstants.DEFAULT_EDGE_LENGTH;
}

// Saving the references
this.graphManager.nodesWithPorts = Object.values(this.nodesWithPorts);

Expand Down Expand Up @@ -1879,7 +1903,9 @@ var Layout = function (_ContinuousLayout) {
this.graphManager.calcLowestCommonAncestors();
this.graphManager.calcInclusionTreeDepths();
this.graphManager.getRoot().calcEstimatedSize();
this.cosepLayout.calcIdealEdgeLengths();
// Ideal edge lengths should be calculated once and it's done above,
// this is because calcIdealEdgeLengths doesn't calculate ideal lengths from a constant anymore
// this.cosepLayout.calcIdealEdgeLengths();
this.graphManager.updateBounds();
this.cosepLayout.level = 0;
this.cosepLayout.initSpringEmbedder();
Expand Down Expand Up @@ -1942,8 +1968,9 @@ var Layout = function (_ContinuousLayout) {
} else {
theNode = parent.add(new CoSEPNode(this.graphManager));
}
// Attach id to the layout node
// Attach id and repulsion value to the layout node
theNode.id = theChild.data("id");
theNode.nodeRepulsion = optFn(this.options.nodeRepulsion, theChild);

// Attach the paddings of cy node to layout node
theNode.paddingLeft = parseInt(theChild.css('padding'));
Expand Down
4 changes: 3 additions & 1 deletion src/CoSEP/CoSEPLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ CoSEPLayout.prototype.initSpringEmbedder = function () {

this.maxIterations = CoSEPConstants.PHASE1_MAX_ITERATIONS;

// Reassign this attribute by using new constant value
this.displacementThresholdPerNode = (3.0 * FDLayoutConstants.DEFAULT_EDGE_LENGTH) / 100;
this.totalDisplacementThreshold =
this.displacementThresholdPerNode * this.getAllNodes().length;

Expand Down Expand Up @@ -133,7 +135,7 @@ CoSEPLayout.prototype.secondPhaseInit = function(){
return;

// Calculate spring forces
let springForce = this.springConstant * (length - idealLength);
let springForce = edge.edgeElasticity * (length - idealLength);

// Project force onto x and y axes
let springForceX = springForce * (edge.lengthX / length);
Expand Down
41 changes: 30 additions & 11 deletions src/layout/CoSEP.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,17 @@ let defaults = {
// Include labels in node dimensions
nodeDimensionsIncludeLabels: false,
// Node repulsion (non overlapping) multiplier
nodeRepulsion: 4500,
nodeRepulsion: node => 4500,
// Ideal edge (non nested) length
idealEdgeLength: 50,
idealEdgeLength: edge => 50,
// Divisor to compute edge forces
edgeElasticity: 0.45,
edgeElasticity: edge => 0.45,
// Nesting factor (multiplier) to compute ideal edge length for nested edges
nestingFactor: 0.1,
// Gravity force (constant)
gravity: 0.25,
// For enabling tiling
tile: true,
// Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function)
tilingPaddingVertical: 10,
// Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function)
Expand All @@ -82,12 +84,6 @@ let defaults = {
* @param options
*/
let getUserOptions = function (options) {
if (options.nodeRepulsion != null)
CoSEPConstants.DEFAULT_REPULSION_STRENGTH = CoSEConstants.DEFAULT_REPULSION_STRENGTH = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = options.nodeRepulsion;
if (options.idealEdgeLength != null)
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = options.idealEdgeLength;
if (options.edgeElasticity != null)
CoSEPConstants.DEFAULT_SPRING_STRENGTH = CoSEConstants.DEFAULT_SPRING_STRENGTH = FDLayoutConstants.DEFAULT_SPRING_STRENGTH = options.edgeElasticity;
if (options.nestingFactor != null)
CoSEPConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = CoSEConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = options.nestingFactor;
if (options.gravity != null)
Expand Down Expand Up @@ -205,13 +201,19 @@ class Layout extends ContinuousLayout {
this.processChildrenList(this.root, this.getTopMostNodes(nodes), cosepLayout);

// Adding edges to GraphManager
let idealLengthTotal = 0;
let edgeCount = 0;
for (let i = 0; i < edges.length; i++) {
let edge = edges[i];
let sourceNode = this.idToLNode[edge.data("source")];
let targetNode = this.idToLNode[edge.data("target")];
if(sourceNode !== targetNode && sourceNode.getEdgesBetween(targetNode).length === 0){
let gmEdge = graphManager.add(cosepLayout.newEdge(), sourceNode, targetNode);
gmEdge.id = edge.id();
gmEdge.idealLength = optFn(this.options.idealEdgeLength, edge);
gmEdge.edgeElasticity = optFn(this.options.edgeElasticity, edge);
idealLengthTotal += gmEdge.idealLength;
edgeCount++;

/**
* Setting variables related to port constraints
Expand Down Expand Up @@ -266,6 +268,20 @@ class Layout extends ContinuousLayout {
}
}
}

// We need to update the ideal edge length constant with the avg. ideal length value after processing edges
// in case there is no edge, use other options
if (this.options.idealEdgeLength != null){
if (edges.length > 0)
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = idealLengthTotal / edgeCount;
else if(!isFn(this.options.idealEdgeLength)) // in case there is no edge, but option gives a value to use
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = this.options.idealEdgeLength;
else // in case there is no edge and we cannot get a value from option (because it's a function)
CoSEPConstants.DEFAULT_EDGE_LENGTH = CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = 50;
// we need to update these constant values based on the ideal edge length constant
CoSEPConstants.MIN_REPULSION_DIST = CoSEConstants.MIN_REPULSION_DIST = FDLayoutConstants.MIN_REPULSION_DIST = FDLayoutConstants.DEFAULT_EDGE_LENGTH / 10.0;
CoSEPConstants.DEFAULT_RADIAL_SEPARATION = CoSEConstants.DEFAULT_RADIAL_SEPARATION = FDLayoutConstants.DEFAULT_EDGE_LENGTH;
}

// Saving the references
this.graphManager.nodesWithPorts = Object.values(this.nodesWithPorts);
Expand Down Expand Up @@ -341,7 +357,9 @@ class Layout extends ContinuousLayout {
this.graphManager.calcLowestCommonAncestors();
this.graphManager.calcInclusionTreeDepths();
this.graphManager.getRoot().calcEstimatedSize();
this.cosepLayout.calcIdealEdgeLengths();
// Ideal edge lengths should be calculated once and it's done above,
// this is because calcIdealEdgeLengths doesn't calculate ideal lengths from a constant anymore
// this.cosepLayout.calcIdealEdgeLengths();
this.graphManager.updateBounds();
this.cosepLayout.level = 0;
this.cosepLayout.initSpringEmbedder();
Expand Down Expand Up @@ -403,8 +421,9 @@ class Layout extends ContinuousLayout {
else {
theNode = parent.add(new CoSEPNode(this.graphManager));
}
// Attach id to the layout node
// Attach id and repulsion value to the layout node
theNode.id = theChild.data("id");
theNode.nodeRepulsion = optFn(this.options.nodeRepulsion, theChild);

// Attach the paddings of cy node to layout node
theNode.paddingLeft = parseInt(theChild.css('padding'));
Expand Down

0 comments on commit 3f43c7c

Please sign in to comment.