一、案例效果
二、案例代码及组件抽离
- 父组件 BloodTopology.vue
<template>
<div>
<TopologyCompact>
<template #main-board-box>
<TopologyDependent domId="featureBloodContainer" :nodeData="originalNodeData" />
</template>
<template #right-drawer-box>
<RightDrawer :width="350">
<template #rightContent> rightContent </template>
</RightDrawer>
</template>
</TopologyCompact>
</div>
</template>
<script lang="ts" setup>
import RightDrawer from '@/common/components/topologyToolKit/RightDrawer.vue';
import TopologyCompact from '@/common/components/topologyToolKit/TopologyCompact.vue';
import TopologyDependent from '@/common/components/topologyToolKit/TopologyDependent.vue';
import { onMounted, ref } from 'vue';
const originalNodeData = ref<any>({
nodes: [],
edges: [],
});
const edges = [
['1', '2'],
['2', '3'],
['2', '4'],
['4', '5'],
['4', '6'],
['4', '7'],
['4', '8'],
['5', '9'],
['6', '10'],
['7', '11'],
['8', '12'],
];
const initNodeData = () => {
for (let i = 1; i <= 12; i++) {
originalNodeData.value.nodes!.push({
id: `${i}`,
shape: 'vue-shape',
width: 32,
height: 32,
label: i,
attrs: {
body: {
fill: '#5F95FF',
stroke: 'transparent',
},
label: {
fill: '#ffffff',
},
},
});
}
edges.forEach((edge: [string, string]) => {
originalNodeData.value.edges!.push({
source: edge[0],
target: edge[1],
attrs: {
line: {
stroke: '#A2B1C3',
strokeWidth: 2,
},
},
});
});
};
onMounted(() => {
initNodeData();
});
</script>
- 子组件 TopologyDependent.vue
<template>
<div :id="domId" class="w-full h-[95%]"></div>
</template>
<script setup lang="ts">
import { registerOption } from '@/views/featureManage/featureList/topologyToolKit/attrConfig';
import { DagreLayout, DagreLayoutOptions } from '@antv/layout';
import { Graph } from '@antv/x6';
import { register } from '@antv/x6-vue-shape';
import { nextTick, onMounted, ref } from 'vue';
import { initDependOption } from './initDependConfig';
const props = defineProps({
domId: {
type: String,
default: '',
},
nodeData: {
type: Object,
},
targetIdData: {
type: Array as () => number[],
required: false,
},
});
const container = ref<any>();
register({ ...registerOption });
const initGraph = (data: any) => {
console.log('-8888---data', data);
container.value = document.getElementById(props.domId);
const width = container.value?.scrollWidth;
const height = container.value?.scrollHeight || 800;
const graph = new Graph({
container: container.value,
width, // 设置图形的宽度
height, // 设置图形的高度
...initDependOption.option,
});
const dagreLayout = new DagreLayout({ ...(initDependOption.layout as DagreLayoutOptions) });
const model = dagreLayout.layout(data);
console.log('111==data', data, model);
graph.fromJSON(model);
graph.on('node:click', ({ e, x, y, node, view }) => {
console.log('---115-e, x, y, node, view', e, x, y, node, view);
});
};
onMounted(() => {
nextTick(() => {
if (props.domId && document.getElementById(props.domId)) {
initGraph(props.nodeData);
}
});
});
</script>
- 自定义节点展示 NodeHtml.vue
<template>
<div class="status-node">
<div class="content" @click="handleClick">这是一段文字</div>
</div>
</template>
<script lang="ts" setup>
const handleClick = () => {
console.log('---handleClick');
};
</script>
<style lang="less" scoped>
.status-node {
background-color: purple;
height: 50px;
width: 100px;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.content {
color: white;
font-size: 14px;
}
</style>
- 相关常量信息
initDependConfig.ts
/**
* x6初始化配置option
*/
export const initDependOption = {
option: {
panning: true, // 启用画布平移功能
autoResize: true, // 启用自动调整画布大小功能
interacting: {
nodeMovable: false, // 禁止节点移动
},
mousewheel: {
enabled: true, // 启用鼠标滚轮缩放功能
factor: 1.1, // 缩放因子,每次滚动时缩放的比例
maxScale: 1.5, // 最大缩放比例
minScale: 0.5, // 最小缩放比例
},
background: {
color: '#F2F7FA',
},
},
layout: {
type: 'dagre',
rankdir: 'TB',
align: 'UR',
ranksep: 50,
nodesep: 48,
},
};
attrConfig.ts
import NodeElement from '@/views/featureManage/featureList/topologyToolKit/NodeHtml.vue';
/**
* 自定义注册节点配置
*/
export const registerOption = {
shape: 'vue-shape',
width: 100,
height: 100,
component: NodeElement,
};