echarts关系图graph修改图片,自定义鼠标节点和线悬停,图片下载,拖拽,右键弹框等功能的实现

1.首先看一下效果图:

效果图

2.代码目录结构

代码结构

3.参考地址:https://gallery.echartsjs.com/editor.html?c=xCLEj67T3H

4.代码部分:(如果不懂,可以看我之前写的关于echarts树图tree部分的代码,步骤都比较清楚,所以这边我直接上全部代码了,就不拆分解释说明了)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 引入 echarts.js -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
    <script type="text/javascript" src="js/echars.js"></script>
    <style>
        *{padding: 0;margin: 0;}
        .menu{
            /*这个样式不写,右键弹框会一直显示在画布的左下角*/
            position: absolute;
            background: rgba(3,3,3,0.6);
            border-radius: 5px;
            left: -99999px;
            top: -999999px;
        }
        .menu ul{list-style: none}
        .menu ul li{
            padding: 5px 10px;
            color: #ffff;
            border-bottom: 1px dashed #ffffff;
            font-size: 14px;
            cursor: pointer;
        }
        .menu ul li:hover{
            color: #659bc5;
        }
        .menu ul li:last-child{
            border-bottom: none;
        }
    </style>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div class="tree-container">
    <div id="main" style="width: 600px;height:500px;"></div>
</div>
<!--右键弹出菜单-->
<div id="rightMenu" class="menu" style="display: none;">
    <ul>
        <li><span class="glyphicon glyphicon-off" aria-hidden="true"></span> 开关</li>
        <li><span class="glyphicon glyphicon-road" aria-hidden="true"></span> 通行</li>
    </ul>
