Просмотр исходного кода

chore(auto-layout): auto layout animation disabled by default (#449)

Louis Young 6 месяцев назад
Родитель
Сommit
25e20d8c20

+ 6 - 1
packages/plugins/free-auto-layout-plugin/src/layout/constant.ts

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { LayoutConfig } from './type';
+import { LayoutConfig, LayoutOptions } from './type';
 
 export const DefaultLayoutConfig: LayoutConfig = {
   rankdir: 'LR',
@@ -16,3 +16,8 @@ export const DefaultLayoutConfig: LayoutConfig = {
   acyclicer: undefined,
   ranker: 'network-simplex',
 };
+
+export const DefaultLayoutOptions: LayoutOptions = {
+  getFollowNode: undefined,
+  enableAnimation: false,
+};

+ 3 - 20
packages/plugins/free-auto-layout-plugin/src/layout/layout.ts

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { GetFollowNode, LayoutConfig, LayoutOptions, LayoutParams } from './type';
+import { LayoutConfig, LayoutOptions, LayoutParams } from './type';
 import { LayoutStore } from './store';
 import { LayoutPosition } from './position';
 import { DagreLayout } from './dagre';
@@ -21,9 +21,8 @@ export class Layout {
     this._position = new LayoutPosition(this._store);
   }
 
-  public init(params: LayoutParams, options: LayoutOptions = {}): void {
-    this._store.create(params);
-    this.setFollowNode(options.getFollowNode);
+  public init(params: LayoutParams, options: LayoutOptions): void {
+    this._store.create(params, options);
   }
 
   public layout(): void {
@@ -39,20 +38,4 @@ export class Layout {
     }
     return await this._position.position();
   }
-
-  public setFollowNode(getFollowNode?: GetFollowNode): void {
-    if (!getFollowNode) return;
-    const context = { store: this._store };
-    this._store.nodes.forEach((node) => {
-      const followTo = getFollowNode(node, context)?.followTo;
-      if (!followTo) return;
-      const followToNode = this._store.getNode(followTo);
-      if (!followToNode) return;
-      if (!followToNode.followedBy) {
-        followToNode.followedBy = [];
-      }
-      followToNode.followedBy.push(node.id);
-      node.followTo = followTo;
-    });
-  }
 }

+ 13 - 0
packages/plugins/free-auto-layout-plugin/src/layout/position.ts

@@ -13,6 +13,19 @@ export class LayoutPosition {
   constructor(private readonly store: LayoutStore) {}
 
   public async position(): Promise<void> {
+    if (this.store.options.enableAnimation) {
+      return this.positionWithAnimation();
+    }
+    return this.positionDirectly();
+  }
+
+  private positionDirectly(): void {
+    this.store.nodes.forEach((layoutNode) => {
+      this.updateNodePosition({ layoutNode, step: 100 });
+    });
+  }
+
+  private async positionWithAnimation(): Promise<void> {
     return new Promise((resolve) => {
       startTween({
         from: { d: 0 },

+ 35 - 2
packages/plugins/free-auto-layout-plugin/src/layout/store.ts

@@ -10,7 +10,14 @@ import {
 } from '@flowgram.ai/free-layout-core';
 import { FlowNodeBaseType, FlowNodeTransformData } from '@flowgram.ai/document';
 
-import type { LayoutConfig, LayoutEdge, LayoutNode, LayoutParams } from './type';
+import type {
+  GetFollowNode,
+  LayoutConfig,
+  LayoutEdge,
+  LayoutNode,
+  LayoutOptions,
+  LayoutParams,
+} from './type';
 
 interface LayoutStoreData {
   nodes: Map<string, LayoutNode>;
@@ -26,6 +33,8 @@ export class LayoutStore {
 
   private container: WorkflowNodeEntity;
 
+  public options: LayoutOptions;
+
   constructor(public readonly config: LayoutConfig) {}
 
   public get initialized(): boolean {
@@ -56,9 +65,10 @@ export class LayoutStore {
     return Array.from(this.store.edges.values());
   }
 
-  public create(params: LayoutParams): void {
+  public create(params: LayoutParams, options: LayoutOptions): void {
     this.store = this.createStore(params);
     this.indexMap = this.createIndexMap();
+    this.setOptions(options);
     this.init = true;
   }
 
@@ -279,4 +289,27 @@ export class LayoutStore {
 
     return uniqueNodeIds;
   }
+
+  /** 记录运行选项 */
+  private setOptions(options: LayoutOptions): void {
+    this.options = options;
+    this.setFollowNode(options.getFollowNode);
+  }
+
+  /** 设置跟随节点配置 */
+  private setFollowNode(getFollowNode?: GetFollowNode): void {
+    if (!getFollowNode) return;
+    const context = { store: this };
+    this.nodes.forEach((node) => {
+      const followTo = getFollowNode(node, context)?.followTo;
+      if (!followTo) return;
+      const followToNode = this.getNode(followTo);
+      if (!followToNode) return;
+      if (!followToNode.followedBy) {
+        followToNode.followedBy = [];
+      }
+      followToNode.followedBy.push(node.id);
+      node.followTo = followTo;
+    });
+  }
 }

+ 1 - 0
packages/plugins/free-auto-layout-plugin/src/layout/type.ts

@@ -71,6 +71,7 @@ export interface LayoutParams {
 
 export interface LayoutOptions {
   getFollowNode?: GetFollowNode;
+  enableAnimation: boolean;
 }
 
 export interface LayoutConfig {

+ 6 - 2
packages/plugins/free-auto-layout-plugin/src/services.ts

@@ -13,6 +13,7 @@ import {
 
 import { AutoLayoutOptions } from './type';
 import { LayoutConfig } from './layout/type';
+import { DefaultLayoutOptions } from './layout/constant';
 import { DefaultLayoutConfig, Layout, type LayoutOptions } from './layout';
 
 @injectable()
@@ -28,8 +29,11 @@ export class AutoLayoutService {
     };
   }
 
-  public async layout(options: LayoutOptions = {}): Promise<void> {
-    await this.layoutNode(this.document.root, options);
+  public async layout(options: Partial<LayoutOptions> = {}): Promise<void> {
+    await this.layoutNode(this.document.root, {
+      ...DefaultLayoutOptions,
+      ...options,
+    });
   }
 
   private async layoutNode(node: WorkflowNodeEntity, options: LayoutOptions): Promise<void> {