StructV2/src/Model/modelConstructor.ts
Phenom 72fcf5394a 基本重构完成
底层渲染库舍弃 zrender,换为 antvG6
2021-04-06 21:45:11 +08:00

243 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Util } from "../Common/util";
import { Engine } from "../engine";
import { LinkOption, PointerOption } from "../options";
import { sourceLinkData, SourceElement, Sources, LinkTarget } from "../sources";
import { Element, Link, Pointer } from "./modelData";
export interface ConstructedData {
element: { [key: string]: Element[] };
link: { [key: string]: Link[] };
pointer: { [key: string]: Pointer[] };
};
export class ModelConstructor {
private engine: Engine;
constructor(engine: Engine) {
this.engine = engine;
}
/**
* 构建elementlink和pointer
* @param sourceData
*/
public construct(sourceData: Sources): ConstructedData {
let elementContainer = this.constructElements(sourceData),
linkContainer = this.constructLinks(this.engine.linkOptions, elementContainer),
pointerContainer = this.constructPointers(this.engine.pointerOptions, elementContainer);
return {
element: elementContainer,
link: linkContainer,
pointer: pointerContainer
};
}
/**
* 从源数据构建 element 集
* @param sourceData
*/
private constructElements(sourceData: Sources): { [key: string]: Element[] } {
let defaultElementName: string = 'default',
elementContainer: { [key: string]: Element[] } = { };
if(Array.isArray(sourceData)) {
elementContainer[defaultElementName] = [];
sourceData.forEach(item => {
if(item) {
let ele = this.createElement(item, defaultElementName);
elementContainer[defaultElementName].push(ele);
}
});
}
else {
Object.keys(sourceData).forEach(prop => {
elementContainer[prop] = [];
sourceData[prop].forEach(item => {
if(item) {
let element = this.createElement(item, prop);
elementContainer[prop].push(element);
}
});
});
}
return elementContainer;
}
/**
* 从配置和 element 集构建 link 集
* @param linkOptions
* @param elementContainer
* @returns
*/
private constructLinks(linkOptions: { [key: string]: LinkOption }, elementContainer: { [key: string]: Element[] }): { [key: string]: Link[] } {
let linkContainer: { [key: string]: Link[] } = { },
elementList: Element[] = Object
.keys(elementContainer)
.map(item => elementContainer[item])
.reduce((prev, cur) => [...prev, ...cur]),
linkNames = Object.keys(linkOptions);
linkNames.forEach(name => {
linkContainer[name] = [];
});
linkNames.forEach(name => {
for(let i = 0; i < elementList.length; i++) {
let element: Element = elementList[i],
sourceLinkData: sourceLinkData = element[name],
options: LinkOption = linkOptions[name],
targetElement: Element | Element[] = null,
link: Link = null;
if(sourceLinkData === undefined || sourceLinkData === null) continue;
// ------------------- 将连接声明字段 sourceLinkData 从 id 变为 Element -------------------
if(Array.isArray(sourceLinkData)) {
element[name] = sourceLinkData.map((item, index) => {
targetElement = this.fetchTargetElements(elementContainer, element, item);
if(targetElement) {
link = new Link(name, element, targetElement, index);
linkContainer[name].push(link);
link.initProps(options);
}
return targetElement;
});
}
else {
targetElement = this.fetchTargetElements(elementContainer, element, sourceLinkData);
if(targetElement) {
link = new Link(name, element, targetElement, null);
linkContainer[name].push(link);
link.initProps(options);
}
element[name] = targetElement;
}
}
});
return linkContainer;
}
/**
* 从配置和 element 集构建 pointer 集
* @param pointerOptions
* @param elementContainer
* @returns
*/
private constructPointers(pointerOptions: { [key: string]: PointerOption }, elementContainer: { [key: string]: Element[] }): { [key: string]: Pointer[] } {
let pointerContainer: { [key: string]: Pointer[] } = { },
elementList: Element[] = Object
.keys(elementContainer)
.map(item => elementContainer[item])
.reduce((prev, cur) => [...prev, ...cur]),
pointerNames = Object.keys(pointerOptions);
pointerNames.forEach(name => {
pointerContainer[name] = [];
});
pointerNames.forEach(name => {
let options = pointerOptions[name];
for(let i = 0; i < elementList.length; i++) {
let element = elementList[i],
pointerData = element[name];
// 若没有指针字段的结点则跳过
if(!pointerData) continue;
let id = name + '#' + (Array.isArray(pointerData)? pointerData.join('-'): pointerData),
pointer = new Pointer(id, name, pointerData, element);
pointer.initProps(options);
pointerContainer[name].push(pointer);
}
});
return pointerContainer;
}
/**
* 元素工厂创建Element
* @param sourceElement
* @param elementName
*/
private createElement(sourceElement: SourceElement, elementName: string): Element {
let elementOption = this.engine.elementOptions[elementName],
element = new Element(elementName, sourceElement),
label = elementOption.label? this.parserElementContent(sourceElement, elementOption.label): '';
element.initProps(elementOption);
element.set('label', label);
return element;
}
/**
* 解析元素文本内容
* @param sourceElement
* @param formatLabel
*/
private parserElementContent(sourceElement: SourceElement, formatLabel: string): string {
let fields = Util.textParser(formatLabel);
if(Array.isArray(fields)) {
let values = fields.map(item => sourceElement[item]);
values.map((item, index) => {
formatLabel = formatLabel.replace('[' + fields[index] + ']', item);
});
}
return formatLabel;
}
/**
* 由source中的连接字段获取真实的连接目标元素
* @param elementContainer
* @param element
* @param linkTarget
*/
private fetchTargetElements(
elementContainer: { [key: string]: Element[] } ,
element: Element,
linkTarget: LinkTarget
): Element {
let elementName = element.name,
elementList: Element[],
targetId = linkTarget,
targetElement = null;
if(linkTarget === null || linkTarget === undefined) {
return null;
}
if(typeof linkTarget === 'string' && linkTarget.includes('#')) {
let info = linkTarget.split('#');
elementName = info[0];
targetId = info[1];
}
if(typeof targetId === 'number') {
targetId = targetId.toString();
}
elementList = elementContainer[elementName];
// 若目标element不存在返回null
if(elementList === undefined) {
return null;
}
targetElement = elementList.find(item => item.id === targetId);
return targetElement || null;
}
};