fix: 修改了节点下标文本的底层实现
This commit is contained in:
parent
6a0139eaeb
commit
e1a69b5e91
@ -16,18 +16,17 @@ SV.registerLayout('Array', {
|
|||||||
|
|
||||||
defineOptions() {
|
defineOptions() {
|
||||||
return {
|
return {
|
||||||
element: {
|
node: {
|
||||||
default: {
|
default: {
|
||||||
type: 'indexed-node',
|
type: 'rect',
|
||||||
label: '[id]',
|
label: '[id]',
|
||||||
size: [60, 30],
|
size: [60, 30],
|
||||||
|
labelOptions: {
|
||||||
|
style: { fontSize: 20 }
|
||||||
|
},
|
||||||
style: {
|
style: {
|
||||||
stroke: '#333',
|
stroke: '#333',
|
||||||
fill: '#95e1d3'
|
fill: '#95e1d3'
|
||||||
},
|
|
||||||
indexOptions: {
|
|
||||||
index: { position: 'bottom' },
|
|
||||||
indexTop: { position: 'top' }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -47,8 +46,9 @@ SV.registerLayout('Array', {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
behavior: {
|
indexLabel: {
|
||||||
dragNode: false
|
index: { position: 'bottom' },
|
||||||
|
indexRight: { position: 'right' }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -84,7 +84,7 @@ SV.registerLayout('Array', {
|
|||||||
|
|
||||||
defineOptions() {
|
defineOptions() {
|
||||||
return {
|
return {
|
||||||
element: {
|
node: {
|
||||||
default: {
|
default: {
|
||||||
type: 'indexed-node',
|
type: 'indexed-node',
|
||||||
label: '[id]',
|
label: '[id]',
|
||||||
@ -92,10 +92,6 @@ SV.registerLayout('Array', {
|
|||||||
style: {
|
style: {
|
||||||
stroke: '#333',
|
stroke: '#333',
|
||||||
fill: '#355c7d'
|
fill: '#355c7d'
|
||||||
},
|
|
||||||
indexOptions: {
|
|
||||||
index: { position: 'bottom' },
|
|
||||||
indexTop: { position: 'top' }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -114,6 +110,10 @@ SV.registerLayout('Array', {
|
|||||||
fill: '#f08a5d'
|
fill: '#f08a5d'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
indexLabel: {
|
||||||
|
index: { position: 'bottom' },
|
||||||
|
indexTop: { position: 'top' }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,11 +1,3 @@
|
|||||||
/*
|
|
||||||
* @Author: your name
|
|
||||||
* @Date: 2021-12-12 20:35:54
|
|
||||||
* @LastEditTime: 2021-12-13 21:31:01
|
|
||||||
* @LastEditors: Please set LastEditors
|
|
||||||
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
|
||||||
* @FilePath: \froend_studentc:\Users\13127\Desktop\最近的前端文件\可视化源码\StructV2\demoV2\Layouter\PTree.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 解析数据:
|
// 解析数据:
|
||||||
// {
|
// {
|
||||||
@ -50,26 +42,28 @@ SV.registerLayout('PTree', {
|
|||||||
|
|
||||||
return sources;
|
return sources;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
defineOptions() {
|
defineOptions() {
|
||||||
return {
|
return {
|
||||||
node: {
|
node: {
|
||||||
default: {
|
default: {
|
||||||
type: 'indexed-node',
|
type: 'rect',
|
||||||
label: '[data]',
|
label: '[data]',
|
||||||
size: [40, 40],
|
size: [40, 40],
|
||||||
|
labelOptions: {
|
||||||
|
style: { fontSize: 16 }
|
||||||
|
},
|
||||||
style: {
|
style: {
|
||||||
stroke: '#333',
|
stroke: '#333',
|
||||||
fill: '#95e1d3',
|
fill: '#95e1d3',
|
||||||
offset: 25
|
offset: 25
|
||||||
},
|
|
||||||
indexOptions: {
|
|
||||||
index: { position: 'top' },
|
|
||||||
indexLeft: { position: 'left' }
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
behavior: {
|
indexLabel: {
|
||||||
dragNode: false
|
index: { position: 'top' },
|
||||||
|
indexLeft: { position: 'left' }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -100,9 +100,23 @@
|
|||||||
|
|
||||||
|
|
||||||
let data = [{
|
let data = [{
|
||||||
Array: {
|
PTree: {
|
||||||
data: [{ id: 1, data: 1 ,}, { id: 2, data: 2 }, { id: 3, data: 3 }, { id: 4, data: 4 }],
|
data: [
|
||||||
layouter: 'Array'
|
{
|
||||||
|
id: '1001',
|
||||||
|
data: 'A',
|
||||||
|
parent: -1,
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '1002',
|
||||||
|
data: 'B',
|
||||||
|
parent: 0,
|
||||||
|
index: 1
|
||||||
|
},
|
||||||
|
],
|
||||||
|
layouter: 'PTree'
|
||||||
|
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
Array: {
|
Array: {
|
||||||
|
|||||||
14115
dist/sv.js
vendored
14115
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
@ -1,55 +1,38 @@
|
|||||||
import { Graph } from "@antv/g6";
|
import { Graph } from "@antv/g6";
|
||||||
import { SVNode } from "../Model/SVNode";
|
import { SVNode } from "../Model/SVNode";
|
||||||
|
import { SVNodeAppendage } from "../Model/SVNodeAppendage";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在初始化渲染器之后,修正节点拖拽时,外部指针没有跟着动的问题
|
* 在初始化渲染器之后,修正节点拖拽时,外部指针或者其他 appendage 没有跟着动的问题
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export function FixNodeMarkerDrag(g6Instance: Graph) {
|
export function FixNodeMarkerDrag(g6Instance: Graph) {
|
||||||
let dragActive: boolean = false;
|
let dragActive: boolean = false,
|
||||||
|
nodeData: { node: SVNode, startX: number, startY: number },
|
||||||
const nodeData = {
|
appendagesData: { appendage: SVNodeAppendage, startX: number, startY: number }[] = [];
|
||||||
node: null,
|
|
||||||
startX: 0,
|
|
||||||
startY: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const markerData = {
|
|
||||||
marker: null,
|
|
||||||
startX: 0,
|
|
||||||
startY: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const freedLabelData = {
|
|
||||||
freedLabel: null,
|
|
||||||
startX: 0,
|
|
||||||
startY: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
g6Instance.on('node:dragstart', event => {
|
g6Instance.on('node:dragstart', event => {
|
||||||
nodeData.node = event.item['SVModel'];
|
let node: SVNode = event.item['SVModel'];
|
||||||
let node: SVNode = nodeData.node;
|
|
||||||
|
|
||||||
if (node.isNode() === false || node.leaked) {
|
if (node.isNode() === false || node.leaked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dragActive = true;
|
dragActive = true;
|
||||||
nodeData.startX = event.canvasX;
|
nodeData = {
|
||||||
nodeData.startY = event.canvasY;
|
node,
|
||||||
|
startX: event.canvasX,
|
||||||
|
startY: event.canvasY
|
||||||
|
};
|
||||||
|
|
||||||
if (node.marker) {
|
node.appendages.forEach(item => {
|
||||||
markerData.marker = node.marker;
|
appendagesData.push({
|
||||||
markerData.startX = markerData.marker.get('x');
|
appendage: item,
|
||||||
markerData.startY = markerData.marker.get('y');
|
startX: item.get('x'),
|
||||||
}
|
startY: item.get('y')
|
||||||
|
});
|
||||||
if(node.freedLabel) {
|
});
|
||||||
freedLabelData.freedLabel = node.freedLabel;
|
|
||||||
freedLabelData.startX = freedLabelData.freedLabel.get('x');
|
|
||||||
freedLabelData.startY = freedLabelData.freedLabel.get('y');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
g6Instance.on('node:dragend', event => {
|
g6Instance.on('node:dragend', event => {
|
||||||
@ -64,15 +47,8 @@ export function FixNodeMarkerDrag(g6Instance: Graph) {
|
|||||||
y: node.G6Item.getModel().y
|
y: node.G6Item.getModel().y
|
||||||
});
|
});
|
||||||
|
|
||||||
nodeData.node = null;
|
nodeData = null;
|
||||||
nodeData.startX = 0;
|
appendagesData.length = 0;
|
||||||
nodeData.startY = 0;
|
|
||||||
markerData.marker = null;
|
|
||||||
markerData.startX = 0;
|
|
||||||
markerData.startY = 0;
|
|
||||||
freedLabelData.freedLabel = null;
|
|
||||||
freedLabelData.startX = 0;
|
|
||||||
freedLabelData.startY = 0;
|
|
||||||
dragActive = false;
|
dragActive = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -85,18 +61,11 @@ export function FixNodeMarkerDrag(g6Instance: Graph) {
|
|||||||
dy = ev.canvasY - nodeData.startY,
|
dy = ev.canvasY - nodeData.startY,
|
||||||
zoom = g6Instance.getZoom();
|
zoom = g6Instance.getZoom();
|
||||||
|
|
||||||
if(markerData.marker) {
|
appendagesData.forEach(item => {
|
||||||
markerData.marker.set({
|
item.appendage.set({
|
||||||
x: markerData.startX + dx / zoom,
|
x: item.startX + dx / zoom,
|
||||||
y: markerData.startY + dy / zoom
|
y: item.startY + dy / zoom
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if(freedLabelData.freedLabel) {
|
|
||||||
freedLabelData.freedLabel.set({
|
|
||||||
x: freedLabelData.startX + dx / zoom,
|
|
||||||
y: freedLabelData.startY + dy / zoom
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1,51 +0,0 @@
|
|||||||
import { INode, NodeConfig } from "@antv/g6-core";
|
|
||||||
import { Util } from "../Common/util";
|
|
||||||
import { MarkerOption, NodeLabelOption, Style } from "../options";
|
|
||||||
import { SVModel } from "./SVModel";
|
|
||||||
import { SVNode } from "./SVNode";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class SVMarker extends SVModel {
|
|
||||||
public target: SVNode;
|
|
||||||
public label: string | string[];
|
|
||||||
public anchor: number;
|
|
||||||
|
|
||||||
public shadowG6Item: INode;
|
|
||||||
public G6Item: INode;
|
|
||||||
|
|
||||||
constructor(id: string, type: string, group: string, layout: string, label: string | string[], target: SVNode, options: MarkerOption) {
|
|
||||||
super(id, type, group, layout, 'marker');
|
|
||||||
|
|
||||||
this.target = target;
|
|
||||||
this.label = label;
|
|
||||||
|
|
||||||
this.target.marker = this;
|
|
||||||
this.G6ModelProps = this.generateG6ModelProps(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected generateG6ModelProps(options: MarkerOption): NodeConfig {
|
|
||||||
this.anchor = options.anchor;
|
|
||||||
|
|
||||||
const type = options.type,
|
|
||||||
defaultSize: [number, number] = type === 'pointer'? [8, 30]: [12, 12];
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
rotation: 0,
|
|
||||||
type: options.type || 'marker',
|
|
||||||
size: options.size || defaultSize,
|
|
||||||
anchorPoints: null,
|
|
||||||
label: typeof this.label === 'string'? this.label: this.label.join(', '),
|
|
||||||
style: Util.objectClone<Style>(options.style),
|
|
||||||
labelCfg: Util.objectClone<NodeLabelOption>(options.labelOptions)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLabelSizeRadius(): number {
|
|
||||||
const { width, height } = this.shadowG6Item.getContainer().getChildren()[2].getBBox();
|
|
||||||
return width > height? width: height;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { Util } from "../Common/util";
|
import { Util } from "../Common/util";
|
||||||
import { ModelOption, Style } from "../options";
|
import { Style } from "../options";
|
||||||
import { BoundingRect } from "../Common/boundingRect";
|
import { BoundingRect } from "../Common/boundingRect";
|
||||||
import { EdgeConfig, Item, NodeConfig } from "@antv/g6-core";
|
import { EdgeConfig, Item, NodeConfig } from "@antv/g6-core";
|
||||||
import { Point } from "@antv/g-base";
|
import { Graph } from "_@antv_g6-pc@0.5.0@@antv/g6-pc";
|
||||||
import { Graph } from "@antv/g6-pc";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ export class SVModel {
|
|||||||
* 定义 G6 model 的属性
|
* 定义 G6 model 的属性
|
||||||
* @param option
|
* @param option
|
||||||
*/
|
*/
|
||||||
protected generateG6ModelProps(options: ModelOption) {
|
protected generateG6ModelProps(options: unknown) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,98 +1,34 @@
|
|||||||
import { INode, NodeConfig } from "@antv/g6-core";
|
import { INode, NodeConfig } from "@antv/g6-core";
|
||||||
import { Util } from "../Common/util";
|
import { Util } from "../Common/util";
|
||||||
import { NodeIndexOption, NodeLabelOption, NodeOption, Style } from "../options";
|
import { NodeLabelOption, NodeOption, Style } from "../options";
|
||||||
import { SourceNode } from "../sources";
|
import { SourceNode } from "../sources";
|
||||||
import { SVLink } from "./SVLink";
|
import { SVLink } from "./SVLink";
|
||||||
import { SVMarker } from "./SVMarker";
|
|
||||||
import { SVModel } from "./SVModel";
|
import { SVModel } from "./SVModel";
|
||||||
|
import { SVAddressLabel, SVFreedLabel, SVIndexLabel, SVMarker, SVNodeAppendage } from "./SVNodeAppendage";
|
||||||
|
|
||||||
|
|
||||||
export class SVFreedLabel extends SVModel {
|
|
||||||
public node: SVNode;
|
|
||||||
|
|
||||||
constructor(id: string, type: string, group: string, layout: string, node: SVNode) {
|
|
||||||
super(id, type, group, layout, 'freedLabel');
|
|
||||||
|
|
||||||
this.node = node;
|
|
||||||
this.node.freedLabel = this;
|
|
||||||
this.G6ModelProps = this.generateG6ModelProps();
|
|
||||||
}
|
|
||||||
|
|
||||||
generateG6ModelProps() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
type: 'rect',
|
|
||||||
label: '已释放',
|
|
||||||
labelCfg: {
|
|
||||||
style: {
|
|
||||||
fill: '#b83b5e',
|
|
||||||
opacity: 0.6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
size: [0, 0],
|
|
||||||
style: {
|
|
||||||
stroke: null,
|
|
||||||
fill: 'transparent'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class SVLeakAddress extends SVModel {
|
|
||||||
public node: SVNode;
|
|
||||||
private sourceId: string;
|
|
||||||
|
|
||||||
constructor(id: string, type: string, group: string, layout: string, node: SVNode) {
|
|
||||||
super(id, type, group, layout, 'leakAddress');
|
|
||||||
|
|
||||||
this.node = node;
|
|
||||||
this.sourceId = node.sourceId;
|
|
||||||
this.node.leakAddress = this;
|
|
||||||
this.G6ModelProps = this.generateG6ModelProps();
|
|
||||||
}
|
|
||||||
|
|
||||||
generateG6ModelProps() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
type: 'rect',
|
|
||||||
label: this.sourceId,
|
|
||||||
labelCfg: {
|
|
||||||
style: {
|
|
||||||
fill: '#666',
|
|
||||||
fontSize: 16
|
|
||||||
}
|
|
||||||
},
|
|
||||||
size: [0, 0],
|
|
||||||
style: {
|
|
||||||
stroke: null,
|
|
||||||
fill: 'transparent'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class SVNode extends SVModel {
|
export class SVNode extends SVModel {
|
||||||
public sourceId: string;
|
public sourceId: string;
|
||||||
public sourceNode: SourceNode;
|
public sourceNode: SourceNode;
|
||||||
public marker: SVMarker;
|
|
||||||
public freedLabel: SVFreedLabel;
|
|
||||||
public leakAddress: SVLeakAddress;
|
|
||||||
public links: {
|
public links: {
|
||||||
inDegree: SVLink[];
|
inDegree: SVLink[];
|
||||||
outDegree: SVLink[];
|
outDegree: SVLink[];
|
||||||
};
|
};
|
||||||
|
|
||||||
private label: string | string[];
|
private label: string | string[];
|
||||||
|
private disable: boolean;
|
||||||
|
|
||||||
public shadowG6Item: INode;
|
public shadowG6Item: INode;
|
||||||
public G6Item: INode;
|
public G6Item: INode;
|
||||||
|
|
||||||
|
public marker: SVMarker;
|
||||||
|
public freedLabel: SVFreedLabel;
|
||||||
|
public indexLabel: SVIndexLabel;
|
||||||
|
public addressLabel: SVAddressLabel;
|
||||||
|
public appendages: SVNodeAppendage[];
|
||||||
|
|
||||||
constructor(id: string, type: string, group: string, layout: string, sourceNode: SourceNode, label: string | string[], options: NodeOption) {
|
constructor(id: string, type: string, group: string, layout: string, sourceNode: SourceNode, label: string | string[], options: NodeOption) {
|
||||||
super(id, type, group, layout, 'node');
|
super(id, type, group, layout, 'node');
|
||||||
|
|
||||||
@ -108,22 +44,15 @@ export class SVNode extends SVModel {
|
|||||||
this.sourceNode = sourceNode;
|
this.sourceNode = sourceNode;
|
||||||
this.sourceId = sourceNode.id.toString();
|
this.sourceId = sourceNode.id.toString();
|
||||||
|
|
||||||
this.marker = null;
|
|
||||||
this.links = { inDegree: [], outDegree: [] };
|
this.links = { inDegree: [], outDegree: [] };
|
||||||
|
this.appendages = [];
|
||||||
this.sourceNode = sourceNode;
|
this.sourceNode = sourceNode;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.G6ModelProps = this.generateG6ModelProps(options);
|
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected generateG6ModelProps(options: NodeOption): NodeConfig {
|
protected generateG6ModelProps(options: NodeOption): NodeConfig {
|
||||||
let indexOptions = Util.objectClone<NodeIndexOption>(options.indexOptions) || { index: { position: 'bottom' } };
|
const style = Util.objectClone<Style>(options.style);
|
||||||
|
|
||||||
if (indexOptions) {
|
|
||||||
Object.keys(indexOptions).map(key => {
|
|
||||||
let indexOptionItem = indexOptions[key];
|
|
||||||
indexOptionItem.value = this.sourceNode[key] ?? '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...this.sourceNode,
|
...this.sourceNode,
|
||||||
@ -135,9 +64,11 @@ export class SVNode extends SVModel {
|
|||||||
size: options.size || [60, 30],
|
size: options.size || [60, 30],
|
||||||
anchorPoints: options.anchorPoints,
|
anchorPoints: options.anchorPoints,
|
||||||
label: this.label as string,
|
label: this.label as string,
|
||||||
style: Util.objectClone<Style>(options.style),
|
style: {
|
||||||
labelCfg: Util.objectClone<NodeLabelOption>(options.labelOptions),
|
...style,
|
||||||
indexCfg: indexOptions
|
fill: this.disable ? '#ccc' : style.fill
|
||||||
|
},
|
||||||
|
labelCfg: Util.objectClone<NodeLabelOption>(options.labelOptions)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
182
src/Model/SVNodeAppendage.ts
Normal file
182
src/Model/SVNodeAppendage.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import { INode, NodeConfig } from "@antv/g6-core";
|
||||||
|
import { Util } from "../Common/util";
|
||||||
|
import { AddressLabelOption, IndexLabelOption, MarkerOption, NodeLabelOption, Style } from "../options";
|
||||||
|
import { SourceNode } from "../sources";
|
||||||
|
import { SVModel } from "./SVModel";
|
||||||
|
import { SVNode } from "./SVNode";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class SVNodeAppendage extends SVModel {
|
||||||
|
public target: SVNode;
|
||||||
|
|
||||||
|
constructor(id: string, type: string, group: string, layout: string, modelType: string, target: SVNode) {
|
||||||
|
super(id, type, group, layout, modelType);
|
||||||
|
|
||||||
|
this.target = target;
|
||||||
|
this.target.appendages.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已释放节点下面的文字(“已释放‘)
|
||||||
|
*/
|
||||||
|
export class SVFreedLabel extends SVNodeAppendage {
|
||||||
|
constructor(id: string, type: string, group: string, layout: string, target: SVNode) {
|
||||||
|
super(id, type, group, layout, 'freedLabel', target);
|
||||||
|
|
||||||
|
this.target.freedLabel = this;
|
||||||
|
this.G6ModelProps = this.generateG6ModelProps();
|
||||||
|
}
|
||||||
|
|
||||||
|
generateG6ModelProps() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
type: 'rect',
|
||||||
|
label: '已释放',
|
||||||
|
labelCfg: {
|
||||||
|
style: {
|
||||||
|
fill: '#b83b5e',
|
||||||
|
opacity: 0.6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
size: [0, 0],
|
||||||
|
style: {
|
||||||
|
stroke: null,
|
||||||
|
fill: 'transparent'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 被移动到泄漏区的节点上面显示的地址
|
||||||
|
*/
|
||||||
|
export class SVAddressLabel extends SVNodeAppendage {
|
||||||
|
private sourceId: string;
|
||||||
|
|
||||||
|
constructor(id: string, type: string, group: string, layout: string, target: SVNode, options: AddressLabelOption) {
|
||||||
|
super(id, type, group, layout, 'addressLabel', target);
|
||||||
|
|
||||||
|
this.sourceId = target.sourceId;
|
||||||
|
this.target.addressLabel = this;
|
||||||
|
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateG6ModelProps(options: AddressLabelOption) {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
type: 'rect',
|
||||||
|
label: this.sourceId,
|
||||||
|
labelCfg: {
|
||||||
|
style: {
|
||||||
|
fill: '#666',
|
||||||
|
fontSize: 16,
|
||||||
|
...options.style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
size: [0, 0],
|
||||||
|
style: {
|
||||||
|
stroke: null,
|
||||||
|
fill: 'transparent'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点的下标文字
|
||||||
|
*/
|
||||||
|
export class SVIndexLabel extends SVNodeAppendage {
|
||||||
|
private value: string;
|
||||||
|
|
||||||
|
constructor(id: string, indexName: string, group: string, layout: string, value: string, target: SVNode, options: IndexLabelOption) {
|
||||||
|
super(id, indexName, group, layout, 'indexLabel', target);
|
||||||
|
|
||||||
|
this.target.indexLabel = this;
|
||||||
|
this.value = value;
|
||||||
|
this.G6ModelProps = this.generateG6ModelProps(options) as NodeConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateG6ModelProps(options: IndexLabelOption) {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
type: 'rect',
|
||||||
|
label: this.value,
|
||||||
|
labelCfg: {
|
||||||
|
style: {
|
||||||
|
fill: '#bbb',
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
...options.style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
size: [0, 0],
|
||||||
|
style: {
|
||||||
|
stroke: null,
|
||||||
|
fill: 'transparent'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部指针
|
||||||
|
*/
|
||||||
|
export class SVMarker extends SVNodeAppendage {
|
||||||
|
public label: string | string[];
|
||||||
|
public anchor: number;
|
||||||
|
|
||||||
|
public shadowG6Item: INode;
|
||||||
|
public G6Item: INode;
|
||||||
|
|
||||||
|
constructor(id: string, type: string, group: string, layout: string, label: string | string[], target: SVNode, options: MarkerOption) {
|
||||||
|
super(id, type, group, layout, 'marker', target);
|
||||||
|
|
||||||
|
this.label = label;
|
||||||
|
|
||||||
|
this.target.marker = this;
|
||||||
|
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected generateG6ModelProps(options: MarkerOption): NodeConfig {
|
||||||
|
this.anchor = options.anchor;
|
||||||
|
|
||||||
|
const type = options.type,
|
||||||
|
defaultSize: [number, number] = type === 'pointer' ? [8, 30] : [12, 12];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
rotation: 0,
|
||||||
|
type: options.type || 'marker',
|
||||||
|
size: options.size || defaultSize,
|
||||||
|
anchorPoints: null,
|
||||||
|
label: typeof this.label === 'string' ? this.label : this.label.join(', '),
|
||||||
|
style: Util.objectClone<Style>(options.style),
|
||||||
|
labelCfg: Util.objectClone<NodeLabelOption>(options.labelOptions)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLabelSizeRadius(): number {
|
||||||
|
const { width, height } = this.shadowG6Item.getContainer().getChildren()[2].getBBox();
|
||||||
|
return width > height ? width : height;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,19 +1,20 @@
|
|||||||
import { Util } from "../Common/util";
|
import { Util } from "../Common/util";
|
||||||
import { Engine } from "../engine";
|
import { Engine } from "../engine";
|
||||||
import { LayoutCreator, LayoutGroupOptions, LinkOption, MarkerOption, NodeOption } from "../options";
|
import { AddressLabelOption, IndexLabelOption, LayoutCreator, LayoutGroupOptions, LinkOption, MarkerOption, NodeOption } from "../options";
|
||||||
import { sourceLinkData, LinkTarget, Sources, SourceNode } from "../sources";
|
import { sourceLinkData, LinkTarget, Sources, SourceNode } from "../sources";
|
||||||
import { SV } from "../StructV";
|
import { SV } from "../StructV";
|
||||||
import { SVLink } from "./SVLink";
|
import { SVLink } from "./SVLink";
|
||||||
import { SVMarker } from "./SVMarker";
|
|
||||||
import { SVModel } from "./SVModel";
|
import { SVModel } from "./SVModel";
|
||||||
import { SVFreedLabel, SVLeakAddress, SVNode } from "./SVNode";
|
import { SVNode } from "./SVNode";
|
||||||
|
import { SVAddressLabel, SVFreedLabel, SVIndexLabel, SVMarker } from "./SVNodeAppendage";
|
||||||
|
|
||||||
|
|
||||||
export type LayoutGroup = {
|
export type LayoutGroup = {
|
||||||
name: string;
|
name: string;
|
||||||
node: SVNode[];
|
node: SVNode[];
|
||||||
|
indexLabel: SVIndexLabel[];
|
||||||
freedLabel: SVFreedLabel[];
|
freedLabel: SVFreedLabel[];
|
||||||
leakAddress: SVLeakAddress[];
|
addressLabel: SVAddressLabel[];
|
||||||
link: SVLink[];
|
link: SVLink[];
|
||||||
marker: SVMarker[];
|
marker: SVMarker[];
|
||||||
layoutCreator: LayoutCreator;
|
layoutCreator: LayoutCreator;
|
||||||
@ -38,7 +39,7 @@ export class ModelConstructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建svnode,svlink 和 svmarker
|
* 构建SVNode,SVLink, SVMarker, SVAddressLabel, SVIndexLabel等
|
||||||
* @param sourceList
|
* @param sourceList
|
||||||
*/
|
*/
|
||||||
public construct(sources: Sources): LayoutGroupTable {
|
public construct(sources: Sources): LayoutGroupTable {
|
||||||
@ -59,7 +60,8 @@ export class ModelConstructor {
|
|||||||
prevString: string = this.prevSourcesStringMap[group],
|
prevString: string = this.prevSourcesStringMap[group],
|
||||||
nodeList: SVNode[] = [],
|
nodeList: SVNode[] = [],
|
||||||
freedLabelList: SVFreedLabel[] = [],
|
freedLabelList: SVFreedLabel[] = [],
|
||||||
leakAddress: SVLeakAddress[] = [],
|
addressLabelList: SVAddressLabel[] = [],
|
||||||
|
indexLabelList: SVIndexLabel[] = [],
|
||||||
markerList: SVMarker[] = [];
|
markerList: SVMarker[] = [];
|
||||||
|
|
||||||
if (prevString === sourceDataString) {
|
if (prevString === sourceDataString) {
|
||||||
@ -69,30 +71,37 @@ export class ModelConstructor {
|
|||||||
const options: LayoutGroupOptions = layoutCreator.defineOptions(sourceGroup.data),
|
const options: LayoutGroupOptions = layoutCreator.defineOptions(sourceGroup.data),
|
||||||
sourceData = layoutCreator.sourcesPreprocess(sourceGroup.data, options),
|
sourceData = layoutCreator.sourcesPreprocess(sourceGroup.data, options),
|
||||||
nodeOptions = options.node || options['element'] || {},
|
nodeOptions = options.node || options['element'] || {},
|
||||||
markerOptions = options.marker || {};
|
markerOptions = options.marker || {},
|
||||||
|
indexLabelOptions = options.indexLabel || {},
|
||||||
|
addressLabelOption = options.addressLabel || {};
|
||||||
|
|
||||||
nodeList = this.constructNodes(nodeOptions, group, sourceData, layout);
|
nodeList = this.constructNodes(group, layout, nodeOptions, sourceData);
|
||||||
markerList = this.constructMarkers(group, layout, markerOptions, nodeList);
|
markerList = this.constructMarkers(group, layout, markerOptions, nodeList);
|
||||||
|
indexLabelList = this.constructIndexLabel(group, layout, indexLabelOptions, nodeList);
|
||||||
|
addressLabelList = this.constructAddressLabel(group, layout, addressLabelOption, nodeList);
|
||||||
nodeList.forEach(item => {
|
nodeList.forEach(item => {
|
||||||
if(item.freedLabel) {
|
if(item.freedLabel) {
|
||||||
freedLabelList.push(item.freedLabel);
|
freedLabelList.push(item.freedLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.leakAddress) {
|
|
||||||
leakAddress.push(item.leakAddress);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
layoutGroupTable.set(group, {
|
layoutGroupTable.set(group, {
|
||||||
name: group,
|
name: group,
|
||||||
node: nodeList,
|
node: nodeList,
|
||||||
freedLabel: freedLabelList,
|
freedLabel: freedLabelList,
|
||||||
leakAddress: leakAddress,
|
addressLabel: addressLabelList,
|
||||||
|
indexLabel: indexLabelList,
|
||||||
link: [],
|
link: [],
|
||||||
marker: markerList,
|
marker: markerList,
|
||||||
options: options,
|
options: options,
|
||||||
layoutCreator,
|
layoutCreator,
|
||||||
modelList: [...nodeList, ...markerList, ...freedLabelList, ...leakAddress],
|
modelList: [
|
||||||
|
...nodeList,
|
||||||
|
...markerList,
|
||||||
|
...freedLabelList,
|
||||||
|
...addressLabelList,
|
||||||
|
...indexLabelList
|
||||||
|
],
|
||||||
layout,
|
layout,
|
||||||
isHide: false
|
isHide: false
|
||||||
});
|
});
|
||||||
@ -100,7 +109,7 @@ export class ModelConstructor {
|
|||||||
|
|
||||||
layoutGroupTable.forEach((layoutGroup: LayoutGroup, group: string) => {
|
layoutGroupTable.forEach((layoutGroup: LayoutGroup, group: string) => {
|
||||||
const linkOptions = layoutGroup.options.link || {},
|
const linkOptions = layoutGroup.options.link || {},
|
||||||
linkList: SVLink[] = this.constructLinks(linkOptions, layoutGroup.node, layoutGroupTable, group, layoutGroup.layout, );
|
linkList: SVLink[] = this.constructLinks(group, layoutGroup.layout, linkOptions, layoutGroup.node, layoutGroupTable);
|
||||||
|
|
||||||
layoutGroup.link = linkList;
|
layoutGroup.link = linkList;
|
||||||
layoutGroup.modelList.push(...linkList);
|
layoutGroup.modelList.push(...linkList);
|
||||||
@ -127,7 +136,7 @@ export class ModelConstructor {
|
|||||||
* @param layout
|
* @param layout
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private constructNodes(nodeOptions: { [key: string]: NodeOption }, group: string, sourceList: SourceNode[], layout: string): SVNode[] {
|
private constructNodes(group: string, layout: string, nodeOptions: { [key: string]: NodeOption }, sourceList: SourceNode[]): SVNode[] {
|
||||||
let defaultSourceNodeType: string = 'default',
|
let defaultSourceNodeType: string = 'default',
|
||||||
nodeList: SVNode[] = [];
|
nodeList: SVNode[] = [];
|
||||||
|
|
||||||
@ -153,7 +162,7 @@ export class ModelConstructor {
|
|||||||
* @param layoutGroupTable
|
* @param layoutGroupTable
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
private constructLinks(linkOptions: { [key: string]: LinkOption }, nodes: SVNode[], layoutGroupTable: LayoutGroupTable, group: string, layout: string): SVLink[] {
|
private constructLinks(group: string, layout: string, linkOptions: { [key: string]: LinkOption }, nodes: SVNode[], layoutGroupTable: LayoutGroupTable): SVLink[] {
|
||||||
let linkList: SVLink[] = [],
|
let linkList: SVLink[] = [],
|
||||||
linkNames = Object.keys(linkOptions);
|
linkNames = Object.keys(linkOptions);
|
||||||
|
|
||||||
@ -200,6 +209,52 @@ export class ModelConstructor {
|
|||||||
return linkList;
|
return linkList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置项构建 indexLabel 集
|
||||||
|
* @param group
|
||||||
|
* @param layout
|
||||||
|
* @param indexLabelOptions
|
||||||
|
*/
|
||||||
|
private constructIndexLabel(group: string, layout: string, indexLabelOptions: { [key: string]: IndexLabelOption }, nodes: SVNode[]): SVIndexLabel[] {
|
||||||
|
let indexLabelList: SVIndexLabel[] = [],
|
||||||
|
indexNames = Object.keys(indexLabelOptions);
|
||||||
|
|
||||||
|
indexNames.forEach(name => {
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i],
|
||||||
|
value = node[name];
|
||||||
|
|
||||||
|
// 若没有指针字段的结点则跳过
|
||||||
|
if (!value) continue;
|
||||||
|
|
||||||
|
let id = `${group}.${name}#${value}`,
|
||||||
|
indexLabel = new SVIndexLabel(id, name, group, layout, value, node, indexLabelOptions[name]);
|
||||||
|
|
||||||
|
indexLabelList.push(indexLabel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return indexLabelList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param group
|
||||||
|
* @param layout
|
||||||
|
* @param addressLabelOption
|
||||||
|
* @param nodes
|
||||||
|
*/
|
||||||
|
private constructAddressLabel(group: string, layout: string, addressLabelOption: AddressLabelOption, nodes: SVNode[]): SVAddressLabel[] {
|
||||||
|
let addressLabelList: SVAddressLabel[] = [];
|
||||||
|
|
||||||
|
nodes.forEach(item => {
|
||||||
|
const addressLabel = new SVAddressLabel(`${item.id}-address-label`, item.sourceType, group, layout, item, addressLabelOption);
|
||||||
|
addressLabelList.push(addressLabel);
|
||||||
|
});
|
||||||
|
|
||||||
|
return addressLabelList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从配置和 node 集构建 marker 集
|
* 从配置和 node 集构建 marker 集
|
||||||
* @param markerOptions
|
* @param markerOptions
|
||||||
@ -219,7 +274,7 @@ export class ModelConstructor {
|
|||||||
if (!markerData) continue;
|
if (!markerData) continue;
|
||||||
|
|
||||||
let id = `${group}.${name}.${Array.isArray(markerData) ? markerData.join('-') : markerData}`,
|
let id = `${group}.${name}.${Array.isArray(markerData) ? markerData.join('-') : markerData}`,
|
||||||
marker = this.createMarker(id, name, markerData, group, layout, node, markerOptions[name]);
|
marker = new SVMarker(id, name, group, layout, markerData, node, markerOptions[name]);
|
||||||
|
|
||||||
markerList.push(marker);
|
markerList.push(marker);
|
||||||
}
|
}
|
||||||
@ -262,7 +317,6 @@ export class ModelConstructor {
|
|||||||
let label: string | string[] = this.resolveNodeLabel(options.label, sourceNode),
|
let label: string | string[] = this.resolveNodeLabel(options.label, sourceNode),
|
||||||
id = sourceNodeType + '.' + sourceNode.id.toString(),
|
id = sourceNodeType + '.' + sourceNode.id.toString(),
|
||||||
node = new SVNode(id, sourceNodeType, group, layout, sourceNode, label, options);
|
node = new SVNode(id, sourceNodeType, group, layout, sourceNode, label, options);
|
||||||
node.leakAddress = new SVLeakAddress(`${id}-leak-adress`, sourceNodeType, group, layout, node);
|
|
||||||
|
|
||||||
if(node.freed) {
|
if(node.freed) {
|
||||||
node.freedLabel = new SVFreedLabel(`${id}-freed-label`, sourceNodeType, group, layout, node);
|
node.freedLabel = new SVFreedLabel(`${id}-freed-label`, sourceNodeType, group, layout, node);
|
||||||
@ -271,21 +325,6 @@ export class ModelConstructor {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 外部指针工厂,创建marker
|
|
||||||
* @param id
|
|
||||||
* @param markerName
|
|
||||||
* @param markerData
|
|
||||||
* @param group
|
|
||||||
* @param layout
|
|
||||||
* @param target
|
|
||||||
* @param options
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
private createMarker(id: string, markerName: string, markerData: string | string[], group: string, layout: string, target: SVNode, options: MarkerOption): SVMarker {
|
|
||||||
return new SVMarker(id, markerName, group, layout, markerData, target, options);;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连线工厂,创建Link
|
* 连线工厂,创建Link
|
||||||
* @param linkName
|
* @param linkName
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
import { registerNode } from '@antv/g6';
|
|
||||||
|
|
||||||
|
|
||||||
export default registerNode('indexed-node', {
|
|
||||||
draw(cfg, group) {
|
|
||||||
cfg.size = cfg.size || [30, 10];
|
|
||||||
|
|
||||||
const width = cfg.size[0],
|
|
||||||
height = cfg.size[1],
|
|
||||||
disable = cfg.disable === undefined ? false : cfg.disable;
|
|
||||||
|
|
||||||
const rect = group.addShape('rect', {
|
|
||||||
attrs: {
|
|
||||||
x: width / 2,
|
|
||||||
y: height / 2,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
stroke: cfg.style.stroke || '#333',
|
|
||||||
fill: disable ? '#ccc' : cfg.style.fill,
|
|
||||||
cursor: cfg.style.cursor,
|
|
||||||
},
|
|
||||||
name: 'wrapper'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (cfg.label) {
|
|
||||||
const style = (cfg.labelCfg && cfg.labelCfg.style) || {};
|
|
||||||
group.addShape('text', {
|
|
||||||
attrs: {
|
|
||||||
x: width,
|
|
||||||
y: height,
|
|
||||||
textAlign: 'center',
|
|
||||||
textBaseline: 'middle',
|
|
||||||
text: cfg.label,
|
|
||||||
fill: style.fill || '#000',
|
|
||||||
fontSize: style.fontSize || 16
|
|
||||||
},
|
|
||||||
name: 'text'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const indexCfg = cfg.indexCfg;
|
|
||||||
const offset = Number(cfg.style.offset) || 20;
|
|
||||||
const indexPositionMap: { [key: string]: (width: number, height: number) => { x: number, y: number } } = {
|
|
||||||
top: (width: number, height: number) => ({ x: width, y: height / 2 - offset }),
|
|
||||||
right: (width: number, height: number) => ({ x: width * 1.5 + offset, y: height }),
|
|
||||||
bottom: (width: number, height: number) => ({ x: width, y: height * 1.5 + offset }),
|
|
||||||
left: (width: number, height: number) => ({ x: width / 2 - offset, y: height })
|
|
||||||
};
|
|
||||||
|
|
||||||
if (indexCfg !== undefined) {
|
|
||||||
Object.keys(indexCfg).map(key => {
|
|
||||||
let indexCfgItem = indexCfg[key];
|
|
||||||
let position = indexCfgItem.position || 'bottom';
|
|
||||||
let { x: indexX, y: indexY } = indexPositionMap[position](width, height);
|
|
||||||
|
|
||||||
group.addShape('text', {
|
|
||||||
attrs: {
|
|
||||||
x: indexX,
|
|
||||||
y: indexY,
|
|
||||||
textAlign: 'center',
|
|
||||||
textBaseline: 'middle',
|
|
||||||
text: indexCfgItem.value.toString(),
|
|
||||||
fill: '#bbb',
|
|
||||||
fontSize: 14,
|
|
||||||
fontStyle: 'italic',
|
|
||||||
...indexCfgItem.style
|
|
||||||
},
|
|
||||||
name: 'index-text'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return rect;
|
|
||||||
},
|
|
||||||
|
|
||||||
getAnchorPoints() {
|
|
||||||
return [
|
|
||||||
[0.5, 0],
|
|
||||||
[1, 0.5],
|
|
||||||
[0.5, 1],
|
|
||||||
[0, 0.5]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -13,7 +13,7 @@ export default registerNode('pointer', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (cfg.label) {
|
if (cfg.label) {
|
||||||
const style = (cfg.labelCfg && cfg.labelCfg.style) || {};
|
const labelStyle = (cfg.labelCfg && cfg.labelCfg.style) || {};
|
||||||
|
|
||||||
const bgRect = group.addShape('rect', {
|
const bgRect = group.addShape('rect', {
|
||||||
attrs: {
|
attrs: {
|
||||||
@ -33,8 +33,8 @@ export default registerNode('pointer', {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
textBaseline: 'middle',
|
textBaseline: 'middle',
|
||||||
text: cfg.label,
|
text: cfg.label,
|
||||||
fill: style.fill || '#999',
|
fill: labelStyle.fill || '#999',
|
||||||
fontSize: style.fontSize || 16
|
fontSize: labelStyle.fontSize || 16
|
||||||
},
|
},
|
||||||
name: 'pointer-text-shape'
|
name: 'pointer-text-shape'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import CLenQueuePointer from "./RegisteredShape/clenQueuePointer";
|
|||||||
import twoCellNode from "./RegisteredShape/twoCellNode";
|
import twoCellNode from "./RegisteredShape/twoCellNode";
|
||||||
import Cursor from "./RegisteredShape/cursor";
|
import Cursor from "./RegisteredShape/cursor";
|
||||||
import { Vector } from "./Common/vector";
|
import { Vector } from "./Common/vector";
|
||||||
import indexedNode from "./RegisteredShape/indexedNode";
|
|
||||||
import { EngineOptions, LayoutCreator } from "./options";
|
import { EngineOptions, LayoutCreator } from "./options";
|
||||||
import { SVNode } from "./Model/SVNode";
|
import { SVNode } from "./Model/SVNode";
|
||||||
import { SourceNode } from "./sources";
|
import { SourceNode } from "./sources";
|
||||||
@ -55,7 +54,6 @@ SV.registeredShape = [
|
|||||||
linkListNode,
|
linkListNode,
|
||||||
binaryTreeNode,
|
binaryTreeNode,
|
||||||
twoCellNode,
|
twoCellNode,
|
||||||
indexedNode,
|
|
||||||
Cursor,
|
Cursor,
|
||||||
CLenQueuePointer,
|
CLenQueuePointer,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -5,11 +5,9 @@ import { Util } from '../Common/util';
|
|||||||
import { Vector } from '../Common/vector';
|
import { Vector } from '../Common/vector';
|
||||||
import { Engine } from '../engine';
|
import { Engine } from '../engine';
|
||||||
import { LayoutGroupTable } from '../Model/modelConstructor';
|
import { LayoutGroupTable } from '../Model/modelConstructor';
|
||||||
import { SVLink } from '../Model/SVLink';
|
|
||||||
import { SVMarker } from '../Model/SVMarker';
|
|
||||||
import { SVModel } from '../Model/SVModel';
|
import { SVModel } from '../Model/SVModel';
|
||||||
import { SVFreedLabel, SVLeakAddress, SVNode } from '../Model/SVNode';
|
import { SVAddressLabel, SVFreedLabel, SVIndexLabel, SVMarker } from '../Model/SVNodeAppendage';
|
||||||
import { LayoutOptions, MarkerOption, ViewOptions } from '../options';
|
import { AddressLabelOption, IndexLabelOption, LayoutOptions, MarkerOption, ViewOptions } from '../options';
|
||||||
import { ViewContainer } from './viewContainer';
|
import { ViewContainer } from './viewContainer';
|
||||||
|
|
||||||
|
|
||||||
@ -111,7 +109,7 @@ export class LayoutProvider {
|
|||||||
*/
|
*/
|
||||||
private layoutFreedLabel(freedLabels: SVFreedLabel[]) {
|
private layoutFreedLabel(freedLabels: SVFreedLabel[]) {
|
||||||
freedLabels.forEach(item => {
|
freedLabels.forEach(item => {
|
||||||
const freedNodeBound = item.node.getBound();
|
const freedNodeBound = item.target.getBound();
|
||||||
|
|
||||||
item.set({
|
item.set({
|
||||||
x: freedNodeBound.x + freedNodeBound.width / 2,
|
x: freedNodeBound.x + freedNodeBound.width / 2,
|
||||||
@ -121,18 +119,64 @@ export class LayoutProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param indexLabels
|
||||||
|
* @param indexLabelOptions
|
||||||
|
*/
|
||||||
|
private layoutIndexLabel(indexLabels: SVIndexLabel[], indexLabelOptions: { [key: string]: IndexLabelOption }) {
|
||||||
|
const indexLabelPositionMap: { [key: string]: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => { x: number, y: number } } = {
|
||||||
|
top: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => {
|
||||||
|
return {
|
||||||
|
x: nodeBound.x + nodeBound.width / 2,
|
||||||
|
y: nodeBound.y - offset
|
||||||
|
};
|
||||||
|
},
|
||||||
|
right: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => {
|
||||||
|
return {
|
||||||
|
x: nodeBound.x + nodeBound.width + offset,
|
||||||
|
y: nodeBound.y + nodeBound.height / 2
|
||||||
|
};
|
||||||
|
},
|
||||||
|
bottom: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => {
|
||||||
|
return {
|
||||||
|
x: nodeBound.x + nodeBound.width / 2,
|
||||||
|
y: nodeBound.y + nodeBound.height + offset
|
||||||
|
};
|
||||||
|
},
|
||||||
|
left: (nodeBound: BoundingRect, labelBound: BoundingRect, offset: number) => {
|
||||||
|
return {
|
||||||
|
x: nodeBound.x - labelBound.width - 2 * offset,
|
||||||
|
y: nodeBound.y + nodeBound.height / 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
indexLabels.forEach(item => {
|
||||||
|
const options: IndexLabelOption = indexLabelOptions[item.sourceType],
|
||||||
|
nodeBound = item.target.getBound(),
|
||||||
|
labelBound = item.getBound(),
|
||||||
|
offset = options.offset ?? 20,
|
||||||
|
position = options.position ?? 'bottom';
|
||||||
|
|
||||||
|
const pos = indexLabelPositionMap[position](nodeBound, labelBound, offset);
|
||||||
|
item.set(pos);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 布局泄漏区节点上面的address label
|
* 布局泄漏区节点上面的address label
|
||||||
* @param leakAddress
|
* @param leakAddress
|
||||||
*/
|
*/
|
||||||
private layoutLeakAddress(leakAddress: SVLeakAddress[]) {
|
private layoutAddressLabel(leakAddress: SVAddressLabel[], addressLabelOption: AddressLabelOption) {
|
||||||
|
const offset = addressLabelOption.offset || 16;
|
||||||
|
|
||||||
leakAddress.forEach(item => {
|
leakAddress.forEach(item => {
|
||||||
const nodeBound = item.node.getBound();
|
const nodeBound = item.target.getBound();
|
||||||
|
|
||||||
item.set({
|
item.set({
|
||||||
x: nodeBound.x + nodeBound.width / 2,
|
x: nodeBound.x + nodeBound.width / 2,
|
||||||
y: nodeBound.y - 16,
|
y: nodeBound.y - offset
|
||||||
size: [nodeBound.width, 0]
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -146,22 +190,28 @@ export class LayoutProvider {
|
|||||||
const modelGroupList: Group[] = [];
|
const modelGroupList: Group[] = [];
|
||||||
|
|
||||||
layoutGroupTable.forEach(group => {
|
layoutGroupTable.forEach(group => {
|
||||||
const options: LayoutOptions = group.options.layout,
|
const modelList: SVModel[] = group.modelList,
|
||||||
modelList: SVModel[] = group.modelList,
|
|
||||||
modelGroup: Group = new Group();
|
modelGroup: Group = new Group();
|
||||||
|
|
||||||
|
const layoutOptions: LayoutOptions = group.options.layout;
|
||||||
|
|
||||||
modelList.forEach(item => {
|
modelList.forEach(item => {
|
||||||
modelGroup.add(item);
|
modelGroup.add(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
group.layoutCreator.layout(group.node, options); // 布局节点
|
group.layoutCreator.layout(group.node, layoutOptions); // 布局节点
|
||||||
modelGroupList.push(modelGroup);
|
modelGroupList.push(modelGroup);
|
||||||
});
|
});
|
||||||
|
|
||||||
layoutGroupTable.forEach(group => {
|
layoutGroupTable.forEach(group => {
|
||||||
|
const markerOptions = group.options.marker || {},
|
||||||
|
indexLabelOptions = group.options.indexLabel || {},
|
||||||
|
addressLabelOption = group.options.addressLabel || {};
|
||||||
|
|
||||||
|
this.layoutIndexLabel(group.indexLabel, indexLabelOptions);
|
||||||
this.layoutFreedLabel(group.freedLabel);
|
this.layoutFreedLabel(group.freedLabel);
|
||||||
this.layoutLeakAddress(group.leakAddress);
|
this.layoutAddressLabel(group.addressLabel, addressLabelOption);
|
||||||
this.layoutMarker(group.marker, group.options.marker); // 布局外部指针
|
this.layoutMarker(group.marker, markerOptions); // 布局外部指针
|
||||||
});
|
});
|
||||||
|
|
||||||
return modelGroupList;
|
return modelGroupList;
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { EventBus } from "../Common/eventBus";
|
|||||||
import { Util } from "../Common/util";
|
import { Util } from "../Common/util";
|
||||||
import { Engine } from "../engine";
|
import { Engine } from "../engine";
|
||||||
import { SVLink } from "../Model/SVLink";
|
import { SVLink } from "../Model/SVLink";
|
||||||
import { SVMarker } from "../Model/SVMarker";
|
|
||||||
import { SVModel } from "../Model/SVModel";
|
import { SVModel } from "../Model/SVModel";
|
||||||
import { SVLeakAddress, SVNode } from "../Model/SVNode";
|
import { SVNode } from "../Model/SVNode";
|
||||||
|
import { SVAddressLabel, SVMarker, SVNodeAppendage } from "../Model/SVNodeAppendage";
|
||||||
import { Animations } from "./animation";
|
import { Animations } from "./animation";
|
||||||
import { Renderer } from "./renderer";
|
import { Renderer } from "./renderer";
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export class Reconcile {
|
|||||||
appendModels.forEach(item => {
|
appendModels.forEach(item => {
|
||||||
let removeIndex = accumulateLeakModels.findIndex(leakModel => item.id === leakModel.id);
|
let removeIndex = accumulateLeakModels.findIndex(leakModel => item.id === leakModel.id);
|
||||||
|
|
||||||
if(removeIndex > -1) {
|
if (removeIndex > -1) {
|
||||||
accumulateLeakModels.splice(removeIndex, 1);
|
accumulateLeakModels.splice(removeIndex, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -83,20 +83,10 @@ export class Reconcile {
|
|||||||
item.leaked = true;
|
item.leaked = true;
|
||||||
leakModels.push(item);
|
leakModels.push(item);
|
||||||
|
|
||||||
if (item.marker) {
|
item.appendages.forEach(appendage => {
|
||||||
item.marker.leaked = true;
|
appendage.leaked = true;
|
||||||
leakModels.push(item.marker);
|
leakModels.push(appendage);
|
||||||
}
|
});
|
||||||
|
|
||||||
if(item.freedLabel) {
|
|
||||||
item.marker.leaked = true;
|
|
||||||
leakModels.push(item.freedLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(item.leakAddress) {
|
|
||||||
item.leakAddress.leaked = true;
|
|
||||||
leakModels.push(item.leakAddress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -190,7 +180,7 @@ export class Reconcile {
|
|||||||
freedNodes.forEach(item => {
|
freedNodes.forEach(item => {
|
||||||
const prev = prevModelList.find(prevModel => item.id === prevModel.id);
|
const prev = prevModelList.find(prevModel => item.id === prevModel.id);
|
||||||
|
|
||||||
if(prev) {
|
if (prev) {
|
||||||
item.set('label', prev.get('label'));
|
item.set('label', prev.get('label'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -205,10 +195,10 @@ export class Reconcile {
|
|||||||
* @param continuousModels
|
* @param continuousModels
|
||||||
*/
|
*/
|
||||||
private handleContinuousModels(continuousModels: SVModel[]) {
|
private handleContinuousModels(continuousModels: SVModel[]) {
|
||||||
for(let i = 0; i < continuousModels.length; i++) {
|
for (let i = 0; i < continuousModels.length; i++) {
|
||||||
let model = continuousModels[i];
|
let model = continuousModels[i];
|
||||||
|
|
||||||
if(model instanceof SVNode) {
|
if (model instanceof SVNode) {
|
||||||
const group = model.G6Item.getContainer();
|
const group = model.G6Item.getContainer();
|
||||||
group.attr({ opacity: 1 });
|
group.attr({ opacity: 1 });
|
||||||
}
|
}
|
||||||
@ -223,9 +213,19 @@ export class Reconcile {
|
|||||||
let { duration, timingFunction } = this.engine.animationOptions;
|
let { duration, timingFunction } = this.engine.animationOptions;
|
||||||
|
|
||||||
appendModels.forEach(item => {
|
appendModels.forEach(item => {
|
||||||
if(item instanceof SVLeakAddress) {
|
if (item instanceof SVNodeAppendage) {
|
||||||
const leakAddressG6Group = item.G6Item.getContainer();
|
// 先不显示泄漏区节点上面的地址文本
|
||||||
leakAddressG6Group.attr({ opacity: 0 });
|
if (item instanceof SVAddressLabel) {
|
||||||
|
// 先将透明度改为0,隐藏掉
|
||||||
|
const AddressLabelG6Group = item.G6Item.getContainer();
|
||||||
|
AddressLabelG6Group.attr({ opacity: 0 });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Animations.FADE_IN(item.G6Item, {
|
||||||
|
duration,
|
||||||
|
timingFunction
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Animations.APPEND(item.G6Item, {
|
Animations.APPEND(item.G6Item, {
|
||||||
@ -262,7 +262,7 @@ export class Reconcile {
|
|||||||
let { duration, timingFunction } = this.engine.animationOptions;
|
let { duration, timingFunction } = this.engine.animationOptions;
|
||||||
|
|
||||||
leakModels.forEach(item => {
|
leakModels.forEach(item => {
|
||||||
if(item instanceof SVLeakAddress) {
|
if (item instanceof SVAddressLabel) {
|
||||||
Animations.FADE_IN(item.G6Item, {
|
Animations.FADE_IN(item.G6Item, {
|
||||||
duration,
|
duration,
|
||||||
timingFunction
|
timingFunction
|
||||||
@ -279,7 +279,7 @@ export class Reconcile {
|
|||||||
*/
|
*/
|
||||||
private handleAccumulateLeakModels(accumulateModels: SVModel[]) {
|
private handleAccumulateLeakModels(accumulateModels: SVModel[]) {
|
||||||
accumulateModels.forEach(item => {
|
accumulateModels.forEach(item => {
|
||||||
if(item.generalStyle) {
|
if (item.generalStyle) {
|
||||||
item.set('style', { ...item.generalStyle });
|
item.set('style', { ...item.generalStyle });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -318,7 +318,7 @@ export class Reconcile {
|
|||||||
* @param models
|
* @param models
|
||||||
*/
|
*/
|
||||||
private handleChangeModels(models: SVModel[]) {
|
private handleChangeModels(models: SVModel[]) {
|
||||||
if(models.length === 0) {
|
if (models.length === 0) {
|
||||||
models = this.prevChangeModels;
|
models = this.prevChangeModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +329,7 @@ export class Reconcile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
models.forEach(item => {
|
models.forEach(item => {
|
||||||
if(item.generalStyle === undefined) {
|
if (item.generalStyle === undefined) {
|
||||||
item.generalStyle = Util.objectClone(item.G6ModelProps.style);
|
item.generalStyle = Util.objectClone(item.G6ModelProps.style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ export class Reconcile {
|
|||||||
this.handleLeakModels(LEAKED);
|
this.handleLeakModels(LEAKED);
|
||||||
this.handleRemoveModels(REMOVE);
|
this.handleRemoveModels(REMOVE);
|
||||||
|
|
||||||
if(this.isFirstPatch) {
|
if (this.isFirstPatch) {
|
||||||
this.isFirstPatch = false;
|
this.isFirstPatch = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { InitDragCanvasWithLeak } from "../BehaviorHelper/dragCanvasWithLeak";
|
|||||||
import { EventBus } from "../Common/eventBus";
|
import { EventBus } from "../Common/eventBus";
|
||||||
import { InitZoomCanvasWithLeak } from "../BehaviorHelper/zoomCanvasWithLeak";
|
import { InitZoomCanvasWithLeak } from "../BehaviorHelper/zoomCanvasWithLeak";
|
||||||
import { Group } from "../Common/group";
|
import { Group } from "../Common/group";
|
||||||
|
import { Graph } from "_@antv_g6-pc@0.5.0@@antv/g6-pc";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -80,10 +81,18 @@ export class ViewContainer {
|
|||||||
/**
|
/**
|
||||||
* 获取 g6 实例
|
* 获取 g6 实例
|
||||||
*/
|
*/
|
||||||
getG6Instance() {
|
getG6Instance(): Graph {
|
||||||
return this.renderer.getG6Instance();
|
return this.renderer.getG6Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取泄漏区里面的元素
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getAccumulateLeakModels(): SVModel[] {
|
||||||
|
return this.accumulateLeakModels;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新视图
|
* 刷新视图
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import { Sources } from "./sources";
|
import { Sources } from "./sources";
|
||||||
import { ModelConstructor } from "./Model/modelConstructor";
|
import { ModelConstructor } from "./Model/modelConstructor";
|
||||||
import { AnimationOptions, EngineOptions, InteractionOptions, ViewOptions } from "./options";
|
import { AnimationOptions, EngineOptions, InteractionOptions, ViewOptions } from "./options";
|
||||||
import { SV } from "./StructV";
|
|
||||||
import { EventBus } from "./Common/eventBus";
|
import { EventBus } from "./Common/eventBus";
|
||||||
import { ViewContainer } from "./View/viewContainer";
|
import { ViewContainer } from "./View/viewContainer";
|
||||||
import { SVLink } from "./Model/SVLink";
|
|
||||||
import { SVNode } from "./Model/SVNode";
|
import { SVNode } from "./Model/SVNode";
|
||||||
import { SVMarker } from "./Model/SVMarker";
|
import { Util } from "./Common/util";
|
||||||
|
import { SVModel } from "./Model/SVModel";
|
||||||
|
|
||||||
|
|
||||||
export class Engine {
|
export class Engine {
|
||||||
@ -107,63 +106,6 @@ export class Engine {
|
|||||||
return this.viewContainer.getG6Instance();
|
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
|
* @param groupNames
|
||||||
@ -188,14 +130,24 @@ export class Engine {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getAllModels(): SVModel[] {
|
||||||
|
const modelList = Util.convertGroupTable2ModelList(this.modelConstructor.getLayoutGroupTable());
|
||||||
|
const accumulateLeakModels = this.viewContainer.getAccumulateLeakModels();
|
||||||
|
|
||||||
|
return [...modelList, ...accumulateLeakModels];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用id查找某个节点
|
* 使用id查找某个节点
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
public findNode(id: string): SVNode {
|
public findNode(id: string): SVNode {
|
||||||
const nodes = this.getNodes();
|
const modelList = this.getAllModels();
|
||||||
const stringId = id.toString();
|
const stringId = id.toString();
|
||||||
const targetNode = nodes.find(item => item.sourceId === stringId);
|
const targetNode: SVNode = modelList.find(item => item instanceof SVNode && item.sourceId === stringId) as SVNode;
|
||||||
|
|
||||||
return targetNode;
|
return targetNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,10 +22,14 @@ export interface NodeLabelOption {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export interface NodeIndexOption extends NodeLabelOption {
|
export interface AddressLabelOption {
|
||||||
|
offset?: number;
|
||||||
|
style?: Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface IndexLabelOption extends NodeLabelOption {
|
||||||
position: 'top' | 'right' | 'bottom' | 'left';
|
position: 'top' | 'right' | 'bottom' | 'left';
|
||||||
value: string;
|
|
||||||
style: Style;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +53,6 @@ export interface NodeOption extends ModelOption {
|
|||||||
rotation: number;
|
rotation: number;
|
||||||
label: string | string[];
|
label: string | string[];
|
||||||
anchorPoints: number[][];
|
anchorPoints: number[][];
|
||||||
indexOptions: NodeIndexOption;
|
|
||||||
labelOptions: NodeLabelOption;
|
labelOptions: NodeLabelOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +81,10 @@ export interface LayoutOptions {
|
|||||||
|
|
||||||
export interface LayoutGroupOptions {
|
export interface LayoutGroupOptions {
|
||||||
node: { [key: string]: NodeOption };
|
node: { [key: string]: NodeOption };
|
||||||
link?: { [key: string]: LinkOption }
|
link?: { [key: string]: LinkOption };
|
||||||
marker?: { [key: string]: MarkerOption }
|
marker?: { [key: string]: MarkerOption };
|
||||||
|
addressLabel?: AddressLabelOption;
|
||||||
|
indexLabel?: { [key: string]: IndexLabelOption };
|
||||||
layout?: LayoutOptions;
|
layout?: LayoutOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user