Vue3使用AntvG6写拓扑图,可添加修改删除节点和边

npm安装antv/g6

npm 复制代码
npm install @antv/g6 --save

上代码

vue 复制代码
<template>
    <div id="tpt1" ref="container" style="width: 100%;height: 100%;"></div>
</template>

<script setup>
    import { Renderer as SVGRenderer } from '@antv/g-svg';//通过svg方式呈现
    import { Graph,iconfont } from '@antv/g6';
    import { onMounted, onUnmounted, ref,nextTick,computed } from 'vue';
    const container = ref();
    const nodes = ref([
        { id: '1', style: { x: 550, y: 100 },data:{id:'1',name:"wifi路由器",type:"路由器"} }//数据格式
    ])
    const edges = ref([
        { id:'1-3-g1',source: '1', target: '3',data:{id:1,name:"线路1",status:0,outRate:"80MB/s",inRate:"50MB/s",scoureName:"url",scoureType:"",scoureUrl:"",targetName:"http",targetType:"",targetUrl:"",watchDevice:"",watchUrl:""} }//数据格式
    ])
    let graph:any = null
    
    onMounted(() => {
        updateChart();
    })
    onUnmounted(() => {
        graph && graph.clear();
    });
    //获取所有节点
    const getNodeData = () => {
        return graph.getNodeData()
    }
    //获取所有边
    const getEdgeData = () => {
        return graph.getEdgeData()
    }
    //获取缩放比例
    const getZoom = () => {
        return graph.getZoom();
    }
    const updateChart = () => {
        const style = document.createElement('style');
        style.innerHTML = `@import url(${iconfont.css});`;
        document.head.appendChild(style);
        graph = new Graph({
            container: container.value,
            data: {
                nodes: nodes.value,
                edges: edges.value,
            },
            edge: {
                // type:"extra-label-edge",
                style: {//线条的样式
                    cursor: 'pointer',
                    lineWidth: 1,
                    labelText: (d:any) => {
                        // 改变边上的第一行第二行颜色
                        nextTick(()=>{
                            let parentElement = document.getElementById(d.id)
                            let tspanList = parentElement.getElementsByTagName("tspan")
                            setTimeout(()=>{
                                if(tspanList.length>=2){
                                    tspanList[0].setAttribute("fill","#81f4f9")
                                    tspanList[1].setAttribute("fill","#eca13c")
                                }
                            })
                        })
                        return props.isEdit||(d.data.outRate==''&&d.data.inRate=='')?'':`⬆${d.data.outRate}\n⬇${d.data.inRate}`;
                    },
                    data:(d)=>{
                            return d.data
                    },
                    endArrow: props.isEdit?true:false,
                    endArrowType: (d) => d.id.split('-')[0],
                    increasedLineWidthForHitTesting:10,
                    stroke: '#83d6dc',
                    labelAutoRotate:true,//是否旋转与边一致
                    labelFill: '#fff',
                    labelFontSize: 11,
                    labelPadding:[3,7],
                    zIndex:2
                },
            },
            transforms: [
                {
                    type:"process-parallel-edges",
                    mode:"bundle",
                    distance: 50
                }
            ],
            node: {
                type: 'image',
                style:{
                    padding:[10,10],
                    size: [60,60],
                    labelText: (d:any) => {
                        return d.data.name;
                    },
                    src: (d)=>{
                        //通过类型自定义节点图片
                        let imgArr:any = {
                            "交换机":"tpt_jhj.png",
                            "路由器":"tpt_lyq.png",
                            "安全设备":"tpt_fhq.png",
                            "其他设备":"tpt_qt.png",
                        }
                        return (d.data.type?getImageUrl(imgArr[d.data.type]):getImageUrl('tpt_qt.png')) || getImageUrl('tpt_qt.png')
                    },
                    data:(d)=>{
                            return d.data
                    },
                    labelPosition: 'bottom',
                    labelFill: '#fff',
                    labelFontSize: 13,
                    labelBackground: false,//背景颜色
                    labelBackgroundFill: 'linear-gradient(#e66465, #9198e5)',
                    labelBackgroundStroke: '#9ec9ff',
                    labelBackgroundRadius: 2,
                    labelFontWeight: 600,
                    labelPadding:[3,10],
                    zIndex:3,
                    labelOffsetY:8,
                    badge: false, // 是否显示徽标
                    badges: [
                        { text: 'x', placement: 'right-top',padding:[2,5] },
                    ],
                    badgePalette: ['red'], // 徽标的背景色板
                    badgeFontSize: 10, // 徽标字体大小
                }
            },
            behaviors: [
                {
                    type:'zoom-canvas'//缩放
                },
                {
                    type: 'drag-canvas',
                    key: 'drag-canvas-1',
                },
                {
                    type:"drag-element",
                    key: 'drag-element-1',
                    enableAnimation:false,
                    shadow:false//拖动样式
                },
                {
                    type: 'create-edge',
                    key:"create-edge-1",
                    trigger: 'click',//drag
                    onCreate: (edge) => {//创建线的样式
                        const { style, ...rest } = edge;
                        return {
                            ...rest,
                            data:{
                                name:"",
                                status:0,
                                scoureName:"",
                                scoureType:"",
                                scoureUrl:"",
                                targetName:"",
                                targetType:"",
                                targetUrl:"",
                                watchDevice:"",
                                watchUrl:"",
                                inRate:"",
                                outRate:"",
                            },
                            style: {
                                ...style,
                                stroke: 'red',
                                lineWidth: 2,
                                endArrow: true,
                            },
                        };
                    },
                },
            ],
            renderer: () => new SVGRenderer(),
        });
        graph.render();
        //鼠标右键点击节点编辑
        graph.on('node:contextmenu', (e) => {
            //添加编辑设备不为0是修改
            form.value = e.target.config.style.data
            submitNode();
        });
    }
    //添加设备按钮
    const addNode = () => {
        form.value.id = 0
        submitNode();
    }
    //添加修改节点
    const submitNode = () => {
        if(form.value.id == 0){
            //添加
            nodes.value = graph.getNodeData();
            graph.addData({
                nodes:[{
                    id: nodes.value.length>0?`${graph.getNodeData().length+1}`:"1",
                    style:{ x: container.value.clientWidth/2, y: 30 },
                    data:{id:nodes.value.length>0?`${graph.getNodeData().length+1}`:"1",name:form.value.name,type:form.value.type}
                }]
            })
        }else{
            graph.updateNodeData([{id:form.value.id,data:form.value}])
        }
        graph.render();
    }
</script>

运行结果

不断更新

相关推荐
^小桃冰茶1 小时前
CSS知识总结
前端·css
运维@小兵1 小时前
vue注册用户使用v-model实现数据双向绑定
javascript·vue.js·ecmascript
巴巴_羊2 小时前
yarn npm pnpm
前端·npm·node.js
chéng ௹3 小时前
vue2 上传pdf,拖拽盖章,下载图片
前端·css·pdf
嗯.~3 小时前
【无标题】如何在sheel中运行Spark
前端·javascript·c#
A_aspectJ6 小时前
【Bootstrap V4系列】学习入门教程之 组件-输入组(Input group)
前端·css·学习·bootstrap·html
兆。6 小时前
电子商城后台管理平台-Flask Vue项目开发
前端·vue.js·后端·python·flask
互联网搬砖老肖6 小时前
Web 架构之负载均衡全解析
前端·架构·负载均衡
sunbyte7 小时前
Tailwind CSS v4 主题化实践入门(自定义 Theme + 主题模式切换)✨
前端·javascript·css·tailwindcss
风之舞_yjf8 小时前
Vue基础(8)_监视属性、深度监视、监视的简写形式
javascript·vue.js·ecmascript