import { Engine } from '../engine'; import { LayoutProvider } from './layoutProvider'; import { LayoutGroupTable } from '../Model/modelConstructor'; import { Util } from '../Common/util'; import { SVModel } from '../Model/SVModel'; import { Renderer } from './renderer'; import { Reconcile } from './reconcile'; import { EventBus } from '../Common/eventBus'; import { Group } from '../Common/group'; import { Graph, Modes } from '@antv/g6-pc'; import { InitG6Behaviors } from '../BehaviorHelper/initG6Behaviors'; import { SVNode } from '../Model/SVNode'; import { SolveBrushSelectDrag, SolveDragCanvasWithLeak, SolveNodeAppendagesDrag, SolveZoomCanvasWithLeak, } from '../BehaviorHelper/behaviorIssueHelper'; export class ViewContainer { private engine: Engine; private layoutProvider: LayoutProvider; private reconcile: Reconcile; public renderer: Renderer; private layoutGroupTable: LayoutGroupTable; private prevModelList: SVModel[]; private accumulateLeakModels: SVModel[]; public hasLeak: boolean; public leakAreaY: number; public brushSelectedModels: SVModel[]; // 保存框选过程中被选中的节点 public clickSelectNode: SVNode; // 点击选中的节点 constructor(engine: Engine, DOMContainer: HTMLElement) { const behaviorsModes: Modes = InitG6Behaviors(engine, this); this.engine = engine; this.layoutProvider = new LayoutProvider(engine, this); this.renderer = new Renderer(engine, DOMContainer, behaviorsModes); this.reconcile = new Reconcile(engine, this.renderer); this.layoutGroupTable = new Map(); this.prevModelList = []; this.accumulateLeakModels = []; this.hasLeak = false; // 判断是否已经发生过泄漏 this.brushSelectedModels = []; this.clickSelectNode = null; const g6Instance = this.renderer.getG6Instance(), leakAreaHeight = this.engine.viewOptions.leakAreaHeight, height = this.getG6Instance().getHeight(), { drag, zoom } = this.engine.behaviorOptions; this.leakAreaY = height - leakAreaHeight; SolveNodeAppendagesDrag(this); SolveBrushSelectDrag(this); drag && SolveDragCanvasWithLeak(this); zoom && SolveZoomCanvasWithLeak(this); } // ---------------------------------------------------------------------------------------------- /** * 对主视图进行重新布局 */ reLayout() { const g6Instance = this.getG6Instance(), group = g6Instance.getGroup(), matrix = group.getMatrix(); if (matrix) { let dx = matrix[6], dy = matrix[7]; g6Instance.translate(-dx, -dy); } this.layoutProvider.layoutAll(this.layoutGroupTable, this.accumulateLeakModels); g6Instance.refresh(); } /** * 获取 g6 实例 */ getG6Instance(): Graph { return this.renderer.getG6Instance(); } /** * 获取泄漏区里面的元素 * @returns */ getAccumulateLeakModels(): SVModel[] { return this.accumulateLeakModels; } /** * */ getLayoutGroupTable(): LayoutGroupTable { return this.layoutGroupTable; } /** * 刷新视图 */ refresh() { this.renderer.getG6Instance().refresh(); } /** * 重新调整容器尺寸 * @param width * @param height */ resize(width: number, height: number) { const g6Instance = this.getG6Instance(), prevContainerHeight = g6Instance.getHeight(), globalGroup: Group = new Group(); globalGroup.add(...this.prevModelList, ...this.accumulateLeakModels); this.renderer.changeSize(width, height); const containerHeight = g6Instance.getHeight(), dy = containerHeight - prevContainerHeight; globalGroup.translate(0, dy); this.renderer.refresh(); this.leakAreaY += dy; EventBus.emit('onLeakAreaUpdate', { leakAreaY: this.leakAreaY, hasLeak: this.hasLeak, }); } /** * 渲染所有视图 * @param models * @param layoutFn */ render(layoutGroupTable: LayoutGroupTable, isSameSources: boolean, isEnterFunction: boolean) { const modelList = Util.convertGroupTable2ModelList(layoutGroupTable); // 如果数据没变的话 if (isSameSources) { modelList.forEach(item => item.restoreHighlight()); return; } const diffResult = this.reconcile.diff( this.layoutGroupTable, this.prevModelList, modelList, this.accumulateLeakModels, isEnterFunction ), renderModelList = [...modelList, ...diffResult.REMOVE, ...diffResult.LEAKED, ...diffResult.ACCUMULATE_LEAK]; // 从有泄漏区变成无泄漏区 if (this.hasLeak === true && this.accumulateLeakModels.length === 0) { this.hasLeak = false; EventBus.emit('onLeakAreaUpdate', { leakAreaY: this.leakAreaY, hasLeak: this.hasLeak, }); } // 从无泄漏区变成有泄漏区 if (diffResult.LEAKED.length) { this.hasLeak = true; EventBus.emit('onLeakAreaUpdate', { leakAreaY: this.leakAreaY, hasLeak: this.hasLeak, }); } this.accumulateLeakModels.push(...diffResult.LEAKED); // 对泄漏节点进行向后累积 this.renderer.build(renderModelList); // 首先在离屏canvas渲染先 this.layoutProvider.layoutAll(layoutGroupTable, this.accumulateLeakModels); // 进行布局(设置model的x,y,样式等) this.beforeRender(); this.renderer.render(renderModelList); // 渲染视图 this.reconcile.patch(diffResult,isEnterFunction); // 对视图上的某些变化进行对应的动作,比如:节点创建动画,节点消失动画等 this.afterRender(); this.layoutGroupTable = layoutGroupTable; this.prevModelList = modelList; } /** * 销毁 */ destroy() { this.renderer.destroy(); this.reconcile.destroy(); this.layoutProvider = null; this.layoutGroupTable = null; this.prevModelList.length = 0; this.accumulateLeakModels.length = 0; this.brushSelectedModels.length = 0; } // ------------------------------------------------------------------------------ /** * 把渲染后要触发的逻辑放在这里 */ private afterRender() { this.prevModelList.forEach(item => { if (item.leaked === false) { item.discarded = true; } }); } /** * 把渲染前要触发的逻辑放在这里 */ private beforeRender() {} }