flow-document.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. import { omit } from 'lodash';
  2. import { inject, injectable, multiInject, optional, postConstruct } from 'inversify';
  3. import { type Disposable, Emitter } from '@flowgram.ai/utils';
  4. import { type EntityData, type EntityDataRegistry, EntityManager } from '@flowgram.ai/core';
  5. import {
  6. AddNodeData,
  7. DEFAULT_FLOW_NODE_META,
  8. type FlowDocumentJSON,
  9. FlowLayout,
  10. FlowLayoutDefault,
  11. FlowNodeBaseType,
  12. type FlowNodeJSON,
  13. FlowNodeRegistry,
  14. FlowNodeType,
  15. } from './typings';
  16. import { FlowVirtualTree } from './flow-virtual-tree';
  17. import { FlowRenderTree } from './flow-render-tree';
  18. import {
  19. ConstantKeys,
  20. FlowDocumentOptions,
  21. FlowDocumentOptionsDefault,
  22. } from './flow-document-options';
  23. import { FlowDocumentContribution } from './flow-document-contribution';
  24. import { FlowDocumentConfig } from './flow-document-config';
  25. import { FlowDocumentTransformerEntity, FlowNodeEntity, FlowRendererStateEntity } from './entities';
  26. export type FlowDocumentProvider = () => FlowDocument;
  27. export const FlowDocumentProvider = Symbol('FlowDocumentProvider');
  28. /**
  29. * 流程整个文档数据
  30. */
  31. @injectable()
  32. export class FlowDocument<T = FlowDocumentJSON> implements Disposable {
  33. @inject(EntityManager) protected entityManager: EntityManager;
  34. @inject(FlowDocumentConfig) readonly config: FlowDocumentConfig;
  35. /**
  36. * 流程画布配置项
  37. */
  38. @inject(FlowDocumentOptions) @optional() public options: FlowDocumentOptions;
  39. @multiInject(FlowDocumentContribution)
  40. @optional()
  41. protected contributions: FlowDocumentContribution[] = [];
  42. protected registers = new Map<FlowNodeType, FlowNodeRegistry>();
  43. private nodeRegistryCache = new Map<string, any>();
  44. protected nodeDataRegistries: EntityDataRegistry[] = [];
  45. protected layouts: FlowLayout[] = [];
  46. protected currentLayoutKey: string = '';
  47. protected onNodeUpdateEmitter = new Emitter<{
  48. node: FlowNodeEntity;
  49. /**
  50. * use 'json' instead
  51. * @deprecated
  52. */
  53. data: FlowNodeJSON;
  54. json: FlowNodeJSON;
  55. }>();
  56. protected onNodeCreateEmitter = new Emitter<{
  57. node: FlowNodeEntity;
  58. /**
  59. * use 'json' instead
  60. * @deprecated
  61. */
  62. data: FlowNodeJSON;
  63. json: FlowNodeJSON;
  64. }>();
  65. protected onNodeDisposeEmitter = new Emitter<{
  66. node: FlowNodeEntity;
  67. }>();
  68. protected onLayoutChangeEmitter = new Emitter<FlowLayout>();
  69. readonly onNodeUpdate = this.onNodeUpdateEmitter.event;
  70. readonly onNodeCreate = this.onNodeCreateEmitter.event;
  71. readonly onNodeDispose = this.onNodeDisposeEmitter.event;
  72. readonly onLayoutChange = this.onLayoutChangeEmitter.event;
  73. private _disposed = false;
  74. root: FlowNodeEntity;
  75. /**
  76. * 原始的 tree 结构
  77. */
  78. originTree: FlowVirtualTree<FlowNodeEntity>;
  79. transformer: FlowDocumentTransformerEntity;
  80. /**
  81. * 渲染相关的全局轧辊台
  82. */
  83. renderState: FlowRendererStateEntity;
  84. /**
  85. * 渲染后的 tree 结构
  86. */
  87. renderTree: FlowRenderTree<FlowNodeEntity>;
  88. /**
  89. *
  90. */
  91. get disposed(): boolean {
  92. return this._disposed;
  93. }
  94. @postConstruct()
  95. init(): void {
  96. if (!this.options) this.options = FlowDocumentOptionsDefault;
  97. this.currentLayoutKey = this.options.defaultLayout || FlowLayoutDefault.VERTICAL_FIXED_LAYOUT;
  98. this.contributions.forEach((contrib) => contrib.registerDocument?.(this));
  99. this.root = this.addNode({ id: 'root', type: FlowNodeBaseType.ROOT });
  100. this.originTree = new FlowVirtualTree<FlowNodeEntity>(this.root);
  101. this.transformer = this.entityManager.createEntity<FlowDocumentTransformerEntity>(
  102. FlowDocumentTransformerEntity,
  103. { document: this }
  104. );
  105. this.renderState =
  106. this.entityManager.createEntity<FlowRendererStateEntity>(FlowRendererStateEntity);
  107. this.renderTree = new FlowRenderTree<FlowNodeEntity>(this.root, this.originTree, this);
  108. // 布局第一次加载时候触发一次
  109. this.layout.reload?.();
  110. }
  111. /**
  112. * 从数据初始化 O(n)
  113. * @param json
  114. */
  115. /**
  116. * 加载数据,可以被重载
  117. * @param json 文档数据更新
  118. * @param fireRender 是否要触发渲染,默认 true
  119. */
  120. fromJSON(json: FlowDocumentJSON | any, fireRender = true): void {
  121. if (this._disposed) return;
  122. // 清空 tree 数据 重新计算
  123. this.originTree.clear();
  124. this.renderTree.clear();
  125. // 暂停触发画布更新
  126. this.entityManager.changeEntityLocked = true;
  127. // 添加前的节点
  128. const oldNodes = this.entityManager.getEntities<FlowNodeEntity>(FlowNodeEntity);
  129. // 添加后的节点
  130. const newNodes: FlowNodeEntity[] = [this.root];
  131. this.addBlocksAsChildren(this.root, json.nodes || [], newNodes);
  132. // 删除无效的节点
  133. oldNodes.forEach((node) => {
  134. if (!newNodes.includes(node)) {
  135. node.dispose();
  136. }
  137. });
  138. this.entityManager.changeEntityLocked = false;
  139. this.transformer.loading = false;
  140. if (fireRender) this.fireRender();
  141. }
  142. get layout(): FlowLayout {
  143. const layout = this.layouts.find((layout) => layout.name == this.currentLayoutKey);
  144. if (!layout) {
  145. throw new Error(`Unknown flow layout: ${this.currentLayoutKey}`);
  146. }
  147. return layout;
  148. }
  149. async load(): Promise<void> {
  150. await Promise.all(this.contributions.map((c) => c.loadDocument?.(this)));
  151. }
  152. get loading(): boolean {
  153. return this.transformer.loading;
  154. }
  155. /**
  156. * 触发 render
  157. */
  158. fireRender(): void {
  159. if (this.transformer.isTreeDirty()) {
  160. this.entityManager.fireEntityChanged(FlowNodeEntity.type);
  161. this.entityManager.fireEntityChanged(FlowDocumentTransformerEntity.type);
  162. }
  163. }
  164. /**
  165. * 从指定节点的下一个节点新增
  166. * @param fromNode
  167. * @param json
  168. */
  169. addFromNode(fromNode: FlowNodeEntity | string, json: FlowNodeJSON): FlowNodeEntity {
  170. const node = typeof fromNode === 'string' ? this.getNode(fromNode)! : fromNode;
  171. this.entityManager.changeEntityLocked = true;
  172. const { parent } = node;
  173. const result = this.addNode({
  174. ...json,
  175. parent,
  176. // originParent,
  177. });
  178. this.originTree.insertAfter(node, result);
  179. this.entityManager.changeEntityLocked = false;
  180. this.entityManager.fireEntityChanged(FlowNodeEntity.type);
  181. return result;
  182. }
  183. removeNode(node: FlowNodeEntity | string) {
  184. if (typeof node === 'string') {
  185. this.getNode(node)?.dispose();
  186. } else {
  187. node.dispose();
  188. }
  189. }
  190. /**
  191. * 添加节点,如果节点已经存在则不会重复创建
  192. * @param data
  193. * @param addedNodes
  194. */
  195. addNode(data: AddNodeData, addedNodes?: FlowNodeEntity[]): FlowNodeEntity {
  196. const { id, type = 'block', originParent, parent, meta, hidden, index } = data;
  197. let node = this.getNode(id);
  198. let isNew = false;
  199. const register = this.getNodeRegistry(type, data.originParent);
  200. // node 类型变化则全部删除重新来
  201. if (node && node.flowNodeType !== data.type) {
  202. node.dispose();
  203. node = undefined;
  204. }
  205. if (!node) {
  206. const { dataRegistries } = register;
  207. node = this.entityManager.createEntity<FlowNodeEntity>(FlowNodeEntity, {
  208. id,
  209. document: this,
  210. flowNodeType: type,
  211. originParent,
  212. meta,
  213. });
  214. const datas = dataRegistries
  215. ? this.nodeDataRegistries.concat(...dataRegistries)
  216. : this.nodeDataRegistries;
  217. node.addInitializeData(datas);
  218. node.onDispose(() => this.onNodeDisposeEmitter.fire({ node: node! }));
  219. this.options.fromNodeJSON?.(node, data, true);
  220. isNew = true;
  221. } else {
  222. this.options.fromNodeJSON?.(node, data, false);
  223. }
  224. // 初始化数据重制
  225. node.initData({
  226. originParent,
  227. parent,
  228. meta,
  229. hidden,
  230. index,
  231. });
  232. // 开始节点加到 root 里边
  233. if (node.isStart) {
  234. this.root.addChild(node);
  235. }
  236. addedNodes?.push(node);
  237. // 自定义创建逻辑
  238. if (register.onCreate) {
  239. const extendNodes = register.onCreate(node, data);
  240. if (extendNodes && addedNodes) {
  241. addedNodes.push(...extendNodes);
  242. }
  243. } else if (data.blocks && data.blocks.length > 0) {
  244. // 兼容老的写法
  245. if (!data.blocks[0].type) {
  246. this.addInlineBlocks(node, data.blocks, addedNodes);
  247. } else {
  248. this.addBlocksAsChildren(node, data.blocks as FlowNodeJSON[], addedNodes);
  249. }
  250. }
  251. if (isNew) {
  252. this.onNodeCreateEmitter.fire({
  253. node,
  254. data,
  255. json: data,
  256. });
  257. } else {
  258. this.onNodeUpdateEmitter.fire({ node, data, json: data });
  259. }
  260. return node;
  261. }
  262. addBlocksAsChildren(
  263. parent: FlowNodeEntity,
  264. blocks: FlowNodeJSON[],
  265. addedNodes?: FlowNodeEntity[]
  266. ): void {
  267. for (const block of blocks) {
  268. this.addNode(
  269. {
  270. ...block,
  271. parent,
  272. },
  273. addedNodes
  274. );
  275. }
  276. }
  277. /**
  278. * block 格式:
  279. * node: (最原始的 id)
  280. * blockIcon
  281. * inlineBlocks
  282. * block
  283. * blockOrderIcon
  284. * block
  285. * blockOrderIcon
  286. * @param node
  287. * @param blocks
  288. * @param addedNodes
  289. */
  290. addInlineBlocks(
  291. node: FlowNodeEntity,
  292. blocks: FlowNodeJSON[],
  293. addedNodes: FlowNodeEntity[] = []
  294. ): FlowNodeEntity[] {
  295. // 块列表开始节点,用来展示块的按钮
  296. const blockIconNode = this.addNode({
  297. id: `$blockIcon$${node.id}`,
  298. type: FlowNodeBaseType.BLOCK_ICON,
  299. originParent: node,
  300. parent: node,
  301. });
  302. addedNodes.push(blockIconNode);
  303. // 水平布局
  304. const inlineBlocksNode = this.addNode({
  305. id: `$inlineBlocks$${node.id}`,
  306. type: FlowNodeBaseType.INLINE_BLOCKS,
  307. originParent: node,
  308. parent: node,
  309. });
  310. addedNodes.push(inlineBlocksNode);
  311. blocks.forEach((blockData) => {
  312. this.addBlock(node, blockData, addedNodes);
  313. });
  314. return addedNodes;
  315. }
  316. /**
  317. * 添加单个 block
  318. * @param target
  319. * @param blockData
  320. * @param addedNodes
  321. * @param parent 默认去找 $inlineBlocks$
  322. */
  323. addBlock(
  324. target: FlowNodeEntity | string,
  325. blockData: FlowNodeJSON,
  326. addedNodes?: FlowNodeEntity[],
  327. parent?: FlowNodeEntity,
  328. index?: number
  329. ): FlowNodeEntity {
  330. const node: FlowNodeEntity = typeof target === 'string' ? this.getNode(target)! : target;
  331. const { onBlockChildCreate } = node.getNodeRegistry();
  332. if (onBlockChildCreate) {
  333. return onBlockChildCreate(node, blockData, addedNodes);
  334. }
  335. parent = parent || this.getNode(`$inlineBlocks$${node.id}`);
  336. // 块节点会生成一个空的 Block 节点用来切割 Block
  337. const block = this.addNode({
  338. ...omit(blockData, 'blocks'),
  339. type: blockData.type || FlowNodeBaseType.BLOCK,
  340. originParent: node,
  341. parent,
  342. index,
  343. });
  344. if (blockData.meta?.defaultCollapsed) {
  345. block.collapsed = true;
  346. }
  347. // 块开始节点
  348. const blockOrderIcon = this.addNode({
  349. id: `$blockOrderIcon$${blockData.id}`,
  350. type: FlowNodeBaseType.BLOCK_ORDER_ICON,
  351. originParent: node,
  352. meta: blockData.meta,
  353. data: blockData.data,
  354. parent: block,
  355. });
  356. addedNodes?.push(block, blockOrderIcon);
  357. if (blockData.blocks) {
  358. this.addBlocksAsChildren(block, blockData.blocks as FlowNodeJSON[], addedNodes);
  359. }
  360. return block;
  361. }
  362. /**
  363. * 根据 id 获取节点
  364. * @param id
  365. */
  366. getNode(id: string): FlowNodeEntity | undefined {
  367. if (!id) return undefined;
  368. return this.entityManager.getEntityById<FlowNodeEntity>(id);
  369. }
  370. /**
  371. * 注册节点
  372. * @param registries
  373. */
  374. registerFlowNodes<T extends FlowNodeRegistry<any>>(...registries: T[]): void {
  375. registries.forEach((newRegistry) => {
  376. if (!newRegistry) {
  377. throw new Error('[FlowDocument] registerFlowNodes parameters get undefined registry.');
  378. }
  379. const preRegistry = this.registers.get(newRegistry.type);
  380. this.registers.set(newRegistry.type, {
  381. ...preRegistry,
  382. ...newRegistry,
  383. meta: {
  384. ...preRegistry?.meta,
  385. ...newRegistry?.meta,
  386. },
  387. extendChildRegistries: FlowNodeRegistry.mergeChildRegistries(
  388. preRegistry?.extendChildRegistries,
  389. newRegistry?.extendChildRegistries
  390. ),
  391. });
  392. });
  393. }
  394. /**
  395. * Check node extend
  396. * @param currentType
  397. * @param parentType
  398. */
  399. isExtend(currentType: FlowNodeType, parentType: FlowNodeType): boolean {
  400. return (this.getNodeRegistry(currentType).__extends__ || []).includes(parentType);
  401. }
  402. /**
  403. * 导出数据,可以重载
  404. */
  405. toJSON(): T | any {
  406. return {
  407. nodes: this.root.toJSON().blocks,
  408. };
  409. }
  410. /**
  411. * @deprecated
  412. * use `getNodeRegistry` instead
  413. */
  414. getNodeRegister<T extends FlowNodeRegistry = FlowNodeRegistry>(
  415. type: FlowNodeType,
  416. originParent?: FlowNodeEntity
  417. ): T {
  418. return this.getNodeRegistry<T>(type, originParent);
  419. }
  420. getNodeRegistry<T extends FlowNodeRegistry = FlowNodeRegistry>(
  421. type: FlowNodeType,
  422. originParent?: FlowNodeEntity
  423. ): T {
  424. const typeKey = `${type}_${originParent?.flowNodeType || ''}`;
  425. if (this.nodeRegistryCache.has(typeKey)) {
  426. return this.nodeRegistryCache.get(typeKey) as T;
  427. }
  428. const customDefaultRegistry = this.options.getNodeDefaultRegistry?.(type);
  429. let register = this.registers.get(type) || { type };
  430. const extendRegisters: FlowNodeRegistry[] = [];
  431. const extendKey = register.extend;
  432. // 继承重载
  433. if (register.extend && this.registers.has(register.extend)) {
  434. register = FlowNodeRegistry.merge(
  435. this.getNodeRegistry(register.extend),
  436. register,
  437. register.type
  438. );
  439. }
  440. // 父节点覆盖
  441. if (originParent) {
  442. const extendRegister = this.getNodeRegistry(
  443. originParent.flowNodeType
  444. ).extendChildRegistries?.find((r) => r.type === type);
  445. if (extendRegister) {
  446. if (extendRegister.extend && this.registers.has(extendRegister.extend)) {
  447. extendRegisters.push(this.registers.get(extendRegister.extend)!);
  448. }
  449. extendRegisters.push(extendRegister);
  450. }
  451. }
  452. register = FlowNodeRegistry.extend(register, extendRegisters);
  453. const defaultNodeMeta = DEFAULT_FLOW_NODE_META(type, this);
  454. defaultNodeMeta.spacing =
  455. this.options?.constants?.[ConstantKeys.NODE_SPACING] || defaultNodeMeta.spacing;
  456. const res = {
  457. ...customDefaultRegistry,
  458. ...register,
  459. meta: {
  460. ...defaultNodeMeta,
  461. ...customDefaultRegistry?.meta,
  462. ...register.meta,
  463. },
  464. } as T;
  465. // Save the "extend" attribute
  466. if (extendKey) {
  467. res.extend = extendKey;
  468. }
  469. this.nodeRegistryCache.set(typeKey, res);
  470. return res;
  471. }
  472. /**
  473. * 节点注入数据
  474. * @param nodeDatas
  475. */
  476. registerNodeDatas(...nodeDatas: EntityDataRegistry[]): void {
  477. this.nodeDataRegistries.push(...nodeDatas);
  478. }
  479. /**
  480. * traverse all nodes, O(n)
  481. * R
  482. * |
  483. * +---1
  484. * | |
  485. * | +---1.1
  486. * | |
  487. * | +---1.2
  488. * | |
  489. * | +---1.3
  490. * | | |
  491. * | | +---1.3.1
  492. * | | |
  493. * | | +---1.3.2
  494. * | |
  495. * | +---1.4
  496. * |
  497. * +---2
  498. * |
  499. * +---2.1
  500. *
  501. * sort: [1, 1.1, 1.2, 1.3, 1.3.1, 1.3.2, 1.4, 2, 2.1]
  502. * @param fn
  503. * @param node
  504. * @param depth
  505. * @return isBreak
  506. */
  507. traverse(
  508. fn: (node: FlowNodeEntity, depth: number, index: number) => boolean | void,
  509. node = this.root,
  510. depth = 0
  511. ): boolean | void {
  512. return this.originTree.traverse(fn, node, depth);
  513. }
  514. get size(): number {
  515. return this.getAllNodes().length;
  516. }
  517. hasNode(nodeId: string): boolean {
  518. return !!this.entityManager.getEntityById(nodeId);
  519. }
  520. getAllNodes(): FlowNodeEntity[] {
  521. return this.entityManager.getEntities(FlowNodeEntity);
  522. }
  523. toString(showType?: boolean): string {
  524. return this.originTree.toString(showType);
  525. }
  526. /**
  527. * 返回需要渲染的数据
  528. */
  529. getRenderDatas<T extends EntityData>(
  530. dataRegistry: EntityDataRegistry<T>,
  531. containHiddenNodes = true
  532. ): T[] {
  533. const result: T[] = [];
  534. this.renderTree.traverse((node) => {
  535. if (!containHiddenNodes && node.hidden) return;
  536. result.push(node.getData<T>(dataRegistry)!);
  537. });
  538. return result;
  539. }
  540. toNodeJSON(node: FlowNodeEntity): FlowNodeJSON {
  541. if (this.options.toNodeJSON) {
  542. return this.options.toNodeJSON(node);
  543. }
  544. const nodesMap: Record<string, FlowNodeJSON> = {};
  545. let startNodeJSON: FlowNodeJSON;
  546. this.traverse((node) => {
  547. const isSystemNode = node.id.startsWith('$');
  548. if (isSystemNode) return;
  549. const nodeJSONData = node.getJSONData();
  550. const nodeJSON: FlowNodeJSON = {
  551. id: node.id,
  552. type: node.flowNodeType,
  553. };
  554. if (nodeJSONData !== undefined) {
  555. nodeJSON.data = nodeJSONData;
  556. }
  557. if (!startNodeJSON) startNodeJSON = nodeJSON;
  558. let { parent } = node;
  559. if (parent && parent.id.startsWith('$')) {
  560. parent = parent.originParent;
  561. }
  562. const parentJSON = parent ? nodesMap[parent.id] : undefined;
  563. if (parentJSON) {
  564. if (!parentJSON.blocks) {
  565. parentJSON.blocks = [];
  566. }
  567. parentJSON.blocks.push(nodeJSON);
  568. }
  569. nodesMap[node.id] = nodeJSON;
  570. }, node);
  571. return startNodeJSON!;
  572. }
  573. /**
  574. * 移动节点
  575. * @param param0
  576. * @returns
  577. */
  578. moveNodes({
  579. dropNodeId,
  580. sortNodeIds,
  581. inside = false,
  582. }: {
  583. dropNodeId: string;
  584. sortNodeIds: string[];
  585. inside?: boolean;
  586. }) {
  587. const dropEntity = this.getNode(dropNodeId);
  588. if (!dropEntity) {
  589. return;
  590. }
  591. const sortNodes = sortNodeIds.map((id) => this.getNode(id)!);
  592. // 按照顺序一个个移动到目标节点下
  593. this.entityManager.changeEntityLocked = true;
  594. for (const node of sortNodes.reverse()) {
  595. if (inside) {
  596. this.originTree.addChild(dropEntity, node, 0);
  597. } else {
  598. this.originTree.insertAfter(dropEntity, node);
  599. }
  600. }
  601. this.entityManager.changeEntityLocked = false;
  602. this.fireRender();
  603. }
  604. /**
  605. * 移动子节点
  606. * @param param0
  607. * @returns
  608. */
  609. moveChildNodes({
  610. toParentId,
  611. toIndex,
  612. nodeIds,
  613. }: {
  614. toParentId: string;
  615. nodeIds: string[];
  616. toIndex: number;
  617. }) {
  618. if (nodeIds.length === 0) {
  619. return;
  620. }
  621. const toParent = this.getNode(toParentId);
  622. if (!toParent) {
  623. return;
  624. }
  625. this.entityManager.changeEntityLocked = true;
  626. this.originTree.moveChilds(
  627. toParent,
  628. nodeIds.map((nodeId) => this.getNode(nodeId) as FlowNodeEntity),
  629. toIndex
  630. );
  631. this.entityManager.changeEntityLocked = false;
  632. this.fireRender();
  633. }
  634. /**
  635. * 注册布局
  636. * @param layout
  637. */
  638. registerLayout(layout: FlowLayout) {
  639. this.layouts.push(layout);
  640. }
  641. /**
  642. * 更新布局
  643. * @param layoutKey
  644. */
  645. setLayout(layoutKey: string) {
  646. if (this.currentLayoutKey === layoutKey) return;
  647. const layout = this.layouts.find((layout) => layout.name === layoutKey);
  648. if (!layout) return;
  649. this.currentLayoutKey = layoutKey;
  650. this.transformer.clear();
  651. layout.reload?.();
  652. this.fireRender();
  653. this.onLayoutChangeEmitter.fire(this.layout);
  654. }
  655. /**
  656. * 切换垂直或水平布局
  657. */
  658. toggleFixedLayout() {
  659. this.setLayout(
  660. this.layout.name === FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT
  661. ? FlowLayoutDefault.VERTICAL_FIXED_LAYOUT
  662. : FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT
  663. );
  664. }
  665. dispose() {
  666. if (this._disposed) return;
  667. this.registers.clear();
  668. this.nodeRegistryCache.clear();
  669. this.originTree.dispose();
  670. this.renderTree.dispose();
  671. this.onNodeUpdateEmitter.dispose();
  672. this.onNodeCreateEmitter.dispose();
  673. this.onNodeDisposeEmitter.dispose();
  674. this.onLayoutChangeEmitter.dispose();
  675. this._disposed = true;
  676. }
  677. }