layers-computing.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { FlowNodeRenderData } from '@flowgram.ai/document';
  2. import type { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';
  3. import type { WorkflowLineEntity } from '@flowgram.ai/free-layout-core';
  4. import type { StackingContext } from './type';
  5. import { StackingBaseIndex, StackingConfig, StackingType } from './constant';
  6. namespace NodeComputing {
  7. export const compute = (node: WorkflowNodeEntity, context: StackingContext): void => {
  8. const zIndex = nodeZIndex(node, context);
  9. const element = nodeElement(node);
  10. element.style.position = 'absolute';
  11. element.style.zIndex = zIndexStringify(zIndex);
  12. };
  13. export const stackingIndex = (stackingType: StackingType, level: number): number | undefined => {
  14. if (level < 1) {
  15. // root节点
  16. return undefined;
  17. }
  18. const baseZIndex = StackingBaseIndex[stackingType];
  19. const zIndex =
  20. StackingConfig.startIndex + StackingConfig.levelIndexStep * (level - 1) + baseZIndex;
  21. return zIndex;
  22. };
  23. export const nodeStackingLevel = (
  24. node: WorkflowNodeEntity,
  25. context: StackingContext,
  26. disableTopLevel = false,
  27. ): number => {
  28. // TODO 后续支持多层级时这个计算逻辑应该去掉,level信息应该直接由 FlowNodeEntity 缓存给出
  29. // 多层时这里的计算会有 O(logN) 时间复杂度,并且在多层级联同计算时会有BUG,本次需求不处理这种情况
  30. const unReversedLinage: WorkflowNodeEntity[] = [];
  31. let currentNode: WorkflowNodeEntity | undefined = node;
  32. while (currentNode) {
  33. unReversedLinage.push(currentNode);
  34. currentNode = currentNode.parent;
  35. }
  36. const linage = unReversedLinage.reverse();
  37. const nodeLevel = linage.length - 1;
  38. const topLevelIndex = linage.findIndex((node: WorkflowNodeEntity) => {
  39. if (context.selectedIDs.includes(node.id)) {
  40. // 存在被选中的父级或自身被选中,直接置顶
  41. return true;
  42. }
  43. return false;
  44. });
  45. const topLevel = StackingConfig.allowLevel + (linage.length - topLevelIndex);
  46. if (!disableTopLevel && topLevelIndex !== -1) {
  47. // 置顶
  48. return topLevel;
  49. }
  50. return nodeLevel;
  51. };
  52. export const zIndexStringify = (zIndex?: number): string => {
  53. if (zIndex === undefined) {
  54. return 'auto';
  55. }
  56. return zIndex.toString();
  57. };
  58. const nodeZIndex = (node: WorkflowNodeEntity, context: StackingContext): number | undefined => {
  59. const level = nodeStackingLevel(node, context);
  60. const zIndex = stackingIndex(StackingType.Node, level);
  61. return zIndex;
  62. };
  63. const nodeElement = (node: WorkflowNodeEntity): HTMLDivElement => {
  64. const nodeRenderData = node.getData<FlowNodeRenderData>(FlowNodeRenderData);
  65. return nodeRenderData.node;
  66. };
  67. }
  68. namespace LineComputing {
  69. export const compute = (line: WorkflowLineEntity, context: StackingContext): void => {
  70. const zIndex = lineZIndex(line, context);
  71. const element = line.node;
  72. element.style.position = 'absolute';
  73. element.style.zIndex = NodeComputing.zIndexStringify(zIndex);
  74. };
  75. const lineStackingLevel = (line: WorkflowLineEntity, context: StackingContext): number => {
  76. if (
  77. line.isDrawing || // 正在绘制
  78. context.hoveredEntityID === line.id || // hover
  79. context.selectedIDs.includes(line.id) // 选中
  80. ) {
  81. // 线条置顶条件:正在绘制 / hover / 选中
  82. return StackingConfig.maxLevel + 1;
  83. }
  84. const fromLevel = NodeComputing.nodeStackingLevel(line.from, context, true);
  85. if (!line.to) {
  86. // 还处于连线中
  87. return fromLevel;
  88. }
  89. const toLevel = NodeComputing.nodeStackingLevel(line.to, context, true);
  90. const level = Math.min(fromLevel, toLevel);
  91. return level;
  92. };
  93. const lineZIndex = (line: WorkflowLineEntity, context: StackingContext): number | undefined => {
  94. const level = lineStackingLevel(line, context);
  95. const zIndex = NodeComputing.stackingIndex(StackingType.Line, level);
  96. return zIndex;
  97. };
  98. }
  99. export const layersComputing = (params: {
  100. nodes: WorkflowNodeEntity[];
  101. lines: WorkflowLineEntity[];
  102. context: StackingContext;
  103. }) => {
  104. const { nodes, lines, context } = params;
  105. nodes.forEach(node => {
  106. NodeComputing.compute(node, context);
  107. });
  108. lines.forEach(line => {
  109. LineComputing.compute(line, context);
  110. });
  111. };