fix: 修复泄漏区布局问题
This commit is contained in:
parent
7bba64cc9e
commit
dd219ce946
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
test
|
test
|
||||||
|
dist
|
||||||
|
|||||||
@ -129,7 +129,6 @@ SV.registerLayout('BinaryTree', {
|
|||||||
*/
|
*/
|
||||||
layout(elements, layoutOptions) {
|
layout(elements, layoutOptions) {
|
||||||
let root = elements[0];
|
let root = elements[0];
|
||||||
let visited = new Group();
|
|
||||||
this.layoutItem(root, null, -1, layoutOptions);
|
this.layoutItem(root, null, -1, layoutOptions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
6
dist/sv.js
vendored
6
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
@ -10,336 +10,343 @@ import { SVAddressLabel, SVFreedLabel, SVIndexLabel, SVMarker } from '../Model/S
|
|||||||
import { AddressLabelOption, IndexLabelOption, LayoutOptions, MarkerOption, ViewOptions } from '../options';
|
import { AddressLabelOption, IndexLabelOption, LayoutOptions, MarkerOption, ViewOptions } from '../options';
|
||||||
import { ViewContainer } from './viewContainer';
|
import { ViewContainer } from './viewContainer';
|
||||||
|
|
||||||
|
|
||||||
export class LayoutProvider {
|
export class LayoutProvider {
|
||||||
private engine: Engine;
|
private engine: Engine;
|
||||||
private viewOptions: ViewOptions;
|
private viewOptions: ViewOptions;
|
||||||
private viewContainer: ViewContainer;
|
private viewContainer: ViewContainer;
|
||||||
|
|
||||||
constructor(engine: Engine, viewContainer: ViewContainer) {
|
constructor(engine: Engine, viewContainer: ViewContainer) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.viewOptions = this.engine.viewOptions;
|
this.viewOptions = this.engine.viewOptions;
|
||||||
this.viewContainer = viewContainer;
|
this.viewContainer = viewContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 布局前处理
|
||||||
|
* @param layoutGroupTable
|
||||||
|
*/
|
||||||
|
private preLayoutProcess(layoutGroupTable: LayoutGroupTable) {
|
||||||
|
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
|
||||||
|
|
||||||
/**
|
modelList.forEach(item => {
|
||||||
* 布局前处理
|
item.preLayout = true;
|
||||||
* @param layoutGroupTable
|
|
||||||
*/
|
|
||||||
private preLayoutProcess(layoutGroupTable: LayoutGroupTable) {
|
|
||||||
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
|
|
||||||
|
|
||||||
modelList.forEach(item => {
|
item.set('rotation', item.get('rotation'));
|
||||||
item.preLayout = true;
|
item.set({ x: 0, y: 0 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
item.set('rotation', item.get('rotation'));
|
/**
|
||||||
item.set({ x: 0, y: 0 });
|
* 布局后处理
|
||||||
});
|
* @param layoutGroupTable
|
||||||
}
|
*/
|
||||||
|
private postLayoutProcess(layoutGroupTable: LayoutGroupTable) {
|
||||||
|
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
|
||||||
|
|
||||||
/**
|
modelList.forEach(item => {
|
||||||
* 布局后处理
|
item.preLayout = false;
|
||||||
* @param layoutGroupTable
|
|
||||||
*/
|
|
||||||
private postLayoutProcess(layoutGroupTable: LayoutGroupTable) {
|
|
||||||
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable);
|
|
||||||
|
|
||||||
modelList.forEach(item => {
|
// 用两个变量保存节点布局完成后的坐标,因为拖拽节点会改变节点的x,y坐标
|
||||||
item.preLayout = false;
|
// 然后当节点移动到泄漏区的时候,不应该保持节点被拖拽后的状态,应该恢复到布局完成后的状态,不然就会很奇怪
|
||||||
|
item.layoutX = item.get('x');
|
||||||
|
item.layoutY = item.get('y');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 用两个变量保存节点布局完成后的坐标,因为拖拽节点会改变节点的x,y坐标
|
/**
|
||||||
// 然后当节点移动到泄漏区的时候,不应该保持节点被拖拽后的状态,应该恢复到布局完成后的状态,不然就会很奇怪
|
* 布局外部指针
|
||||||
item.layoutX = item.get('x');
|
* @param marker
|
||||||
item.layoutY = item.get('y');
|
* @param markerOptions
|
||||||
});
|
*/
|
||||||
}
|
private layoutMarker(markers: SVMarker[], markerOptions: { [key: string]: MarkerOption }) {
|
||||||
|
markers.forEach(item => {
|
||||||
|
const options: MarkerOption = markerOptions[item.sourceType],
|
||||||
|
offset = options.offset ?? 8,
|
||||||
|
anchor = item.anchor ?? 0,
|
||||||
|
labelOffset = options.labelOffset ?? 2;
|
||||||
|
|
||||||
/**
|
let target = item.target,
|
||||||
* 布局外部指针
|
targetBound: BoundingRect = target.getBound(),
|
||||||
* @param marker
|
g6AnchorPosition = item.target.shadowG6Item.getAnchorPoints()[anchor] as IPoint,
|
||||||
* @param markerOptions
|
center: [number, number] = [
|
||||||
*/
|
targetBound.x + targetBound.width / 2,
|
||||||
private layoutMarker(markers: SVMarker[], markerOptions: { [key: string]: MarkerOption }) {
|
targetBound.y + targetBound.height / 2,
|
||||||
markers.forEach(item => {
|
],
|
||||||
const options: MarkerOption = markerOptions[item.sourceType],
|
markerPosition: [number, number],
|
||||||
offset = options.offset ?? 8,
|
markerEndPosition: [number, number];
|
||||||
anchor = item.anchor ?? 0,
|
|
||||||
labelOffset = options.labelOffset ?? 2;
|
|
||||||
|
|
||||||
let target = item.target,
|
let anchorPosition: [number, number] = [g6AnchorPosition.x, g6AnchorPosition.y];
|
||||||
targetBound: BoundingRect = target.getBound(),
|
|
||||||
g6AnchorPosition = item.target.shadowG6Item.getAnchorPoints()[anchor] as IPoint,
|
|
||||||
center: [number, number] = [targetBound.x + targetBound.width / 2, targetBound.y + targetBound.height / 2],
|
|
||||||
markerPosition: [number, number],
|
|
||||||
markerEndPosition: [number, number];
|
|
||||||
|
|
||||||
let anchorPosition: [number, number] = [g6AnchorPosition.x, g6AnchorPosition.y];
|
let anchorVector = Vector.subtract(anchorPosition, center),
|
||||||
|
angle = 0,
|
||||||
|
len = Vector.length(anchorVector) + offset;
|
||||||
|
|
||||||
let anchorVector = Vector.subtract(anchorPosition, center),
|
if (anchorVector[0] === 0) {
|
||||||
angle = 0, len = Vector.length(anchorVector) + offset;
|
angle = anchorVector[1] > 0 ? -Math.PI : 0;
|
||||||
|
} else {
|
||||||
|
angle = Math.sign(anchorVector[0]) * (Math.PI / 2 - Math.atan(anchorVector[1] / anchorVector[0]));
|
||||||
|
}
|
||||||
|
|
||||||
if (anchorVector[0] === 0) {
|
const markerHeight = item.get('size')[1],
|
||||||
angle = anchorVector[1] > 0 ? -Math.PI : 0;
|
labelRadius = item.getLabelSizeRadius() / 2;
|
||||||
}
|
|
||||||
else {
|
|
||||||
angle = Math.sign(anchorVector[0]) * (Math.PI / 2 - Math.atan(anchorVector[1] / anchorVector[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const markerHeight = item.get('size')[1],
|
anchorVector = Vector.normalize(anchorVector);
|
||||||
labelRadius = item.getLabelSizeRadius() / 2;
|
markerPosition = Vector.location(center, anchorVector, len);
|
||||||
|
markerEndPosition = Vector.location(center, anchorVector, markerHeight + len + labelRadius + labelOffset);
|
||||||
|
markerEndPosition = Vector.subtract(markerEndPosition, markerPosition);
|
||||||
|
|
||||||
anchorVector = Vector.normalize(anchorVector);
|
item.set({
|
||||||
markerPosition = Vector.location(center, anchorVector, len);
|
x: markerPosition[0],
|
||||||
markerEndPosition = Vector.location(center, anchorVector, markerHeight + len + labelRadius + labelOffset);
|
y: markerPosition[1],
|
||||||
markerEndPosition = Vector.subtract(markerEndPosition, markerPosition);
|
rotation: angle,
|
||||||
|
markerEndPosition,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
item.set({
|
/**
|
||||||
x: markerPosition[0],
|
* 布局节点的‘已释放’文本
|
||||||
y: markerPosition[1],
|
* @param freedLabels
|
||||||
rotation: angle,
|
*/
|
||||||
markerEndPosition
|
private layoutFreedLabel(freedLabels: SVFreedLabel[]) {
|
||||||
});
|
freedLabels.forEach(item => {
|
||||||
});
|
const freedNodeBound = item.target.getBound();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
item.set({
|
||||||
* 布局节点的‘已释放’文本
|
x: freedNodeBound.x + freedNodeBound.width / 2,
|
||||||
* @param freedLabels
|
y: freedNodeBound.y + freedNodeBound.height * 1.5,
|
||||||
*/
|
size: [freedNodeBound.width, 0],
|
||||||
private layoutFreedLabel(freedLabels: SVFreedLabel[]) {
|
});
|
||||||
freedLabels.forEach(item => {
|
});
|
||||||
const freedNodeBound = item.target.getBound();
|
}
|
||||||
|
|
||||||
item.set({
|
/**
|
||||||
x: freedNodeBound.x + freedNodeBound.width / 2,
|
*
|
||||||
y: freedNodeBound.y + freedNodeBound.height * 1.5,
|
* @param indexLabels
|
||||||
size: [freedNodeBound.width, 0]
|
* @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 - offset,
|
||||||
|
y: nodeBound.y + nodeBound.height / 2,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
indexLabels.forEach(item => {
|
||||||
*
|
const options: IndexLabelOption = indexLabelOptions[item.sourceType],
|
||||||
* @param indexLabels
|
nodeBound = item.target.getBound(),
|
||||||
* @param indexLabelOptions
|
labelBound = item.getBound(),
|
||||||
*/
|
offset = options.offset ?? 20,
|
||||||
private layoutIndexLabel(indexLabels: SVIndexLabel[], indexLabelOptions: { [key: string]: IndexLabelOption }) {
|
position = options.position ?? 'bottom';
|
||||||
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 - offset,
|
|
||||||
y: nodeBound.y + nodeBound.height / 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
indexLabels.forEach(item => {
|
const pos = indexLabelPositionMap[position](nodeBound, labelBound, offset);
|
||||||
const options: IndexLabelOption = indexLabelOptions[item.sourceType],
|
item.set(pos);
|
||||||
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
|
||||||
});
|
* @param leakAddress
|
||||||
}
|
*/
|
||||||
|
private layoutAddressLabel(leakAddress: SVAddressLabel[], addressLabelOption: AddressLabelOption) {
|
||||||
|
const offset = addressLabelOption.offset || 16;
|
||||||
|
|
||||||
/**
|
leakAddress.forEach(item => {
|
||||||
* 布局泄漏区节点上面的address label
|
const nodeBound = item.target.getBound();
|
||||||
* @param leakAddress
|
|
||||||
*/
|
|
||||||
private layoutAddressLabel(leakAddress: SVAddressLabel[], addressLabelOption: AddressLabelOption) {
|
|
||||||
const offset = addressLabelOption.offset || 16;
|
|
||||||
|
|
||||||
leakAddress.forEach(item => {
|
item.set({
|
||||||
const nodeBound = item.target.getBound();
|
x: nodeBound.x + nodeBound.width / 2,
|
||||||
|
y: nodeBound.y - offset,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
item.set({
|
/**
|
||||||
x: nodeBound.x + nodeBound.width / 2,
|
* 对每个组内部的model进行布局
|
||||||
y: nodeBound.y - offset
|
* @param layoutGroupTable
|
||||||
});
|
*/
|
||||||
});
|
private layoutModels(layoutGroupTable: LayoutGroupTable): Group[] {
|
||||||
}
|
const modelGroupList: Group[] = [];
|
||||||
|
|
||||||
|
layoutGroupTable.forEach(group => {
|
||||||
|
const modelList: SVModel[] = group.modelList,
|
||||||
|
modelGroup: Group = new Group();
|
||||||
|
|
||||||
/**
|
const layoutOptions: LayoutOptions = group.options.layout;
|
||||||
* 对每个组内部的model进行布局
|
|
||||||
* @param layoutGroupTable
|
|
||||||
*/
|
|
||||||
private layoutModels(layoutGroupTable: LayoutGroupTable): Group[] {
|
|
||||||
const modelGroupList: Group[] = [];
|
|
||||||
|
|
||||||
layoutGroupTable.forEach(group => {
|
modelList.forEach(item => {
|
||||||
const modelList: SVModel[] = group.modelList,
|
modelGroup.add(item);
|
||||||
modelGroup: Group = new Group();
|
});
|
||||||
|
|
||||||
const layoutOptions: LayoutOptions = group.options.layout;
|
group.layoutCreator.layout(group.node, layoutOptions); // 布局节点
|
||||||
|
modelGroupList.push(modelGroup);
|
||||||
|
});
|
||||||
|
|
||||||
modelList.forEach(item => {
|
layoutGroupTable.forEach(group => {
|
||||||
modelGroup.add(item);
|
const markerOptions = group.options.marker || {},
|
||||||
});
|
indexLabelOptions = group.options.indexLabel || {},
|
||||||
|
addressLabelOption = group.options.addressLabel || {};
|
||||||
|
|
||||||
group.layoutCreator.layout(group.node, layoutOptions); // 布局节点
|
this.layoutIndexLabel(group.indexLabel, indexLabelOptions);
|
||||||
modelGroupList.push(modelGroup);
|
this.layoutFreedLabel(group.freedLabel);
|
||||||
});
|
this.layoutAddressLabel(group.addressLabel, addressLabelOption);
|
||||||
|
this.layoutMarker(group.marker, markerOptions); // 布局外部指针
|
||||||
|
});
|
||||||
|
|
||||||
layoutGroupTable.forEach(group => {
|
return modelGroupList;
|
||||||
const markerOptions = group.options.marker || {},
|
}
|
||||||
indexLabelOptions = group.options.indexLabel || {},
|
|
||||||
addressLabelOption = group.options.addressLabel || {};
|
|
||||||
|
|
||||||
this.layoutIndexLabel(group.indexLabel, indexLabelOptions);
|
/**
|
||||||
this.layoutFreedLabel(group.freedLabel);
|
* 对泄漏区进行布局
|
||||||
this.layoutAddressLabel(group.addressLabel, addressLabelOption);
|
* @param leakModels
|
||||||
this.layoutMarker(group.marker, markerOptions); // 布局外部指针
|
* @param accumulateLeakModels
|
||||||
});
|
*/
|
||||||
|
private layoutLeakModels(leakModels: SVModel[], accumulateLeakModels: SVModel[]) {
|
||||||
|
const group: Group = new Group(),
|
||||||
|
containerHeight = this.viewContainer.getG6Instance().getHeight(),
|
||||||
|
leakAreaHeight = this.engine.viewOptions.leakAreaHeight,
|
||||||
|
leakAreaY = containerHeight - leakAreaHeight,
|
||||||
|
xOffset = 60;
|
||||||
|
|
||||||
return modelGroupList;
|
let prevBound: BoundingRect;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// 避免在泄漏前拖拽节点导致的位置变化,先把节点位置重置为布局后的标准位置
|
||||||
* 对泄漏区进行布局
|
leakModels.forEach(item => {
|
||||||
* @param leakModels
|
item.set({
|
||||||
* @param accumulateLeakModels
|
x: item.layoutX,
|
||||||
*/
|
y: item.layoutY,
|
||||||
private layoutLeakModels(leakModels: SVModel[], accumulateLeakModels: SVModel[]) {
|
});
|
||||||
const group: Group = new Group(),
|
});
|
||||||
containerHeight = this.viewContainer.getG6Instance().getHeight(),
|
|
||||||
leakAreaHeight = this.engine.viewOptions.leakAreaHeight,
|
|
||||||
leakAreaY = containerHeight - leakAreaHeight,
|
|
||||||
xOffset = 60;
|
|
||||||
|
|
||||||
let prevBound: BoundingRect;
|
const globalLeakGroupBound: BoundingRect = accumulateLeakModels.length
|
||||||
|
? Bound.union(...accumulateLeakModels.map(item => item.getBound()))
|
||||||
|
: { x: 0, y: leakAreaY, width: 0, height: 0 };
|
||||||
|
|
||||||
// 避免在泄漏前拖拽节点导致的位置变化,先把节点位置重置为布局后的标准位置
|
const layoutGroups = Util.groupBy(leakModels, 'group');
|
||||||
leakModels.forEach(item => {
|
Object.keys(layoutGroups).forEach(key => {
|
||||||
item.set({
|
group.add(...layoutGroups[key]);
|
||||||
x: item.layoutX,
|
|
||||||
y: item.layoutY
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const globalLeakGroupBound: BoundingRect = accumulateLeakModels.length ?
|
const currentBound: BoundingRect = group.getBound(),
|
||||||
Bound.union(...accumulateLeakModels.map(item => item.getBound())) :
|
prevBoundEnd = prevBound ? prevBound.x + prevBound.width : 0,
|
||||||
{ x: 0, y: leakAreaY, width: 0, height: 0 };
|
{ x: groupX, y: groupY } = currentBound,
|
||||||
|
dx = globalLeakGroupBound.x + globalLeakGroupBound.width + prevBoundEnd + xOffset - groupX,
|
||||||
|
dy = globalLeakGroupBound.y - groupY;
|
||||||
|
|
||||||
const layoutGroups = Util.groupBy(leakModels, 'group');
|
group.translate(dx, dy);
|
||||||
Object.keys(layoutGroups).forEach(key => {
|
group.clear();
|
||||||
group.add(...layoutGroups[key]);
|
Bound.translate(currentBound, dx, dy);
|
||||||
|
|
||||||
const currentBound: BoundingRect = group.getBound(),
|
prevBound = currentBound;
|
||||||
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);
|
* @param modelGroupTable
|
||||||
|
*/
|
||||||
|
private layoutGroups(modelGroupList: Group[]): Group {
|
||||||
|
let wrapperGroup: Group = new Group(),
|
||||||
|
group: Group,
|
||||||
|
prevBound: BoundingRect,
|
||||||
|
bound: BoundingRect,
|
||||||
|
boundList: BoundingRect[] = [],
|
||||||
|
dx = 0;
|
||||||
|
|
||||||
prevBound = currentBound;
|
// 左往右布局
|
||||||
});
|
for (let i = 0; i < modelGroupList.length; i++) {
|
||||||
}
|
group = modelGroupList[i];
|
||||||
|
bound = group.getPaddingBound(this.viewOptions.groupPadding);
|
||||||
|
|
||||||
/**
|
if (prevBound) {
|
||||||
* 对所有组进行相互布局
|
dx = prevBound.x + prevBound.width - bound.x;
|
||||||
* @param modelGroupTable
|
} else {
|
||||||
*/
|
dx = bound.x;
|
||||||
private layoutGroups(modelGroupList: Group[]): Group {
|
}
|
||||||
let wrapperGroup: Group = new Group(),
|
|
||||||
group: Group,
|
|
||||||
prevBound: BoundingRect,
|
|
||||||
bound: BoundingRect,
|
|
||||||
boundList: BoundingRect[] = [],
|
|
||||||
dx = 0;
|
|
||||||
|
|
||||||
// 左往右布局
|
group.translate(dx, 0);
|
||||||
for (let i = 0; i < modelGroupList.length; i++) {
|
Bound.translate(bound, dx, 0);
|
||||||
group = modelGroupList[i];
|
boundList.push(bound);
|
||||||
bound = group.getPaddingBound(this.viewOptions.groupPadding);
|
wrapperGroup.add(group);
|
||||||
|
prevBound = bound;
|
||||||
|
}
|
||||||
|
|
||||||
if (prevBound) {
|
return wrapperGroup;
|
||||||
dx = prevBound.x + prevBound.width - bound.x;
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
dx = bound.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
group.translate(dx, 0);
|
/**
|
||||||
Bound.translate(bound, dx, 0);
|
* 将视图调整至画布中心
|
||||||
boundList.push(bound);
|
* @param models
|
||||||
wrapperGroup.add(group);
|
* @param leakAreaHeight
|
||||||
prevBound = bound;
|
*/
|
||||||
}
|
private fitCenter(group: Group) {
|
||||||
|
let width = this.viewContainer.getG6Instance().getWidth(),
|
||||||
|
height = this.viewContainer.getG6Instance().getHeight(),
|
||||||
|
viewBound: BoundingRect = group.getBound(),
|
||||||
|
leakAreaHeight = this.engine.viewOptions.leakAreaHeight;
|
||||||
|
|
||||||
return wrapperGroup;
|
const centerX = width / 2,
|
||||||
}
|
centerY = height / 2,
|
||||||
|
boundCenterX = viewBound.x + viewBound.width / 2;
|
||||||
|
|
||||||
|
let dx = centerX - boundCenterX,
|
||||||
|
dy = 0;
|
||||||
|
|
||||||
/**
|
if (this.viewContainer.hasLeak) {
|
||||||
* 将视图调整至画布中心
|
const boundBottomY = viewBound.y + viewBound.height;
|
||||||
* @param models
|
dy = height - leakAreaHeight - 100 - boundBottomY;
|
||||||
* @param leakAreaHeight
|
} else {
|
||||||
*/
|
const boundCenterY = viewBound.y + viewBound.height / 2;
|
||||||
private fitCenter(group: Group) {
|
dy = centerY - boundCenterY;
|
||||||
let width = this.viewContainer.getG6Instance().getWidth(),
|
}
|
||||||
height = this.viewContainer.getG6Instance().getHeight(),
|
|
||||||
leakAreaHeight = this.engine.viewOptions.leakAreaHeight;
|
|
||||||
|
|
||||||
if (this.viewContainer.hasLeak) {
|
group.translate(dx, dy);
|
||||||
height = height - leakAreaHeight;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const viewBound: BoundingRect = group.getBound(),
|
/**
|
||||||
centerX = width / 2, centerY = height / 2,
|
* 布局
|
||||||
boundCenterX = viewBound.x + viewBound.width / 2,
|
* @param layoutGroupTable
|
||||||
boundCenterY = viewBound.y + viewBound.height / 2,
|
* @param leakModels
|
||||||
dx = centerX - boundCenterX,
|
* @param hasLeak
|
||||||
dy = centerY - boundCenterY;
|
* @param needFitCenter
|
||||||
|
*/
|
||||||
|
public layoutAll(layoutGroupTable: LayoutGroupTable, accumulateLeakModels: SVModel[], leakModels: SVModel[]) {
|
||||||
|
this.preLayoutProcess(layoutGroupTable);
|
||||||
|
|
||||||
group.translate(dx, dy);
|
const modelGroupList: Group[] = this.layoutModels(layoutGroupTable);
|
||||||
}
|
const generalGroup: Group = this.layoutGroups(modelGroupList);
|
||||||
|
|
||||||
|
if (leakModels.length) {
|
||||||
|
this.layoutLeakModels(leakModels, accumulateLeakModels);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fitCenter(generalGroup);
|
||||||
/**
|
this.postLayoutProcess(layoutGroupTable);
|
||||||
* 布局
|
}
|
||||||
* @param layoutGroupTable
|
|
||||||
* @param leakModels
|
|
||||||
* @param hasLeak
|
|
||||||
* @param needFitCenter
|
|
||||||
*/
|
|
||||||
public layoutAll(layoutGroupTable: LayoutGroupTable, accumulateLeakModels: SVModel[], leakModels: SVModel[]) {
|
|
||||||
this.preLayoutProcess(layoutGroupTable);
|
|
||||||
|
|
||||||
const modelGroupList: Group[] = this.layoutModels(layoutGroupTable);
|
|
||||||
const generalGroup: Group = this.layoutGroups(modelGroupList);
|
|
||||||
|
|
||||||
if (leakModels.length) {
|
|
||||||
this.layoutLeakModels(leakModels, accumulateLeakModels);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fitCenter(generalGroup);
|
|
||||||
this.postLayoutProcess(layoutGroupTable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ export class ViewContainer {
|
|||||||
* @param models
|
* @param models
|
||||||
* @param layoutFn
|
* @param layoutFn
|
||||||
*/
|
*/
|
||||||
render(layoutGroupTable: LayoutGroupTable) {
|
render(layoutGroupTable: LayoutGroupTable, a: boolean) {
|
||||||
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable),
|
const modelList = Util.convertGroupTable2ModelList(layoutGroupTable),
|
||||||
diffResult = this.reconcile.diff(this.layoutGroupTable, this.prevModelList, modelList, this.accumulateLeakModels),
|
diffResult = this.reconcile.diff(this.layoutGroupTable, this.prevModelList, modelList, this.accumulateLeakModels),
|
||||||
renderModelList = [
|
renderModelList = [
|
||||||
|
|||||||
@ -67,7 +67,7 @@ export class Engine {
|
|||||||
const layoutGroupTable = this.modelConstructor.construct(source);
|
const layoutGroupTable = this.modelConstructor.construct(source);
|
||||||
|
|
||||||
// 2 渲染(使用g6进行渲染)
|
// 2 渲染(使用g6进行渲染)
|
||||||
this.viewContainer.render(layoutGroupTable);
|
this.viewContainer.render(layoutGroupTable, source.enterFunction as boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export interface SourceNode {
|
|||||||
|
|
||||||
|
|
||||||
export type Sources = {
|
export type Sources = {
|
||||||
|
enterFunction: any;
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
data: SourceNode[];
|
data: SourceNode[];
|
||||||
layouter: string;
|
layouter: string;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user