Skip to content

Commit 47d7863

Browse files
committed
feat: add plugin support to ngu-flow
1 parent a30c971 commit 47d7863

15 files changed

+249
-100
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"start": "ng serve --port 52666",
77
"build": "ng build",
88
"watch": "ng build --watch --configuration development",
9+
"gh": "ng deploy --dir=dist/angular-flow/browser --base-href=/ngu-flow/",
910
"test": "jest"
1011
},
1112
"private": true,

projects/flow/src/lib/flow-child.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ export class FlowChildComponent implements OnInit, OnChanges, OnDestroy {
9595
});
9696

9797
this.positionChange.subscribe((x) => {
98-
const { left, top } = this.flow.zRect;
98+
// const { left, top } = this.flow.zRect;
9999
// if (!this.position) console.log(this.position);
100-
this.updatePosition(this.position.x + left, this.position.y + top);
100+
this.updatePosition(this.position.x, this.position.y);
101101
});
102102
}
103103

projects/flow/src/lib/flow-interface.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { FlowComponent } from './flow.component';
2+
13
export interface ChildInfo {
24
position: FlowOptions;
35
dots?: DOMRect[];
@@ -26,6 +28,7 @@ export interface DotOptions extends FlowOptions {
2628
export class FlowConfig {
2729
Arrows = true;
2830
ArrowSize = 20;
31+
Plugins: { [x: string]: FlowPlugin } = {};
2932
}
3033

3134
export type FlowDirection = 'horizontal' | 'vertical';
@@ -36,3 +39,8 @@ export type ArrowPathFn = (
3639
arrowSize: number,
3740
strokeWidth: number
3841
) => string;
42+
43+
export interface FlowPlugin {
44+
onInit?(data: FlowComponent): void;
45+
afterInit?(data: FlowComponent): void;
46+
}

projects/flow/src/lib/flow.component.ts

+18-22
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import {
1010
ElementRef,
1111
NgZone,
1212
ChangeDetectionStrategy,
13+
Input,
14+
OnInit,
1315
} from '@angular/core';
1416
import { startWith } from 'rxjs';
15-
import { Arrangements2 as Arrangements } from './arrangements';
17+
import { Arrangements2 as Arrangements } from './plugins/arrangements';
1618
import { Connections } from './connections';
1719
import { FlowChildComponent } from './flow-child.component';
1820
import { FlowService } from './flow.service';
@@ -22,9 +24,9 @@ import {
2224
FlowDirection,
2325
DotOptions,
2426
ArrowPathFn,
27+
FlowConfig,
2528
} from './flow-interface';
2629
import { blendCorners, flowPath, bezierPath, blendCorners1 } from './svg';
27-
import { FitToWindow } from './fit-to-window';
2830

2931
const BASE_SCALE_AMOUNT = 0.05;
3032

@@ -125,10 +127,11 @@ const BASE_SCALE_AMOUNT = 0.05;
125127
],
126128
})
127129
export class FlowComponent
128-
implements AfterContentInit, AfterViewInit, OnDestroy
130+
implements OnInit, AfterContentInit, AfterViewInit, OnDestroy
129131
{
130-
@ContentChildren(FlowChildComponent) children: QueryList<FlowChildComponent> =
131-
new QueryList();
132+
@Input() config: FlowConfig = new FlowConfig();
133+
@ContentChildren(FlowChildComponent) children =
134+
new QueryList<FlowChildComponent>();
132135

133136
// @ViewChildren('arrowPaths') arrowPaths: QueryList<ElementRef<SVGPathElement>>;
134137
@ViewChild('zoomContainer') zoomContainer: ElementRef<HTMLDivElement>;
@@ -143,7 +146,9 @@ export class FlowComponent
143146
public el: ElementRef<HTMLElement>,
144147
public flow: FlowService,
145148
private ngZone: NgZone
146-
) {
149+
) {}
150+
151+
ngOnInit(): void {
147152
this.flow.zoomContainer = this.el.nativeElement;
148153
this.flow.arrowsChange.subscribe((e) => this.updateArrows(e));
149154
this.ngZone.runOutsideAngular(() => {
@@ -166,6 +171,12 @@ export class FlowComponent
166171

167172
ngAfterViewInit(): void {
168173
this.createArrows();
174+
for (const key in this.config.Plugins) {
175+
if (Object.prototype.hasOwnProperty.call(this.config.Plugins, key)) {
176+
const element = this.config.Plugins[key];
177+
element.afterInit?.(this);
178+
}
179+
}
169180
}
170181

171182
ngAfterContentInit() {
@@ -281,22 +292,7 @@ export class FlowComponent
281292
return { scale: newScale, panX: newPanX, panY: newPanY };
282293
}
283294

284-
fitToWindow() {
285-
const ftw = new FitToWindow(
286-
this.list,
287-
this.zoomContainer.nativeElement.getBoundingClientRect(),
288-
this.flow.scale,
289-
this.flow.panX,
290-
this.flow.panY
291-
);
292-
const { scale, panX, panY } = ftw.fitToWindow();
293-
this.flow.scale = scale;
294-
this.flow.panX = panX;
295-
this.flow.panY = panY;
296-
this.updateZoomContainer();
297-
}
298-
299-
private updateZoomContainer() {
295+
updateZoomContainer() {
300296
this.zoomContainer.nativeElement.style.transform = `translate3d(${this.flow.panX}px, ${this.flow.panY}px, 0) scale(${this.flow.scale})`;
301297
}
302298

projects/flow/src/lib/flow.service.ts

-16
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export class FlowService {
4747
};
4848

4949
update(children: FlowOptions[]) {
50-
// console.log('update', children);
5150
this.items.clear();
5251
children.forEach((child) => {
5352
this.items.set(child.id, child);
@@ -62,21 +61,6 @@ export class FlowService {
6261
});
6362
}
6463

65-
// delete(option: FlowOptions) {
66-
// this.items.delete(option.id);
67-
// this.deps.delete(option.id);
68-
// this.deps.forEach((v, k) => {
69-
// const index = v.indexOf(option.id);
70-
// if (index > -1) {
71-
// v.splice(index, 1);
72-
// }
73-
// });
74-
// }
75-
76-
get list() {
77-
return Array.from(this.items.values());
78-
}
79-
8064
get zRect() {
8165
return this.zoomContainer.getBoundingClientRect();
8266
}

projects/flow/src/lib/arrangements.spec.ts projects/flow/src/lib/plugins/arrangements.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Arrangements, Arrangements2 } from './arrangements';
2-
import { ChildInfo } from './flow-interface';
2+
import { ChildInfo } from '../flow-interface';
33

44
export const FLOW_LIST = [
55
{ x: 40, y: 40, id: '1', deps: [] },

projects/flow/src/lib/arrangements.ts projects/flow/src/lib/plugins/arrangements.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { FlowOptions, ChildInfo, FlowDirection } from './flow-interface';
1+
import {
2+
FlowOptions,
3+
ChildInfo,
4+
FlowDirection,
5+
FlowPlugin,
6+
} from '../flow-interface';
7+
import { FlowComponent } from '../flow.component';
28

39
export class Arrangements {
410
constructor(
@@ -122,7 +128,7 @@ const ROOT_DEPS = new Map<string, string[]>();
122128
const HORIZONTAL_PADDING = 100;
123129
const VERTICAL_PADDING = 20;
124130

125-
export class Arrangements2 {
131+
export class Arrangements2 implements FlowPlugin {
126132
root: string[] = [];
127133

128134
constructor(
@@ -151,6 +157,10 @@ export class Arrangements2 {
151157
});
152158
}
153159

160+
onInit(data: FlowComponent): void {
161+
this.autoArrange();
162+
}
163+
154164
public autoArrange(): Map<string, FlowOptions> {
155165
this.root.forEach((id) => {
156166
const node = ROOT_DATA.get(id)!;
@@ -162,6 +172,7 @@ export class Arrangements2 {
162172
for (const item of this.list) {
163173
newItems.set(item.position.id, item.position);
164174
}
175+
console.log([...newItems.values()]);
165176
return newItems;
166177
}
167178
}

projects/flow/src/lib/fit-to-window.spec.ts projects/flow/src/lib/plugins/fit-to-window.spec.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,25 @@ describe('FitToWindow', () => {
8080
scale = 1;
8181
panX = 0;
8282
panY = 0;
83-
fitToWindow = new FitToWindow(list, containerRect, scale, panX, panY);
83+
fitToWindow = new FitToWindow();
84+
fitToWindow.onInit({
85+
list,
86+
zoomContainer: {
87+
nativeElement: { getBoundingClientRect: () => containerRect },
88+
},
89+
flow: {
90+
scale,
91+
panX,
92+
panY,
93+
zRect: containerRect,
94+
},
95+
updateZoomContainer: () => {},
96+
} as any);
97+
fitToWindow.run(list, containerRect, scale, panX, panY);
8498
});
8599

86100
it('should return positions', () => {
87-
const positions = fitToWindow.getPositions();
101+
const positions = fitToWindow._getPositions();
88102
expect(positions).toEqual([
89103
{ x: 121, y: 342.5, width: 400, height: 395 },
90104
{ x: 621, y: 342.5, width: 400, height: 395 },
@@ -98,20 +112,20 @@ describe('FitToWindow', () => {
98112
{ x: 0, y: 0, width: 100, height: 100 },
99113
{ x: 100, y: 100, width: 100, height: 100 },
100114
];
101-
const { minX, maxX, minY, maxY } = fitToWindow.getBoundaries(positions);
115+
const { minX, maxX, minY, maxY } = fitToWindow._getBoundaries(positions);
102116
expect(minX).toBe(0);
103117
expect(maxX).toBe(200);
104118
expect(minY).toBe(0);
105119
expect(maxY).toBe(200);
106120
});
107121

108122
it('should return new scale', () => {
109-
const newScale = fitToWindow.getNewScale(100, 100);
123+
const newScale = fitToWindow._getNewScale(100, 100);
110124
expect(newScale).toBe(6.28);
111125
});
112126

113127
it('should return pan values', () => {
114-
const { panX, panY } = fitToWindow.getPanValues(
128+
const { panX, panY } = fitToWindow._getPanValues(
115129
1430,
116130
840,
117131
0.7476,
@@ -123,7 +137,7 @@ describe('FitToWindow', () => {
123137
});
124138

125139
it('should return pan and scale values', () => {
126-
const { scale, panX, panY } = fitToWindow.fitToWindow();
140+
const { scale, panX, panY } = fitToWindow._updateValue();
127141
expect(scale).toBe(0.7476190476190476);
128142
expect(panX).toBe(-29.19047619047616);
129143
expect(panY).toBe(-38.876190476190494);

0 commit comments

Comments
 (0)