RelationMap图谱--VUE,真实项目提供mock数据

news2024/11/28 6:48:14

RelationMap官网: 在线配置官网(可以把数据放进去,直接看效果)

VUE2 效果:左侧列表栏,点击右侧显示对应的图谱

代码:按照代码直接贴过去,直接出效果

relationMap/index.vue

<template>
  <div class="graphBody">
    <List :list="list" @select-Graph="getGraph" />
    <Graph v-if="showGraph" :key="graphItem.rootId" :item="graphItem" />
  </div>
</template>

<script lang="ts">
import { getUuid } from "@/utils/generateUuid";

import List from "./list/index.vue";
import Graph from "./graph/index.vue";
import mockInfo from "./mock.json";

export default {
  components: {
    List,
    Graph,
  },
  data() {
    return {
      list: [],
      showGraph: false,
      graphItem: {},
    };
  },
  methods: {
    initListData() {
      this.list = mockInfo.data;
    },
    getGraph(item) {
      const data = {
        id: getUuid(),
        name: item.globalVariable.name,
        DefineType: item.globalVariable.defineType,
        ActualType: item.globalVariable.actualType,
        children: [],
      };

      const graphMap = new Map();

      item.callFunction.forEach((item) => {
        item.call.forEach((call) => {
          const fileName = call.location.split("/").pop();
          const secondNode = {
            id: getUuid(),
            fileName: fileName,
            location: call.location,
            children: [],
          };

          const threeNode = {
            id: getUuid(),
            functionName: item.functionName,
            children: [
              {
                id: getUuid(),
                startRow: call.startRow,
                endRow: call.endRow,
                startColumn: call.startColumn,
                endColumn: call.endColumn,
                mode: call.mode,
              },
            ],
          };
          // 如果没有相同文件
          if (!graphMap.has(call.location)) {
            secondNode.children.push(threeNode);
            graphMap.set(call.location, secondNode);
          } else {
            const copy = graphMap.get(call.location);

            copy.children[0].children.push({
              id: getUuid(),
              startRow: call.startRow,
              endRow: call.endRow,
              startColumn: call.startColumn,
              endColumn: call.endColumn,
            });

            graphMap.set(call.location, copy);
          }
        });

        const valuesIterator = graphMap.values();
        const valuesArray = Array.from(valuesIterator);
        data.children.push(...valuesArray);
        graphMap.clear();
      });

      // 合并具有相同 location 属性的对象的 children 属性
      const mergedData = data.children.reduce((acc, obj) => {
        const existingObj = acc.find((item) => item.location === obj.location);
        if (existingObj) {
          existingObj.children = existingObj.children.concat(obj.children);
        } else {
          acc.push(obj);
        }
        return acc;
      }, []);
      const newValue = { ...data, children: mergedData };
      const { nodes, edges } = this.convertToNodesAndLines(newValue);
      const graphData = {
        rootId: newValue.id,
        nodes,
        lines: edges,
      };
      this.graphItem = graphData;
      if (this.graphItem) {
        this.showGraph = true;
      }
    },
    convertToNodesAndLines(data) {
      const treeToNode = (node, parentId) => {
        const result = [];
        const { children, ...nodeData } = node;
        result.push({
          id: node.id,
          text: node.id,
          data: nodeData,
        });
        if (node.children && node.children.length > 0) {
          node.children.forEach(
            (item) => {
              result.push(...treeToNode(item, node.id));
            }
          );
        }
        return result;
      };
      const nodeArray = treeToNode(data, data.id);
      const treeToEdge = (node) => {
        const links = [];
        if (node.children && node.children.length > 0) {
          node.children.forEach(
            (item) => {
              const to = item.id;
              const from = node.id;
              links.push({
                id: `${to}->${from}`,
                to,
                from,
              });
              links.push(...treeToEdge(item));
            }
          );
        }
        return links;
      };
      const edgeArray = treeToEdge(data);
      return { nodes: nodeArray, edges: edgeArray };
    },
  },
  mounted() {
    this.initListData();
  },
};
</script>

<style scoped>
.graphBody {
  height: 100%;
  border-radius: 4px;
  border: 1px solid #222529;
  background: #191c1f;
  display: flex;
}

::-webkit-scrollbar {
  display: block;
}

::-webkit-scrollbar-thumb {
  background: #393d45;
}
</style>

使用的方法util/generateUuid.js

import { v1 as uuidv1 } from 'uuid'

// 去除-携带时间戳-uuid
export function getUuid() {
  // const timestamp = new Date().getTime()
  // 生成UUID时去掉连字符
  const uuid = uuidv1().replace(/-/g, '')
  // 截取前8位作为8位UUID
  const eightDigitUuid = uuid.substring(0, 12)
  return `${eightDigitUuid}`
}

