echarts关系图graph点击折叠

首选参考别人的地址:echarts节点折叠实现_SongJingzhou的博客-CSDN博客

echarts下载: echarts下载

其次先看一下我改的效果图:

效果图

 接下来分段解释一下需要的代码:

1.声明一个全局的变量:

var globalData = []; //用来存放被收起的某节点的子节点

2. 在data节点数据中添加category字段,一开始就上代码好多人可能会很闷,具体如下图所示稍作解释:

category解释

3.点击事件

/**
     * 单击折叠功能
     * 点击隐藏节点实现,定义数组globalData用来存储被隐藏的节点的子节点
     */
    myChart.on('click', function(params) {
        if (params.dataType === "node") {
            var deletedFlag = false; // 标记点击的此节点是否存在子节点,若不存在则说明可能在上次的操作中已经删除,这时就需要尝试把之前删除的节点重新添加进去
            for (var i = data.length - 1; i >= 0; i--) {
                if (data[i].category == params.data.id) {
                    if (data[i].category != data[i].id) { //排除删除根元素的可能
                        deletedFlag = true;
                        for (var ii = data.length - 1; ii >= 0; ii--) { //删除第一级节点的子节点
                            if (data[ii].category == data[i].id) {
                                for (var iii = data.length - 1; iii >= 0; iii--) { //删除第二级节点的子节点
                                    if (data[iii].category == data[ii].id) {
                                        globalData.push(data[iii]);
                                        data.splice(iii, 1);
                                    }
                                }
                                globalData.push(data[ii]);
                                data.splice(ii, 1);
                            }
                        }
                        globalData.push(data[i]);
                        data.splice(i, 1); //删除该元素的第一级子节点,最多需删除三级
                    }
                }
            }
            if (!deletedFlag) { //这种情况下需要恢复该节点的子节点
                var nodeChildren = []; //存放本次恢复的数据,然后将它们从globalData中删除
                for (var n = globalData.length - 1; n >= 0; n--) {
                    if (params.data.id == globalData[n].category) { //显示该节点第一级子节点
                        data.push(globalData[n]);
                        nodeChildren.push(globalData[n]);
                        for (var nn = globalData.length - 1; nn >= 0; nn--) {
                            if (globalData[n].id == globalData[nn].category) { //显示该节点第二级子节点
                                data.push(globalData[nn]);
                                nodeChildren.push(globalData[nn]);
                                for (var nnn = globalData.length - 1; nnn >= 0; nnn--) {
                                    if (globalData[nn].id == globalData[nnn].category) { //显示该节点第三级子节点
                                        data.push(globalData[nnn]);
                                        nodeChildren.push(globalData[nnn]);
                                    }
                                }
                            }
                        }
                    }
                }
                if (nodeChildren.length > 0) {
                    for (var s = 0; s < nodeChildren.length; s++) {
                        for (var n = globalData.length - 1; n >= 0; n--) {
                            if (nodeChildren[s].id == globalData[n].id) {
                                globalData.splice(n, 1);
                            }
                        }
                    }
                }
            }
            myChart.setOption(option);
        }
    });

