vue用vis插件如何实现网络拓扑图

目录
  • vis插件实现网络拓扑图
    • 安装引入vis
    • vis使用示例
    • vis官方文档
  • vis.js网络拓扑图点击折叠节点和展开节点
    • 首先看一下效果图

vis插件实现网络拓扑图

安装引入vis

1.npm安装vis

npm install vis

2.引入vis

import { DataSet, Network } from 'vis';

vis使用示例

methods:{
   globalTrace () {
      // create an array with nodes
      var nodes = new DataSet([
        {id: 1, label: 'Node 1'},
        {id: 2, label: 'Node 2'},
        {id: 3, label: 'Node 3'},
        {id: 4, label: 'Node 4'},
        {id: 5, label: 'Node 5'}
      ]);
      // create an array with edges
      var edges = new DataSet([
        {from: 1, to: 3},
        {from: 1, to: 2},
        {from: 2, to: 4},
        {from: 2, to: 5}
      ]);
      // create a network
      var container = document.querySelector('#global_trace_content');
      // provide the data in the vis format
      var data = {
          nodes: nodes,
          edges: edges
      };
      var options = {
      	//节点样式
        nodes: {
          shape: "box",//设置节点node样式为矩形
          fixed:true,//节点node固定不可移动
          font: {
			color: "white", //字体的颜色
			size: 30 //显示字体大小
		  },
          scaling: {
			min: 16,
			max: 32 //缩放效果比例
		  },
        },
        //连接线的样式
        edges: {
          color: {
            color: "rgb(97, 168, 224)",
            highlight: "rgb(97, 168, 224)",
            hover: "green",
            inherit: "from",
            opacity: 1.0
          },
          font: {
            align: "top",//连接线文字位置
          },
          smooth: true, //是否显示方向箭头
          arrows: {to : true },//箭头指向from节点
        },
        layout: {
        //以分层方式定位节点
          hierarchical: {
            direction: "LR",//分层排序方向
            sortMethod: "directed",//分层排序方法
            levelSeparation:400//不同级别之间的距离
          },
        },
        interaction: {
          navigationButtons: true,
          // hover: true, //鼠标移过后加粗该节点和连接线
          selectConnectedEdges: false, //选择节点后是否显示连接线
        },

      };
      // initialize your network!
      this.network = new Network(container, data, options);
      this.network.on("click",e=> this.showDetail(e));//单击事件
      this.network.on("doubleClick",e=> this.enterService(e))//双击事件
    },
},
mounted(){
	this.globalTrace()
}

vis官方文档

使用文档

官方示例

vis.js网络拓扑图点击折叠节点和展开节点

首先看一下效果图

1.数据中要添加的属性如下图所示:

2.数据中添加入上图属性后,添加点击事件即可,代码如下:

//todo 双击时折叠和展开
    network.on("doubleClick", function(params) {//双击事件
        if (params.nodes.length != 0) {//确定为节点双击事件
            var click_node_id = params.nodes[0];
            remove_all_sub_nodes(click_node_id);
        }
    });

    //todo 删除下级所有节点
    function remove_all_sub_nodes(node_id) {
        var sub_nodes = get_directly_sub_nodes(node_id);
        // console.log('sub_nodes',sub_nodes)
        if (sub_nodes.length == 0) {//当前点击的为叶子节点
            //判断是否有下级节点
            // console.log('sub',allNodes[node_id - 1]['subids']);
            if (typeof (allNodes[node_id - 1]['subids']) != 'undefined') {
                $.each(allNodes[node_id - 1]['subids'], function(index, item) {
                    // console.log('allNodes[item - 1]',allNodes[item - 1])
                    nodes.add(allNodes[item - 1]);
                    edges.add({id: node_id + '_' + item, from: node_id, to: item});
                });
            } else {
                alert('当前为叶子节点');
            }
        } else {
            $.each(sub_nodes, function(index, item) {
                var sub_sub_nodes = get_directly_sub_nodes(item);
                if (sub_sub_nodes.length == 0) {
                    nodes.remove({id: item});
                    edges.remove({id: node_id + '_' + item});
                } else {
                    remove_all_sub_nodes(item);
                }
                nodes.remove({id: item});
                edges.remove({id: node_id + '_' + item});
            });
        }
    }

    //todo 获取某节点直属下级节点
    function get_directly_sub_nodes(node_id) {
        var return_nodes = [];
        var connectedNodes = network.getConnectedNodes(node_id);//获取所有连接节点
        $.each(connectedNodes, function(index, item) {
            // console.log('allNodes',allNodes)
            if (item != allNodes[node_id - 1]['pid']) {//当前节点的父节点 ,不操作
                return_nodes.push(item);
            }
        });
        return return_nodes;
    }

