上图
自定义图和交互
import * as G6 from '@antv/g6';
import nodeShapes from './Node';
import lines from './Edge';
import behaviors from './Behavior';
export default function registry() {
// 注册自定义行为
Reflect.ownKeys(behaviors).forEach((key) => {
const myKey = key as string;
G6.registerBehavior(myKey, behaviors[myKey]);
});
// 注册自定义连线
Reflect.ownKeys(lines).forEach((key) => {
const myKey = key as string;
G6.registerEdge(myKey, lines[myKey], 'line');
});
// 注册自定义节点
Reflect.ownKeys(nodeShapes).forEach((key) => {
const myKey = key as string;
G6.registerNode(`custom-${myKey}`, nodeShapes[myKey], 'node');
});
}
自定义节点
const user: ShapeOptions = {
drawShape(cfg?: ModelConfig | undefined, group?: IGroup | undefined): IShape {
const [wrapWidth, wrapHeight] = cfg?.size as Array<number>;
const referenceX = (cfg?.x as number) - wrapWidth / 2;
const referenceY = (cfg?.y as number) - wrapHeight / 2;
const radius = (cfg?.radius as number) || 4;
// 构建外层的包裹成层
const wrapId = cfg?.id || uuid();
const shape = group?.addShape((cfg?.shapeType as string), {
attrs: {
id: wrapId,
x: referenceX,
y: referenceY,
width: wrapWidth,
height: wrapHeight,
radius,
fill: cfg?.fill as string,
stroke: cfg?.stroke as string,
name: 'wrap-box',
editable: cfg?.editable,
shapeType: 'rect',
},
draggable: true,
});
if (group) {
// title-box
group.addShape('rect', {
attrs: {
x: referenceX + 1,
y: referenceY + 1,
width: wrapWidth - 2,
height: 24,
radius: [radius - 1, radius - 1, 0, 0],
parentId: wrapId,
fill: cfg?.titleFill as string,
name: 'title-box',
},
});
// label
group.addShape('text', {
attrs: {
textBaseline: 'top',
x: referenceX + 24,
y: referenceY + 8,
lineHeight: 20,
text: cfg?.title,
fill: '#fff',
parentId: wrapId,
name: 'title',
},
});
// name
group.addShape('text', {
attrs: {
textBaseline: 'top',
x: referenceX + 24,
y: referenceY + 36,
lineHeight: 20,
text: cfg?.name,
fill: '#000',
parentId: wrapId,
name: 'name',
},
});
// close Icon
group.addShape('image', {
attrs: {
x: referenceX + wrapWidth - 20,
y: referenceY + 4,
width: 16,
height: 16,
cursor: 'pointer',
img: delIcon,
parentId: wrapId,
name: 'close-icon',
opacity: 0,
isClose: true,
},
});
// first Icon
if (cfg?.titleImg) {
group.addShape('image', {
attrs: {
x: referenceX + 4,
y: referenceY + 5,
width: 16,
height: 16,
cursor: 'pointer',
img: cfg?.titleImg,
},
name: 'title-icon',
});
}
}
return shape as IShape;
},
setState(name, value, item?: INode | IEdge | ICombo| undefined) {
if (item) {
const group = item.getContainer();
const shape = group.get('children')[0];
const closeIcon = group.findAll((circle) => circle.attrs.isClose);
const children = group.findAll((g) => g.attrs.parentId === shape.attrs.id);
const model = item.getModel();
const selectStyles = () => {
shape.attr('stroke', 'rgb(50,150,250)');
shape.attr('cursor', 'pointer');
if (model.key !== 'START') {
closeIcon.forEach((circle) => {
circle.attr('opacity', 1);
});
}
children.forEach((child) => {
child.attr('cursor', 'pointer');
});
};
const unSelectStyles = () => {
shape.attr('stroke', '#ddd');
shape.attr('cursor', 'default');
closeIcon.forEach((circle) => {
circle.attr('opacity', 0);
});
children.forEach((child) => {
child.attr('cursor', 'default');
});
};
switch (name) {
case 'selected':
if (value) {
selectStyles();
} else {
unSelectStyles();
}
break;
case 'hover':
if (value) {
selectStyles();
} else {
unSelectStyles();
}
break;
default:
break;
}
}
},
};
开发体验
Antv-G6提供了相当的便利,使得像如此的工具变得简单。同时它也是可视化工具库的解决方案。