231 lines
6.4 KiB
TypeScript
231 lines
6.4 KiB
TypeScript
import { Sources } from "./sources";
|
||
import { ModelConstructor } from "./Model/modelConstructor";
|
||
import { AnimationOptions, EngineOptions, InteractionOptions, LayoutGroupOptions, ViewOptions } from "./options";
|
||
import { SV } from "./StructV";
|
||
import { EventBus } from "./Common/eventBus";
|
||
import { ViewContainer } from "./View/viewContainer";
|
||
import { SVLink } from "./Model/SVLink";
|
||
import { SVNode } from "./Model/SVNode";
|
||
import { SVMarker } from "./Model/SVMarker";
|
||
|
||
|
||
export class Engine {
|
||
private modelConstructor: ModelConstructor;
|
||
private viewContainer: ViewContainer
|
||
private prevStringSourceData: string;
|
||
|
||
public engineOptions: EngineOptions;
|
||
public viewOptions: ViewOptions;
|
||
public animationOptions: AnimationOptions;
|
||
public interactionOptions: InteractionOptions;
|
||
|
||
public optionsTable: { [key: string]: LayoutGroupOptions };
|
||
|
||
constructor(DOMContainer: HTMLElement, engineOptions: EngineOptions) {
|
||
this.optionsTable = {};
|
||
this.engineOptions = Object.assign({}, engineOptions);
|
||
|
||
this.viewOptions = Object.assign({
|
||
fitCenter: true,
|
||
fitView: false,
|
||
groupPadding: 20,
|
||
leakAreaHeight: 150,
|
||
updateHighlight: '#fc5185'
|
||
}, engineOptions.view);
|
||
|
||
this.animationOptions = Object.assign({
|
||
enable: true,
|
||
duration: 750,
|
||
timingFunction: 'easePolyOut'
|
||
}, engineOptions.animation);
|
||
|
||
this.interactionOptions = Object.assign({
|
||
drag: true,
|
||
zoom: true,
|
||
dragNode: true,
|
||
selectNode: true
|
||
}, engineOptions.interaction);
|
||
|
||
// 初始化布局器配置项
|
||
Object.keys(SV.registeredLayout).forEach(layout => {
|
||
if(this.optionsTable[layout] === undefined) {
|
||
const options: LayoutGroupOptions = SV.registeredLayout[layout].defineOptions();
|
||
this.optionsTable[layout] = options;
|
||
}
|
||
});
|
||
|
||
this.modelConstructor = new ModelConstructor(this);
|
||
this.viewContainer = new ViewContainer(this, DOMContainer);
|
||
}
|
||
|
||
/**
|
||
* 输入数据进行渲染
|
||
* @param sourcesData
|
||
*/
|
||
public render(sourceData: Sources) {
|
||
if(sourceData === undefined || sourceData === null) {
|
||
return;
|
||
}
|
||
|
||
let stringSourceData = JSON.stringify(sourceData);
|
||
if(this.prevStringSourceData === stringSourceData) {
|
||
return;
|
||
}
|
||
this.prevStringSourceData = stringSourceData;
|
||
|
||
// 1 转换模型(data => model)
|
||
const layoutGroupTable = this.modelConstructor.construct(sourceData);
|
||
|
||
// 2 渲染(使用g6进行渲染)
|
||
this.viewContainer.render(layoutGroupTable);
|
||
}
|
||
|
||
/**
|
||
* 重新布局
|
||
*/
|
||
public reLayout() {
|
||
this.viewContainer.reLayout();
|
||
}
|
||
|
||
/**
|
||
* 获取 G6 实例
|
||
*/
|
||
public getGraphInstance() {
|
||
return this.viewContainer.getG6Instance();
|
||
}
|
||
|
||
/**
|
||
* 获取所有 element
|
||
* @param group
|
||
*/
|
||
public getNodes(group?: string): SVNode[] {
|
||
const layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
|
||
|
||
if(group && layoutGroupTable.has('group')) {
|
||
return layoutGroupTable.get('group').node;
|
||
}
|
||
|
||
const nodes: SVNode[] = [];
|
||
layoutGroupTable.forEach(item => {
|
||
nodes.push(...item.node);
|
||
})
|
||
|
||
return nodes;
|
||
}
|
||
|
||
/**
|
||
* 获取所有 marker
|
||
* @param group
|
||
*/
|
||
public getMarkers(group?: string): SVMarker[] {
|
||
const layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
|
||
|
||
if(group && layoutGroupTable.has('group')) {
|
||
return layoutGroupTable.get('group').marker;
|
||
}
|
||
|
||
const markers: SVMarker[] = [];
|
||
layoutGroupTable.forEach(item => {
|
||
markers.push(...item.marker);
|
||
})
|
||
|
||
return markers;
|
||
}
|
||
|
||
/**
|
||
* 获取所有 link
|
||
* @param group
|
||
*/
|
||
public getLinks(group?: string): SVLink[] {
|
||
const layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
|
||
|
||
if(group && layoutGroupTable.has('group')) {
|
||
return layoutGroupTable.get('group').link;
|
||
}
|
||
|
||
const links: SVLink[] = [];
|
||
layoutGroupTable.forEach(item => {
|
||
links.push(...item.link);
|
||
})
|
||
|
||
return links;
|
||
}
|
||
|
||
/**
|
||
* 隐藏某些组
|
||
* @param groupNames
|
||
*/
|
||
public hideGroups(groupNames: string | string[]) {
|
||
const names = Array.isArray(groupNames)? groupNames: [groupNames],
|
||
instance = this.viewContainer.getG6Instance(),
|
||
layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
|
||
|
||
layoutGroupTable.forEach(item => {
|
||
const hasName = names.find(name => name === item.layout);
|
||
|
||
if(hasName && !item.isHide) {
|
||
item.modelList.forEach(model => instance.hideItem(model.G6Item));
|
||
item.isHide = true;
|
||
}
|
||
|
||
if(!hasName && item.isHide) {
|
||
item.modelList.forEach(model => instance.showItem(model.G6Item));
|
||
item.isHide = false;
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 使用id查找某个节点
|
||
* @param id
|
||
*/
|
||
public findNode(id: string): SVNode {
|
||
const nodes = this.getNodes();
|
||
const stringId = id.toString();
|
||
const targetNode = nodes.find(item => item.sourceId === stringId);
|
||
|
||
return targetNode;
|
||
}
|
||
|
||
/**
|
||
* 调整容器尺寸
|
||
* @param width
|
||
* @param height
|
||
*/
|
||
public resize(width: number, height: number) {
|
||
this.viewContainer.resize(width, height);
|
||
}
|
||
|
||
/**
|
||
* 绑定 G6 事件
|
||
* @param eventName
|
||
* @param callback
|
||
*/
|
||
public on(eventName: string, callback: Function) {
|
||
if(typeof callback !== 'function') {
|
||
return;
|
||
}
|
||
|
||
if(eventName === 'onFreed' || eventName === 'onLeak') {
|
||
EventBus.on(eventName, callback);
|
||
return;
|
||
}
|
||
|
||
if(eventName === 'onLeakAreaUpdate') {
|
||
EventBus.on(eventName, callback);
|
||
return;
|
||
}
|
||
|
||
this.viewContainer.getG6Instance().on(eventName, event => {
|
||
callback(event.item['SVModel']);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 销毁引擎
|
||
*/
|
||
public destroy() {
|
||
this.modelConstructor.destroy();
|
||
this.viewContainer.destroy();
|
||
}
|
||
}; |