stacking-computing.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import { FlowNodeBaseType } from '@flowgram.ai/document';
  2. import { WorkflowNodeEntity, WorkflowNodeLinesData } from '@flowgram.ai/free-layout-core';
  3. import type { StackingContext } from './type';
  4. export class StackingComputing {
  5. private currentLevel: number;
  6. private topLevel: number;
  7. private maxLevel: number;
  8. private nodeIndexes: Map<string, number>;
  9. private nodeLevel: Map<string, number>;
  10. private lineLevel: Map<string, number>;
  11. private context: StackingContext;
  12. public compute(params: {
  13. root: WorkflowNodeEntity;
  14. nodes: WorkflowNodeEntity[];
  15. context: StackingContext;
  16. }): {
  17. /** 节点层级 */
  18. nodeLevel: Map<string, number>;
  19. /** 线条层级 */
  20. lineLevel: Map<string, number>;
  21. /** 正常渲染的最高层级 */
  22. topLevel: number;
  23. /** 选中计算叠加后可能计算出的最高层级 */
  24. maxLevel: number;
  25. } {
  26. this.clearCache();
  27. const { root, nodes, context } = params;
  28. this.context = context;
  29. this.nodeIndexes = this.computeNodeIndexesMap(nodes);
  30. this.topLevel = this.computeTopLevel(nodes);
  31. this.maxLevel = this.topLevel * 2;
  32. this.layerHandler(root.collapsedChildren);
  33. return {
  34. nodeLevel: this.nodeLevel,
  35. lineLevel: this.lineLevel,
  36. topLevel: this.topLevel,
  37. maxLevel: this.maxLevel,
  38. };
  39. }
  40. private clearCache(): void {
  41. this.currentLevel = 0;
  42. this.topLevel = 0;
  43. this.maxLevel = 0;
  44. this.nodeIndexes = new Map();
  45. this.nodeLevel = new Map();
  46. this.lineLevel = new Map();
  47. }
  48. private computeNodeIndexesMap(nodes: WorkflowNodeEntity[]): Map<string, number> {
  49. const nodeIndexMap = new Map<string, number>();
  50. nodes.forEach((node, index) => {
  51. nodeIndexMap.set(node.id, index);
  52. });
  53. return nodeIndexMap;
  54. }
  55. private computeTopLevel(nodes: WorkflowNodeEntity[]): number {
  56. const nodesWithoutRoot = nodes.filter(node => node.id !== FlowNodeBaseType.ROOT);
  57. const nodeHasChildren = nodesWithoutRoot.reduce((count, node) => {
  58. if (node.collapsedChildren.length > 0) {
  59. return count + 1;
  60. } else {
  61. return count;
  62. }
  63. }, 0);
  64. // 最高层数 = 节点个数 + 容器节点个数(线条单独占一层) + 抬高一层
  65. return nodesWithoutRoot.length + nodeHasChildren + 1;
  66. }
  67. private layerHandler(nodes: WorkflowNodeEntity[], pinTop: boolean = false): void {
  68. const sortedNodes = nodes.sort((a, b) => {
  69. const aIndex = this.nodeIndexes.get(a.id);
  70. const bIndex = this.nodeIndexes.get(b.id);
  71. if (aIndex === undefined || bIndex === undefined) {
  72. return 0;
  73. }
  74. return aIndex - bIndex;
  75. });
  76. const lines = nodes
  77. .map(node => {
  78. const linesData = node.getData<WorkflowNodeLinesData>(WorkflowNodeLinesData);
  79. const outputLines = linesData.outputLines.filter(Boolean);
  80. const inputLines = linesData.inputLines.filter(Boolean);
  81. // 前后线条会有重复,下面 Map 会通过线条 ID 过滤掉
  82. return [...outputLines, ...inputLines];
  83. })
  84. .flat();
  85. // 线条统一设为当前层级最低
  86. lines.forEach(line => {
  87. if (
  88. line.isDrawing || // 正在绘制
  89. this.context.hoveredEntityID === line.id || // hover
  90. this.context.selectedIDs.includes(line.id) // 选中
  91. ) {
  92. // 线条置顶条件:正在绘制 / hover / 选中
  93. this.lineLevel.set(line.id, this.maxLevel);
  94. } else {
  95. this.lineLevel.set(line.id, this.getLevel(pinTop));
  96. }
  97. });
  98. this.levelIncrease();
  99. sortedNodes.forEach(node => {
  100. const selected = this.context.selectedIDs.includes(node.id);
  101. if (selected) {
  102. // 节点置顶条件:选中
  103. this.nodeLevel.set(node.id, this.topLevel);
  104. } else {
  105. this.nodeLevel.set(node.id, this.getLevel(pinTop));
  106. }
  107. // 节点层级逐层增高
  108. this.levelIncrease();
  109. if (node.collapsedChildren.length > 0) {
  110. // 子节点层级需低于后续兄弟节点,因此需要先进行计算
  111. this.layerHandler(node.collapsedChildren, pinTop || selected);
  112. }
  113. });
  114. }
  115. private getLevel(pinTop: boolean): number {
  116. if (pinTop) {
  117. return this.topLevel + this.currentLevel;
  118. }
  119. return this.currentLevel;
  120. }
  121. private levelIncrease(): void {
  122. this.currentLevel += 1;
  123. }
  124. }