关于antv/x6 2.0的一些基本使用
注册节点
Graph.registerNode(
'custom-rect',
{
inherit: 'rect',
width: 66,
height: 36,
attrs: {
body: {
strokeWidth: 1,
stroke: '#d2dae3',
fill: '#fff',
},
text: {
fontSize: 14,
fill: '#262626',
},
},
ports: { groups: {
group3: {
position: 'top',
attrs: { circle },
},
group4: {
position: 'bottom',
attrs: { circle },
},
},
items: [{ group: 'group3' }, { group: 'group4' }], },
},
true,
)
自定义注册节点
export class StepNode extends Component {
render() {
const { node, graph, disabled } = this.props;
const label = node.prop('label');
const data = node.getData();
return (
{label}
);
}
}
使用
import { StepNode } from '@c/x6Node';
chart_register_node = () => {
register({
shape: 'custom-react-step',
width: 200,
height: 32,
effect: ['data'],
component: ,
});
};
初始化画布
import { Snapline } from '@antv/x6-plugin-snapline' //对齐线
import { Clipboard } from '@antv/x6-plugin-clipboard' // 复制粘贴
import { Selection } from '@antv/x6-plugin-selection' //选中状态 ,需配合样式使用
import { Keyboard } from '@antv/x6-plugin-keyboard' //键盘事件
draw = data => {
if (window.graph) {
window.graph.fromJSON(data || '')
return
}
let g = new Graph({
container: this.ref.current,
connecting: {
connector: { name: 'smooth' },
createEdge() {
return new Shape.Edge({
attrs: {
line: {
stroke: '#0CB9DD',
strokeWidth: 1,
},
},
zIndex: -1,
});
},
router: {
name: 'normal', //’manhattan‘:智能正交路径
args: {
// offset: 25,
// direction: 'H',
},
},
allowMulti: false, // 是否允许在相同的起始节点和终止之间创建多条边,默认为 true。
allowBlank: false,
sourceAnchor: {
name: 'bottom', // 锚点会在节点右侧中心往上偏移 10px
args: {
dy: 0,
},
},
targetAnchor: {
name: 'top', // 锚点会在节点右侧中心往上偏移 10px
args: {
dy: 0,
},
},
connectionPoint: 'anchor',
},
// 鼠标拖动画布
panning: true,
// 鼠标缩放画布
mousewheel: true,
background: {
color: '#F2F7FA',
},
grid: {
visible: true,
type: 'doubleMesh',
args: [
{
color: '#eee', // 主网格线颜色
thickness: 1, // 主网格线宽度
},
{
color: '#ddd', // 次网格线颜色
thickness: 1, // 次网格线宽度
factor: 4, // 主次网格线间隔
},
],
},
embedding: {
enabled: true,
findParent({ node }) {
const bbox = node.getBBox()
return this.getNodes().filter(n => {
const data = n.getData()
if (data && data.parent) {
const targetBBox = n.getBBox()
return bbox.isIntersectWithRect(targetBBox)
}
return false
})
},
},
})
g.fromJSON(data ) // 渲染元素
// g.centerContent(); // 居中显示
g.use(new Keyboard())
g.use(new Snapline({ enabled: true }))
g.use(new Clipboard({ enabled: true, useLocalStorage: true }))
g.use(
new Selection({
enabled: true,
multiple: true,
rubberEdge: true,
rubberNode: true,
modifiers: 'shift',
rubberband: true,
// showEdgeSelectionBox: true,
// showNodeSelectionBox: true,
}),
)
window.graph = g
this.chart_add_events(g)
this.props.initDrag(g)
}
**css**
.x6-node-selected rect {
// border-color: #1890ff;
stroke: #1890ff;
border-radius: 2px;
box-shadow: 0 0 0 4px #d4e8fe;
}
.x6-node-selected .node-step {
border-color: #1890ff;
border-radius: 2px;
box-shadow: 0 0 0 4px #d4e8fe;
}
.x6-edge:hover path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1px;
}
.x6-edge-selected path:nth-child(2) {
stroke: #1890ff;
stroke-width: 1.5px !important;
}
注册事件
chart_add_events = g => {
g.on('edge:connected', ({ e, edge }) => {
const { source, target } = edge
g.getEdges().forEach(e => {
e.setAttrs(LineAttr)
})
})
g.on('node:click', ({ node }) => {
this.setState({
info: { ...node.getData(), nodeId: node.id },
})
})
g.on('node:dblclick', ({ node }) => {
const { index } = this.state
if (index !== 0) {
this.setState({
index: 0,
info: { ...node.getData(), nodeId: node.id },
})
} else {
this.setState({
info: { ...node.getData(), nodeId: node.id },
})
}
})
g.on('blank:click', e => {
this.onClose()
setTimeout(() => {
this.setState({
info: {},
})
}, 100)
})
g.bindKey('delete', () => {
const cells = g.getSelectedCells()
console.log(cells, 'cells')
if (cells && cells.length) {
g.removeCells(cells)
}
return false
})
}
Dnd拖拽组件
import { Dnd } from '@antv/x6-plugin-dnd'
initDrag = target => {
this.dnd = new Dnd({
target,
scaled: false,
dndContainer: this.ref.current,
})
}
startDrag = (e, v) => {
const g = window.graph
const { x, y } = window.graph?.graphToLocal()
const config = {
shape: 'custom-rect',
...size1,
x,
y,
ports,
label: v.name,
data: v,
zIndex: 3,
}
this.dnd.start(g.createNode(config), e.nativeEvent)
}
render() {
const { loading } = this.state
return (
)
}
导出
handleExport = () => {
const json = window.graph?.toJSON();
const cells = json?.cells;
exportFileJSON(cells, `导出.json`);
};
// 对象导出为json文件
export const exportFileJSON = (data, filename) => {
if (typeof data === 'object') {
data = JSON.stringify(data, null, 4);
}
// 导出数据
const blob = new Blob([data], { type: 'text/json' }),
e = new MouseEvent('click'),
a = document.createElement('a');
a.download = filename;
a.href = window.URL.createObjectURL(blob);
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
a.dispatchEvent(e);
};
导入
handleImport = (a) => {
const num = this.state.count;
importFileJSON(a)
.then((data) => {
if (Array.isArray(data)) {
const g = window.graph;
let json = g.toJSON();
let list = data.map((v, i) => {
if (v.id) {
v.id = v.id + num;
}
if (v.ports) {
v.ports.items.forEach((vs) => vs + num);
}
if (v.source) {
v.source.cell = v.source.cell + num;
v.source.port = v.source.port + num;
}
if (v.target) {
v.target.cell = v.target.cell + num;
}
return v;
});
json.cells = json.cells.concat(list);
g.fromJSON(json);
this.setState({ count: this.state.count + 1 });
}
})
.catch((e) => {
message.error(e);
});
};
// 导入解析json文件
export const importFileJSON = (ev) => {
return new Promise((resolve, reject) => {
const fileDom = ev.target,
file = fileDom.files[0];
// 格式判断
if (file.type !== 'application/json') {
reject('仅允许上传json文件');
}
// 检验是否支持FileRender
if (typeof FileReader === 'undefined') {
reject('当前浏览器不支持FileReader');
}
// 执行后清空input的值,防止下次选择同一个文件不会触发onchange事件
ev.target.value = '';
// 执行读取json数据操作
const reader = new FileReader();
reader.readAsText(file); // 读取的结果还有其他读取方式,我认为text最为方便
reader.onerror = (err) => {
reject('json文件解析失败', err);
};
reader.onload = () => {
const resultData = reader.result;
if (resultData) {
try {
const importData = JSON.parse(resultData);
resolve(importData);
} catch (error) {
reject('读取数据解析失败', error);
}
} else {
reject('读取数据解析失败');
}
};
});
};