relationMap/graph/index.vue

<template>
  <div>
    <div id="relation-graph-container" class="graph-wrapper">
      <RelationGraph ref="graphRef" :options="graphOptions">
        <template slot="node" slot-scope="{ node }">
          <div
            :class="`node-container node-type`"
            @click="nodeClick(node.data)"
          >
            <span
              v-if="node.data?.DefineType || node.data?.ActualType"
              class="type-style"
            >
              <div class="type-title">{{ node.data.name }}</div>
              <div class="content word-hidden type-content">
                <p>DefineType: {{ node.data.DefineType }}</p>
                <p>ActualType: {{ node.data.ActualType }}</p>
              </div>
            </span>
            <span v-if="node.data?.location" class="file-style">
              <div class="file-title">
                <div>{{ node.data.fileName || node.data.name }}</div>
              </div>
              <div>
                <span class="content word-hidden file-path"
                  >路径: {{ node.data?.location }}</span
                >
              </div>
            </span>
            <div v-if="node.data?.functionName" class="function-style">
              <div>
                <span clsss="content word-hidden1"
                  >函数名:{{ node.data?.functionName }}</span
                >
              </div>
            </div>
            <div v-if="node.data?.startRow" class="rowRolumn-style">
              <span clsss="content word-hidden"
                >行号:{{ node.data?.startRow }} 列号:{{
                  node.data?.startColumn
                }}-{{ node.data?.endColumn }}</span
              ><span
                ><span
                  >【{{ node.data.mode === "read" ? "读取" : "写入" }}】</span
                ></span
              >
            </div>
          </div>
        </template>
      </RelationGraph>
    </div>
  </div>
</template>

<script>
import RelationGraph from "relation-graph";
import { set } from "vue";
export default {
  name: "Graph",
  components: {
    RelationGraph,
  },
  props: {
    item: Object,
  },
  data() {
    return {
      graphOptions: {
        backgroundImageNoRepeat: true,
        moveToCenterWhenRefresh: false,
        zoomToFitWhenRefresh: false,
        defaultNodeBorderWidth: 0,
        defaultNodeShape: 1,
        layouts: [
          {
            label: "中心",
            layoutName: "tree",
            from: "left",
          },
        ],
      },
    };
  },
  mounted() {
    this.$refs.graphRef.setJsonData(this.item, (graphInstance) => {});
  },
};
</script>
<style scoped>
.node-container {
  width: 240px;
  min-height: 40px;
  border-radius: 4px;
  background-color: #484750;
}

.type-style {
  height: 120px;
}

.type-title {
  color: #4880ff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 8px 12px;
  text-align: left;
  border-radius: 4px;
  border-bottom: 1px solid #383b3e;
}

.type-content {
  text-align: left;
  line-height: 22px;
  padding: 3px 6px;
}

.file-style {
  height: 120px;
  border-radius: 4px;
}

.file-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background-color: #387dff;
  padding: 8px 12px;
  text-align: left;
  border-radius: 4px;
}

.file-path {
  text-align: left;
  line-height: 22px;
  padding: 3px 6px;
}

.function-style {
  height: 40px;
  line-height: 40px;
  text-align: left;
  background: #aabee3;
  border-radius: 4px;
  padding: 0 4px;
  color: #000;
}

.rowRolumn-style {
  height: 40px;
  line-height: 40px;
  text-align: left;
  padding: 0 4px;
  border-radius: 2px;
}

.content {
  padding: 4px 2px 2px;
  width: 240px;
  align-items: left;
}

