Merge branch 'main' of https://gitlab.com/phenomLi/StructV2 into main
This commit is contained in:
commit
2cdc35ff30
@ -14,6 +14,10 @@ SV.registerLayout('Array', {
|
||||
return sources;
|
||||
},
|
||||
|
||||
defineLeakRule(nodes) {
|
||||
return [];
|
||||
},
|
||||
|
||||
defineOptions() {
|
||||
return {
|
||||
node: {
|
||||
@ -49,6 +53,9 @@ SV.registerLayout('Array', {
|
||||
indexLabel: {
|
||||
index: { position: 'bottom' },
|
||||
indexRight: { position: 'right' }
|
||||
},
|
||||
behavior: {
|
||||
dragNode: false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@ -42,10 +42,10 @@ SV.registerLayout('LinkList', {
|
||||
}
|
||||
},
|
||||
loopNext: {
|
||||
type: 'arc',
|
||||
curveOffset: 50,
|
||||
type: 'quadratic',
|
||||
curveOffset: -100,
|
||||
sourceAnchor: 2,
|
||||
targetAnchor: 4,
|
||||
targetAnchor: 7,
|
||||
style: {
|
||||
stroke: '#333',
|
||||
endArrow: 'default',
|
||||
|
||||
@ -13,11 +13,15 @@ SV.registerLayout('Stack', {
|
||||
return sources;
|
||||
},
|
||||
|
||||
defineLeakRule(nodes) {
|
||||
return [];
|
||||
},
|
||||
|
||||
defineOptions() {
|
||||
return {
|
||||
element: {
|
||||
default: {
|
||||
type: 'indexed-node',
|
||||
type: 'array-node',
|
||||
label: '[id]',
|
||||
size: [60, 30],
|
||||
style: {
|
||||
@ -49,6 +53,9 @@ SV.registerLayout('Stack', {
|
||||
}
|
||||
}
|
||||
},
|
||||
indexLabel: {
|
||||
index: { position: 'left' }
|
||||
},
|
||||
behavior: {
|
||||
dragNode: false
|
||||
}
|
||||
|
||||
@ -99,84 +99,123 @@
|
||||
|
||||
|
||||
let data = [{
|
||||
Array: {
|
||||
data: [
|
||||
{ id: 1, data: 1, child: [2, 3], external: 'exx' },
|
||||
{ id: 2, data: 2 },
|
||||
{ id: 3, data: 3, child: [6, 4] },
|
||||
{ id: 4, data: 4 },
|
||||
{ id: 6, data: 6 }
|
||||
],
|
||||
layouter: 'BinaryTree'
|
||||
},
|
||||
L: {
|
||||
data: [
|
||||
{ id: 11, data: 11, next: 22, external: 'tt' },
|
||||
{ id: 22, data: 22, next: 33 },
|
||||
{ id: 33, data: 33, next: 44 },
|
||||
{ id: 44, data: 44, freed: true }
|
||||
],
|
||||
layouter: 'LinkList'
|
||||
},
|
||||
"ChainHashTable": {
|
||||
"sqStack0": {
|
||||
"data": [
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x618090",
|
||||
"data": "T"
|
||||
"id": "0x617eb5",
|
||||
"data": "",
|
||||
"index": 5,
|
||||
"cursor": "top"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x618030",
|
||||
"data": "N"
|
||||
"id": "0x617eb4",
|
||||
"data": "2",
|
||||
"index": 4
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x6180f0",
|
||||
"data": "U",
|
||||
"start": "node#0x618030"
|
||||
"id": "0x617eb3",
|
||||
"data": "6",
|
||||
"index": 3
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x617ff0",
|
||||
"data": "V",
|
||||
"next": "node#0x617fd0"
|
||||
"id": "0x617eb2",
|
||||
"data": "7",
|
||||
"index": 2
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x617fd0",
|
||||
"data": "A"
|
||||
"id": "0x617eb1",
|
||||
"data": "9",
|
||||
"index": 1
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x618010",
|
||||
"data": "O",
|
||||
"start": "node#0x617ff0"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"id": "0x618050",
|
||||
"data": "K"
|
||||
},
|
||||
{
|
||||
"type": "head",
|
||||
"id": "0x6180b0",
|
||||
"data": "R",
|
||||
"start": "node#0x618050"
|
||||
"id": "0x617eb0",
|
||||
"data": "1",
|
||||
"index": 0,
|
||||
"external": "S"
|
||||
}
|
||||
],
|
||||
"layouter": "ChainHashTable"
|
||||
"layouter": "Stack"
|
||||
}
|
||||
}, {
|
||||
Array: {
|
||||
data: [
|
||||
{ id: 1, data: 1, child: [2, 3], external: 'exx' },
|
||||
{ id: 2, data: 2 },
|
||||
{ id: 3, data: 3, child: [6, 7] },
|
||||
{ id: 7, data: 7 }
|
||||
"sqStack0": {
|
||||
"data": [
|
||||
{
|
||||
"id": "0x617eb4",
|
||||
"data": "2",
|
||||
"index": 4,
|
||||
"cursor": "top",
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb3",
|
||||
"data": "6",
|
||||
"index": 3,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb2",
|
||||
"data": "7",
|
||||
"index": 2,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb1",
|
||||
"data": "9",
|
||||
"index": 1,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb0",
|
||||
"data": "1",
|
||||
"index": 0,
|
||||
"bottomExternal": "S",
|
||||
"type": "default"
|
||||
}
|
||||
],
|
||||
layouter: 'BinaryTree'
|
||||
"layouter": "Stack"
|
||||
}
|
||||
}, {
|
||||
"data": [
|
||||
{
|
||||
"id": "0x617eb5",
|
||||
"data": "",
|
||||
"index": 5,
|
||||
"cursor": "top",
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb4",
|
||||
"data": "2",
|
||||
"index": 4,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb3",
|
||||
"data": "6",
|
||||
"index": 3,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb2",
|
||||
"data": "7",
|
||||
"index": 2,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb1",
|
||||
"data": "9",
|
||||
"index": 1,
|
||||
"type": "default"
|
||||
},
|
||||
{
|
||||
"id": "0x617eb0",
|
||||
"data": "1",
|
||||
"index": 0,
|
||||
"bottomExternal": "S",
|
||||
"type": "default"
|
||||
}
|
||||
],
|
||||
"layouter": "Stack"
|
||||
}];
|
||||
|
||||
|
||||
|
||||
14127
dist/sv.js
vendored
14127
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
@ -102,6 +102,10 @@ export function SolveNodeAppendagesDrag(viewContainer: ViewContainer) {
|
||||
|
||||
node.appendages.forEach(item => {
|
||||
item.setSelectedState(false);
|
||||
item.set({
|
||||
x: item.G6Item.getModel().x,
|
||||
y: item.G6Item.getModel().y
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -110,6 +114,15 @@ export function SolveNodeAppendagesDrag(viewContainer: ViewContainer) {
|
||||
x: item.G6Item.getModel().x,
|
||||
y: item.G6Item.getModel().y
|
||||
});
|
||||
|
||||
if(item instanceof SVNode) {
|
||||
item.appendages.forEach(appendage => {
|
||||
appendage.set({
|
||||
x: appendage.G6Item.getModel().x,
|
||||
y: appendage.G6Item.getModel().y
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -47,6 +47,28 @@ export const Util = {
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
* 将列表分类
|
||||
* @param list
|
||||
* @param category
|
||||
* @returns
|
||||
*/
|
||||
groupBy<T>(list: T[], category: string): { [key: string]: T[] } {
|
||||
const result = {} as { [key: string]: T[] };
|
||||
|
||||
list.forEach(item => {
|
||||
let value = item[category];
|
||||
|
||||
if(result[value] === undefined) {
|
||||
result[value] = [];
|
||||
}
|
||||
|
||||
result[value].push(item);
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 断言函数
|
||||
* @param assertFn
|
||||
|
||||
@ -129,7 +129,7 @@ export class SVModel {
|
||||
}
|
||||
};
|
||||
|
||||
this.G6ModelProps = merge(this.G6ModelProps, newG6ModelProps);
|
||||
this.G6ModelProps = merge.recursive(this.G6ModelProps, newG6ModelProps);
|
||||
|
||||
if (this.G6Item) {
|
||||
this.g6Instance.updateItem(this.G6Item, this.G6ModelProps);
|
||||
|
||||
@ -177,6 +177,6 @@ export class SVMarker extends SVNodeAppendage {
|
||||
|
||||
public getLabelSizeRadius(): number {
|
||||
const { width, height } = this.shadowG6Item.getContainer().getChildren()[2].getBBox();
|
||||
return width > height ? width : height;
|
||||
return Math.max(width, height);
|
||||
}
|
||||
};
|
||||
@ -217,10 +217,10 @@ export class ModelConstructor {
|
||||
value = node[name];
|
||||
|
||||
// 若没有指针字段的结点则跳过
|
||||
if (!value) continue;
|
||||
if (value === undefined || value === null) continue;
|
||||
|
||||
let id = `${group}.${name}#${value}`,
|
||||
indexLabel = new SVIndexLabel(id, name, group, layout, value, node, indexLabelOptions[name]);
|
||||
indexLabel = new SVIndexLabel(id, name, group, layout, value.toString(), node, indexLabelOptions[name]);
|
||||
|
||||
indexLabelList.push(indexLabel);
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ export default Util.registerShape('cursor', {
|
||||
x: 0,
|
||||
y: 0,
|
||||
text: cfg.label,
|
||||
fill: '#fafafa',
|
||||
fill: 'transparent',
|
||||
radius: 2,
|
||||
},
|
||||
name: 'bgRect'
|
||||
|
||||
@ -64,7 +64,8 @@ export default Util.registerShape('link-list-node', {
|
||||
[1, 0.5],
|
||||
[5 / 6, 1],
|
||||
[0.5, 1],
|
||||
[0, 0.5]
|
||||
[0, 0.5],
|
||||
[1 / 3, 1]
|
||||
];
|
||||
}
|
||||
}, 'rect');
|
||||
@ -14,6 +14,7 @@ import { EngineOptions, LayoutCreator } from "./options";
|
||||
import { SourceNode } from "./sources";
|
||||
import { Util } from "./Common/util";
|
||||
import { SVModel } from "./Model/SVModel";
|
||||
import { SVNode } from "./Model/SVNode";
|
||||
|
||||
|
||||
|
||||
@ -72,7 +73,7 @@ SV.registerLayout = function(name: string, layoutCreator: LayoutCreator) {
|
||||
}
|
||||
|
||||
if(typeof layoutCreator.defineLeakRule !== 'function') {
|
||||
layoutCreator.defineLeakRule = function(models: SVModel[]): SVModel[] {
|
||||
layoutCreator.defineLeakRule = function(models: SVNode[]): SVNode[] {
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ export class LayoutProvider {
|
||||
},
|
||||
left: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => {
|
||||
return {
|
||||
x: nodeBound.x - labelBound.width - 2 * offset,
|
||||
x: nodeBound.x - labelBound.width - offset,
|
||||
y: nodeBound.y + nodeBound.height / 2
|
||||
};
|
||||
}
|
||||
@ -227,8 +227,11 @@ export class LayoutProvider {
|
||||
containerHeight = this.viewContainer.getG6Instance().getHeight(),
|
||||
leakAreaHeight = this.engine.viewOptions.leakAreaHeight,
|
||||
leakAreaY = containerHeight - leakAreaHeight,
|
||||
xOffset = 50;
|
||||
xOffset = 60;
|
||||
|
||||
let prevBound: BoundingRect;
|
||||
|
||||
// 避免在泄漏前拖拽节点导致的位置变化,先把节点位置重置为布局后的标准位置
|
||||
leakModels.forEach(item => {
|
||||
item.set({
|
||||
x: item.layoutX,
|
||||
@ -236,17 +239,26 @@ export class LayoutProvider {
|
||||
});
|
||||
});
|
||||
|
||||
group.add(...leakModels);
|
||||
const currentLeakGroupBound: BoundingRect = group.getBound(),
|
||||
globalLeakGroupBound: BoundingRect = accumulateLeakModels.length ?
|
||||
Bound.union(...accumulateLeakModels.map(item => item.getBound())) :
|
||||
{ x: 0, y: leakAreaY, width: 0, height: 0 };
|
||||
const globalLeakGroupBound: BoundingRect = accumulateLeakModels.length ?
|
||||
Bound.union(...accumulateLeakModels.map(item => item.getBound())) :
|
||||
{ x: 0, y: leakAreaY, width: 0, height: 0 };
|
||||
|
||||
const { x: groupX, y: groupY } = currentLeakGroupBound,
|
||||
dx = globalLeakGroupBound.x + globalLeakGroupBound.width + xOffset - groupX,
|
||||
dy = globalLeakGroupBound.y - groupY;
|
||||
const layoutGroups = Util.groupBy(leakModels, 'group');
|
||||
Object.keys(layoutGroups).forEach(key => {
|
||||
group.add(...layoutGroups[key]);
|
||||
|
||||
group.translate(dx, dy);
|
||||
const currentBound: BoundingRect = group.getBound(),
|
||||
prevBoundEnd = prevBound? prevBound.x + prevBound.width: 0,
|
||||
{ x: groupX, y: groupY } = currentBound,
|
||||
dx = globalLeakGroupBound.x + globalLeakGroupBound.width + prevBoundEnd + xOffset - groupX,
|
||||
dy = globalLeakGroupBound.y - groupY;
|
||||
|
||||
group.translate(dx, dy);
|
||||
group.clear();
|
||||
Bound.translate(currentBound, dx, dy);
|
||||
|
||||
prevBound = currentBound;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { EventBus } from "../Common/eventBus";
|
||||
import { Util } from "../Common/util";
|
||||
import { Engine } from "../engine";
|
||||
import { LayoutGroupTable } from "../Model/modelConstructor";
|
||||
import { SVLink } from "../Model/SVLink";
|
||||
import { SVModel } from "../Model/SVModel";
|
||||
import { SVNode } from "../Model/SVNode";
|
||||
@ -66,16 +67,31 @@ export class Reconcile {
|
||||
|
||||
/**
|
||||
* 获取被泄露的节点
|
||||
* @param layoutGroupTable
|
||||
* @param prevModelList
|
||||
* @param modelList
|
||||
* @returns
|
||||
*/
|
||||
private getLeakModels(prevModelList: SVModel[], modelList: SVModel[]): SVModel[] {
|
||||
const potentialLeakModels: SVModel[] = prevModelList.filter(item =>
|
||||
private getLeakModels(layoutGroupTable: LayoutGroupTable, prevModelList: SVModel[], modelList: SVModel[]): SVModel[] {
|
||||
let potentialLeakModels: SVModel[] = prevModelList.filter(item =>
|
||||
!modelList.find(model => model.id === item.id) && !item.freed
|
||||
);
|
||||
const leakModels: SVModel[] = [];
|
||||
|
||||
// 先把节点拿出来
|
||||
const potentialLeakNodes = potentialLeakModels.filter(item => item.isNode()) as SVNode[],
|
||||
groups = Util.groupBy<SVNode>(potentialLeakNodes, 'group');
|
||||
|
||||
// 再把非节点的model拿出来
|
||||
potentialLeakModels = potentialLeakModels.filter(item => item.isNode() === false);
|
||||
|
||||
Object.keys(groups).forEach(key => {
|
||||
const leakRule = layoutGroupTable.get(key).layoutCreator.defineLeakRule;
|
||||
if(leakRule && typeof leakRule === 'function') {
|
||||
potentialLeakModels.push(...leakRule(groups[key]));
|
||||
}
|
||||
});
|
||||
|
||||
potentialLeakModels.forEach(item => {
|
||||
if (item instanceof SVNode) {
|
||||
item.leaked = true;
|
||||
@ -345,14 +361,15 @@ export class Reconcile {
|
||||
|
||||
/**
|
||||
* 进行diff
|
||||
* @param prevLayoutGroupTable
|
||||
* @param layoutGroupTable
|
||||
* @param accumulateLeakModels
|
||||
* @param prevModelList
|
||||
* @param modelList
|
||||
* @param accumulateLeakModels
|
||||
* @returns
|
||||
*/
|
||||
public diff(prevModelList: SVModel[], modelList: SVModel[], accumulateLeakModels: SVModel[]): DiffResult {
|
||||
public diff(layoutGroupTable: LayoutGroupTable, prevModelList: SVModel[], modelList: SVModel[], accumulateLeakModels: SVModel[]): DiffResult {
|
||||
const continuousModels: SVModel[] = this.getContinuousModels(prevModelList, modelList);
|
||||
const leakModels: SVModel[] = this.getLeakModels(prevModelList, modelList);
|
||||
const leakModels: SVModel[] = this.getLeakModels(layoutGroupTable, prevModelList, modelList);
|
||||
const appendModels: SVModel[] = this.getAppendModels(prevModelList, modelList, accumulateLeakModels);
|
||||
const removeModels: SVModel[] = this.getRemoveModels(prevModelList, modelList);
|
||||
const updateModels: SVModel[] = [
|
||||
|
||||
@ -20,7 +20,7 @@ export class ViewContainer {
|
||||
private reconcile: Reconcile;
|
||||
public renderer: Renderer;
|
||||
|
||||
private prevLayoutGroupTable: LayoutGroupTable;
|
||||
private layoutGroupTable: LayoutGroupTable;
|
||||
private prevModelList: SVModel[];
|
||||
private accumulateLeakModels: SVModel[];
|
||||
|
||||
@ -37,7 +37,7 @@ export class ViewContainer {
|
||||
this.layoutProvider = new LayoutProvider(engine, this);
|
||||
this.renderer = new Renderer(engine, DOMContainer, behaviorsModes);
|
||||
this.reconcile = new Reconcile(engine, this.renderer);
|
||||
this.prevLayoutGroupTable = new Map();
|
||||
this.layoutGroupTable = new Map();
|
||||
this.prevModelList = [];
|
||||
this.accumulateLeakModels = [];
|
||||
this.hasLeak = false; // 判断是否已经发生过泄漏
|
||||
@ -75,7 +75,7 @@ export class ViewContainer {
|
||||
g6Instance.translate(-dx, -dy);
|
||||
}
|
||||
|
||||
this.layoutProvider.layoutAll(this.prevLayoutGroupTable, this.accumulateLeakModels, []);
|
||||
this.layoutProvider.layoutAll(this.layoutGroupTable, this.accumulateLeakModels, []);
|
||||
g6Instance.refresh();
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ export class ViewContainer {
|
||||
*
|
||||
*/
|
||||
getLayoutGroupTable(): LayoutGroupTable {
|
||||
return this.prevLayoutGroupTable;
|
||||
return this.layoutGroupTable;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +142,7 @@ export class ViewContainer {
|
||||
*/
|
||||
render(layoutGroupTable: LayoutGroupTable) {
|
||||
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable),
|
||||
diffResult = this.reconcile.diff(this.prevModelList, modelList, this.accumulateLeakModels),
|
||||
diffResult = this.reconcile.diff(this.layoutGroupTable, this.prevModelList, modelList, this.accumulateLeakModels),
|
||||
renderModelList = [
|
||||
...modelList,
|
||||
...diffResult.REMOVE,
|
||||
@ -176,7 +176,7 @@ export class ViewContainer {
|
||||
|
||||
this.accumulateLeakModels.push(...diffResult.LEAKED); // 对泄漏节点进行累积
|
||||
|
||||
this.prevLayoutGroupTable = layoutGroupTable;
|
||||
this.layoutGroupTable = layoutGroupTable;
|
||||
this.prevModelList = modelList;
|
||||
}
|
||||
|
||||
@ -187,9 +187,10 @@ export class ViewContainer {
|
||||
this.renderer.destroy();
|
||||
this.reconcile.destroy();
|
||||
this.layoutProvider = null;
|
||||
this.prevLayoutGroupTable = null;
|
||||
this.layoutGroupTable = null;
|
||||
this.prevModelList.length = 0;
|
||||
this.accumulateLeakModels.length = 0;
|
||||
this.brushSelectedModels.length = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ export interface EngineOptions {
|
||||
export interface LayoutCreator {
|
||||
defineOptions(sourceData: SourceNode[]): LayoutGroupOptions;
|
||||
sourcesPreprocess?(sourceData: SourceNode[], options: LayoutGroupOptions): SourceNode[];
|
||||
defineLeakRule?(models: SVModel[]): SVModel[];
|
||||
defineLeakRule?(models: SVNode[]): SVNode[];
|
||||
layout(nodes: SVNode[], layoutOptions: LayoutOptions);
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user