free-stack-plugin.mdx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { PackageManagerTabs } from '@theme';
  2. # @flowgram.ai/free-stack-plugin
  3. A layer management plugin that provides z-index layer control functionality for nodes and connections in free layout canvas.
  4. ## Features
  5. - Intelligently calculates layer relationships between nodes and connections to avoid occlusion issues
  6. - Supports automatic top-level display for selected nodes
  7. - Supports highlighting of hovered nodes and connections
  8. - Customizable node sorting rules to control rendering order of nodes at the same level
  9. - Automatically handles parent-child node layer relationships
  10. - Supports intelligent layer management for connections, ensuring connection visibility
  11. - Real-time response to node selection, hover, and entity change events
  12. ## Quick Start
  13. 1. Installation
  14. <PackageManagerTabs command="install @flowgram.ai/free-stack-plugin" />
  15. 2. Register Plugin
  16. The plugin registration method is basically the same as other flowgram plugins. Just make sure not to create duplicates and finally pass it to the corresponding FreeLayoutEditorProvider.
  17. ```tsx
  18. import { createFreeStackPlugin } from '@flowgram.ai/free-stack-plugin';
  19. const editorProps = useMemo(() => ({
  20. plugins: () => [
  21. createFreeStackPlugin()
  22. ]
  23. }), []);
  24. return (
  25. <FreeLayoutEditorProvider {...editorProps}>
  26. <EditorRenderer />
  27. </FreeLayoutEditorProvider>
  28. )
  29. ```
  30. 3. Custom Node Sorting
  31. You can customize the sorting rules for nodes at the same level through the `sortNodes` function:
  32. ```tsx
  33. import { createFreeStackPlugin } from '@flowgram.ai/free-stack-plugin';
  34. import { WorkflowNodeType } from './nodes/constants';
  35. const editorProps = useMemo(() => ({
  36. plugins: () => [
  37. createFreeStackPlugin({
  38. sortNodes: (nodes) => {
  39. const commentNodes = [];
  40. const otherNodes = [];
  41. // Separate comment nodes from other nodes
  42. nodes.forEach((node) => {
  43. if (node.flowNodeType === WorkflowNodeType.Comment) {
  44. commentNodes.push(node);
  45. } else {
  46. otherNodes.push(node);
  47. }
  48. });
  49. // Comment nodes render at the bottom layer, other nodes at the top layer
  50. return [...commentNodes, ...otherNodes];
  51. },
  52. })
  53. ]
  54. }), []);
  55. ```
  56. ## Configuration Options
  57. ### FreeStackPluginOptions
  58. Plugin configuration options:
  59. ```typescript
  60. interface FreeStackPluginOptions {
  61. /** Custom node sorting function */
  62. sortNodes?: (nodes: WorkflowNodeEntity[]) => WorkflowNodeEntity[];
  63. }
  64. ```
  65. ### sortNodes Function
  66. Used to customize sorting rules for nodes at the same level:
  67. ```typescript
  68. type SortNodesFunction = (nodes: WorkflowNodeEntity[]) => WorkflowNodeEntity[];
  69. ```
  70. **Parameter Description:**
  71. - `nodes`: Array of nodes to be sorted
  72. - **Return Value**: Array of sorted nodes
  73. **Use Cases:**
  74. - Place specific types of nodes (like comments) at the bottom layer
  75. - Sort nodes by business priority
  76. - Sort by creation time or other attributes
  77. ## Layer Management Algorithm
  78. ### Basic Layer Calculation
  79. The plugin uses an intelligent algorithm to calculate the layer for each node and connection:
  80. 1. **Base Layer**: Starts calculation from `BASE_Z_INDEX` (default is 8)
  81. 2. **Node Layer**: Calculated based on node nesting relationships and sorting rules
  82. 3. **Connection Layer**: Ensures connections are not occluded by nodes while handling special cases
  83. ### Layer Elevation Rules
  84. The following situations will trigger layer elevation:
  85. - **Selected Nodes**: Selected nodes will be elevated to the top layer
  86. - **Hovered Elements**: Hovered nodes or connections will be highlighted
  87. - **Drawing Connections**: Connections being drawn will be placed at the top layer
  88. - **Parent-Child Relationship Connections**: Connections between parent-child nodes will be prioritized for display
  89. ### Layer Calculation Process
  90. 1. **Initialization**: Clear cache, calculate basic parameters
  91. 2. **Node Indexing**: Establish node index mapping
  92. 3. **Selected Node Processing**: Mark parent relationships of selected nodes
  93. 4. **Layer Assignment**: Recursively process node layers
  94. 5. **Connection Processing**: Calculate connection layers, ensure visibility
  95. 6. **Style Application**: Apply calculation results to DOM elements
  96. ## Advanced Usage
  97. ### Complex Sorting Rules
  98. You can implement complex node sorting logic:
  99. ```typescript
  100. const sortNodes = (nodes: WorkflowNodeEntity[]) => {
  101. return nodes.sort((a, b) => {
  102. // 1. Sort by node type priority
  103. const typeOrder = {
  104. [WorkflowNodeType.Comment]: 0,
  105. [WorkflowNodeType.Start]: 1,
  106. [WorkflowNodeType.End]: 2,
  107. // ... other types
  108. };
  109. const aOrder = typeOrder[a.flowNodeType] ?? 999;
  110. const bOrder = typeOrder[b.flowNodeType] ?? 999;
  111. if (aOrder !== bOrder) {
  112. return aOrder - bOrder;
  113. }
  114. // 2. Sort by creation time
  115. return a.createTime - b.createTime;
  116. });
  117. };
  118. ```
  119. ## FAQ
  120. ### Q: How to keep specific types of nodes always at the bottom layer?
  121. A: Place these nodes at the front of the array through the `sortNodes` function:
  122. ```typescript
  123. const sortNodes = (nodes) => {
  124. const backgroundNodes = nodes.filter(node =>
  125. node.flowNodeType === WorkflowNodeType.Comment
  126. );
  127. const foregroundNodes = nodes.filter(node =>
  128. node.flowNodeType !== WorkflowNodeType.Comment
  129. );
  130. return [...backgroundNodes, ...foregroundNodes];
  131. };
  132. ```
  133. ### Q: How to disable automatic layer management?
  134. A: Currently, the plugin does not provide a disable option. If you need complete custom layer management, it is recommended not to use this plugin and directly set z-index in node components.
  135. ### Q: Performance optimization suggestions?
  136. A: The plugin already has built-in performance optimizations:
  137. - Uses debounce mechanism to reduce calculation frequency
  138. - Only recalculates layers when necessary
  139. - Uses Map data structure to improve lookup efficiency
  140. For large canvases (over 1000 nodes), it is recommended to:
  141. - Simplify the logic of the `sortNodes` function
  142. - Avoid complex calculations in sorting functions