diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9480aa74781..0d7398bbdd1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# ChangeLog
+### 4.7.8
+
+- feat: pointPadding config for loop edges with non-circle nodes, closes: #3974;
+- fix: image lost while updating the size for an image node, closes: #3938;
+
### 4.7.7
- feat: getContentPlaceholder and getTitlePlaceholder for Annotation plugin;
diff --git a/packages/core/package.json b/packages/core/package.json
index 69b38197ebf..32ac658d7ff 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6-core",
- "version": "0.7.7",
+ "version": "0.7.8",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
diff --git a/packages/core/src/element/shapeBase.ts b/packages/core/src/element/shapeBase.ts
index cd634fb49ba..60d12df2d17 100644
--- a/packages/core/src/element/shapeBase.ts
+++ b/packages/core/src/element/shapeBase.ts
@@ -79,9 +79,7 @@ export const shapeBase: ShapeOptions = {
return {};
},
getOptions(cfg: ModelConfig, updateType?: UpdateType): ModelConfig {
- if (updateType === 'move' || updateType?.includes('bbox')) {
- return {};
- }
+ if (updateType === 'move' || updateType?.includes('bbox')) return cfg;
return deepMix(
{},
this.options,
diff --git a/packages/core/src/global.ts b/packages/core/src/global.ts
index 70431a048f6..eb5f8f39f46 100644
--- a/packages/core/src/global.ts
+++ b/packages/core/src/global.ts
@@ -64,7 +64,7 @@ const colorSet = {
};
export default {
- version: '0.7.7',
+ version: '0.7.8',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',
diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts
index 0249cd4b7a5..58bbd87fbff 100644
--- a/packages/core/src/types/index.ts
+++ b/packages/core/src/types/index.ts
@@ -298,6 +298,8 @@ export type LoopConfig = Partial<{
position: string;
// 如果逆时针画,交换起点和终点
clockwise: boolean;
+ // 对于非圆形节点设置的连接点与节点中心坐标(`top-right`,`bottom-right`,`top-left`,`bottom-left`较特殊,为四个角坐标)在 x 轴或 y 轴方向的偏移量,默认为 `节点宽高中最小值的1/4`
+ pointPadding: number;
}>;
export interface LayoutConfig {
diff --git a/packages/core/src/util/graphic.ts b/packages/core/src/util/graphic.ts
index 721a78d318b..ff977f152a0 100644
--- a/packages/core/src/util/graphic.ts
+++ b/packages/core/src/util/graphic.ts
@@ -11,7 +11,7 @@ import {
ComboTree,
ComboConfig,
ICombo,
- GraphAnimateConfig
+ GraphAnimateConfig,
} from '../types';
import { applyMatrix } from './math';
import letterAspectRatio from './letterAspectRatio';
@@ -83,93 +83,146 @@ export const getLoopCfgs = (cfg: EdgeData): EdgeData => {
let startPoint = [cfg.startPoint.x, cfg.startPoint.y];
let endPoint = [cfg.endPoint.x, cfg.endPoint.y];
- let rstart = bbox.height / 2;
- let rend = bbox.height / 2;
+ let halfOfHeight = bbox.height / 2;
+ let halfOfWidth = bbox.width / 2;
+ let rstart = halfOfHeight;
+ let rend = halfOfHeight;
+
let sinDeltaStart = rstart * SELF_LINK_SIN;
let cosDeltaStart = rstart * SELF_LINK_COS;
let sinDeltaEnd = rend * SELF_LINK_SIN;
let cosDeltaEnd = rend * SELF_LINK_COS;
+ const shapeType = keyShape.get('type');
+
+ // 美观考虑,pointPadding 默认取宽高中最小的1/4
+ const defaultPointPadding = Math.min(halfOfHeight / 2, halfOfWidth / 2);
+ const maxPointPadding = Math.min(halfOfHeight, halfOfWidth);
+
+ // 对于非圆形节点设置的连接点与节点中心坐标(`top-right`,`bottom-right`,`top-left`,`bottom-left`较特殊,为四个角坐标)在 x 轴或 y 轴方向的偏移量,默认为 `节点宽高中最小值的1/4`
+ const pointPadding = loopCfg?.pointPadding
+ ? Math.min(maxPointPadding, loopCfg?.pointPadding)
+ : defaultPointPadding;
// 如果定义了锚点的,直接用锚点坐标,否则,根据自环的 cfg 计算
if (startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1]) {
switch (position) {
case 'top':
- startPoint = [center[0] - sinDeltaStart, center[1] - cosDeltaStart];
- endPoint = [center[0] + sinDeltaEnd, center[1] - cosDeltaEnd];
+ if (shapeType === 'circle') {
+ startPoint = [center[0] - sinDeltaStart, center[1] - cosDeltaStart];
+ endPoint = [center[0] + sinDeltaEnd, center[1] - cosDeltaEnd];
+ } else {
+ startPoint = [center[0] - pointPadding, center[1] - halfOfHeight];
+ endPoint = [center[0] + pointPadding, center[1] - halfOfHeight];
+ }
break;
case 'top-right':
- rstart = bbox.height / 2;
- rend = bbox.width / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] + sinDeltaStart, center[1] - cosDeltaStart];
- endPoint = [center[0] + cosDeltaEnd, center[1] - sinDeltaEnd];
+ rstart = halfOfHeight;
+ rend = halfOfWidth;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] + sinDeltaStart, center[1] - cosDeltaStart];
+ endPoint = [center[0] + cosDeltaEnd, center[1] - sinDeltaEnd];
+ } else {
+ startPoint = [center[0] + halfOfWidth - pointPadding, center[1] - halfOfHeight];
+ endPoint = [center[0] + halfOfWidth, center[1] - halfOfHeight + pointPadding];
+ }
break;
case 'right':
- rstart = bbox.width / 2;
- rend = bbox.width / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] + cosDeltaStart, center[1] - sinDeltaStart];
- endPoint = [center[0] + cosDeltaEnd, center[1] + sinDeltaEnd];
+ rstart = halfOfWidth;
+ rend = halfOfWidth;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] + cosDeltaStart, center[1] - sinDeltaStart];
+ endPoint = [center[0] + cosDeltaEnd, center[1] + sinDeltaEnd];
+ } else {
+ startPoint = [center[0] + halfOfWidth, center[1] - pointPadding];
+ endPoint = [center[0] + halfOfWidth, center[1] + pointPadding];
+ }
break;
case 'bottom-right':
- rstart = bbox.width / 2;
- rend = bbox.height / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] + cosDeltaStart, center[1] + sinDeltaStart];
- endPoint = [center[0] + sinDeltaEnd, center[1] + cosDeltaEnd];
+ rstart = halfOfWidth;
+ rend = halfOfHeight;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] + cosDeltaStart, center[1] + sinDeltaStart];
+ endPoint = [center[0] + sinDeltaEnd, center[1] + cosDeltaEnd];
+ } else {
+ startPoint = [center[0] + halfOfWidth, center[1] + halfOfHeight - pointPadding];
+ endPoint = [center[0] + halfOfWidth - pointPadding, center[1] + halfOfHeight];
+ }
break;
case 'bottom':
- rstart = bbox.height / 2;
- rend = bbox.height / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] + sinDeltaStart, center[1] + cosDeltaStart];
- endPoint = [center[0] - sinDeltaEnd, center[1] + cosDeltaEnd];
+ rstart = halfOfHeight;
+ rend = halfOfHeight;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] + sinDeltaStart, center[1] + cosDeltaStart];
+ endPoint = [center[0] - sinDeltaEnd, center[1] + cosDeltaEnd];
+ } else {
+ startPoint = [center[0] - pointPadding, center[1] + halfOfHeight];
+ endPoint = [center[0] + pointPadding, center[1] + halfOfHeight];
+ }
break;
case 'bottom-left':
- rstart = bbox.height / 2;
- rend = bbox.width / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] - sinDeltaStart, center[1] + cosDeltaStart];
- endPoint = [center[0] - cosDeltaEnd, center[1] + sinDeltaEnd];
+ rstart = halfOfHeight;
+ rend = halfOfWidth;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] - sinDeltaStart, center[1] + cosDeltaStart];
+ endPoint = [center[0] - cosDeltaEnd, center[1] + sinDeltaEnd];
+ } else {
+ startPoint = [center[0] - halfOfWidth, center[1] + halfOfHeight - pointPadding];
+ endPoint = [center[0] - halfOfWidth + pointPadding, center[1] + halfOfHeight];
+ }
break;
case 'left':
- rstart = bbox.width / 2;
- rend = bbox.width / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] - cosDeltaStart, center[1] + sinDeltaStart];
- endPoint = [center[0] - cosDeltaEnd, center[1] - sinDeltaEnd];
+ rstart = halfOfWidth;
+ rend = halfOfWidth;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] - cosDeltaStart, center[1] + sinDeltaStart];
+ endPoint = [center[0] - cosDeltaEnd, center[1] - sinDeltaEnd];
+ } else {
+ startPoint = [center[0] - halfOfWidth, center[1] - pointPadding];
+ endPoint = [center[0] - halfOfWidth, center[1] + pointPadding];
+ }
break;
case 'top-left':
- rstart = bbox.width / 2;
- rend = bbox.height / 2;
- sinDeltaStart = rstart * SELF_LINK_SIN;
- cosDeltaStart = rstart * SELF_LINK_COS;
- sinDeltaEnd = rend * SELF_LINK_SIN;
- cosDeltaEnd = rend * SELF_LINK_COS;
- startPoint = [center[0] - cosDeltaStart, center[1] - sinDeltaStart];
- endPoint = [center[0] - sinDeltaEnd, center[1] - cosDeltaEnd];
+ rstart = halfOfWidth;
+ rend = halfOfHeight;
+ if (shapeType === 'circle') {
+ sinDeltaStart = rstart * SELF_LINK_SIN;
+ cosDeltaStart = rstart * SELF_LINK_COS;
+ sinDeltaEnd = rend * SELF_LINK_SIN;
+ cosDeltaEnd = rend * SELF_LINK_COS;
+ startPoint = [center[0] - cosDeltaStart, center[1] - sinDeltaStart];
+ endPoint = [center[0] - sinDeltaEnd, center[1] - cosDeltaEnd];
+ } else {
+ startPoint = [center[0] - halfOfWidth + pointPadding, center[1] - halfOfHeight];
+ endPoint = [center[0] - halfOfWidth, center[1] - halfOfHeight + pointPadding];
+ }
break;
default:
- rstart = bbox.width / 2;
- rend = bbox.width / 2;
+ rstart = halfOfWidth;
+ rend = halfOfWidth;
sinDeltaStart = rstart * SELF_LINK_SIN;
cosDeltaStart = rstart * SELF_LINK_COS;
sinDeltaEnd = rend * SELF_LINK_SIN;
@@ -381,7 +434,7 @@ export const truncateLabelByLength = (text: string, length: number) => {
return text;
}
return text.substring(0, length) + '...';
-}
+};
/**
* construct the trees from combos data
@@ -600,7 +653,11 @@ export const reconstructTree = (
return trees;
};
-export const getComboBBox = (children: ComboTree[], graph: IAbstractGraph, combo?: ICombo): BBox => {
+export const getComboBBox = (
+ children: ComboTree[],
+ graph: IAbstractGraph,
+ combo?: ICombo,
+): BBox => {
const comboBBox = {
minX: Infinity,
minY: Infinity,
@@ -625,7 +682,7 @@ export const getComboBBox = (children: ComboTree[], graph: IAbstractGraph, combo
x: x,
y: y,
width: undefined,
- height: undefined
+ height: undefined,
};
}
@@ -671,26 +728,26 @@ export const shouldRefreshEdge = (cfg) => {
export const cloneBesidesImg = (obj) => {
const clonedObj = {};
- Object.keys(obj).forEach(key1 => {
+ Object.keys(obj).forEach((key1) => {
const obj2 = obj[key1];
if (isObject(obj2) && !isArray(obj2)) {
const clonedObj2 = {};
- Object.keys(obj2).forEach(key2 => {
+ Object.keys(obj2).forEach((key2) => {
const v = obj2[key2];
if (key2 === 'img' && !isString(v)) return;
clonedObj2[key2] = clone(v);
- })
+ });
clonedObj[key1] = clonedObj2;
} else {
clonedObj[key1] = clone(obj2);
}
});
return clonedObj;
-}
+};
export const getAnimateCfgWithCallback = ({
animateCfg,
- callback
+ callback,
}: {
animateCfg: GraphAnimateConfig;
callback: () => void;
@@ -699,7 +756,7 @@ export const getAnimateCfgWithCallback = ({
if (!animateCfg) {
animateConfig = {
duration: 500,
- callback
+ callback,
};
} else {
animateConfig = clone(animateCfg);
@@ -708,10 +765,10 @@ export const getAnimateCfgWithCallback = ({
animateConfig.callback = () => {
callback();
animateCfgCallback();
- }
+ };
} else {
animateConfig.callback = callback;
}
}
return animateConfig;
-}
+};
diff --git a/packages/element/package.json b/packages/element/package.json
index 266152c0ea0..84e8cae3d72 100644
--- a/packages/element/package.json
+++ b/packages/element/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6-element",
- "version": "0.7.7",
+ "version": "0.7.8",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@@ -61,7 +61,7 @@
},
"dependencies": {
"@antv/g-base": "^0.5.1",
- "@antv/g6-core": "0.7.7",
+ "@antv/g6-core": "0.7.8",
"@antv/util": "~2.0.5"
},
"devDependencies": {
diff --git a/packages/g6/package.json b/packages/g6/package.json
index 2134e2588a8..5a67a8e8129 100644
--- a/packages/g6/package.json
+++ b/packages/g6/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6",
- "version": "4.7.7",
+ "version": "4.7.8",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@@ -66,7 +66,7 @@
]
},
"dependencies": {
- "@antv/g6-pc": "0.7.7"
+ "@antv/g6-pc": "0.7.8"
},
"devDependencies": {
"@babel/core": "^7.7.7",
diff --git a/packages/g6/src/index.ts b/packages/g6/src/index.ts
index a961bec8e30..2ef104c2706 100644
--- a/packages/g6/src/index.ts
+++ b/packages/g6/src/index.ts
@@ -1,7 +1,7 @@
import G6 from '@antv/g6-pc';
-G6.version = '4.7.7';
+G6.version = '4.7.8';
export * from '@antv/g6-pc';
export default G6;
-export const version = '4.7.7';
+export const version = '4.7.8';
diff --git a/packages/pc/package.json b/packages/pc/package.json
index 4af4f5c4c99..761ce5195ef 100644
--- a/packages/pc/package.json
+++ b/packages/pc/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6-pc",
- "version": "0.7.7",
+ "version": "0.7.8",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@@ -75,9 +75,9 @@
"@antv/g-canvas": "^0.5.2",
"@antv/g-math": "^0.1.1",
"@antv/g-svg": "^0.5.1",
- "@antv/g6-core": "0.7.7",
- "@antv/g6-element": "0.7.7",
- "@antv/g6-plugin": "0.7.7",
+ "@antv/g6-core": "0.7.8",
+ "@antv/g6-element": "0.7.8",
+ "@antv/g6-plugin": "0.7.8",
"@antv/hierarchy": "^0.6.7",
"@antv/layout": "^0.3.0",
"@antv/matrix-util": "^3.1.0-beta.3",
diff --git a/packages/pc/src/global.ts b/packages/pc/src/global.ts
index 132d29a7775..86eba0a578b 100644
--- a/packages/pc/src/global.ts
+++ b/packages/pc/src/global.ts
@@ -7,7 +7,7 @@ const textColor = 'rgb(0, 0, 0)';
const colorSet = getColorsWithSubjectColor(subjectColor, backColor);
export default {
- version: '0.7.7',
+ version: '0.7.8',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',
diff --git a/packages/pc/tests/unit/issues-loop-spec.ts b/packages/pc/tests/unit/issues-loop-spec.ts
new file mode 100644
index 00000000000..1dd5809c67e
--- /dev/null
+++ b/packages/pc/tests/unit/issues-loop-spec.ts
@@ -0,0 +1,372 @@
+import G6, { Graph } from '../../src';
+import { Arrow } from '../../src';
+
+const div = document.createElement('div');
+div.id = 'container';
+document.body.appendChild(div);
+
+
+describe('issues', () => {
+ it('basic test ui', () => {
+
+ const nodes = [
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ },
+ {
+ id: '2',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 400,
+ size: [400, 80],
+ label: 'rect',
+ },
+ {
+ id: '3',
+ type: 'circle',
+ color: '#666',
+ x: 100,
+ y: 700,
+ size: [200, 40],
+ label: 'circle',
+ },
+ ];
+
+ const directions = [
+ 'top-left',
+ 'top',
+ 'top-right',
+ 'right',
+ 'bottom-right',
+ 'bottom',
+ 'bottom-left',
+ 'left',
+ ];
+
+ const edges = [];
+ nodes.forEach((node) => {
+ const perNodeEdge = directions.map((currentDirection) => ({
+ source: node.id,
+ target: node.id,
+ type: 'loop',
+ loopCfg: {
+ position: currentDirection,
+ dist: 20,
+ pointPadding: 15,
+ clockwise: true,
+ },
+ }));
+ edges.push(...perNodeEdge);
+ });
+
+ const data = {
+ nodes,
+ edges,
+ };
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ defaultNode: {
+ type: 'rect',
+ },
+ });
+
+ graph.data(data);
+ graph.render();
+ });
+
+ it('test position right calc pointPadding value is ok ', () => {
+ const node =
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ style: {
+ lineWidth: 0
+ },
+ }
+ const edge = {
+ source: '1',
+ target: '1',
+ type: 'loop',
+ loopCfg: {
+ position: 'right',
+ dist: 20,
+ pointPadding: 15,
+ },
+ }
+
+ const data = {
+ nodes: [node],
+ edges: [edge],
+ };
+
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ });
+
+ const center = [node.x, node.y]
+ const halfOfWidth = node.size[0] / 2
+ const halfOfHeight = node.size[1] / 2
+ const pointPadding = edge.loopCfg.pointPadding
+ graph.data(data);
+ graph.render();
+ const startPoint = [center[0] + halfOfWidth, center[1] - pointPadding];
+ const endPoint = [center[0] + halfOfWidth, center[1] + pointPadding];
+
+ const { edges } = data
+ const currentEdges = edges[0]
+
+ //@ts-ignore
+ expect([currentEdges.startPoint.x, currentEdges.startPoint.y]).toEqual(startPoint);
+ //@ts-ignore
+ expect([currentEdges.endPoint.x, currentEdges.endPoint.y]).toEqual(endPoint);
+ })
+
+ it('test position top-right calc pointPadding value is ok ', () => {
+ const node =
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ style: {
+ lineWidth: 0
+ },
+ }
+ const edge = {
+ source: '1',
+ target: '1',
+ type: 'loop',
+ loopCfg: {
+ position: 'top-right',
+ dist: 20,
+ pointPadding: 15,
+ },
+ }
+
+ const data = {
+ nodes: [node],
+ edges: [edge],
+ };
+
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ });
+
+
+ const center = [node.x, node.y]
+ const halfOfWidth = node.size[0] / 2
+ const halfOfHeight = node.size[1] / 2
+ const pointPadding = edge.loopCfg.pointPadding
+ graph.data(data);
+ graph.render();
+
+ const startPoint = [center[0] + halfOfWidth - pointPadding, center[1] - halfOfHeight];
+ const endPoint = [center[0] + halfOfWidth, center[1] - halfOfHeight + pointPadding];
+
+ const { edges } = data
+ const currentEdges = edges[0]
+
+ //@ts-ignore
+ expect([currentEdges.startPoint.x, currentEdges.startPoint.y]).toEqual(startPoint);
+ //@ts-ignore
+ expect([currentEdges.endPoint.x, currentEdges.endPoint.y]).toEqual(endPoint);
+ })
+
+
+ it('test unset pointPadding and final pointPadding calc is ok', () => {
+ const node =
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ style: {
+ lineWidth: 0
+ },
+ }
+ const edge = {
+ source: '1',
+ target: '1',
+ type: 'loop',
+ loopCfg: {
+ position: 'top-right',
+ dist: 20,
+ },
+ }
+
+ const data = {
+ nodes: [node],
+ edges: [edge],
+ };
+
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ });
+
+ const center = [node.x, node.y]
+ const halfOfWidth = node.size[0] / 2
+ const halfOfHeight = node.size[1] / 2
+ // 预期 pointPadding 为 20
+ const pointPadding = 20
+ graph.data(data);
+ graph.render();
+
+ const startPoint = [center[0] + halfOfWidth - pointPadding, center[1] - halfOfHeight];
+ const endPoint = [center[0] + halfOfWidth, center[1] - halfOfHeight + pointPadding];
+
+ const { edges } = data
+ const currentEdges = edges[0]
+
+ //@ts-ignore
+ expect([currentEdges.startPoint.x, currentEdges.startPoint.y]).toEqual(startPoint);
+ //@ts-ignore
+ expect([currentEdges.endPoint.x, currentEdges.endPoint.y]).toEqual(endPoint);
+ })
+
+ it('test set pointPadding greater than minimum height and width minimum value , final pointPadding calc is ok', () => {
+ const node =
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ style: {
+ lineWidth: 0
+ },
+ }
+ const edge = {
+ source: '1',
+ target: '1',
+ type: 'loop',
+ loopCfg: {
+ position: 'top-right',
+ dist: 20,
+ clockwise: true,
+ pointPadding: 1000,
+ },
+ }
+
+ const data = {
+ nodes: [node],
+ edges: [edge],
+ };
+
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ });
+
+ const center = [node.x, node.y]
+ const halfOfWidth = node.size[0] / 2
+ const halfOfHeight = node.size[1] / 2
+ // 预期 pointPadding 为 40
+ const pointPadding = 40
+ graph.data(data);
+ graph.render();
+
+ const startPoint = [center[0] + halfOfWidth - pointPadding, center[1] - halfOfHeight];
+ const endPoint = [center[0] + halfOfWidth, center[1] - halfOfHeight + pointPadding];
+
+ const { edges } = data
+ const currentEdges = edges[0]
+
+ //@ts-ignore
+ expect([currentEdges.startPoint.x, currentEdges.startPoint.y]).toEqual(startPoint);
+ //@ts-ignore
+ expect([currentEdges.endPoint.x, currentEdges.endPoint.y]).toEqual(endPoint);
+ })
+
+
+ it('test set clockwise => true, calc pointPadding is ok', () => {
+ const node =
+ {
+ id: '1',
+ type: 'rect',
+ color: '#333',
+ x: 100,
+ y: 200,
+ size: [80, 80],
+ label: 'rect',
+ style: {
+ lineWidth: 0
+ },
+ }
+ const edge = {
+ source: '1',
+ target: '1',
+ type: 'loop',
+ loopCfg: {
+ position: 'top-right',
+ dist: 20,
+ clockwise: true,
+ pointPadding: 1000,
+ },
+ }
+
+ const data = {
+ nodes: [node],
+ edges: [edge],
+ };
+
+ const graph = new G6.Graph({
+ container: div,
+ width: 800,
+ height: 800,
+ fitCenter: true,
+ });
+
+ const center = [node.x, node.y]
+ const halfOfWidth = node.size[0] / 2
+ const halfOfHeight = node.size[1] / 2
+ // 预期 pointPadding 为 40
+ const pointPadding = 40
+ graph.data(data);
+ graph.render();
+
+ const startPoint = [center[0] + halfOfWidth - pointPadding, center[1] - halfOfHeight];
+ const endPoint = [center[0] + halfOfWidth, center[1] - halfOfHeight + pointPadding];
+
+ const { edges } = data
+ const currentEdges = edges[0]
+
+ //@ts-ignore
+ expect([currentEdges.startPoint.x, currentEdges.startPoint.y]).toEqual(startPoint);
+ //@ts-ignore
+ expect([currentEdges.endPoint.x, currentEdges.endPoint.y]).toEqual(endPoint);
+ })
+});
diff --git a/packages/plugin/package.json b/packages/plugin/package.json
index d3cf3cd4fc6..d53abc45446 100644
--- a/packages/plugin/package.json
+++ b/packages/plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6-plugin",
- "version": "0.7.7",
+ "version": "0.7.8",
"description": "G6 Plugin",
"main": "lib/index.js",
"module": "es/index.js",
@@ -22,8 +22,8 @@
"@antv/g-base": "^0.5.1",
"@antv/g-canvas": "^0.5.2",
"@antv/g-svg": "^0.5.2",
- "@antv/g6-core": "0.7.7",
- "@antv/g6-element": "0.7.7",
+ "@antv/g6-core": "0.7.8",
+ "@antv/g6-element": "0.7.8",
"@antv/matrix-util": "^3.1.0-beta.3",
"@antv/scale": "^0.3.4",
"@antv/util": "^2.0.9",
diff --git a/packages/site/docs/manual/middle/elements/edges/built-in/loop.en.md b/packages/site/docs/manual/middle/elements/edges/built-in/loop.en.md
index 0292f15a9a8..de9d9bc0306 100644
--- a/packages/site/docs/manual/middle/elements/edges/built-in/loop.en.md
+++ b/packages/site/docs/manual/middle/elements/edges/built-in/loop.en.md
@@ -132,11 +132,12 @@ const graph = new G6.Graph({
### loopCfg
-`loopCfg` is an object that configures the direction, height, and clockwise.
+`loopCfg` is an object that configures the direction, height, and clockwise, connection point start and end position.
- `position`: The relative position to the source/target node. Options: `top`, `top-right`, `right`,`bottom-right`, `bottom`, `bottom-left`, `left`, `top-left`. `top` by default.
- `dist`: The distance between the keyShape of the source/target node to the highest position of the loop. It is equal to the height of the source/target node by default.
- `clockwise`: Whether to draw the loop clockwisely. `true` by default
+- `pointPadding`: For non-circular nodes, the offset between the connection point and the node center coordinates ('top right', 'bottom right', 'top left', 'bottom left', which are special, four angular coordinates) in the x-axis or y-axis direction, the default value is' 1/4 of the minimum value of node width and height '. *Supported by v4.7.8.*
Base on the code in [style](#style) section, we add `loopCfg` to `defaultEdge`.
@@ -152,6 +153,7 @@ const graph = new G6.Graph({
position: 'left',
dist: 100,
clockwise: false,
+ pointPadding: 15,
},
},
});
diff --git a/packages/site/docs/manual/middle/elements/edges/built-in/loop.zh.md b/packages/site/docs/manual/middle/elements/edges/built-in/loop.zh.md
index 8c3114b5ba4..c2dc5753aab 100644
--- a/packages/site/docs/manual/middle/elements/edges/built-in/loop.zh.md
+++ b/packages/site/docs/manual/middle/elements/edges/built-in/loop.zh.md
@@ -132,11 +132,12 @@ const graph = new G6.Graph({
### 自环特殊配置 loopCfg
-Object 类型。通过 `loopCfg` 配置自环的方位、高度、顺逆时针。
+Object 类型。通过 `loopCfg` 配置自环的方位、高度、顺逆时针、连接起始点位置。
- `position`: 指定自环与节点的相对位置。默认为:`top`。支持的值有:`top`, `top-right`, `right`,`bottom-right`, `bottom`, `bottom-left`, `left`, `top-left`
- `dist`: 从节点 keyShape 的边缘到自环最顶端的位置,用于指定自环的曲度,默认为节点的高度。
- `clockwise`: 指定是否顺时针画环,默认为 `true`。
+- `pointPadding`: 对于非圆形节点设置的连接点与节点中心坐标(`top-right`,`bottom-right`,`top-left`,`bottom-left`较特殊,为四个角坐标)在 x 轴或 y 轴方向的偏移量,默认为 `节点宽高中最小值的1/4`,*v4.7.8 后支持*。
基于上面 [样式属性 style](#XQFb2) 中的代码,下面代码在 `defaultEdge` 中增加了 `loopCfg` 配置项进行文本的配置,使之达到如下图效果。
@@ -152,6 +153,7 @@ const graph = new G6.Graph({
position: 'left',
dist: 100,
clockwise: false,
+ pointPadding: 15,
},
},
});
diff --git a/packages/site/package.json b/packages/site/package.json
index 7ba2f68013c..72dfe14fe7b 100644
--- a/packages/site/package.json
+++ b/packages/site/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@antv/g6-site",
- "version": "4.7.7",
+ "version": "4.7.8",
"description": "G6 sites deployed on gh-pages",
"keywords": [
"antv",
@@ -36,7 +36,7 @@
"dependencies": {
"@ant-design/icons": "^4.0.6",
"@antv/chart-node-g6": "^0.0.3",
- "@antv/g6": "4.7.7",
+ "@antv/g6": "4.7.8",
"@antv/gatsby-theme-antv": "1.1.15",
"@antv/util": "^2.0.9",
"@antv/vis-predict-engine": "^0.1.1",