<template>
<div>
<div id="container" style="width:100%; height: 600px;"></div>
<!-- 添加节点的对话框 -->
<el-dialog v-model="dialogVisible" title="添加新节点" width="30%">
<el-input v-model="newNodeName" placeholder="请输入节点名称" />
<div style="margin-top: 20px;">
<span style="margin-right: 10px;">选择类型:</span>
<el-select v-model="proxyType">
<el-option label="Proxy" value="proxy" />
<el-option label="Global" value="global" />
</el-select>
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="addChildNode">确认</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { Graph,treeToGraphData,register,ExtensionCategory } from '@antv/g6';
import {TREELIST} from './data'
import networkimg from "@/assets/img/network.png"
const graph = ref(null);
const rawData = ref(TREELIST)
let dialogVisible =ref(false)
onMounted(() => {
const container = document.getElementById('container');
function isLeafNode(d) {
return !d.children || d.children.length === 0;
}
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: treeToGraphData(rawData.value),
behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element', 'collapse-expand'],
node: {
type: 'image',
style: (d) => {
const style = {
src: networkimg,
labelText: d.id,
labelPlacement: 'right',
labelOffsetX: 2,
labelBackground: true,
ports: [{ placement: 'top' }, { placement: 'bottom' }],
};
if (isLeafNode(d)) {
Object.assign(style, {
labelTransform: [
['rotate', 90],
['translate', 18],
],
labelBaseline: 'center',
labelTextAlign: 'left',
});
}
return style;
},
animation: {
enter: false,
},
},
edge: {
type: 'cubic-vertical',
animation: {
enter: false,
},
},
layout: {
preventOverlap: true,
type: 'compact-box',
direction: 'TB',
getHeight: function getHeight() {
return 16;
},
getWidth: function getWidth() {
return 16;
},
getVGap: function getVGap() {
return 80;
},
getHGap: function getHGap() {
return 20;
},
},
plugins: [
{
type: 'contextmenu',
trigger: 'click', // 'click' or 'contextmenu'
onClick: (value, target, current) => {
// alert('You have clicked the「' + value + '」item');
if(value == 'add'){
dialogVisible.value=true
// const parentId = current.id
// if (parentId) {
// addChildNode(parentId, graph)
// }
}else{
deleteNode(current.id, graph)
}
},
getItems: () => {
return [
{ name: '添加节点', value: 'add' },
{ name: '删除', value: 'delete' },
];
},
},
],
});
graph.render();
});
function addChildNode(parentId, graphInstance) {
const newNode = { id: `node-${Date.now()}` }
// 需要确保rawData是响应式数据
const currentData = rawData.value // 深拷贝原始数据
const traverse = (node) => {
if (node.id === parentId) {
if (!node.children) node.children = []
node.children.push(newNode)
return true
}
return node.children?.some(child => traverse(child))
}
if (traverse(currentData)) {
// 更新图形数据
graphInstance.setData(treeToGraphData(currentData))
// graphInstance.layout()
graphInstance.fitView()
graphInstance.render() // 确保重新渲染
}
}
function deleteNode(nodeId, graphInstance) {
// 特殊情况处理:不允许删除根节点
if (nodeId === rawData.value.id) {
alert('Cannot delete root node!')
return
}
// 深拷贝原始数据以避免直接修改响应式数据
const currentData = rawData.value
// 递归查找并删除目标节点
const traverse = (node) => {
if (node.children) {
const index = node.children.findIndex(child => child.id === nodeId)
if (index !== -1) {
node.children.splice(index, 1)
return true
}
return node.children.some(child => traverse(child))
}
return false
}
if (traverse(currentData)) {
// 更新原始数据
rawData.value = currentData
// 更新图形数据
graphInstance.setData(treeToGraphData(currentData))
graphInstance.fitView()
graphInstance.render()
}
}
const getNodeImage = (d) => {
// 根据节点类型返回不同的图片URL
// 你可以根据实际情况调整这里的逻辑
if (d.type === 'web') return 'https://gw.alipayobjects.com/zos/basement_pr我要第二层节点换成别的图片
最新发布