最后完整代码如下:
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>graph折叠</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'));
    var globalData = []; //用来存放被收起的某节点的子节点
    //todo  节点信息
    var data = [
        {
            "id": 0,
            "category": "0",
            "name": "外部网络",
            "type": "Internet",
            "ip":"1.1.1.1",
            "port":"未知",
            "ignore":"false",
            "flag":"true"
        }, {
            "id": 1,
            "category": "0",
            "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,
            "category": "1",
            "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,
            "category": "1",
            "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,
            "category": "1",
            "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,
            "category": "1",
            "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,
            "category": "2",
            "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,
            "category": "2",
            "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);

    /**
     * 单击折叠功能
     * 点击隐藏节点实现,定义数组globalData用来存储被隐藏的节点的子节点
     */
    myChart.on('click', function(params) {
        if (params.dataType === "node") {
            var deletedFlag = false; // 标记点击的此节点是否存在子节点,若不存在则说明可能在上次的操作中已经删除,这时就需要尝试把之前删除的节点重新添加进去
            for (var i = data.length - 1; i >= 0; i--) {
                if (data[i].category == params.data.id) {
                    if (data[i].category != data[i].id) { //排除删除根元素的可能
                        deletedFlag = true;
                        for (var ii = data.length - 1; ii >= 0; ii--) { //删除第一级节点的子节点
                            if (data[ii].category == data[i].id) {
                                for (var iii = data.length - 1; iii >= 0; iii--) { //删除第二级节点的子节点
                                    if (data[iii].category == data[ii].id) {
                                        globalData.push(data[iii]);
                                        data.splice(iii, 1);
                                    }
                                }
                                globalData.push(data[ii]);
                                data.splice(ii, 1);
                            }
                        }
                        globalData.push(data[i]);
                        data.splice(i, 1); //删除该元素的第一级子节点,最多需删除三级
                    }
                }
            }
            if (!deletedFlag) { //这种情况下需要恢复该节点的子节点
                var nodeChildren = []; //存放本次恢复的数据,然后将它们从globalData中删除
                for (var n = globalData.length - 1; n >= 0; n--) {
                    if (params.data.id == globalData[n].category) { //显示该节点第一级子节点
                        data.push(globalData[n]);
                        nodeChildren.push(globalData[n]);
                        for (var nn = globalData.length - 1; nn >= 0; nn--) {
                            if (globalData[n].id == globalData[nn].category) { //显示该节点第二级子节点
                                data.push(globalData[nn]);
                                nodeChildren.push(globalData[nn]);
                                for (var nnn = globalData.length - 1; nnn >= 0; nnn--) {
                                    if (globalData[nn].id == globalData[nnn].category) { //显示该节点第三级子节点
                                        data.push(globalData[nnn]);
                                        nodeChildren.push(globalData[nnn]);
                                    }
                                }
                            }
                        }
                    }
                }
                if (nodeChildren.length > 0) {
                    for (var s = 0; s < nodeChildren.length; s++) {
                        for (var n = globalData.length - 1; n >= 0; n--) {
                            if (nodeChildren[s].id == globalData[n].id) {
                                globalData.splice(n, 1);
                            }
                        }
                    }
                }
            }
            myChart.setOption(option);
        }
    });
</script>
</body>
</html>

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 30
    评论
很抱歉,作为一个文本AI模型,我无法直接显示图片。但是,你可以通过以下步骤来获取Echarts关系图片: 1. 首先,你需要安装Echarts库。你可以在Echarts的官方网站(https://www.echartsjs.com/zh/index.html)上找到安装和使用文档。 2. 使用Echarts创建你想要的关系,并将其保存为图片。你可以使用Echarts提供的API和配置选项来定义表的样式和数据。 3. 保存关系图片Echarts提供了`echarts.convertToImage`方法,可以将关系转换为图片,并可以选择下载或保存。 以下是一个简单的示例代码,展示了如何使用Echarts创建一个关系并保存为图片: ```javascript // 引入Echarts库 import echarts from 'echarts'; // 创建一个关系实例 const chart = echarts.init(document.getElementById('chart-container')); // 配置关系的样式和数据 const option = { // 配置选项... series: [{ type: 'graph', // 数据... }] }; // 设置关系的配置项 chart.setOption(option); // 将关系转换为图片 chart.convertToImage({ type: 'png', // 图片类型 pixelRatio: 1, // 分辨率 backgroundColor: '#fff', // 背景颜色 }); // 保存关系图片 chart.saveAsImage('relation_chart.png'); ``` 请确保你已经正确安装了Echarts库,并在HTML文件中添加了一个具有唯一id的div元素(例如`<div id="chart-container"></div>`)作为关系的容器。 希望这能帮到你!如果你有任何其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值