.word-hidden {
  word-break: break-all;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

.word-hidden1 {
  word-break: break-all;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
}
</style>
<style>
.graph-wrapper {
  height: calc(100vh - 160px);
  width: 1200px;
}

.c-current-zoom {
  color: #999999 !important;
}

.relation-graph .rel-map {
  background-color: #191c1f !important;
}

.relation-graph .rel-toolbar .c-mb-button:hover {
  background-color: rgba(153, 153, 153, 0.5) !important;
}

.relation-graph .rel-node-checked {
  width: 100% !important;
  box-shadow: 0 0px 5px 2px #191c1f !important;
}
</style>

relationMap/list/index.vue

该页面使用了虚拟滚动RecycleScroller,需要安装一下,参考文档: 虚拟滚动

安装: npm i vue-virtual-scroller

main.ts: 

  1. // vue virtual scroller

  2. import "vue-virtual-scroller/dist/vue-virtual-scroller.css" // 引入它的 css

  3. import VueVirtualScroller from "vue-virtual-scroller" // 引入它

  4. Vue.use(VueVirtualScroller) //

<template>
  <RecycleScroller
    class="scroller"
    :items="list"
    :item-size="36"
    key-field="id"
    v-slot="{ item }"
  >
    <div class="user" @click="selectGraph(item)">
      <span style="margin-left: 16px"> {{ item.globalVariable.name }}</span>
    </div>
  </RecycleScroller>
</template>

<script>
export default {
  props: {
    list: Array,
  },
  methods: {
    selectGraph(item) {
      this.$emit("select-Graph", item);
    },
  },
};
</script>

<style scoped>
.scroller {
  height: 800px;
  width: 240px;
}

.user {
  height: 36px;
  position: relative;
  display: flex;
  align-items: center;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: "Source Han Sans CN";
  font-size: 14px;
  font-style: normal;
  font-weight: 700;
  line-height: 20px; /* 142.857% */
}
.user:hover {
  background: #222529;
}
/* 在:hover状态下添加before伪类的样式 */
.user:hover::before {
  content: ""; /* 必须有content属性才能显示 */
  display: block;
  width: 3px;
  height: 36px;
  position: absolute;
  left: 0;
  top: 0;
  background-color: #4880ff;
}
</style>

mock.json 数据量太大了,这个页面放不下了,看这里:mock.json

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1670856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1W、2W 3KVAC隔离 宽电压输入 交直两用AC/DC 电源模块 ——TP01(02)AZ 系列

TP01(02)AZ为客户提供一款超小体积模块式开关电源&#xff0c;该系列模块电源输出功率为1W、2W&#xff0c;具有极低的空载损耗&#xff0c;低漏电流仅0.1mA&#xff0c;小体积&#xff0c;隔离耐压高达3KV等特点。产品安全可靠&#xff0c;EMC 性能好&#xff0c;EMC 及安全规…

MQTT 5.0 报文解析 04:PINGREQ 与 PINGRESP

欢迎阅读 MQTT 5.0 报文系列 的第四篇文章。在上一篇中&#xff0c;我们已经介绍了 MQTT 5.0 中的 SUBSCRIBE 报文和 UNSUBSCRIBE 报文。现在&#xff0c;我们将介绍用于维持连接的控制报文&#xff1a;PINGREQ 和 PINGRESP。 除了用于连接、发布和订阅的控制报文&#xff0c;…

【Linux基础】Vim保姆级一键配置教程(手把手教你把Vim打造成高效率C++开发环境)

目录 一、前言 二、安装Vim 三、原始Vim编译器的缺陷分析 四、Vim配置 &#x1f95d;预备知识----.vimrc 隐藏文件 &#x1f34b;手动配置 Vim --- &#xff08;不推荐&#xff09; &#x1f347;自动化一键配置 Vim --- (强烈推荐) ✨功能演示 五、共勉 一、前言 Vim作为…

半小时搞懂STM32面经知识——ADC

1.ADC 1.1 ADC是什么&#xff1f; 将连续变量的模拟信号转换为离散变量的数字信号 1.2 ADC的位数&#xff1f;&#xff08;采样精度&#xff09; F1和F4都具有3个ADC&#xff0c;F1可提供21个输入通道&#xff0c;F4可以提供24个输入通道。 F4的ADC支持12位&#xff0c;10位…

3W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP03AC 系列

TP03AC系列电源模块额定输出功率为3W&#xff0c;此系列产品输入电压范围宽&#xff0c;可以交直流两用。并具备高可靠性、高精度、更安全、更稳定&#xff0c;大功率密度&#xff0c;超小体积&#xff0c;无需外加散热器&#xff0c;输出电压稳定等特点&#xff0c;且均集成有…

代码大师的工具箱:现代软件开发利器

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

2024年可以做的网上兼职有哪些?10个正规赚钱软件平台分享

在数字化浪潮席卷全球的今天&#xff0c;兼职工作早已不再局限于传统的线下模式。只要有一部手机或电脑&#xff0c;你就能轻松开启兼职之旅&#xff0c;实现躺着也能赚钱的梦想&#xff01; 接下来&#xff0c;就让我们一起看看2024年那些靠谱又有趣的网上兼职项目吧&#xff…

制造业精益生产KPI和智慧供应链管理方案和实践案例分享

随着工业4.0的推进和国家对制造业高质量发展的重视&#xff0c;工业数据已跃升为生产经营活动中不可或缺的核心要素&#xff0c;同时&#xff0c;工业数据也是形成新质生产力的优质生产要素&#xff0c;助力企业实现高效精益生产。 工业数据在制造业中的作用不可忽视&#xff…

汇聚荣科技:拼多多开店时后期押金可以退吗?

在电商领域&#xff0c;拼多多以其独特的团购模式迅速崛起&#xff0c;吸引了众多商家入驻。对于这些商家而言&#xff0c;了解平台的各项费用政策尤为重要&#xff0c;其中押金的退还问题是大家关注的焦点之一。那么&#xff0c;拼多多开店时后期押金可以退吗?答案是肯定的。…

免费获取SSL证书的几种方法

免费获取SSL证书的方法有很多种&#xff0c;以下是一些常见的途径&#xff1a; 1、Lets Encrypt&#xff1a;Lets Encrypt是一个由非营利组织提供的免费SSL证书服务&#xff0c;其安装部署简单、方便&#xff0c;且已被Firefox、Chrome、IE等浏览器所支持。您可以通过其官方网…

基于SpringBoot+Vue的法律咨询系统

课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域的鸿沟&#xff0c;信息的传播速度极慢&#xff0c;信息处理的速…

【C++】命名空间、缺省参数、函数重载、引用

文章目录 1.认识命名空间2.命名空间的使用3.C的输入和输出4.缺省参数4.1缺省参数的概念4.2缺省参数的分类 5.函数重载6.引用6.1引用的概念6.2引用的特性6.3常引用(重点题目)6.4引用和指针的区别 1.认识命名空间 C总计63个关键字&#xff0c;C语言32个关键字 下面让我们学习一…

Ubuntu虚拟机上推荐一款免费好用的git版本管理工具

工具叫: gitg 软件界面如下&#xff1a; FR:徐海涛(hunkxu)

上海计算机学会2022年5月月赛C++丙组T3打印金字塔

题目描述 给定一个整数 n&#xff0c;请打印一个具有 n 层结构的三角形金字塔&#xff0c;例如当 n3 时&#xff0c;打印如下图形&#xff1a; /\ /__\/\ /\/__\/__\/\ /\ /\ /__\/__\/__\输入格式 单个整数&#xff1a;表示 n。 输出格式 根据题意输出层次为 n 的三角形…

祝贺嫦娥六号发射成功,思迈特再为航天项目提供数据支持和保障

近日&#xff0c;嫦娥六号由长征五号遥八运载火箭在中国文昌航天发射场发射成功。 据悉&#xff0c;嫦娥六号是中国探月工程的第六个探测器&#xff0c;其主要任务是前往月球背面的南极-艾特肯盆地进行科学探测和样品采集。 嫦娥六号任务不仅是技术上的挑战&#xff0c;也是科学…

图片转表格的免费软件,这几款值得收藏!

在数字化时代&#xff0c;图片转表格的需求日益增多。无论是工作汇报、数据分析还是学术研究&#xff0c;将图片中的信息转化为表格都能极大地提高工作效率。然而&#xff0c;许多人在面对这一任务时&#xff0c;往往感到无从下手。今天&#xff0c;我将为大家推荐几款免费的图…

【软件的安装与基本设置】AD21软件的基本设置

软件安装好以后&#xff0c;需要对软件进行一些基本设置&#xff0c;以方便原理图绘制和pcb设计时的操作&#xff0c;提高效率。 点击右上角的设置按钮 打开后包含以下设置&#xff0c;但是不是所有都需要设置&#xff0c;只是将需要用到的功能设置即可。 对于系统参数设置 第…

Kubernetes的Pod控制器深度解析

1.1 Pod控制器介绍 在Kubernetes中&#xff0c;Pod是最小的管理单元&#xff0c;用于运行容器。根据Pod的创建方式&#xff0c;可以将其分为两类&#xff1a; 自主式Pod&#xff08;Stateless Pods&#xff09;&#xff1a;这些Pod是直接由用户或管理员创建的&#xff0c;通常…

【JAVA入门】Day04 - 方法

【JAVA入门】Day04 - 方法 文章目录 【JAVA入门】Day04 - 方法一、方法的格式1.1 无参无返回值的方法定义和调用1.2 带参数的方法定义和调用1.3 形参和实参1.4 带返回值的方法定义和调用1.5 方法的注意事项 二、方法的重载三、方法的使用四、方法的内存原理4.1 方法调用的基本内…

深度学习技术之加宽前馈全连接神经网络

深度学习技术 加宽前馈全连接神经网络1. Functional API 搭建神经网络模型1.1 利用Functional API编写宽深神经网络模型进行手写数字识别1.1.1 导入需要的库1.1.2 加载虹膜&#xff08;Iris&#xff09;数据集1.1.3 分割训练集和测试集1.1.4 定义模型输入层1.1.5 添加隐藏层1.1…