From e0bd2bf5e9529a058cd41b4b88376a9975384938 Mon Sep 17 00:00:00 2001 From: Sheik Althaf Date: Wed, 14 Feb 2024 23:23:54 +0530 Subject: [PATCH] feat: add plugin support to ngu-flow --- package.json | 1 + projects/flow/src/lib/flow-child.component.ts | 8 +- projects/flow/src/lib/flow-interface.ts | 9 ++ projects/flow/src/lib/flow.component.ts | 61 ++++------ projects/flow/src/lib/flow.service.ts | 16 --- .../lib/{ => plugins}/arrangements.spec.ts | 25 +++-- .../src/lib/{ => plugins}/arrangements.ts | 57 ++++++++-- .../lib/{ => plugins}/fit-to-window.spec.ts | 26 ++++- .../src/lib/{ => plugins}/fit-to-window.ts | 106 +++++++++++------- .../flow/src/lib/plugins/scroll-into-view.ts | 34 ++++++ projects/flow/src/public-api.ts | 3 + src/app/demo/demo-one.component.ts | 56 ++++++++- src/app/demo/demo-two.component.ts | 39 ++++++- src/app/demo/demo.service.ts | 13 ++- src/app/demo/toolbar.component.ts | 15 +-- 15 files changed, 327 insertions(+), 142 deletions(-) rename projects/flow/src/lib/{ => plugins}/arrangements.spec.ts (78%) rename projects/flow/src/lib/{ => plugins}/arrangements.ts (84%) rename projects/flow/src/lib/{ => plugins}/fit-to-window.spec.ts (79%) rename projects/flow/src/lib/{ => plugins}/fit-to-window.ts (59%) create mode 100644 projects/flow/src/lib/plugins/scroll-into-view.ts diff --git a/package.json b/package.json index 298999b..7f1b1b2 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "start": "ng serve --port 52666", "build": "ng build", "watch": "ng build --watch --configuration development", + "gh": "ng deploy --dir=dist/angular-flow/browser --base-href=/ngu-flow/", "test": "jest" }, "private": true, diff --git a/projects/flow/src/lib/flow-child.component.ts b/projects/flow/src/lib/flow-child.component.ts index 2ca6455..914505c 100644 --- a/projects/flow/src/lib/flow-child.component.ts +++ b/projects/flow/src/lib/flow-child.component.ts @@ -95,9 +95,9 @@ export class FlowChildComponent implements OnInit, OnChanges, OnDestroy { }); this.positionChange.subscribe((x) => { - const { left, top } = this.flow.zRect; + // const { left, top } = this.flow.zRect; // if (!this.position) console.log(this.position); - this.updatePosition(this.position.x + left, this.position.y + top); + this.updatePosition(this.position.x, this.position.y); }); } @@ -135,8 +135,8 @@ export class FlowChildComponent implements OnInit, OnChanges, OnDestroy { (this.flow.gridSize * this.flow.scale) ) * this.flow.gridSize; - this.position.x = x - zRect.left; - this.position.y = y - zRect.top; + this.position.x = x; + this.position.y = y; this.positionChange.next(this.position); this.flow.arrowsChange.next(this.position); } diff --git a/projects/flow/src/lib/flow-interface.ts b/projects/flow/src/lib/flow-interface.ts index 5b697fe..bf051bc 100644 --- a/projects/flow/src/lib/flow-interface.ts +++ b/projects/flow/src/lib/flow-interface.ts @@ -1,3 +1,5 @@ +import { FlowComponent } from './flow.component'; + export interface ChildInfo { position: FlowOptions; dots?: DOMRect[]; @@ -26,6 +28,7 @@ export interface DotOptions extends FlowOptions { export class FlowConfig { Arrows = true; ArrowSize = 20; + Plugins: { [x: string]: FlowPlugin } = {}; } export type FlowDirection = 'horizontal' | 'vertical'; @@ -36,3 +39,9 @@ export type ArrowPathFn = ( arrowSize: number, strokeWidth: number ) => string; + +export interface FlowPlugin { + onInit?(data: FlowComponent): void; + afterInit?(data: FlowComponent): void; + beforeArrowUpdate?(data: FlowComponent): void; +} diff --git a/projects/flow/src/lib/flow.component.ts b/projects/flow/src/lib/flow.component.ts index 2e37a3a..23cc775 100644 --- a/projects/flow/src/lib/flow.component.ts +++ b/projects/flow/src/lib/flow.component.ts @@ -10,9 +10,10 @@ import { ElementRef, NgZone, ChangeDetectionStrategy, + Input, + OnInit, } from '@angular/core'; import { startWith } from 'rxjs'; -import { Arrangements2 as Arrangements } from './arrangements'; import { Connections } from './connections'; import { FlowChildComponent } from './flow-child.component'; import { FlowService } from './flow.service'; @@ -22,9 +23,10 @@ import { FlowDirection, DotOptions, ArrowPathFn, + FlowConfig, + FlowPlugin, } from './flow-interface'; import { blendCorners, flowPath, bezierPath, blendCorners1 } from './svg'; -import { FitToWindow } from './fit-to-window'; const BASE_SCALE_AMOUNT = 0.05; @@ -125,10 +127,11 @@ const BASE_SCALE_AMOUNT = 0.05; ], }) export class FlowComponent - implements AfterContentInit, AfterViewInit, OnDestroy + implements OnInit, AfterContentInit, AfterViewInit, OnDestroy { - @ContentChildren(FlowChildComponent) children: QueryList = - new QueryList(); + @Input() config: FlowConfig = new FlowConfig(); + @ContentChildren(FlowChildComponent) children = + new QueryList(); // @ViewChildren('arrowPaths') arrowPaths: QueryList>; @ViewChild('zoomContainer') zoomContainer: ElementRef; @@ -143,7 +146,9 @@ export class FlowComponent public el: ElementRef, public flow: FlowService, private ngZone: NgZone - ) { + ) {} + + ngOnInit(): void { this.flow.zoomContainer = this.el.nativeElement; this.flow.arrowsChange.subscribe((e) => this.updateArrows(e)); this.ngZone.runOutsideAngular(() => { @@ -166,6 +171,16 @@ export class FlowComponent ngAfterViewInit(): void { this.createArrows(); + this.runPlugin((e) => e.afterInit?.(this)); + } + + private runPlugin(callback: (e: FlowPlugin) => void) { + for (const key in this.config.Plugins) { + if (Object.prototype.hasOwnProperty.call(this.config.Plugins, key)) { + const element = this.config.Plugins[key]; + callback(element); + } + } } ngAfterContentInit() { @@ -173,7 +188,7 @@ export class FlowComponent .pipe(startWith(this.children)) .subscribe((children) => { this.flow.update(this.children.map((x) => x.position)); - this.arrangeChildren(); + this.runPlugin((e) => e.beforeArrowUpdate?.(this)); this.createArrows(); }); requestAnimationFrame(() => this.updateArrows()); // this required for angular to render the dot @@ -189,7 +204,7 @@ export class FlowComponent updateDirection(direction: FlowDirection) { this.flow.direction = direction; - this.arrangeChildren(); + this.runPlugin((e) => e.beforeArrowUpdate?.(this)); this.createArrows(); } @@ -281,38 +296,10 @@ export class FlowComponent return { scale: newScale, panX: newPanX, panY: newPanY }; } - fitToWindow() { - const ftw = new FitToWindow( - this.list, - this.zoomContainer.nativeElement.getBoundingClientRect(), - this.flow.scale, - this.flow.panX, - this.flow.panY - ); - const { scale, panX, panY } = ftw.fitToWindow(); - this.flow.scale = scale; - this.flow.panX = panX; - this.flow.panY = panY; - this.updateZoomContainer(); - } - - private updateZoomContainer() { + updateZoomContainer() { this.zoomContainer.nativeElement.style.transform = `translate3d(${this.flow.panX}px, ${this.flow.panY}px, 0) scale(${this.flow.scale})`; } - arrangeChildren() { - const arrangements = new Arrangements( - this.list, - this.flow.direction, - this.flow.horizontalPadding, - this.flow.verticalPadding, - this.flow.groupPadding - ); - const newList = arrangements.autoArrange(); - this.flow.update([...newList.values()]); - this.flow.layoutUpdated.next(); - } - get list() { return this.children.toArray().map((x) => { // calculate the width and height with scale diff --git a/projects/flow/src/lib/flow.service.ts b/projects/flow/src/lib/flow.service.ts index 699cf8f..9cc29ca 100644 --- a/projects/flow/src/lib/flow.service.ts +++ b/projects/flow/src/lib/flow.service.ts @@ -47,7 +47,6 @@ export class FlowService { }; update(children: FlowOptions[]) { - // console.log('update', children); this.items.clear(); children.forEach((child) => { this.items.set(child.id, child); @@ -62,21 +61,6 @@ export class FlowService { }); } - // delete(option: FlowOptions) { - // this.items.delete(option.id); - // this.deps.delete(option.id); - // this.deps.forEach((v, k) => { - // const index = v.indexOf(option.id); - // if (index > -1) { - // v.splice(index, 1); - // } - // }); - // } - - get list() { - return Array.from(this.items.values()); - } - get zRect() { return this.zoomContainer.getBoundingClientRect(); } diff --git a/projects/flow/src/lib/arrangements.spec.ts b/projects/flow/src/lib/plugins/arrangements.spec.ts similarity index 78% rename from projects/flow/src/lib/arrangements.spec.ts rename to projects/flow/src/lib/plugins/arrangements.spec.ts index 05f2d93..b1e8354 100644 --- a/projects/flow/src/lib/arrangements.spec.ts +++ b/projects/flow/src/lib/plugins/arrangements.spec.ts @@ -1,5 +1,6 @@ -import { Arrangements, Arrangements2 } from './arrangements'; -import { ChildInfo } from './flow-interface'; +import { ArrangementsOld, Arrangements } from './arrangements'; +import { ChildInfo } from '../flow-interface'; +import { FlowComponent } from '../flow.component'; export const FLOW_LIST = [ { x: 40, y: 40, id: '1', deps: [] }, @@ -13,7 +14,7 @@ export const FLOW_LIST = [ ]; describe('Arrangements', () => { - let arrangements: Arrangements; + let arrangements: ArrangementsOld; it('should be created', () => { const childObj: ChildInfo[] = FLOW_LIST.map((x) => ({ @@ -21,7 +22,7 @@ describe('Arrangements', () => { elRect: { width: 200, height: 200 } as any, })); - arrangements = new Arrangements(childObj); + arrangements = new ArrangementsOld(childObj); arrangements.verticalPadding = 20; arrangements.groupPadding = 100; const expected = { @@ -40,7 +41,7 @@ describe('Arrangements', () => { }); describe('Arrangements2', () => { - let arrangements: Arrangements2; + let arrangements: Arrangements; it('should be created', () => { const childObj: ChildInfo[] = FLOW_LIST.map((x) => ({ @@ -48,9 +49,15 @@ describe('Arrangements2', () => { elRect: { width: 200, height: 200 } as any, })); - arrangements = new Arrangements2(childObj); - arrangements.verticalPadding = 20; - arrangements.groupPadding = 100; + arrangements = new Arrangements(); + arrangements.onInit({ + list: childObj, + flow: { + direction: 'vertical', + verticalPadding: 20, + groupPadding: 100, + }, + } as Partial as any); const expected = { '1': { x: 330, y: 0, id: '1', deps: [] }, '2': { x: 110, y: 300, id: '2', deps: ['1'] }, @@ -61,7 +68,7 @@ describe('Arrangements2', () => { '7': { x: 660, y: 600, id: '7', deps: ['5'] }, '8': { x: 660, y: 900, id: '8', deps: ['6', '7'] }, }; - const actual = Object.fromEntries(arrangements.autoArrange()); + const actual = Object.fromEntries(arrangements._autoArrange()); expect(actual).toEqual(expected); }); }); diff --git a/projects/flow/src/lib/arrangements.ts b/projects/flow/src/lib/plugins/arrangements.ts similarity index 84% rename from projects/flow/src/lib/arrangements.ts rename to projects/flow/src/lib/plugins/arrangements.ts index 20ac455..9beaaed 100644 --- a/projects/flow/src/lib/arrangements.ts +++ b/projects/flow/src/lib/plugins/arrangements.ts @@ -1,6 +1,12 @@ -import { FlowOptions, ChildInfo, FlowDirection } from './flow-interface'; +import { + FlowOptions, + ChildInfo, + FlowDirection, + FlowPlugin, +} from '../flow-interface'; +import { FlowComponent } from '../flow.component'; -export class Arrangements { +export class ArrangementsOld { constructor( private list: ChildInfo[], private direction: 'horizontal' | 'vertical' = 'horizontal', @@ -122,16 +128,44 @@ const ROOT_DEPS = new Map(); const HORIZONTAL_PADDING = 100; const VERTICAL_PADDING = 20; -export class Arrangements2 { +export class Arrangements implements FlowPlugin { root: string[] = []; + data: FlowComponent; + private list: ChildInfo[]; + private direction: FlowDirection = 'vertical'; + public horizontalPadding = 100; + public verticalPadding = 20; + public groupPadding = 20; + + constructor() {} + + onInit(data: FlowComponent): void { + this.data = data; + } + + beforeArrowUpdate(data: FlowComponent): void { + this.data = data; + this.runArrange(); + } + + private runArrange() { + const newList = this._autoArrange(); + this.data.flow.update([...newList.values()]); + this.data.flow.layoutUpdated.next(); + } + + arrange() { + this.runArrange(); + this.data.updateArrows(); + } + + public _autoArrange(): Map { + this.list = this.data.list; + this.direction = this.data.flow.direction; + this.horizontalPadding = this.data.flow.horizontalPadding; + this.verticalPadding = this.data.flow.verticalPadding; + this.groupPadding = this.data.flow.groupPadding; - constructor( - private list: ChildInfo[], - private direction: FlowDirection = 'vertical', - public horizontalPadding = 100, - public verticalPadding = 20, - public groupPadding = 20 - ) { ROOT_DATA.clear(); ROOT_DEPS.clear(); this.list.forEach((item) => { @@ -149,9 +183,7 @@ export class Arrangements2 { this.root.push(item.position.id); } }); - } - public autoArrange(): Map { this.root.forEach((id) => { const node = ROOT_DATA.get(id)!; node.arrange(0, 0, this.direction); @@ -162,6 +194,7 @@ export class Arrangements2 { for (const item of this.list) { newItems.set(item.position.id, item.position); } + console.log([...newItems.values()]); return newItems; } } diff --git a/projects/flow/src/lib/fit-to-window.spec.ts b/projects/flow/src/lib/plugins/fit-to-window.spec.ts similarity index 79% rename from projects/flow/src/lib/fit-to-window.spec.ts rename to projects/flow/src/lib/plugins/fit-to-window.spec.ts index 3287679..1f9a7e8 100644 --- a/projects/flow/src/lib/fit-to-window.spec.ts +++ b/projects/flow/src/lib/plugins/fit-to-window.spec.ts @@ -80,11 +80,25 @@ describe('FitToWindow', () => { scale = 1; panX = 0; panY = 0; - fitToWindow = new FitToWindow(list, containerRect, scale, panX, panY); + fitToWindow = new FitToWindow(); + fitToWindow.onInit({ + list, + zoomContainer: { + nativeElement: { getBoundingClientRect: () => containerRect }, + }, + flow: { + scale, + panX, + panY, + zRect: containerRect, + }, + updateZoomContainer: () => {}, + } as any); + fitToWindow.run(list, containerRect, scale, panX, panY); }); it('should return positions', () => { - const positions = fitToWindow.getPositions(); + const positions = fitToWindow._getPositions(); expect(positions).toEqual([ { x: 121, y: 342.5, width: 400, height: 395 }, { x: 621, y: 342.5, width: 400, height: 395 }, @@ -98,7 +112,7 @@ describe('FitToWindow', () => { { x: 0, y: 0, width: 100, height: 100 }, { x: 100, y: 100, width: 100, height: 100 }, ]; - const { minX, maxX, minY, maxY } = fitToWindow.getBoundaries(positions); + const { minX, maxX, minY, maxY } = fitToWindow._getBoundaries(positions); expect(minX).toBe(0); expect(maxX).toBe(200); expect(minY).toBe(0); @@ -106,12 +120,12 @@ describe('FitToWindow', () => { }); it('should return new scale', () => { - const newScale = fitToWindow.getNewScale(100, 100); + const newScale = fitToWindow._getNewScale(100, 100); expect(newScale).toBe(6.28); }); it('should return pan values', () => { - const { panX, panY } = fitToWindow.getPanValues( + const { panX, panY } = fitToWindow._getPanValues( 1430, 840, 0.7476, @@ -123,7 +137,7 @@ describe('FitToWindow', () => { }); it('should return pan and scale values', () => { - const { scale, panX, panY } = fitToWindow.fitToWindow(); + const { scale, panX, panY } = fitToWindow._updateValue(); expect(scale).toBe(0.7476190476190476); expect(panX).toBe(-29.19047619047616); expect(panY).toBe(-38.876190476190494); diff --git a/projects/flow/src/lib/fit-to-window.ts b/projects/flow/src/lib/plugins/fit-to-window.ts similarity index 59% rename from projects/flow/src/lib/fit-to-window.ts rename to projects/flow/src/lib/plugins/fit-to-window.ts index abf87fe..336c13d 100644 --- a/projects/flow/src/lib/fit-to-window.ts +++ b/projects/flow/src/lib/plugins/fit-to-window.ts @@ -1,17 +1,56 @@ -import { ChildInfo } from './flow-interface'; - -export class FitToWindow { - cRect: CPosition; - containerPadding = 0; - - constructor( - private list: ChildInfo[], - private containerRect: DOMRect, - private scale: number, - private panX: number, - private panY: number +import { ChildInfo, FlowPlugin } from '../flow-interface'; +import { FlowComponent } from '../flow.component'; + +export class FitToWindow implements FlowPlugin { + private cRect: CPosition; + private containerPadding = 0; + private data: FlowComponent; + + private list: ChildInfo[]; + private containerRect: DOMRect; + private scale: number; + private panX: number; + private panY: number; + + constructor(private init = false) {} + + onInit(data: FlowComponent): void { + this.data = data; + } + + afterInit(data: FlowComponent): void { + this.data = data; + if (this.init) { + this.fitToWindow(); + } + } + + fitToWindow() { + this.run( + this.data.list, + this.data.zoomContainer.nativeElement.getBoundingClientRect(), + this.data.flow.scale, + this.data.flow.panX, + this.data.flow.panY + ); + } + + run( + list: ChildInfo[], + cRect: DOMRect, + scale: number, + panX: number, + panY: number ) { - const tt = { list, containerRect, scale, panX, panY }; + this.list = list; + this.containerRect = cRect; + this.scale = scale; + this.panX = panX; + this.panY = panY; + this._fitToWindowInternal(); + } + + private _fitToWindowInternal() { this.containerPadding = 30 / this.scale; this.cRect = { x: this.containerRect.x / this.scale - this.panX, @@ -19,15 +58,20 @@ export class FitToWindow { width: this.containerRect.width / this.scale, height: this.containerRect.height / this.scale, }; + const { scale, panX, panY } = this._updateValue(); + this.data.flow.scale = scale; + this.data.flow.panX = panX; + this.data.flow.panY = panY; + this.data.updateZoomContainer(); } - fitToWindow() { - const positions = this.getPositions(); - const { minX, maxX, minY, maxY } = this.getBoundaries(positions); + _updateValue() { + const positions = this._getPositions(); + const { minX, maxX, minY, maxY } = this._getBoundaries(positions); const adjMaxX = maxX - minX + this.containerPadding; const adjMaxY = maxY - minY + this.containerPadding; - const newScale = this.getNewScale(adjMaxX, adjMaxY); - const { panX, panY } = this.getPanValues( + const newScale = this._getNewScale(adjMaxX, adjMaxY); + const { panX, panY } = this._getPanValues( adjMaxX, adjMaxY, newScale, @@ -37,7 +81,7 @@ export class FitToWindow { return { scale: newScale, panX, panY }; } - getPositions() { + _getPositions() { return this.list.map((child) => { const scaledX = child.elRect.x / this.scale - this.panX; const scaledY = child.elRect.y / this.scale - this.panY; @@ -52,7 +96,7 @@ export class FitToWindow { }); } - getBoundaries(positions: CPosition[]) { + _getBoundaries(positions: CPosition[]) { const minX = Math.min(...positions.map((p) => p.x)); const maxX = Math.max(...positions.map((p) => p.x + p.width)); const minY = Math.min(...positions.map((p) => p.y)); @@ -60,31 +104,13 @@ export class FitToWindow { return { minX, maxX, minY, maxY }; } - getNewScale(adjMaxX: number, adjMaxY: number) { + _getNewScale(adjMaxX: number, adjMaxY: number) { const scaleX = this.cRect.width / adjMaxX; const scaleY = this.cRect.height / adjMaxY; return Math.min(scaleX, scaleY); } - // getPanValues( - // adjMaxX: number, - // adjMaxY: number, - // newScale: number, - // minX: number, - // minY: number - // ) { - // const panX = - // this.cRect.x + - // (this.cRect.width - (adjMaxX - this.containerPadding) * newScale) / 2 - - // minX * newScale; - // const panY = - // this.cRect.y + - // (this.cRect.height - (adjMaxY - this.containerPadding) * newScale) / 2 - - // minY * newScale; - // return { panX, panY }; - // } - // } - getPanValues( + _getPanValues( adjMaxX: number, adjMaxY: number, newScale: number, diff --git a/projects/flow/src/lib/plugins/scroll-into-view.ts b/projects/flow/src/lib/plugins/scroll-into-view.ts new file mode 100644 index 0000000..d967f7d --- /dev/null +++ b/projects/flow/src/lib/plugins/scroll-into-view.ts @@ -0,0 +1,34 @@ +import { FlowPlugin } from '../flow-interface'; +import { FlowComponent } from '../flow.component'; + +export class ScrollIntoView implements FlowPlugin { + private data: FlowComponent; + + constructor(private id: string) {} + + afterInit(data: FlowComponent): void { + this.data = data; + this.focus(this.id); + } + + focus(id: string) { + const item = this.data.list.find((x) => x.position.id === id); + if (item) { + const { x, y } = item.position; + const { width, height } = item.elRect; + // this.flow.panX = -x * this.flow.scale + this.flow.zRect.width / 2; + if (x + width * this.data.flow.scale > this.data.flow.zRect.width) { + this.data.flow.panX = + -x * this.data.flow.scale + (this.data.flow.zRect.width - width); + } else if ( + this.data.flow.panX + x * this.data.flow.scale < + this.data.flow.zRect.width + ) { + this.data.flow.panX = -x * this.data.flow.scale; + } + this.data.flow.panY = + -y * this.data.flow.scale + (this.data.flow.zRect.height - height) / 2; + this.data.updateZoomContainer(); + } + } +} diff --git a/projects/flow/src/public-api.ts b/projects/flow/src/public-api.ts index 7fbd8d6..64df422 100644 --- a/projects/flow/src/public-api.ts +++ b/projects/flow/src/public-api.ts @@ -12,3 +12,6 @@ export { FlowConfig, } from './lib/flow-interface'; export * from './lib/svg'; +export { FitToWindow } from './lib/plugins/fit-to-window'; +export { ScrollIntoView } from './lib/plugins/scroll-into-view'; +export { Arrangements } from './lib/plugins/arrangements'; diff --git a/src/app/demo/demo-one.component.ts b/src/app/demo/demo-one.component.ts index 1976fd1..e46fba1 100644 --- a/src/app/demo/demo-one.component.ts +++ b/src/app/demo/demo-one.component.ts @@ -5,10 +5,19 @@ import { ViewChild, inject, } from '@angular/core'; -import { FlowComponent, FlowChildComponent, FlowOptions } from '@ngu/flow'; +import { + FlowComponent, + FlowChildComponent, + FlowOptions, + FlowConfig, + FitToWindow, + ScrollIntoView, + Arrangements, +} from '@ngu/flow'; import { EditorComponent } from '../editor.component'; import { ToolbarComponent } from './toolbar.component'; import { DemoService } from './demo.service'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; @Component({ selector: 'app-demo-one', @@ -19,11 +28,25 @@ import { DemoService } from './demo.service'; FlowChildComponent, EditorComponent, ToolbarComponent, + ReactiveFormsModule, ], template: `
- - + + + @for (item of list; track item.id; let i = $index) {
('11', { nonNullable: true }); constructor() { this.list = structuredClone(FLOW_LIST); + this.selectedNode.valueChanges.subscribe((id) => { + this.plugins.scroll.focus(id); + }); + + // setTimeout(() => { + // this.flowComponent.scrollIntoView('3'); + // }); } ngAfterViewInit(): void { this.demoService.flow = this.flowComponent; } + fitToWindow() { + this.plugins.fitWindow.fitToWindow(); + } + + autoArrange() { + this.plugins.arrange.arrange(); + } + deleteNode(id: string) { this.list = structuredClone(this.demoService.deleteNodeI(id, this.list)); } diff --git a/src/app/demo/demo-two.component.ts b/src/app/demo/demo-two.component.ts index 96df1d2..3c32d3a 100644 --- a/src/app/demo/demo-two.component.ts +++ b/src/app/demo/demo-two.component.ts @@ -5,7 +5,15 @@ import { ViewChild, inject, } from '@angular/core'; -import { FlowComponent, FlowChildComponent, FlowOptions } from '@ngu/flow'; +import { + FlowComponent, + FlowChildComponent, + FlowOptions, + FlowConfig, + ScrollIntoView, + FitToWindow, + Arrangements, +} from '@ngu/flow'; import { EditorComponent } from '../editor.component'; import { ToolbarComponent } from './toolbar.component'; import { DemoService } from './demo.service'; @@ -22,8 +30,15 @@ import { DemoService } from './demo.service'; ], template: `
- - + + @for (item of list; track item.id; let i = $index) {
0) { - const index = list.findIndex((x) => x.id == id); - const deletedNode = list.splice(index, 1)[0]; - // Remove dependencies of the deleted node return list.reduce((acc, item) => { const initialLength = item.deps.length; - item.deps = item.deps.filter((dep) => dep !== deletedNode.id); - if (item.deps.length === initialLength || item.deps.length > 0) + item.deps = item.deps.filter((dep) => !removeId.includes(dep)); + if (initialLength > 0 && item.deps.length === 0) { + removeId.push(item.id); + } else if ( + !removeId.includes(item.id) && + (item.deps.length === initialLength || item.deps.length > 0) + ) acc.push(item); return acc; }, [] as FlowOptions[]); diff --git a/src/app/demo/toolbar.component.ts b/src/app/demo/toolbar.component.ts index 708d7db..96e2c0b 100644 --- a/src/app/demo/toolbar.component.ts +++ b/src/app/demo/toolbar.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { Component, EventEmitter, OnInit, Output, inject } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { DemoService } from './demo.service'; import { @@ -39,7 +39,7 @@ import { (click)="animatePathFn()" />Animate - +