修复泄漏节点计算的bug

This commit is contained in:
黎智洲 2021-06-17 09:26:58 +08:00
parent a7d9aed4ab
commit efe430ca48
6 changed files with 80 additions and 83 deletions

View File

@ -39,24 +39,26 @@
background-color: #fafafa;
}
</style>
</head>
<body>
<div class="container" id="container"></div>
<div class="container" id="container">
</div>
<button id="btn">change</button>
<button id="btn-next">reLayout</button>
<button id="btn-set">set</button>
<span id="pos"></span>
<div class="down">
<div class="down container">
<div id="freed"></div>
<div id="leak"></div>
</div>
<script src="./../dist/sv.js"></script>
<script>
@ -130,8 +132,6 @@ container.addEventListener('mousemove', e => {
});
</script>
</body>
</html>

2
dist/sv.js vendored

File diff suppressed because one or more lines are too long

View File

@ -87,21 +87,16 @@ export const Animations = {
* @param model
* @param animationConfig
*/
animate_moveTo(model: Model, animationConfig: animationConfig) {
animate_fadeOut(model: Model, animationConfig: animationConfig) {
const G6Item = model.G6Item,
group = G6Item.getContainer(),
Mat3 = SV.Mat3,
target = animationConfig.payload,
animateCfg = {
duration: animationConfig.duration,
duration: 1200,
easing: animationConfig.timingFunction,
callback: animationConfig.callback
};
let matrix = Mat3.clone(group.getMatrix());
Mat3.translate(matrix, matrix, [target.x, target.y]);
group.animate({ opacity: 0, matrix }, animateCfg);
group.animate({ opacity: 0 }, animateCfg);
}
};

View File

@ -1,5 +1,7 @@
import { Engine } from "../../engine";
import { Link, Model } from "../../Model/modelData";
import { InteractionOptions, LayoutGroupOptions } from "../../options";
import { Animations } from "../animation";
import { Container } from "./container";
@ -8,7 +10,39 @@ import { Container } from "./container";
*
*/
export class MainContainer extends Container {
private leakContainerPosition: { x: number, y: number } = null;
private freedContainerPosition: { x: number, y: number } = null;
constructor(engine: Engine, DOMContainer: HTMLElement, g6Options: { [key: string]: any } = { }) {
super(engine, DOMContainer, g6Options);
this.leakContainerPosition = this.getDOMPosition(this.engine.engineOptions.leakContainer);
this.freedContainerPosition = this.getDOMPosition(this.engine.engineOptions.freedContainer);
}
/**
*
* @param dom
* @returns
*/
private getDOMPosition(dom: HTMLElement): { x: number, y: number } {
if(dom === null) {
return { x: 0, y: 0 };
}
const bound = dom.getBoundingClientRect();
return {
x: bound.x + bound.width / 2,
y: bound.y + bound.height / 2
};
}
/**
*
* @param optionsTable
* @returns
*/
protected initBehaviors(optionsTable: { [key: string]: LayoutGroupOptions }) {
const dragNodeTable: { [key: string]: boolean | string[] } = { },
selectNodeTable: { [key: string]: boolean | string[] } = { },
@ -152,8 +186,6 @@ import { Container } from "./container";
});
}
protected
protected handleChangeModels(models: Model[]) {
const changeHighlightColor: string = this.interactionOptions.changeHighlight;

View File

@ -19,7 +19,7 @@ export class ViewManager {
private freedContainer: Container;
private leakContainer: Container;
private prevLayoutGroupTable: LayoutGroupTable;
private prevModelList: Model[];
private shadowG6Instance;
@ -27,7 +27,7 @@ export class ViewManager {
this.engine = engine;
this.layouter = new Layouter(engine);
this.mainContainer = new MainContainer(engine, DOMContainer, { tooltip: true });
this.prevLayoutGroupTable = null;
this.prevModelList = [];
const options: EngineOptions = this.engine.engineOptions;
@ -48,21 +48,11 @@ export class ViewManager {
* model Canvas G6 item
* @param constructList
*/
private build(layoutGroupTable: LayoutGroupTable) {
layoutGroupTable.forEach(group => {
group.element.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
group.pointer.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
group.link.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('edge', item));
group.element.forEach(item => {
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
});
group.pointer.forEach(item => {
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
});
group.link.forEach(item => {
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
});
private build(modelList: Model[]) {
modelList.forEach(item => {
const type = item instanceof Link? 'edge': 'node';
this.shadowG6Instance.addItem(type, item.cloneProps());
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
});
}
@ -71,7 +61,7 @@ export class ViewManager {
* @param layoutGroupTable
* @returns
*/
private getFreedConstructList(layoutGroupTable: LayoutGroupTable): Model[] {
private getFreedModelList(layoutGroupTable: LayoutGroupTable): Model[] {
let freedList: Model[] = [],
freedGroup: LayoutGroup = null,
freedGroupName: string = null,
@ -104,29 +94,15 @@ export class ViewManager {
/**
*
* @param constructList
* @param prevConstructList
* @param prevModelList
* @param modelList
* @returns
*/
private getLeakConstructList(prevLayoutGroupTable: LayoutGroupTable, layoutGroupTable: LayoutGroupTable): LayoutGroupTable {
const leakLayoutGroupTable = new Map<string, LayoutGroup>();
prevLayoutGroupTable.forEach((item, groupName) => {
let prevGroup = item,
curGroup = layoutGroupTable.get(groupName),
elements: Element[] = [],
links: Link[] = [],
elementIds: string[] = [];
if(curGroup) {
elements = prevGroup.element.filter(item => !curGroup.element.find(n => n.id === item.id)).filter(item => item.freed === false),
links = prevGroup.link.filter(item => !curGroup.link.find(n => n.id === item.id));
elements = curGroup.layouter.defineLeakRule(elements);
}
else {
elements = prevGroup.element;
links = prevGroup.link;
}
private getLeakModelList(prevModelList: Model[], modelList: Model[]): Model[] {
const leakModelList: Model[] = prevModelList.filter(item => !modelList.find(n => n.id === item.id)),
elements: Element[] = <Element[]>leakModelList.filter(item => item instanceof Element && item.freed === false),
links: Link[] = <Link[]>leakModelList.filter(item => item instanceof Link),
elementIds: string[] = [];
elements.forEach(item => {
elementIds.push(item.id);
@ -134,32 +110,22 @@ export class ViewManager {
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--;
}
}
leakLayoutGroupTable.set(groupName, {
element: elements,
link: links,
pointer: [],
layouter: prevGroup.layouter,
options: prevGroup.options,
modelList: [...elements, ...links]
});
});
return leakLayoutGroupTable;
return [...elements, ...links];
}
// ----------------------------------------------------------------------------------------------
@ -216,17 +182,19 @@ export class ViewManager {
renderAll(layoutGroupTable: LayoutGroupTable) {
this.shadowG6Instance.clear();
this.build(layoutGroupTable);
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
let freedList = this.getFreedConstructList(layoutGroupTable),
leakLayoutGroupTable = null;
this.build(modelList);
let freedList = this.getFreedModelList(layoutGroupTable),
leakModelList = null;
if(this.leakContainer && this.prevLayoutGroupTable) {
leakLayoutGroupTable = this.getLeakConstructList(this.prevLayoutGroupTable, layoutGroupTable);
this.build(leakLayoutGroupTable);
if(this.leakContainer) {
leakModelList = this.getLeakModelList(this.prevModelList, modelList);
this.build(leakModelList);
}
if(this.freedContainer) {
if(this.freedContainer && freedList.length) {
EventBus.emit('onFreed', freedList);
this.freedContainer.render(freedList);
}
@ -234,17 +202,19 @@ export class ViewManager {
// 进行布局设置model的xy
this.layouter.layoutAll(this.mainContainer, layoutGroupTable);
const modelList: Model[] = Util.convertGroupTable2ModelList(layoutGroupTable);
this.mainContainer.render(modelList);
if(this.leakContainer && this.prevLayoutGroupTable) {
if(this.leakContainer) {
this.mainContainer.afterRemoveModels(() => {
EventBus.emit('onLeak', leakLayoutGroupTable);
this.leakContainer.render(Util.convertGroupTable2ModelList(leakLayoutGroupTable));
this.leakContainer.render(leakModelList);
if(leakModelList.length) {
EventBus.emit('onLeak', leakModelList);
}
});
}
this.prevLayoutGroupTable = layoutGroupTable;
this.prevModelList = modelList;
}
/**

View File

@ -35,7 +35,7 @@ export class Engine {
this.animationOptions = Object.assign({
enable: true,
duration: 750,
duration: 1000,
timingFunction: 'easePolyOut'
}, engineOptions.animation);