Skip to content

Commit

Permalink
updated compound node placement so that they dont overlap - added dis…
Browse files Browse the repository at this point in the history
…play initial position option
  • Loading branch information
hamzaislam101 committed Mar 29, 2023
1 parent ad6577b commit 180f988
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 26 deletions.
7 changes: 6 additions & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ <h1>Cytoscape - HySE</h1>
<input class="form-check-input" type="checkbox" id="performPostProcessing" checked>
</div>

<div class="row">
<label class="form-label" for="displayInitialPositions">Display Initial Positions</label>
<input class="form-check-input" type="checkbox" id="displayInitialPositions">
</div>

<div class="row">
<button title="Delete Selected Items" onclick="deleteSelected()">Delete Selected</button>
</div>
Expand Down Expand Up @@ -381,4 +386,4 @@ <h2 class="accordion-header" id="panelsStayOpen-headingOne">

</body>

</html>
</html>
3 changes: 2 additions & 1 deletion demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ function getOptions() {
"maxNodeDisplacement",
"expansionCoefficient",
"performPostProcessing",
"displayInitialPositions",
];
const o = { name: "hyse" };
for (let i = 0; i < opts.length; i++) {
Expand Down Expand Up @@ -360,4 +361,4 @@ function loadGraph(){

function deleteSelected(){
cy.$(':selected').remove();
}
}
164 changes: 141 additions & 23 deletions src/hyse-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class HySELayout extends CoSELayout {
oldDirectedDisplacement = 0;
oldUndirectedDisplacement = 0;
performPostProcessing = true;
displayInitialPositions = false;
[x: string]: any;
constructor(layering, cy) {
console.trace();
Expand Down Expand Up @@ -221,6 +222,10 @@ export class HySELayout extends CoSELayout {
let mostRightNode = this.graphManager.allNodes[0];
let mostTopNode = this.graphManager.allNodes[0];
let mostBottomNode = this.graphManager.allNodes[0];
let leftCompoundNodes:HySENode[] = [];
let rightCompoundNodes:HySENode[] = [];
let topCompoundNodes:HySENode[] = [];
let bottomCompoundNodes:HySENode[] = [];
let allUndirected = true;
if(this.orderedLayers.length > 0){
allUndirected = false;
Expand Down Expand Up @@ -327,9 +332,12 @@ export class HySELayout extends CoSELayout {
let distanceLeft = Math.abs(xCenter-mostLeftNode.getCenterX());
let distanceRight = Math.abs(xCenter-mostRightNode.getCenterX());

let up = distanceUp < distanceDown?true:false;
let left = distanceLeft < distanceRight?true:false;

let min = Math.min(distanceUp,distanceDown,distanceLeft,distanceRight);
let up = distanceUp == min?true:false;
let left = distanceLeft == min?true:false;
let right = distanceRight == min?true:false;
let down = distanceDown == min?true:false;



//find the closest point on the rectangle whose sides are mostLeftNode, mostRightNode, mostTopNode, mostBottomNode
Expand All @@ -338,6 +346,126 @@ export class HySELayout extends CoSELayout {


let seedCenter = new layoutBase.PointD(xCenter,yCenter);

let placeNewNode = function(newNode:HySENode,side:string,nodesToCheck:HySENode[]){
if(side == "right"){
//check if the node is colliding with any other node
let colliding = false;
let collidingNode:any = null;
nodesToCheck.forEach(x=>{
if(newNode.rect.intersects(x.rect)){
if(collidingNode != null && collidingNode instanceof HySENode){
if(collidingNode.rect.x + collidingNode.rect.width < x.rect.x + x.rect.width){
collidingNode = x;
}
colliding = true;
}
else{
collidingNode = x;
colliding = true;
}
}
});
if(colliding && collidingNode != null){
newNode.setRect({x:collidingNode.rect.x + collidingNode.rect.width + 50,y:seedCenter.y - (newNode.rect.height/2)},newNode.rect);
placeNewNode(newNode,side,nodesToCheck);
}

}
else if(side == "left"){
//check if the node is colliding with any other node
let colliding = false;
let collidingNode:any = null;
nodesToCheck.forEach(x=>{
if(newNode.rect.intersects(x.rect)){
if(collidingNode != null && collidingNode instanceof HySENode){
if(collidingNode.rect.x - collidingNode.rect.width > x.rect.x - x.rect.width){
collidingNode = x;
}
colliding = true;
}
else{
collidingNode = x;
colliding = true;
}
}
});
if(colliding && collidingNode != null){
newNode.setRect({x:collidingNode.rect.x - newNode.rect.width - 50,y:seedCenter.y - (newNode.rect.height/2)},newNode.rect);
placeNewNode(newNode,side,nodesToCheck);
}
}
else if(side == "up"){
//check if the node is colliding with any other node
let colliding = false;
let collidingNode:any = null;
nodesToCheck.forEach(x=>{
if(newNode.rect.intersects(x.rect)){
if(collidingNode != null && collidingNode instanceof HySENode){
if(collidingNode.rect.y - collidingNode.rect.height > x.rect.y - x.rect.height){
collidingNode = x;
}
colliding = true;
}
else{
collidingNode = x;
colliding = true;
}
}
});
if(colliding && collidingNode != null){
newNode.setRect({x:seedCenter.x - (newNode.rect.width/2),y:collidingNode.rect.y - newNode.rect.height - 50},newNode.rect);
placeNewNode(newNode,side,nodesToCheck);
}
}
else if(side == "down"){
//check if the node is colliding with any other node
let colliding = false;
let collidingNode:any = null;
nodesToCheck.forEach(x=>{
if(newNode.rect.intersects(x.rect)){
if(collidingNode != null && collidingNode instanceof HySENode){
if(collidingNode.rect.y + collidingNode.rect.height < x.rect.y + x.rect.height){
collidingNode = x;
}
colliding = true;
}
else{
collidingNode = x;
colliding = true;
}
}
});
if(colliding && collidingNode != null){
newNode.setRect({x:seedCenter.x - (newNode.rect.width/2),y:collidingNode.rect.y + collidingNode.rect.height + 50},newNode.rect);
placeNewNode(newNode,side,nodesToCheck);
}
}
}

if(up){
newNode.setRect({x:seedCenter.x - (newNode.rect.width/2),y:mostTopNode.rect.y - newNode.rect.height - 50},newNode.rect);
placeNewNode(newNode,"up",topCompoundNodes);
topCompoundNodes.push(newNode);
}
else if(down){
newNode.setRect({x:seedCenter.x - (newNode.rect.width/2),y:mostBottomNode.rect.y + mostBottomNode.rect.height + 50},newNode.rect);
placeNewNode(newNode,"down",bottomCompoundNodes);
bottomCompoundNodes.push(newNode);
}
else if(left){
newNode.setRect({x:mostLeftNode.rect.x - newNode.rect.width - 50,y:seedCenter.y - (newNode.rect.height/2)},newNode.rect);
placeNewNode(newNode,"left",leftCompoundNodes);
leftCompoundNodes.push(newNode);
}
else if(right){
newNode.setRect({x:mostRightNode.rect.x + mostRightNode.rect.width + 50,y:seedCenter.y - (newNode.rect.height/2)},newNode.rect);
placeNewNode(newNode,"right",rightCompoundNodes);
rightCompoundNodes.push(newNode);
}



//add the nodes in the group to the new node
group.forEach(x=>{
//get random position for the node within the compound node
Expand All @@ -346,61 +474,51 @@ export class HySELayout extends CoSELayout {
if(left && up){
if(distanceUp < distanceLeft){
//up
randomChildY = mostTopNode.rect.y - Math.floor(Math.random() * newNode.rect.height) -50;
randomChildY = newNode.rect.y + Math.floor(Math.random() * newNode.rect.height) -50;
randomChildX = seedCenter.x - (newNode.rect.width/2) + Math.floor(Math.random() * newNode.rect.width);
}
else{
//left
randomChildX = mostLeftNode.rect.x - Math.floor(Math.random() * newNode.rect.width) -50;
randomChildX = newNode.rect.x + Math.floor(Math.random() * newNode.rect.width) -50;
randomChildY = seedCenter.y - (newNode.rect.height/2) + Math.floor(Math.random() * newNode.rect.height);
}
}
else if(left && !up){
if(distanceDown < distanceLeft){
//down
randomChildY = mostBottomNode.rect.y + mostBottomNode.rect.height + Math.floor(Math.random() * newNode.rect.height) +50;
randomChildY = newNode.rect.y + Math.floor(Math.random() * newNode.rect.height) +50;
randomChildX = seedCenter.x - (newNode.rect.width/2) + Math.floor(Math.random() * newNode.rect.width);
}
else{
//left
randomChildX = mostLeftNode.rect.x - Math.floor(Math.random() * newNode.rect.width) -100;
randomChildX = newNode.rect.x + Math.floor(Math.random() * newNode.rect.width) -100;
randomChildY = seedCenter.y - (newNode.rect.height/2) + Math.floor(Math.random() * newNode.rect.height);
}
}
else if(!left && up){
if(distanceUp < distanceRight){
//up
randomChildY = mostTopNode.rect.y - Math.floor(Math.random() * newNode.rect.height) -50;
randomChildY = newNode.rect.y + Math.floor(Math.random() * newNode.rect.height) -50;
randomChildX = seedCenter.x - (newNode.rect.width/2) + Math.floor(Math.random() * newNode.rect.width);
}
else{
//right
randomChildX = mostRightNode.rect.x + mostRightNode.rect.width + Math.floor(Math.random() * newNode.rect.width) +100;
randomChildX = newNode.rect.x + Math.floor(Math.random() * newNode.rect.width);
randomChildY = seedCenter.y - (newNode.rect.height/2) + Math.floor(Math.random() * newNode.rect.height);
}
}
else{
if(distanceDown < distanceRight){
//down
randomChildY = mostBottomNode.rect.y + mostBottomNode.rect.height + Math.floor(Math.random() * newNode.rect.height) +50;
randomChildY = newNode.rect.y + Math.floor(Math.random() * newNode.rect.height) +50;
randomChildX = seedCenter.x - (newNode.rect.width/2) + Math.floor(Math.random() * newNode.rect.width);
}
else{
//right
randomChildX = mostRightNode.rect.x + mostRightNode.rect.width + Math.floor(Math.random() * newNode.rect.width) +100;
randomChildX = newNode.rect.x + Math.floor(Math.random() * newNode.rect.width) +100;
randomChildY = seedCenter.y - (newNode.rect.height/2) + Math.floor(Math.random() * newNode.rect.height);
}
}
//randomChildY = newNode.rect.height*Math.random() + seedCenter.y - newNode.rect.height/2;


// if(up){

// randomChildY = (seedCenter.y/2) + Math.floor(Math.random() * newNode.rect.height);
// }
// else{
// randomChildY = (seedCenter.y/2) - Math.floor(Math.random() * newNode.rect.height);
// }

let childpoints = new layoutBase.PointD(randomChildX, randomChildY);
x.setRect(childpoints,x.rect);
Expand Down Expand Up @@ -457,11 +575,11 @@ export class HySELayout extends CoSELayout {
this.beforeLayout();
console.log(this.graphManager.getAllNodes());
let layoutEnded = false;
while (!layoutEnded) {
while (!this.displayInitialPositions && !layoutEnded) {
layoutEnded = this.tick();
}

if(this.performPostProcessing){
if(!this.displayInitialPositions && this.performPostProcessing){
//this.postLayoutOverlapRemoval();
this.postLayoutRepulsionPhase();
}
Expand Down
3 changes: 2 additions & 1 deletion src/spring-embedder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export function runSpringEmbedder(g, layering: string[][], opts, cy) {
l.expansionCoefficient = opts.expansionCoefficient;
l.orderGap = opts.orderGap;
l.performPostProcessing = opts.performPostProcessing;
l.displayInitialPositions = opts.displayInitialPositions;
coseBase.CoSEConstants.TILE = false;
console.log("opts: " ,opts);

Expand Down Expand Up @@ -280,4 +281,4 @@ function randomizeOrderInLayers(layering: any[][]) {
for (let i = 0; i < layering.length; i++) {
layering[i].sort(() => Math.random() - 0.5);
}
}
}

0 comments on commit 180f988

Please sign in to comment.