修复泄漏节点计算的bug
This commit is contained in:
parent
a7d9aed4ab
commit
efe430ca48
@ -39,24 +39,26 @@
|
|||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container" id="container"></div>
|
<div class="container" id="container">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<button id="btn">change</button>
|
<button id="btn">change</button>
|
||||||
<button id="btn-next">reLayout</button>
|
<button id="btn-next">reLayout</button>
|
||||||
<button id="btn-set">set</button>
|
<button id="btn-set">set</button>
|
||||||
|
|
||||||
<span id="pos"></span>
|
<span id="pos"></span>
|
||||||
|
|
||||||
<div class="down">
|
<div class="down container">
|
||||||
<div id="freed"></div>
|
<div id="freed"></div>
|
||||||
<div id="leak"></div>
|
<div id="leak"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script src="./../dist/sv.js"></script>
|
<script src="./../dist/sv.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@ -130,8 +132,6 @@ container.addEventListener('mousemove', e => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
2
dist/sv.js
vendored
2
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
@ -87,21 +87,16 @@ export const Animations = {
|
|||||||
* @param model
|
* @param model
|
||||||
* @param animationConfig
|
* @param animationConfig
|
||||||
*/
|
*/
|
||||||
animate_moveTo(model: Model, animationConfig: animationConfig) {
|
animate_fadeOut(model: Model, animationConfig: animationConfig) {
|
||||||
const G6Item = model.G6Item,
|
const G6Item = model.G6Item,
|
||||||
group = G6Item.getContainer(),
|
group = G6Item.getContainer(),
|
||||||
Mat3 = SV.Mat3,
|
|
||||||
target = animationConfig.payload,
|
|
||||||
animateCfg = {
|
animateCfg = {
|
||||||
duration: animationConfig.duration,
|
duration: 1200,
|
||||||
easing: animationConfig.timingFunction,
|
easing: animationConfig.timingFunction,
|
||||||
callback: animationConfig.callback
|
callback: animationConfig.callback
|
||||||
};
|
};
|
||||||
|
|
||||||
let matrix = Mat3.clone(group.getMatrix());
|
group.animate({ opacity: 0 }, animateCfg);
|
||||||
|
|
||||||
Mat3.translate(matrix, matrix, [target.x, target.y]);
|
|
||||||
group.animate({ opacity: 0, matrix }, animateCfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import { Engine } from "../../engine";
|
||||||
import { Link, Model } from "../../Model/modelData";
|
import { Link, Model } from "../../Model/modelData";
|
||||||
import { InteractionOptions, LayoutGroupOptions } from "../../options";
|
import { InteractionOptions, LayoutGroupOptions } from "../../options";
|
||||||
|
import { Animations } from "../animation";
|
||||||
import { Container } from "./container";
|
import { Container } from "./container";
|
||||||
|
|
||||||
|
|
||||||
@ -8,7 +10,39 @@ import { Container } from "./container";
|
|||||||
* 主可视化视图
|
* 主可视化视图
|
||||||
*/
|
*/
|
||||||
export class MainContainer extends 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 }) {
|
protected initBehaviors(optionsTable: { [key: string]: LayoutGroupOptions }) {
|
||||||
const dragNodeTable: { [key: string]: boolean | string[] } = { },
|
const dragNodeTable: { [key: string]: boolean | string[] } = { },
|
||||||
selectNodeTable: { [key: string]: boolean | string[] } = { },
|
selectNodeTable: { [key: string]: boolean | string[] } = { },
|
||||||
@ -152,8 +186,6 @@ import { Container } from "./container";
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
protected handleChangeModels(models: Model[]) {
|
protected handleChangeModels(models: Model[]) {
|
||||||
const changeHighlightColor: string = this.interactionOptions.changeHighlight;
|
const changeHighlightColor: string = this.interactionOptions.changeHighlight;
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export class ViewManager {
|
|||||||
private freedContainer: Container;
|
private freedContainer: Container;
|
||||||
private leakContainer: Container;
|
private leakContainer: Container;
|
||||||
|
|
||||||
private prevLayoutGroupTable: LayoutGroupTable;
|
private prevModelList: Model[];
|
||||||
|
|
||||||
private shadowG6Instance;
|
private shadowG6Instance;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ export class ViewManager {
|
|||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.layouter = new Layouter(engine);
|
this.layouter = new Layouter(engine);
|
||||||
this.mainContainer = new MainContainer(engine, DOMContainer, { tooltip: true });
|
this.mainContainer = new MainContainer(engine, DOMContainer, { tooltip: true });
|
||||||
this.prevLayoutGroupTable = null;
|
this.prevModelList = [];
|
||||||
|
|
||||||
const options: EngineOptions = this.engine.engineOptions;
|
const options: EngineOptions = this.engine.engineOptions;
|
||||||
|
|
||||||
@ -48,21 +48,11 @@ export class ViewManager {
|
|||||||
* 对每一个 model 在离屏 Canvas 上构建 G6 item,用作布局
|
* 对每一个 model 在离屏 Canvas 上构建 G6 item,用作布局
|
||||||
* @param constructList
|
* @param constructList
|
||||||
*/
|
*/
|
||||||
private build(layoutGroupTable: LayoutGroupTable) {
|
private build(modelList: Model[]) {
|
||||||
layoutGroupTable.forEach(group => {
|
modelList.forEach(item => {
|
||||||
group.element.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
|
const type = item instanceof Link? 'edge': 'node';
|
||||||
group.pointer.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('node', item));
|
this.shadowG6Instance.addItem(type, item.cloneProps());
|
||||||
group.link.map(item => item.cloneProps()).forEach(item => this.shadowG6Instance.addItem('edge', item));
|
item.shadowG6Item = this.shadowG6Instance.findById(item.id);
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +61,7 @@ export class ViewManager {
|
|||||||
* @param layoutGroupTable
|
* @param layoutGroupTable
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private getFreedConstructList(layoutGroupTable: LayoutGroupTable): Model[] {
|
private getFreedModelList(layoutGroupTable: LayoutGroupTable): Model[] {
|
||||||
let freedList: Model[] = [],
|
let freedList: Model[] = [],
|
||||||
freedGroup: LayoutGroup = null,
|
freedGroup: LayoutGroup = null,
|
||||||
freedGroupName: string = null,
|
freedGroupName: string = null,
|
||||||
@ -104,29 +94,15 @@ export class ViewManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取被泄露的节点
|
* 获取被泄露的节点
|
||||||
* @param constructList
|
* @param prevModelList
|
||||||
* @param prevConstructList
|
* @param modelList
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private getLeakConstructList(prevLayoutGroupTable: LayoutGroupTable, layoutGroupTable: LayoutGroupTable): LayoutGroupTable {
|
private getLeakModelList(prevModelList: Model[], modelList: Model[]): Model[] {
|
||||||
const leakLayoutGroupTable = new Map<string, LayoutGroup>();
|
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),
|
||||||
prevLayoutGroupTable.forEach((item, groupName) => {
|
links: Link[] = <Link[]>leakModelList.filter(item => item instanceof Link),
|
||||||
let prevGroup = item,
|
elementIds: string[] = [];
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.forEach(item => {
|
elements.forEach(item => {
|
||||||
elementIds.push(item.id);
|
elementIds.push(item.id);
|
||||||
@ -149,17 +125,7 @@ export class ViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leakLayoutGroupTable.set(groupName, {
|
return [...elements, ...links];
|
||||||
element: elements,
|
|
||||||
link: links,
|
|
||||||
pointer: [],
|
|
||||||
layouter: prevGroup.layouter,
|
|
||||||
options: prevGroup.options,
|
|
||||||
modelList: [...elements, ...links]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return leakLayoutGroupTable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------
|
||||||
@ -216,17 +182,19 @@ export class ViewManager {
|
|||||||
renderAll(layoutGroupTable: LayoutGroupTable) {
|
renderAll(layoutGroupTable: LayoutGroupTable) {
|
||||||
this.shadowG6Instance.clear();
|
this.shadowG6Instance.clear();
|
||||||
|
|
||||||
this.build(layoutGroupTable);
|
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
|
||||||
|
|
||||||
let freedList = this.getFreedConstructList(layoutGroupTable),
|
this.build(modelList);
|
||||||
leakLayoutGroupTable = null;
|
|
||||||
|
|
||||||
if(this.leakContainer && this.prevLayoutGroupTable) {
|
let freedList = this.getFreedModelList(layoutGroupTable),
|
||||||
leakLayoutGroupTable = this.getLeakConstructList(this.prevLayoutGroupTable, layoutGroupTable);
|
leakModelList = null;
|
||||||
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);
|
EventBus.emit('onFreed', freedList);
|
||||||
this.freedContainer.render(freedList);
|
this.freedContainer.render(freedList);
|
||||||
}
|
}
|
||||||
@ -234,17 +202,19 @@ export class ViewManager {
|
|||||||
// 进行布局(设置model的x,y)
|
// 进行布局(设置model的x,y)
|
||||||
this.layouter.layoutAll(this.mainContainer, layoutGroupTable);
|
this.layouter.layoutAll(this.mainContainer, layoutGroupTable);
|
||||||
|
|
||||||
const modelList: Model[] = Util.convertGroupTable2ModelList(layoutGroupTable);
|
|
||||||
this.mainContainer.render(modelList);
|
this.mainContainer.render(modelList);
|
||||||
|
|
||||||
if(this.leakContainer && this.prevLayoutGroupTable) {
|
if(this.leakContainer) {
|
||||||
this.mainContainer.afterRemoveModels(() => {
|
this.mainContainer.afterRemoveModels(() => {
|
||||||
EventBus.emit('onLeak', leakLayoutGroupTable);
|
this.leakContainer.render(leakModelList);
|
||||||
this.leakContainer.render(Util.convertGroupTable2ModelList(leakLayoutGroupTable));
|
|
||||||
|
if(leakModelList.length) {
|
||||||
|
EventBus.emit('onLeak', leakModelList);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.prevLayoutGroupTable = layoutGroupTable;
|
this.prevModelList = modelList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export class Engine {
|
|||||||
|
|
||||||
this.animationOptions = Object.assign({
|
this.animationOptions = Object.assign({
|
||||||
enable: true,
|
enable: true,
|
||||||
duration: 750,
|
duration: 1000,
|
||||||
timingFunction: 'easePolyOut'
|
timingFunction: 'easePolyOut'
|
||||||
}, engineOptions.animation);
|
}, engineOptions.animation);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user