3.完整代码如下:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vis.js</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="external nofollow"  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="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
    <!--<script type="text/javascript" src="js/vis-network.min.js"></script>-->
    <style type="text/css">
        #mynetwork {
            width: 600px;
            height: 600px;
            border: 1px solid lightgray;
        }
        *{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 solid #ffffff;
            font-size: 14px;
            cursor: pointer;
            list-style: none;
        }
        .menu ul li:hover{
            color: #659bc5;
        }
        .menu ul li:last-child{
            border-bottom: none;
            padding: 5px 10px 0 10px;
        }
    </style>
</head>
<body>
<div id="mynetwork"></div>
<!--菜单操作-->
<div id="menuOperation" 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>
<!--节点悬停-->
<div class="menu" id="divHoverNode" style="display: none;">
    <!--<ul></ul>-->
</div>
<script type="text/javascript">
    // 创建节点数据数组
    var allNodes = [
        {id: 1,name: "外部网络",type: "Internet",ip:"1.1.1.1",port:"未知",pid:0,subids: [2]},
        {id: 2,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",pid:1, subids: [3, 4, 5, 6]},
        {id: 3,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",pid: 2,subids: [7, 8]},
        {id:4,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",pid: 2},
        {id:5,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",pid: 2},
        {id:6,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",pid:2},
        {id:7,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",pid: 3},
        {id:8,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",pid:3}
    ];
    // 创建边数据数组
    var allEdges = [
        { id:"1_2",from: 1, to: 2 },
        { id:"2_3",from: 2, to: 3 },
        { id:"2_4",from: 2, to: 4 },
        { id:"2_5",from: 2, to: 5 },
        { id:"2_6",from: 2, to: 6 },
        { id:"3_7",from: 3, to: 7 },
        { id:"3_8",from: 3, to: 8 }
    ];
    /**
     * 自定义图片
     */
    for (var i = 0;i < allNodes.length;i++){
        if (allNodes[i].type == 'Internet'){
            allNodes[i].image = 'image/internet.png';
        }
        if (allNodes[i].type == 'switch'){
            allNodes[i].image = 'image/switch.png';
        }
        if (allNodes[i].type == 'hub'){
            allNodes[i].image = 'image/hub.png';
        }
        if (allNodes[i].type == 'computer'){
            allNodes[i].image = 'image/computer.png';
        }
        if (allNodes[i].type == 'rooter'){
            allNodes[i].image = 'image/rooter.png';
        }
        if (allNodes[i].type == 'service'){
            allNodes[i].image = 'image/service.png';
        }
        if (allNodes[i].type == 'print'){
            allNodes[i].image = 'image/print.png';
        }
        if (allNodes[i].type == 'phone'){
            allNodes[i].image = 'image/phone.png';
        }
    }
    // 获取容器
    var container = document.getElementById('mynetwork');
    // 创建节点对象
    var nodes = new vis.DataSet(allNodes);
    // 创建连线对象
    var edges = new vis.DataSet(allEdges);
    // 将数据赋值给vis 数据格式化器
    var data = {
        nodes: nodes,
        edges: edges
    };
    console.log('nodes',data.nodes);

    var options = {
        nodes:{
            shape: 'image'//设置图片
            // image:"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599645215703&di=0cb23e74736a6a1222f35b822f5bf833&imgtype=0&src=http%3A%2F%2Fa1.att.hudong.com%2F05%2F00%2F01300000194285122188000535877.jpg"
        },
        interaction:{
            hover:true,
            hoverConnectedEdges: true
        },
        layout: {
            //树形
            // hierarchical: {direction: 'UD', sortMethod: 'hubsize'}
        },
    };

    // 初始化关系图
    var network = new vis.Network(container, data, options);

    /**
     * 节点鼠标悬停(点击)获取到的信息
     * 因为hoverNode事件官方文档中给的信息悬停时只传了id值,想在鼠标悬停的时候显示该节点的信息拿不到值,所以遍历节点,相等的时候return改节点的信息
     * @param option-----鼠标悬停时取得的id
     * @returns {{flag, port, ip, name, ignore, id, type}|{flag, port, ip, name, ignore, model, id, type, mac, uptime}|{flag, port, ip, name, ignore, model, location, id, type, mac, account, uptime}|*}
     */
    function getNode(option) {
        for (var i = 0;i < allNodes.length;i++){
            if (option == allNodes[i].id){
                // console.log('i',allNodes[i]);
                return allNodes[i];
            }
        }
    }
    /**
     * 线悬停(点击)时两端节点的信息(与节点类似)
     * edges中加了id属性,代表线条指向,悬停时通过edges--id与nodes--id对比,将两端节点信息拼凑出来
     * @param option----鼠标悬停在线上时取得的id
     * @returns {Array}
     */
    function getEdge(option){
        var linkId = option;
        var linkIdFirst = linkId.substring(0,1);//截取第一位
        var linkIdLast = linkId.substring(linkId.length-1,linkId.length);//截取最后一位
        var dataList = [];//存放线条两边的节点nodes数据
        for (var j =0;j<allNodes.length;j++){
            if (linkIdFirst == allNodes[j].id || linkIdLast == allNodes[j].id){
                dataList.push(allNodes[j]);
            }
        }
        return dataList;
    }
    //todo  悬停在节点上--显示弹框
    network.on('hoverNode',function(properties){
        // console.log('悬停节点',properties);
        var hoveNodeList = getNode(properties.node);
        // console.log('hoveNodeList',hoveNodeList);
        var deviceType = hoveNodeList.type;
        var imgPathSrc = hoveNodeList.image;
        if (deviceType == "Internet" || deviceType == "hub"){
            var $ul = "<ul>"
                +"<li><img src=' "+imgPathSrc+" ' width='30px' height='25px'><span> "+hoveNodeList.name+" </span> </li>"
                +"</ul>";
            $("#divHoverNode").append($ul);
        }
        else if (deviceType == "switch"){
            var $ul = "<ul>"
                +"<li><img src=' "+imgPathSrc+" ' width='30px' height='25px'><span> 设备类型: "+hoveNodeList.name+" </span> </li>"
                +"<li>IP:"+ hoveNodeList.ip+"</li>"
                +"<li>MAC:"+ hoveNodeList.mac+"</li>"
                +"<li>设备型号:"+ hoveNodeList.model+"</li>"
                +"</ul>";
            $("#divHoverNode").append($ul);
        }else{
            var $ul = "<ul>"
                +"<li><img src=' "+imgPathSrc+" ' width='30px' height='25px'><span> 设备类型:"+hoveNodeList.name+" </span> </li>"
                +"<li>IP:"+ hoveNodeList.ip+"</li>"
                +"<li>MAC:"+ hoveNodeList.mac+"</li>"
                +"<li>账号:"+ hoveNodeList.account+"</li>"
                +"<li>所在位置:"+ hoveNodeList.location+"</li>"
                +"<li>最后登录时间:"+ hoveNodeList.uptime+"</li>"
                +"</ul>";
            $("#divHoverNode").append($ul);
        }
        $('#divHoverNode').css({
            'display': 'block',
            'left': properties.event.offsetX + 15,
            'top' : properties.event.offsetY + 15
        });
        $('#menuOperation').hide();
    });
    //todo  从节点移开---隐藏弹框
    network.on('blurNode',function(){
        $("#divHoverNode").hide();
        $("#divHoverNode").empty();//移除之后清空div
    });
    //todo  悬停在边上--显示弹框
    network.on('hoverEdge',function(properties){
        // console.log('悬停边',properties);
        var hoveEdgeList = getEdge(properties.edge);
        // console.log('hoveEdgeList',hoveEdgeList);
        var $ul = "<ul>"
            +"<li>名称:"+ hoveEdgeList[0].name+"->"+hoveEdgeList[1].name+"</li>"
            +"<li>端口号:"+ hoveEdgeList[0].ip+"->"+hoveEdgeList[1].ip+"</li>"
            +"</ul>";
        $("#divHoverNode").append($ul);
        $('#divHoverNode').css({
            'display': 'block',
            'left': properties.event.offsetX + 15,
            'top' : properties.event.offsetY + 15
        });
        $('#menuOperation').hide();
    });
    //todo  从边上移开---隐藏弹框
    network.on('blurEdge',function(properties){
        $("#divHoverNode").hide();
        $("#divHoverNode").empty();//移除之后清空div
    });
    //todo  点击的判断是否选中节点时候显示隐藏
    network.on('click',function(properties){
        var clickNodeList = getNode(properties.nodes[0]);
        // console.log('clickNodeList',clickNodeList);
        if (typeof(clickNodeList) == "undefined") {
            $('#menuOperation').hide();
        }else{
            $('#menuOperation').css({
                'display': 'block',
                'left': properties.event.center.x + 15,
                'top' : properties.event.center.y + 15
            });
            $("#divHoverNode").hide();
        }
    });
    //todo 双击时折叠和展开
    network.on("doubleClick", function(params) {//双击事件
        if (params.nodes.length != 0) {//确定为节点双击事件
            var click_node_id = params.nodes[0];
            remove_all_sub_nodes(click_node_id);
        }
    });
    //todo 删除下级所有节点
    function remove_all_sub_nodes(node_id) {
        var sub_nodes = get_directly_sub_nodes(node_id);
        // console.log('sub_nodes',sub_nodes)
        if (sub_nodes.length == 0) {//当前点击的为叶子节点
            //判断是否有下级节点
            // console.log('sub',allNodes[node_id - 1]['subids']);
            if (typeof (allNodes[node_id - 1]['subids']) != 'undefined') {
                $.each(allNodes[node_id - 1]['subids'], function(index, item) {
                    // console.log('allNodes[item - 1]',allNodes[item - 1])
                    nodes.add(allNodes[item - 1]);
                    edges.add({id: node_id + '_' + item, from: node_id, to: item});
                });
            } else {
                alert('当前为叶子节点');
            }
        } else {
            $.each(sub_nodes, function(index, item) {
                var sub_sub_nodes = get_directly_sub_nodes(item);
                if (sub_sub_nodes.length == 0) {
                    nodes.remove({id: item});
                    edges.remove({id: node_id + '_' + item});
                } else {
                    remove_all_sub_nodes(item);
                }
                nodes.remove({id: item});
                edges.remove({id: node_id + '_' + item});
            });
        }
    }
    //todo 获取某节点直属下级节点
    function get_directly_sub_nodes(node_id) {
        var return_nodes = [];
        var connectedNodes = network.getConnectedNodes(node_id);//获取所有连接节点
        $.each(connectedNodes, function(index, item) {
            // console.log('allNodes',allNodes)
            if (item != allNodes[node_id - 1]['pid']) {//当前节点的父节点 ,不操作
                return_nodes.push(item);
            }
        });
        return return_nodes;
    }
</script>
</body>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Vue snippets插件原理与使用介绍

    目录 vue-snippets snippets是什么 vue-3-snippets插件支持的功能 vue-snippets 随着开发者的年限的增加,不仅头发有点少,重复的代码也不断的增多,为了能够少写代码,GitHub友好的给我们提供了智能代码提示,而我们也以友好的方式赞助它,当然也有很多开发者写了类似的插件. 那我为什么要写呢? 我想要有适合自己的代码片段,同时也支持更多的代码片段,更加方便开发者快速使用. snippets是什么 snippets简单来说就是代码片段,比如你想实现下面这段代

  • Vue混入与插件的使用介绍

    目录 1. 混入 2. 插件 1. 混入 概述: 混入(mixins)是一种分发Vue组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项.当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项. 简单来说,混入用于公共代码复用. 混入分为:全局和局部. 混入的执行顺序: <div id="app"> <h3>{{name}}</h3> <hr> <h3>{{showName}}</h3> &l

  • 使用vue插件axios传数据的Content-Type及格式问题详解

    目录 1.一般来说,前后台对接,常用的Content-Type有: 2.get请求 3.post请求 1.一般来说,前后台对接,常用的Content-Type有: application/json,application/x-www-form-urlencoded 以及 multipart/form-data,当我们使用axios时,一般不需要我们主动去设置Content-Type,而是跟着我们传的数据格式自动适应. 2.get请求 get请求时传递的参数是会出现在url里面的,我们使用aixo

  • vue用vis插件如何实现网络拓扑图

    目录 vis插件实现网络拓扑图 安装引入vis vis使用示例 vis官方文档 vis.js网络拓扑图点击折叠节点和展开节点 首先看一下效果图 vis插件实现网络拓扑图 安装引入vis 1.npm安装vis npm install vis 2.引入vis import { DataSet, Network } from 'vis'; vis使用示例 methods:{ globalTrace () { // create an array with nodes var nodes = new D

  • vue 集成 vis-network 实现网络拓扑图的方法

    vis.js  网站 https://visjs.org/ vs  code 下安装命令 npm install vis-network 在vue  下引入 vis-network组件 const vis = require("vis-network/dist/vis-network.min.js"); require("vis-network/dist/vis-network.min.css"); 例子代码使用 let DIR = "/jtopo/&qu

  • vue 代码高亮插件全面对比测评

    全面对比 从活跃方面来看 从功能方面来看 代码高亮是必须的,社区必须活跃,不然修复bug没有一点点参考,太费时间.自动补全缩进,快捷键操作,搜索和替换等功能不是必须的,如果有,能拿来装逼当然最好,不能也不影响使用. 故而挑出了以下几个,再具体分析,逐个调查,查看后续开发,部署的坑,坑少方便的就被我选中. 深入对比 1,ace Ace是一个用JavaScript编写的嵌入式代码编辑器.它与Sublime,Vim和TextMate等原生编辑器的功能和性能相匹配.它可以很容易地嵌入到任何网页和Java

  • vue引入swiper插件的使用实例

    本文介绍了vue引入swiper插件,分享给大家,希望对大家有帮助 步骤一:安装vue, $ npm install vue 步骤二:创建vue项目 # 全局安装 vue-cli $ npm install -g vue-cli $ cd my-project $ npm install $ npm run dev 上面这些就是安装好vue项目,最主要的就是下面的步骤 步骤三:下载好swiper相关的js和css,js放在static目录下,css放在assets目录下. 步骤四:  安装run

  • vue引入jq插件的实例讲解

    今天做官网,把unslider做成指令,但是一直提示$(el).unslider() no a function,一开始我想复杂了,后来在网上看了很多帖子,大多数都是修改webpack.base.config.js,仔细尝试,网上确实是对的,尝试过程中,提醒大家最好把这3个加全,比如unslider插件,(function(){})(window.jQuery) { jQuery: "jquery", "window.jQuery": "jquery&qu

  • Vue.js devtool插件安装后无法使用的解决办法

    初次使用Vue.js devtool插件的新人在安装了Vue.js devtool插件后,都会经常有一个疑问.我在chrome浏览器里面已经成功安装好Vue.js devtool插件,怎么点击后提示vue.js not detected,无法正常使用呢?对于这样的问题,新人可能会花费很多时间去找答案,今天我们就来整理了解决方法,希望对大家有帮助. 首先,我们先要确保Vue.js devtool插件已经安装成功了.具体的Vue.js devtool插件的安装方法可以:chrome插件CRX的离线安

  • 基于Vue渲染与插件的加载顺序的问题详解

    Vue实践分享(三)在实际项目的开发过程中,经常会遇到页面还没渲染完成而插件就已经开始加载的问题,这样就会导致显示和功能出错. 可以通过Vue中的nextTick来解决 Vue.nextTick(function() { //widget }); 这样就会在页面渲染完成后再执行nextTick内的插件 以上这篇基于Vue渲染与插件的加载顺序的问题详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们. 您可能感兴趣的文章: 浅谈Vue的加载顺序探讨 Vue.js学习教程

  • Vue瀑布流插件的使用示例

    我自己写的一个的Vue瀑布流插件,列数自适应,不用设置每个卡片的高度. 测试页面:Page.vue 模板页面:WaterFollow.vue 和 WFColumn.vue 在Page.vue中,修改itemW的值,设置每列的最小宽度.例如:itemW="200"(意为200px).list为数组.高度不用设置,:style="{height:item+'px'}"是我为了创造卡片高度加上去的,不加就显示卡片的原来大小. 经测试,created加载数据正常,mount

  • vue的滚动条插件实现代码

    这篇文章主要介绍了vue的滚动条插件实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 效果如下 代码如下 <template> <div class="vue-scroll" ref="vueScrollW"> <div class="vue-scroll-w" ref="vueScroll" > <div class=&quo

  • vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单

    今天分享的不是技术,今天给大家分享个插件,针对现有的vue右键菜单插件,大多数都是需要使用插件本身自定义的标签,很多地方不方便,可扩展性也很低,所以我决定写了一款自定义指令调用右键菜单(vuerightmenu) 安装  npm install rightmenu --save-dev   开始 //main.js import vue from "vue"; import rightMenu from "rightMenu"; vue.use(rightMenu)

随机推荐