Skip to content

Commit 594106e

Browse files
Yanyan-WangBlakkoouyuranyuranou
authored
fix: combo collapsed edge problems, closes: #3839; (#3885)
* fix: combo collapsed edge problems, closes: #3839; * feat: fitItems function (#3838) * feat: fitItems function * Add test * Fix bbox lower boundary * Refactor into focusItems * chore: update version num * fix:Add success call in layoutWithWorker (#3873) Co-authored-by: Yuran Ou <[email protected]> Co-authored-by: Fabio Tacchelli <[email protected]> Co-authored-by: Yuran Ou <[email protected]> Co-authored-by: Yuran Ou <[email protected]>
1 parent 8289a1e commit 594106e

File tree

21 files changed

+229
-45
lines changed

21 files changed

+229
-45
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# ChangeLog
22

3+
#### 4.7.0
4+
5+
- fix: combo collapsed edge problems, closes: #3839;
6+
37
#### 4.7.0-beta
48

59
- feat: force2 from graphin-force;

packages/core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@antv/g6-core",
3-
"version": "0.7.0-beta.2",
3+
"version": "0.7.0",
44
"description": "A Graph Visualization Framework in JavaScript",
55
"keywords": [
66
"antv",

packages/core/src/global.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const colorSet = {
6464
};
6565

6666
export default {
67-
version: '0.7.0-beta.1',
67+
version: '0.7.0',
6868
rootContainerClassName: 'root-container',
6969
nodeContainerClassName: 'node-container',
7070
edgeContainerClassName: 'edge-container',

packages/core/src/graph/controller/layout.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ export default abstract class LayoutController {
297297
}
298298
}
299299

300+
/**
301+
* execute a preset layout before running layout
302+
*/
300303
public abstract initWithPreset(): boolean;
301304

302305
// 初始化节点到 center 附近
@@ -308,7 +311,7 @@ export default abstract class LayoutController {
308311
const nodeLength = nodes ? nodes.length : 0;
309312
if (!nodeLength) return;
310313

311-
const hasPreset = this.initWithPreset();
314+
const hasPreset = this.initWithPreset?.();
312315

313316
if (hasPreset) return false;
314317

packages/core/src/graph/controller/view.ts

+85-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export default class ViewController {
4545
graph.translate(viewCenter.x - groupCenter.x, viewCenter.y - groupCenter.y, animate, animateCfg);
4646
}
4747

48-
private animatedFitView(group: IGroup, startMatrix: number[], animateCfg: GraphAnimateConfig, bbox: BBox, viewCenter: Point, groupCenter: Point, ratio: number): void {
48+
private animatedFitView(group: IGroup, startMatrix: number[], animateCfg: GraphAnimateConfig, bbox: BBox, viewCenter: Point, groupCenter: Point,
49+
ratio: number, zoomToFit: boolean): void {
4950
const { graph } = this;
5051
animateCfg = animateCfg ? animateCfg : { duration: 500, easing: 'easeCubic' };
5152

@@ -58,6 +59,20 @@ export default class ViewController {
5859
if (isNaN(vx) || isNaN(vy)) return;
5960
const translatedMatrix = transform(matrix, [['t', vx, vy]]);
6061

62+
if (!zoomToFit) {
63+
// If zooming is not needed just animate the current translated matrix and return
64+
const animationConfig = getAnimateCfgWithCallback({
65+
animateCfg,
66+
callback: () => {
67+
graph.emit('viewportchange', { action: 'translate', matrix: translatedMatrix });
68+
}
69+
});
70+
group.animate((ratio: number) => {
71+
return { matrix: lerpArray(startMatrix, translatedMatrix, ratio) };
72+
}, animationConfig);
73+
return;
74+
}
75+
6176
// Zoom
6277
const minZoom: number = graph.get('minZoom');
6378
const maxZoom: number = graph.get('maxZoom');
@@ -67,7 +82,7 @@ export default class ViewController {
6782
realRatio = minZoom;
6883
console.warn('fitview failed, ratio out of range, ratio: %f', ratio, 'graph minzoom has been used instead');
6984
} else if (maxZoom && ratio > maxZoom) {
70-
realRatio = minZoom;
85+
realRatio = maxZoom;
7186
console.warn('fitview failed, ratio out of range, ratio: %f', ratio, 'graph maxzoom has been used instead');
7287
}
7388
let zoomedMatrix = transform(translatedMatrix, [
@@ -120,7 +135,7 @@ export default class ViewController {
120135
}
121136

122137
if (animate) {
123-
this.animatedFitView(group, startMatrix, animateCfg, bbox, viewCenter, groupCenter, ratio);
138+
this.animatedFitView(group, startMatrix, animateCfg, bbox, viewCenter, groupCenter, ratio, true);
124139
} else {
125140
const dx = viewCenter.x - groupCenter.x;
126141
const dy = viewCenter.y - groupCenter.y;
@@ -175,7 +190,7 @@ export default class ViewController {
175190
}
176191

177192
if (animate) {
178-
this.animatedFitView(group, startMatrix, animateCfg, bbox, viewCenter, groupCenter, ratio);
193+
this.animatedFitView(group, startMatrix, animateCfg, bbox, viewCenter, groupCenter, ratio, true);
179194
} else {
180195
const initZoomRatio = graph.getZoom();
181196
let endZoom = initZoomRatio * ratio;
@@ -316,6 +331,72 @@ export default class ViewController {
316331
}
317332
}
318333

334+
public focusItems(items: Item[], zoomToFit: boolean, animate?: boolean, animateCfg?: GraphAnimateConfig): void {
335+
if (!items.length) {
336+
return;
337+
}
338+
339+
const { graph } = this;
340+
const padding = this.getFormatPadding();
341+
const width: number = graph.get('width');
342+
const height: number = graph.get('height');
343+
const group: IGroup = graph.get('group');
344+
const startMatrix = group.getMatrix() || [1, 0, 0, 0, 1, 0, 0, 0, 1];
345+
group.resetMatrix();
346+
347+
let bbox: BBox = {
348+
x: 0, y: 0,
349+
minX: Number.MAX_SAFE_INTEGER, minY: Number.MAX_SAFE_INTEGER,
350+
maxX: Number.MIN_SAFE_INTEGER, maxY: Number.MIN_SAFE_INTEGER,
351+
width: 0, height: 0
352+
};
353+
for (const item of items) {
354+
const itemBBox = item.getBBox();
355+
if (itemBBox.minX < bbox.minX) {
356+
bbox.minX = itemBBox.minX;
357+
}
358+
if (itemBBox.minY < bbox.minY) {
359+
bbox.minY = itemBBox.minY;
360+
}
361+
if (itemBBox.maxX > bbox.maxX) {
362+
bbox.maxX = itemBBox.maxX;
363+
}
364+
if (itemBBox.maxY > bbox.maxY) {
365+
bbox.maxY = itemBBox.maxY;
366+
}
367+
}
368+
bbox.x = bbox.minX;
369+
bbox.y = bbox.minY;
370+
bbox.width = bbox.maxX - bbox.minX;
371+
bbox.height = bbox.maxY - bbox.minY;
372+
373+
if (bbox.width === 0 || bbox.height === 0) return;
374+
const viewCenter = this.getViewCenter();
375+
376+
const groupCenter: Point = {
377+
x: bbox.x + bbox.width / 2,
378+
y: bbox.y + bbox.height / 2,
379+
};
380+
381+
// Compute ratio
382+
const w = (width - padding[1] - padding[3]) / bbox.width;
383+
const h = (height - padding[0] - padding[2]) / bbox.height;
384+
let ratio = w;
385+
if (w > h) {
386+
ratio = h;
387+
}
388+
389+
if (animate) {
390+
this.animatedFitView(group, startMatrix, animateCfg, bbox, viewCenter, groupCenter, ratio, zoomToFit);
391+
} else {
392+
graph.translate(viewCenter.x - groupCenter.x, viewCenter.y - groupCenter.y);
393+
394+
if (zoomToFit && !graph.zoom(ratio, viewCenter)) {
395+
console.warn('zoom failed, ratio out of range, ratio: %f', ratio);
396+
}
397+
}
398+
}
399+
319400
/**
320401
* 改变 canvas 画布的宽度和高度
321402
* @param width canvas 宽度

packages/core/src/graph/graph.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,18 @@ export default abstract class AbstractGraph extends EventEmitter implements IAbs
800800
this.autoPaint();
801801
}
802802

803+
/**
804+
* Focus on the passed items
805+
* @param {Item[]} items Items you want to focus on
806+
* @param {boolean} zoomToFit Wether to zoom on the passed items
807+
* @param {boolean} animate Wether to animate the transition
808+
* @param {GraphAnimateConfig} animateCfg Animation configuration
809+
*/
810+
public focusItems(items: Item[], zoomToFit?: boolean, animate?: boolean, animateCfg?: GraphAnimateConfig): void {
811+
const viewController: ViewController = this.get('viewController');
812+
viewController.focusItems(items, zoomToFit, animate, animateCfg);
813+
}
814+
803815
/**
804816
* 自动重绘
805817
* @internal 仅供内部更新机制调用,外部根据需求调用 render 或 paint 接口
@@ -2743,8 +2755,8 @@ export default abstract class AbstractGraph extends EventEmitter implements IAbs
27432755
let selfEndModel = selfEnd.getModel();
27442756
// find the nearest visible ancestor
27452757
while (!selfEnd.isVisible()) {
2746-
const { parentId: selfEndPId, comboId: selfEndCId } = otherEndModel;
2747-
const selfEndParentId = selfEndPId || selfEndCId;
2758+
const { parentId: selfEndPId, comboId: selfEndCId } = selfEndModel;
2759+
const selfEndParentId = (selfEndPId || selfEndCId) as string;
27482760
selfEnd = this.findById(selfEndParentId) as ICombo;
27492761
if (!selfEnd || !selfEndParentId) {
27502762
return; // if all the ancestors of the oppsite are all hidden, ignore the edge

packages/core/src/interface/graph.ts

+9
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@ export interface IAbstractGraph extends EventEmitter {
171171
*/
172172
focusItem: (item: Item | string, animate?: boolean, animateCfg?: GraphAnimateConfig) => void;
173173

174+
/**
175+
* Fits the passed items into the view. If no items are passed it will fit the whole graph
176+
* @param {Item[]} items Items you want to fit into the view
177+
* @param {boolean} zoomToFit Wether to zoom on the passed items
178+
* @param {boolean} animate Wheter to animate the transition
179+
* @param {GraphAnimateConfig} animateCfg Animation configuration
180+
*/
181+
focusItems: (items: Item[], zoomToFit?: boolean, animate?: boolean, animateCfg?: GraphAnimateConfig) => void;
182+
174183
/**
175184
* 调整视口适应视图
176185
* @param {Padding} padding 四周围边距

packages/core/tests/unit/graph/controller/view-spec.ts

+71-5
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,83 @@ describe('view', () => {
111111
expect(centerPoint.x - 50 < 0.1).toBe(true);
112112
expect(centerPoint.y - 50 < 0.1).toBe(true);
113113
});
114+
it('focus items', () => {
115+
const data = {
116+
nodes: [
117+
{
118+
id: 'node-1',
119+
x: 100,
120+
y: 100,
121+
size: [150, 100],
122+
type: 'simple-rect',
123+
color: '#333',
124+
style: {
125+
fill: '#666',
126+
},
127+
},
128+
{
129+
id: 'node-2',
130+
x: 200,
131+
y: 200,
132+
size: [150, 100],
133+
type: 'simple-rect',
134+
color: '#333',
135+
style: {
136+
fill: '#666',
137+
},
138+
}
139+
],
140+
};
141+
graph.data(data);
142+
graph.render();
143+
144+
const canvas: AbstractCanvas = graph.get('canvas');
145+
146+
let bbox = canvas.getCanvasBBox();
147+
148+
expect(numberEqual(bbox.x, 50, 1)).toBe(true);
149+
expect(numberEqual(bbox.y, 89, 1)).toBe(true);
150+
expect(numberEqual(bbox.maxX, 450, 1)).toBe(true);
151+
expect(numberEqual(bbox.maxY, 410, 1)).toBe(true);
152+
expect(numberEqual(bbox.width, 400, 1)).toBe(true);
153+
expect(numberEqual(bbox.height, 320, 1)).toBe(true);
154+
155+
const node1 = graph.findById('node-1');
156+
graph.focusItems([node1], true);
157+
158+
bbox = graph.get('canvas').getCanvasBBox();
159+
160+
expect(numberEqual(bbox.x, 50, 1)).toBe(true);
161+
expect(numberEqual(bbox.y, 116, 1)).toBe(true);
162+
expect(numberEqual(bbox.maxX, 714, 1)).toBe(true);
163+
expect(numberEqual(bbox.maxY, 648, 1)).toBe(true);
164+
expect(numberEqual(bbox.width, 664, 1)).toBe(true);
165+
expect(numberEqual(bbox.height, 532, 1)).toBe(true);
166+
167+
const node2 = graph.findById('node-2');
168+
graph.focusItems([node1, node2], true);
169+
170+
bbox = graph.get('canvas').getCanvasBBox();
171+
172+
expect(numberEqual(bbox.x, 50, 1)).toBe(true);
173+
expect(numberEqual(bbox.y, 89, 1)).toBe(true);
174+
expect(numberEqual(bbox.maxX, 450, 1)).toBe(true);
175+
expect(numberEqual(bbox.maxY, 410, 1)).toBe(true);
176+
expect(numberEqual(bbox.width, 400, 1)).toBe(true);
177+
expect(numberEqual(bbox.height, 320, 1)).toBe(true);
178+
});
114179
it('focus edge', () => {
115180
const data = {
116-
nodes: [{id: '1', x: 10, y: 10}, {id: '2', x: 25, y: 40}, {id: '3', x: -50, y: 80}],
117-
edges: [{source: '1', target: '2'}, {source: '1', target: '3'}]
181+
nodes: [{ id: '1', x: 10, y: 10 }, { id: '2', x: 25, y: 40 }, { id: '3', x: -50, y: 80 }],
182+
edges: [{ source: '1', target: '2' }, { source: '1', target: '3' }]
118183
}
119184
const g = new Graph({
120185
container: div,
121186
width: 500,
122187
height: 500,
123188
})
124189
g.read(data);
125-
g.get('canvas').get('el').style.backgroundColor='#ccc';
190+
g.get('canvas').get('el').style.backgroundColor = '#ccc';
126191
g.zoom(2, { x: 10, y: 10 });
127192
g.focusItem(g.getEdges()[0]);
128193
let centerPoint = g.getPointByCanvas(250, 250);
@@ -137,8 +202,9 @@ describe('view', () => {
137202

138203
it('getPointByCanvas', () => {
139204
const point = graph.getPointByCanvas(250, 250);
140-
expect(numberEqual(point.x, 50, 0.1)).toBe(true);
141-
expect(numberEqual(point.y, 50, 0.1)).toBe(true);
205+
console.log('point', point);
206+
expect(numberEqual(point.x, 150, 0.1)).toBe(true);
207+
expect(numberEqual(point.y, 150, 0.1)).toBe(true);
142208
});
143209
});
144210

packages/element/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@antv/g6-element",
3-
"version": "0.7.0-beta.2",
3+
"version": "0.7.0",
44
"description": "A Graph Visualization Framework in JavaScript",
55
"keywords": [
66
"antv",
@@ -61,7 +61,7 @@
6161
},
6262
"dependencies": {
6363
"@antv/g-base": "^0.5.1",
64-
"@antv/g6-core": "0.7.0-beta.2",
64+
"@antv/g6-core": "0.7.0",
6565
"@antv/util": "~2.0.5"
6666
},
6767
"devDependencies": {

packages/g6/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@antv/g6",
3-
"version": "4.7.0-beta.2",
3+
"version": "4.7.0",
44
"description": "A Graph Visualization Framework in JavaScript",
55
"keywords": [
66
"antv",
@@ -66,7 +66,7 @@
6666
]
6767
},
6868
"dependencies": {
69-
"@antv/g6-pc": "0.7.0-beta.2"
69+
"@antv/g6-pc": "0.7.0"
7070
},
7171
"devDependencies": {
7272
"@babel/core": "^7.7.7",

packages/g6/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import G6 from '@antv/g6-pc';
22

3-
G6.version = '4.7.0-beta.2';
3+
G6.version = '4.7.0';
44

55
export * from '@antv/g6-pc';
66
export default G6;
7-
export const version = '4.7.0-beta.2';
7+
export const version = '4.7.0';

packages/pc/package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@antv/g6-pc",
3-
"version": "0.7.0-beta.2",
3+
"version": "0.7.0",
44
"description": "A Graph Visualization Framework in JavaScript",
55
"keywords": [
66
"antv",
@@ -75,11 +75,11 @@
7575
"@antv/g-canvas": "^0.5.2",
7676
"@antv/g-math": "^0.1.1",
7777
"@antv/g-svg": "^0.5.1",
78-
"@antv/g6-core": "0.7.0-beta.2",
79-
"@antv/g6-element": "0.7.0-beta.2",
80-
"@antv/g6-plugin": "0.7.0-beta.2",
78+
"@antv/g6-core": "0.7.0",
79+
"@antv/g6-element": "0.7.0",
80+
"@antv/g6-plugin": "0.7.0",
8181
"@antv/hierarchy": "^0.6.7",
82-
"@antv/layout": "^0.3.0-beta.1",
82+
"@antv/layout": "^0.3.0",
8383
"@antv/matrix-util": "^3.1.0-beta.3",
8484
"@antv/path-util": "^2.0.3",
8585
"@antv/util": "~2.0.5",

packages/pc/src/global.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const textColor = 'rgb(0, 0, 0)';
77
const colorSet = getColorsWithSubjectColor(subjectColor, backColor);
88

99
export default {
10-
version: '0.7.0-beta.2',
10+
version: '0.7.0',
1111
rootContainerClassName: 'root-container',
1212
nodeContainerClassName: 'node-container',
1313
edgeContainerClassName: 'edge-container',

0 commit comments

Comments
 (0)