</div>
<script>
    var myChart = echarts.init(document.getElementById('main'));
    //todo  节点信息
    var data = [
        {
            "id": 0,
            "name": "外部网络",
            "type": "Internet",
            "ip":"1.1.1.1",
            "port":"未知",
            "ignore":"false",
            "flag":"true"
        }, {
            "id": 1,
            "name": "交换机",
            "type": "switch",
            "ip":"192.168.30.125",
            "mac":"48:de:3d:e2:49:a8",
            "model":"H3C",
            "uptime":"2020-09-03 10:50:50",
            "port":"22",
            "ignore":"true",
            "flag":"true"
        }, {
            "id": 2,
            "name": "交换机",
            "type": "switch",
            "ip":"192.168.1.8",
            "mac":"cd:bd:3d:e2:55:55",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "port":"33",
            "ignore":"true",
            "flag":"true"
        }, {
            "id": 3,
            "name": "计算机",
            "type": "computer",
            "ip":"192.168.1.8",
            "mac":"dv:bd:fd:e2:df:fd",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "account":"xiaox",
            "location":"xianm",
            "port":"44",
            "ignore":"true",
            "flag":"true"
        }, {
            "id": 4,
            "name": "路由器",
            "type": "rooter",
            "ip":"192.168.1.8",
            "mac":"ds:bd:3d:e2:ds:55",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "account":"xiaox",
            "location":"xianm",
            "port":"55",
            "ignore":"true",
            "flag":"true"
        }, {
            "id": 5,
            "name": "服务器",
            "type": "service",
            "ip":"192.168.1.8",
            "mac":"vf:eq:dd:e2:55:55",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "account":"xiaox",
            "location":"xianm",
            "port":"66",
            "ignore":"true",
            "flag":"true"
        }, {
            "id":6,
            "name": "打印机",
            "type": "print",
            "ip":"192.168.1.8",
            "mac":"ss:bd:3d:ju:55:55",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "account":"xiaox",
            "location":"xianm",
            "port":"77",
            "ignore":"true",
            "flag":"true"
        }, {
            "id": 7,
            "name": "手机",
            "type": "phone",
            "ip":"192.168.1.8",
            "mac":"ju:ju:3d:e2:55:uy",
            "model":"pf",
            "uptime":"2020-09-03 10:50:50",
            "account":"xiaox",
            "location":"xianm",
            "port":"88",
            "ignore":"true",
            "flag":"true"
        }
    ];
    //todo 连线信息(线条中的source和target都对应节点data数据中的id指向)
    //todo 我看了其他例子,好像也可以是其它的字段,不一定是id
    var links = [{
        "source": 0,
        "target": 1
    }, {
        "source": 1,
        "target": 2
    }, {
        "source": 1,
        "target": 3
    }, {
        "source": 1,
        "target": 4
    }, {
        "source": 1,
        "target": 5
    }, {
        "source": 2,
        "target": 6
    }, {
        "source": 2,
        "target": 7
    }];
    /**
     * 自定义图片
     */
    for (var i = 0;i < data.length;i++){
        if (data[i].type == 'Internet'){
            data[i].symbol = 'image://image/internet.png';
            data[i].symbolSize = 70;
        }
        if (data[i].type == 'switch'){
            data[i].symbol = 'image://image/switch.png';
        }
        if (data[i].type == 'hub'){
            data[i].symbol = 'image://image/hub.png';
        }
        if (data[i].type == 'computer'){
            data[i].symbol = 'image://image/computer.png';
        }
        if (data[i].type == 'rooter'){
            data[i].symbol = 'image://image/rooter.png';
        }
        if (data[i].type == 'service'){
            data[i].symbol = 'image://image/service.png';
        }
        if (data[i].type == 'print'){
            data[i].symbol = 'image://image/print.png';
        }
        if (data[i].type == 'phone'){
            data[i].symbol = 'image://image/phone.png';
        }
    }
    // var categoryName = [];
    // var categoryStatus = {'外部网络':true,'交换机':true,'hub':true};
    // var categories =  [ {name : '外部网络'}, {name : '交换机'}, {name : 'hub'}];

    var option = {
        tooltip: {//弹窗
            enterable:true,//鼠标是否可进入提示框浮层中
            formatter:formatterHover,//修改鼠标悬停显示的内容
        },
        toolbox: {
            show: true,
            top:20,
            left:20,
            feature: {
                restore: {
                    title:'刷新'//刷新echarts图标
                },
                saveAsImage: {
                    title:'下载图片',//鼠标悬停在下载图标上时,显示的文字
                    name:'network-topology'//下载图片的文件名为network-topology.png
                }
            }
        },
        color:['#09022C',
            '#040193',
            '#073CFE',
            '#0065C2'],
        series : [ {//图片配置
            type : 'graph', //关系图
            //name : "拓扑图", //系列名称,用于tooltip的显示,legend 的图例筛选,在 setOption 更新数据和配置项时用于指定对应的系列。
            layout : 'force', //图的布局,类型为力导图,'circular' 采用环形布局,见示例 Les Miserables
            legendHoverLink : true,//是否启用图例 hover(悬停) 时的联动高亮。
            hoverAnimation : true,//是否开启鼠标悬停节点的显示动画
            coordinateSystem : null,//坐标系可选
            xAxisIndex : 0, //x轴坐标 有多种坐标系轴坐标选项
            yAxisIndex : 0, //y轴坐标
            force: {
                repulsion: 450,//相距距离
                edgeLength: [150, 200],
                layoutAnimation: true
            },
            roam : true,//是否开启鼠标缩放和平移漫游。默认不开启。如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move'。设置成 true 为都开启
            nodeScaleRatio : 0.6,//鼠标漫游缩放时节点的相应缩放比例,当设为0时节点不随着鼠标的缩放而缩放
            draggable : true,//节点是否可拖拽,只在使用力引导布局的时候有用。
            focusNodeAdjacency : true,//是否在鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点。
            edgeSymbol : [ 'none', 'arrow' ],//边两端的标记类型,可以是一个数组分别指定两端,也可以是单个统一指定。默认不显示标记,常见的可以设置为箭头,如下:edgeSymbol: ['circle', 'arrow']
            symbolSize:[40,40],//图形大小
            edgeSymbolSize : 10,//边两端的标记大小,可以是一个数组分别指定两端,也可以是单个统一指定。
            lineStyle : { //todo==========节点连线样式。
                normal : {
                    color : '#31354B',
                    width : '1',
                    type : 'solid', //线的类型 'solid'(实线)'dashed'(虚线)'dotted'(点线)
                    curveness : 0, //线条的曲线程度,从0到1
                    opacity : 1
                    // 图形透明度。支持从 0 到 1 的数字,为 0 时不绘制该图形。默认0.5
                },
                emphasis : {//高亮状态

                }
            },
            label : { //todo=============图形上的文本标签(图片名称)
                normal : {
                    show : true,//是否显示标签。
                    position : 'bottom',//标签的位置。['50%', '50%'] [x,y]   'inside'
                    textStyle : { //标签的字体样式
                        color : '#2D2F3B', //字体颜色
                        fontStyle : 'normal',//文字字体的风格 'normal'标准 'italic'斜体 'oblique' 倾斜
                        fontWeight : 'bolder',//'normal'标准'bold'粗的'bolder'更粗的'lighter'更细的或100 | 200 | 300 | 400...
                        fontFamily : 'sans-serif', //文字的字体系列
                        fontSize : 12, //字体大小
                    }
                },
                emphasis : {//高亮状态

                }
            },
            data: data,
            links: links //edges是其别名代表节点间的关系数据。
        } ]
    };
    /**
     * 鼠标悬停时显示详情
     */
    function formatterHover(params){
        // console.log(params);
        // console.log('data1',data);
        //todo 节点node悬停效果
        if (params.dataType == "node") {
            var deviceType = params.data.type;
            var imgPath = params.data.symbol;
            //图片地址截取,因为echarts修改图片的时候有一个------image://---前缀,前缀后面的才是图片真正的地址
            var imgPathSrc = imgPath.split("image://")[1];
            // console.log('str',imgPathSrc);
            if (deviceType === 'Internet' || deviceType === 'hub'){
                return "<img src='"+imgPathSrc+" ' width='30px' height='30px'>" + '<span style="padding:0 5px;font-size: 14px;">'+ params.data.name+'</span>';
                // return firstParams.name + '  ' + firstParams.seriesName + '<br>' + '装机:' + firstParams.data + ' 亿千瓦<br>增长率:' + sndParams.data +' %';
            }  if (deviceType === 'switch'){
                return "<img src='"+imgPathSrc+" ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:'+ params.data.name+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:'+ params.data.ip+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:'+ params.data.mac+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">设备型号:'+ params.data.model+'</span>'+ '<br>'
                    +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> 路由列表</button>'
                    +'<button style="padding:2px 5px;border:none;outline:none;color:#ffffff;border-radius: 5px;background:rgba(0,0,0,0.5);margin-left: 10px;"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span> ARP列表</button>';
            }else{
                return "<img src='"+imgPathSrc+" ' width='30px' height='30px'>" + '<span style="padding: 0 5px;font-size: 14px;">设备类型:'+ params.data.name+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">IP:'+ params.data.ip+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">MAC:'+ params.data.mac+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">账号:'+ params.data.account+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">所在位置:'+ params.data.location+'</span>'+ '<br>'
                    + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">最后登录时间:'+ params.data.uptime+'</span>';
            }
        }
        //todo 自定义线条悬停效果,因为线条中没有node节点的信息,所有自定义拿到节点信息,显示悬停效果
        if (params.dataType == "edge") {
            var linkName = params.name;
            var nameString = linkName.split(">");//将字符串以“>”隔开
            console.log('nameString',nameString);
            var linkNameFirst = nameString[0].trim();//截取“>”之前的数字--------.trim()因为取的数字中有空格,去掉空格
            var linkNameLast = nameString[1].trim();//截取“>”之后的数字
            //todo 以前的方法写的太局限
            //todo 例如:411>2223,截取第一位是4,最后一位是3,不是我们要的完整的数据
            // var linkNameFirst = linkName.substring(0,1);//截取第一位
            // var linkNameLast = linkName.substring(linkName.length-1,linkName.length);//截取最后一位
            console.log('linkName',linkName);
            console.log('params',params);
            console.log('linkNameFirst',linkNameFirst);
            console.log('linkNameLast',linkNameLast);
            var dataList = [];//存放线条两边的节点node数据
            for (var j =0;j<data.length;j++){
                if (linkNameFirst == data[j].id || linkNameLast == data[j].id){
                    // console.log('j',data[j]);
                    dataList.push(data[j]);
                }
            }
            // console.log('dataList',dataList);
            return '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">名称:'+ dataList[0].name+'->'+dataList[1].name+'</span>'+ '<br>'
                + '<span style="padding-left:5px;height:30px;line-height:30px;display: inline-block;font-size: 14px;">端口号:'+ dataList[0].ip+':'+dataList[0].port+'->'+dataList[1].ip+':'+dataList[1].port+'</span>';
        }
    }
    /**
     * 鼠标右键,弹出右键操作菜单
     */
    $("#main").bind("contextmenu", function () { return false; });//防止默认菜单弹出(查看图像,图像另存为等)
    myChart.on("contextmenu", function(params){
        // console.log('params',params.data.type);
        var rightType = params.data.type;
        if(rightType != "Internet" && rightType != "switch" && rightType != "hub"){
            $('#rightMenu').css({
                'display': 'block',
                'left': params.event.offsetX + 15,
                'top' : params.event.offsetY + 15
            });
            //todo 右键菜单刚弹出时,隐藏鼠标悬停菜单
            $("#main>div:nth-child(2)").hide();
        }
    });
    /**
     * 点击画布的时候隐藏右键菜单
     */
    $('.tree-container').click(function () {
        $('#rightMenu').css({
            'display': 'none',
            'left': '-9999px',
            'top': '-9999px'
        });
    });
    myChart.setOption(option);
</script>
</body>
</html>

  • 11
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值