manager.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { debounce } from 'lodash';
  2. import { inject, injectable } from 'inversify';
  3. import { FlowNodeRenderData } from '@flowgram.ai/document';
  4. import { EntityManager, PipelineRegistry, PipelineRenderer } from '@flowgram.ai/core';
  5. import {
  6. WorkflowHoverService,
  7. WorkflowNodeEntity,
  8. WorkflowSelectService,
  9. } from '@flowgram.ai/free-layout-core';
  10. import { WorkflowLineEntity } from '@flowgram.ai/free-layout-core';
  11. import { WorkflowDocument } from '@flowgram.ai/free-layout-core';
  12. import { domUtils } from '@flowgram.ai/utils';
  13. import { Disposable } from '@flowgram.ai/utils';
  14. import type { StackingContext } from './type';
  15. import { StackingComputing } from './stacking-computing';
  16. import { layersComputing } from './layers-computing';
  17. import { StackingComputeMode, StackingConfig } from './constant';
  18. @injectable()
  19. export class StackingContextManager {
  20. @inject(WorkflowDocument) private readonly document: WorkflowDocument;
  21. @inject(EntityManager) private readonly entityManager: EntityManager;
  22. @inject(PipelineRenderer)
  23. private readonly pipelineRenderer: PipelineRenderer;
  24. @inject(PipelineRegistry)
  25. private readonly pipelineRegistry: PipelineRegistry;
  26. @inject(WorkflowHoverService)
  27. private readonly hoverService: WorkflowHoverService;
  28. @inject(WorkflowSelectService)
  29. private readonly selectService: WorkflowSelectService;
  30. public readonly node = domUtils.createDivWithClass(
  31. 'gedit-playground-layer gedit-flow-render-layer',
  32. );
  33. private disposers: Disposable[] = [];
  34. private mode: StackingComputeMode = StackingComputeMode.Stacking;
  35. constructor() {}
  36. public init(mode?: StackingComputeMode): void {
  37. if (mode) this.mode = mode;
  38. this.pipelineRenderer.node.appendChild(this.node);
  39. this.mountListener();
  40. }
  41. public ready(): void {
  42. this.compute();
  43. }
  44. public dispose(): void {
  45. this.disposers.forEach(disposer => disposer.dispose());
  46. }
  47. /**
  48. * 触发计算
  49. * 10ms内仅计算一次
  50. */
  51. private compute = debounce(this._compute, 10);
  52. private _compute(): void {
  53. if (this.mode === StackingComputeMode.Stacking) {
  54. return this.stackingCompute();
  55. } else {
  56. return layersComputing({
  57. nodes: this.nodes,
  58. lines: this.lines,
  59. context: this.context,
  60. });
  61. }
  62. }
  63. private stackingCompute(): void {
  64. const context = this.context;
  65. const stackingComputing = new StackingComputing();
  66. const { nodeLevel, lineLevel } = stackingComputing.compute({
  67. root: this.document.root,
  68. nodes: this.nodes,
  69. context,
  70. });
  71. this.nodes.forEach(node => {
  72. const level = nodeLevel.get(node.id);
  73. const nodeRenderData = node.getData<FlowNodeRenderData>(FlowNodeRenderData);
  74. const element = nodeRenderData.node;
  75. element.style.position = 'absolute';
  76. if (!level) {
  77. element.style.zIndex = 'auto';
  78. return;
  79. }
  80. element.style.zIndex = String(StackingConfig.startIndex + level);
  81. });
  82. this.lines.forEach(line => {
  83. const level = lineLevel.get(line.id);
  84. const element = line.node;
  85. element.style.position = 'absolute';
  86. if (!level) {
  87. element.style.zIndex = 'auto';
  88. return;
  89. }
  90. element.style.zIndex = String(StackingConfig.startIndex + level);
  91. });
  92. }
  93. private get nodes(): WorkflowNodeEntity[] {
  94. return this.entityManager.getEntities<WorkflowNodeEntity>(WorkflowNodeEntity);
  95. }
  96. private get lines(): WorkflowLineEntity[] {
  97. return this.entityManager.getEntities<WorkflowLineEntity>(WorkflowLineEntity);
  98. }
  99. private get context(): StackingContext {
  100. return {
  101. hoveredEntity: this.hoverService.hoveredNode,
  102. hoveredEntityID: this.hoverService.hoveredNode?.id,
  103. selectedEntities: this.selectService.selection,
  104. selectedIDs: this.selectService.selection.map(entity => entity.id),
  105. };
  106. }
  107. private mountListener(): void {
  108. const entityChangeDisposer = this.onEntityChange();
  109. const zoomDisposer = this.onZoom();
  110. const hoverDisposer = this.onHover();
  111. const selectDisposer = this.onSelect();
  112. this.disposers = [entityChangeDisposer, zoomDisposer, hoverDisposer, selectDisposer];
  113. }
  114. private onZoom(): Disposable {
  115. return this.pipelineRegistry.onZoom((scale: number) => {
  116. this.node.style.transform = `scale(${scale})`;
  117. });
  118. }
  119. private onHover(): Disposable {
  120. return this.hoverService.onHoveredChange(() => {
  121. this.compute();
  122. });
  123. }
  124. private onEntityChange(): Disposable {
  125. return this.entityManager.onEntityChange(() => {
  126. this.compute();
  127. });
  128. }
  129. private onSelect(): Disposable {
  130. return this.selectService.onSelectionChanged(() => {
  131. this.compute();
  132. });
  133. }
  134. }