213 lines
6.7 KiB
TypeScript
213 lines
6.7 KiB
TypeScript
import { Engine } from "../engine";
|
||
import { Element, Link } from "../Model/modelData";
|
||
import { EngineInitOptions, LayoutOptions } from "../options";
|
||
import { Container } from "./container/container";
|
||
import { SV } from '../StructV';
|
||
import { ConstructList } from "../Model/modelConstructor";
|
||
import { MainContainer } from "./container/main";
|
||
import { FreedContainer } from "./container/freed";
|
||
import { LeakContainer } from "./container/leak";
|
||
import { Layouter } from "./layouter";
|
||
|
||
|
||
export class ViewManager {
|
||
private engine: Engine;
|
||
private layouter: Layouter;
|
||
private mainContainer: Container;
|
||
private freedContainer: Container;
|
||
private leakContainer: Container;
|
||
|
||
private prevConstructList: ConstructList = { element:[], pointer: [], link: [] };
|
||
private freedConstructList: ConstructList = { element:[], pointer: [], link: [] };
|
||
private leakConstructList: ConstructList = { element:[], pointer: [], link: [] };
|
||
|
||
private shadowG6Instance;
|
||
|
||
constructor(engine: Engine, DOMContainer: HTMLElement) {
|
||
this.engine = engine;
|
||
this.layouter = new Layouter(engine);
|
||
this.mainContainer = new MainContainer(engine, DOMContainer);
|
||
|
||
const options: EngineInitOptions = this.engine.initOptions;
|
||
|
||
if(options.freedContainer) {
|
||
this.freedContainer = new FreedContainer(engine, options.freedContainer, { fitCenter: true });
|
||
}
|
||
|
||
if(options.leakContainer) {
|
||
this.leakContainer = new LeakContainer(engine, options.leakContainer, { fitCenter: true });
|
||
}
|
||
|
||
this.shadowG6Instance = new SV.G6.Graph({
|
||
container: DOMContainer.cloneNode()
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 对每一个 model 在离屏 Canvas 上构建 G6 item,用作布局
|
||
* @param constructList
|
||
*/
|
||
private build(constructList: ConstructList) {
|
||
constructList.element.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
|
||
constructList.pointer.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
|
||
constructList.link.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('edge', item));
|
||
|
||
constructList.element.forEach(item => {
|
||
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
|
||
});
|
||
constructList.pointer.forEach(item => {
|
||
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
|
||
});
|
||
constructList.link.forEach(item => {
|
||
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取被 free 的节点
|
||
* @param constructList
|
||
* @returns
|
||
*/
|
||
private getFreedConstructList(constructList: ConstructList): ConstructList {
|
||
const freedList: ConstructList = {
|
||
element: constructList.element.filter(item => item.free),
|
||
pointer: [],
|
||
link: []
|
||
};
|
||
|
||
freedList.element.forEach(fItem => {
|
||
constructList.element.splice(constructList.element.findIndex(item => item.id === fItem.id), 1);
|
||
constructList.link.splice(constructList.link.findIndex(item => item.element.id === fItem.id || item.target.id === fItem.id));
|
||
constructList.pointer.splice(constructList.pointer.findIndex(item => item.target.id === fItem.id));
|
||
});
|
||
|
||
return freedList;
|
||
}
|
||
|
||
/**
|
||
* 获取被泄露的节点
|
||
* @param constructList
|
||
* @param prevConstructList
|
||
* @returns
|
||
*/
|
||
private getLeakConstructList(prevConstructList: ConstructList, constructList: ConstructList): ConstructList {
|
||
const elements: Element[] = prevConstructList.element.filter(item => !constructList.element.find(n => n.id === item.id)),
|
||
links: Link[] = prevConstructList.link.filter(item => !constructList.link.find(n => n.id === item.id)),
|
||
elementIds: string[] = elements.map(item => item.id);
|
||
|
||
elements.forEach(item => {
|
||
item.set('style', {
|
||
fill: '#ccc'
|
||
});
|
||
});
|
||
|
||
for(let i = 0; i < links.length; i++) {
|
||
let sourceId = links[i].element.id,
|
||
targetId = links[i].target.id;
|
||
|
||
links[i].set('style', {
|
||
stroke: '#333'
|
||
});
|
||
|
||
if(elementIds.find(item => item === sourceId) === undefined || elementIds.find(item => item === targetId) === undefined) {
|
||
links.splice(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
|
||
return {
|
||
element: elements,
|
||
link: links,
|
||
pointer: []
|
||
};
|
||
}
|
||
|
||
// ----------------------------------------------------------------------------------------------
|
||
|
||
/**
|
||
* 对主视图进行重新布局
|
||
* @param constructList
|
||
* @param layoutFn
|
||
*/
|
||
reLayout(constructList: ConstructList, layoutFn: (elements: Element[], layoutOptions: LayoutOptions) => void) {
|
||
this.layouter.layout(this.mainContainer, constructList, layoutFn);
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取 g6 实例
|
||
*/
|
||
getG6Instance() {
|
||
return this.mainContainer.getG6Instance();
|
||
}
|
||
|
||
/**
|
||
* 刷新视图
|
||
*/
|
||
refresh() {
|
||
this.mainContainer.getG6Instance().refresh();
|
||
}
|
||
|
||
/**
|
||
* 重新调整容器尺寸
|
||
* @param width
|
||
* @param height
|
||
*/
|
||
resize(width: number, height: number) {
|
||
this.mainContainer.getG6Instance().changeSize(width, height);
|
||
}
|
||
|
||
/**
|
||
* 渲染所有视图
|
||
* @param models
|
||
* @param layoutFn
|
||
*/
|
||
renderAll(constructList: ConstructList, layoutFn: (elements: Element[], layoutOptions: LayoutOptions) => void) {
|
||
this.shadowG6Instance.clear();
|
||
|
||
this.build(constructList);
|
||
|
||
this.freedConstructList = this.getFreedConstructList(constructList);
|
||
this.leakConstructList = this.getLeakConstructList(this.prevConstructList, constructList);
|
||
|
||
this.build(this.leakConstructList);
|
||
|
||
if(this.freedContainer) {
|
||
this.freedContainer.render(this.freedConstructList, layoutFn);
|
||
}
|
||
|
||
// 进行布局(设置model的x,y)
|
||
this.layouter.layout(this.mainContainer, constructList, layoutFn);
|
||
this.mainContainer.render(constructList, layoutFn);
|
||
|
||
if(this.leakContainer) {
|
||
this.mainContainer.afterRemoveModels(() => {
|
||
this.leakContainer.render(this.leakConstructList, layoutFn);
|
||
});
|
||
}
|
||
|
||
this.prevConstructList = constructList;
|
||
}
|
||
|
||
/**
|
||
* 销毁
|
||
*/
|
||
destroy() {
|
||
this.shadowG6Instance.destroy();
|
||
this.mainContainer.destroy();
|
||
this.freedContainer && this.freedContainer.destroy();
|
||
this.leakContainer && this.leakContainer.destroy();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|