fix: image lost while updating the size for an image node, closes: #3938; (#3991)

* fix: image lost while updating the size for an image node, closes: #3938;

* chore: update version num

* 自环边样式 startPoint & endPoint 计算问题 #3974 (#3990)

* fix: 自环问题连接点问题修复

* feat: change var to halfOfWidth and halfOfHeight

* feat: 修改注释

* feat: 完善文档

* feat: 修改注释

* feat: 修改注释

* feat: add loop feat unit test

* feat: 删除空行

* feat: 修改名称

Co-authored-by: linjie <xinxinsong.sxx@alibaba-inc.com>

Co-authored-by: tulaoda <coderaxin@163.com>
Co-authored-by: linjie <xinxinsong.sxx@alibaba-inc.com>
This commit is contained in:
Yanyan Wang 2022-10-13 16:00:52 +08:00 committed by GitHub
parent 6561f296bd
commit ce0dbae399
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 535 additions and 97 deletions

View File

@ -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;

View File

@ -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",

View File

@ -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,

View File

@ -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',

View File

@ -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 {

View File

@ -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;
}
};

View File

@ -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": {

View File

@ -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",

View File

@ -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';

View File

@ -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",

View File

@ -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',

View File

@ -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);
})
});

View File

@ -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",

View File

@ -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`.<br /> <img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*z9dwTZvACcEAAAAAAAAAAABkARQnAQ' width=100 alt='img'/>
@ -152,6 +153,7 @@ const graph = new G6.Graph({
position: 'left',
dist: 100,
clockwise: false,
pointPadding: 15,
},
},
});

View File

@ -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`  配置项进行文本的配置,使之达到如下图效果。<br /> <img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*z9dwTZvACcEAAAAAAAAAAABkARQnAQ' width=100 alt='img'/>
@ -152,6 +153,7 @@ const graph = new G6.Graph({
position: 'left',
dist: 100,
clockwise: false,
pointPadding: 15,
},
},
});

View File

@ -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",