Skip to content

Commit

Permalink
fix: vertical flow support
Browse files Browse the repository at this point in the history
  • Loading branch information
sheikalthaf committed Nov 14, 2023
1 parent 7175132 commit 11759af
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 167 deletions.
68 changes: 48 additions & 20 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,61 @@
import { Component, ViewChild, inject } from '@angular/core';
import { NgForOf } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { FlowChildComponent } from './flow/flow-child.component';
import { FlowComponent } from './flow/flow.component';
import { FlowOptions } from './flow/flow-interface';

@Component({
selector: 'app-root',
standalone: true,
imports: [NgForOf, RouterOutlet, FlowComponent, FlowChildComponent],
imports: [
NgForOf,
RouterOutlet,
ReactiveFormsModule,
FlowComponent,
FlowChildComponent,
],
template: `
<button (click)="trigger()">Arrange</button>
<label for="zoomingId">
<input
id="zoomingId"
type="checkbox"
[checked]="zooming"
(click)="zoomingFn()"
/>zooming
</label>
<label for="childDraggingId">
<input
id="childDraggingId"
type="checkbox"
[checked]="childDragging"
(click)="childDraggingFn()"
/>Child Dragging
</label>
<button (click)="fitToWindow()">Fit to window</button>
<div class="flex items-center gap-3">
<button (click)="trigger()">Arrange</button>
<label for="zoomingId">
<input
id="zoomingId"
type="checkbox"
[checked]="zooming"
(click)="zoomingFn()"
/>zooming
</label>
<label for="childDraggingId">
<input
id="childDraggingId"
type="checkbox"
[checked]="childDragging"
(click)="childDraggingFn()"
/>Child Dragging
</label>
<button (click)="fitToWindow()">Fit to window</button>
<!-- radio group for horizontal or vertical -->
<label for="direction">
<input
id="direction"
type="radio"
[value]="'horizontal'"
[formControl]="direction"
/>Horizontal
</label>
<label for="direction1">
<input
id="direction1"
type="radio"
[value]="'vertical'"
[formControl]="direction"
/>Vertical
</label>
</div>
<div class="flex items-center justify-center h-[700px]">
<app-flow class="max-w-[90%] max-h-[90%] border">
<div
Expand Down Expand Up @@ -83,6 +110,7 @@ export class AppComponent {
list: FlowOptions[] = [];
zooming = true;
childDragging = true;
direction = new FormControl<'horizontal' | 'vertical'>('horizontal');
linkingFrom: number | null = null; // Store the index of the node that we start linking from
@ViewChild(FlowComponent) flowComponent: FlowComponent;

Expand Down
88 changes: 29 additions & 59 deletions src/app/flow/arrangements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,22 @@ export class Arrangements {
public autoArrange(): Map<string, FlowOptions> {
const newItems = new Map<string, FlowOptions>();
let currentX = 0;
let currentY = 0;

if (this.direction === 'horizontal') {
// Start by positioning the base nodes
const baseNodes = this.list.filter(
(node) => node.position.deps.length === 0
);

let level = 0;
// Handle both horizontal and vertical directions
const baseNodes = this.list.filter(
(node) => node.position.deps.length === 0
);

for (const baseNode of baseNodes) {
const consumedHeight = this.positionDependents(
baseNode,
0,
0,
newItems
);
// const centerY = consumedHeight / 2;
// newItems.set(baseNode.position.id, {
// ...baseNode.position,
// x: currentX,
// y: centerY - baseNode.elRect.height / 2,
// });
for (const baseNode of baseNodes) {
if (this.direction === 'horizontal') {
this.positionDependents(baseNode, currentX, 0, newItems);
currentX += baseNode.elRect.width + this.horizontalPadding;
} else {
// Vertical arrangement
this.positionDependents(baseNode, 0, currentY, newItems);
currentY += baseNode.elRect.height + this.horizontalPadding;
}
} else {
// direction === 'vertical'
// let currentY = 0;
// for (const level in levelsMap) {
// const itemsInLevel = levelsMap[level];
// let currentX = 0;
// // Sort items within the level by their current x position
// itemsInLevel.sort((a, b) => a.position.x - b.position.x);
// for (const node of itemsInLevel) {
// const newNode: FlowOptions = {
// ...node.position,
// x: currentX,
// y: currentY,
// };
// currentX += node.elRect.width + this.horizontalPadding;
// newItems.set(node.position.id, newNode);
// }
// const maxHeightItem = itemsInLevel.reduce((max, item) => {
// return item.elRect.height > max.elRect.height ? item : max;
// }, itemsInLevel[0]);
// currentY +=
// maxHeightItem.elRect.height +
// this.verticalPadding +
// this.groupPadding;
// }
}

return newItems;
Expand All @@ -77,14 +44,17 @@ export class Arrangements {
gp: -this.groupPadding * 2,
maxDepLength: 0,
}
): { consumedHeight: number; dep: boolean } {
): { consumedSpace: number; dep: boolean } {
const dependents = this.list.filter((child) =>
child.position.deps.includes(baseNode.position.id)
);

const isV = this.direction === 'vertical';

let startY = baseY;
let newX = baseX + baseNode.elRect.width + this.horizontalPadding;
const height = baseNode.elRect.height;
const { width: w, height: h } = baseNode.elRect;
let newX = baseX + (isV ? h : w) + this.horizontalPadding;
const height = isV ? w : h;

const childC: { first: boolean; gp: number; maxDepLength: number } = {
first: true,
Expand All @@ -95,7 +65,7 @@ export class Arrangements {
const depLast = i === dependents.length - 1;
childC.first = i === 0;
const dependent = dependents[i];
const { consumedHeight, dep } = this.positionDependents(
const { consumedSpace, dep } = this.positionDependents(
dependent,
newX,
startY,
Expand All @@ -109,7 +79,7 @@ export class Arrangements {
startY += this.groupPadding;
config.gp += this.groupPadding;
}
startY += consumedHeight + (!depLast ? this.verticalPadding : 0);
startY += consumedSpace + (!depLast ? this.verticalPadding : 0);
}

// baseY += childC.gp;
Expand All @@ -118,12 +88,12 @@ export class Arrangements {
let y = 0;
if (dependents.length > 1) {
// find the first and last dependent and there y position
const firstDep = dependents[0];
const lastDep = dependents[dependents.length - 1];
const firstDepY = newItems.get(firstDep.position.id)!.y;
const lastDepY = newItems.get(lastDep.position.id)!.y;
const firstDepId = dependents[0].position.id;
const lastDepId = dependents[dependents.length - 1].position.id;
const firstDep = newItems.get(firstDepId)!;
const lastDep = newItems.get(lastDepId)!;
// find the center of the first and last dependent
y = (firstDepY + lastDepY) / 2;
y = (isV ? firstDep.x + lastDep.x : firstDep.y + lastDep.y) / 2;
} else {
y = baseY + (dependents.length ? (startY - baseY) / 2 - height / 2 : 0);

Expand All @@ -136,13 +106,13 @@ export class Arrangements {
}
newItems.set(baseNode.position.id, {
...baseNode.position,
x: baseX,
y: y,
x: isV ? y : baseX,
y: isV ? baseX : y,
});
// add groupPadding if there are more than one dependency
const groupPad =
dependents.length > 1 ? this.groupPadding - this.verticalPadding : 0;
const consumedHeight = startY + (dependents.length ? 0 : height) + groupPad;
return { consumedHeight, dep: dependents.length > 0 };
const consumedSpace = startY + (dependents.length ? 0 : height) + groupPad;
return { consumedSpace, dep: dependents.length > 0 };
}
}
21 changes: 16 additions & 5 deletions src/app/flow/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ export class Connections {
// value = index of the closest dot
closestDots = new Map<string, number>();

constructor(private list: ChildInfo[]) {
constructor(
private list: ChildInfo[],
private direction: 'horizontal' | 'vertical' = 'horizontal'
) {
this.setReverseDepsMap(list.map((x) => x.position));
// console.count('Connections');
}
Expand Down Expand Up @@ -77,6 +80,7 @@ export class Connections {
// sides dot index order: [top, right, bottom, left]
const thresholdDistance = 10; // Example distance threshold. Adjust as needed.
let swapped = false;
const isV = this.direction === 'vertical';
// correct the parent based on the deps
if (!child.position.deps.includes(parent.position.id)) {
const _t = child;
Expand All @@ -91,10 +95,17 @@ export class Connections {
const { x, y } = child.position;
const { x: px, y: py } = parent.position;

if (x + width < px) return 'left';
if (x - width > px) return 'right';
if (y + height < py) return 'top';
if (y - height > py) return 'bottom';
if (!isV) {
if (x + width < px) return 'left';
if (x - width > px) return 'right';
if (y + height < py) return 'top';
if (y - height > py) return 'bottom';
} else {
if (y + height < py) return 'top';
if (y - height > py) return 'bottom';
if (x + width < px) return 'left';
if (x - width > px) return 'right';
}
return 'right';
})();

Expand Down
Loading

0 comments on commit 11759af

Please sign in to comment.