关系图组件库 Relation Graph

2,008 阅读1分钟

github.com/seeksdream/… github地址

relation-graph.com/#/docs/star… 文档地址

使用Vue + Relation Graph 基于这个组件库实现了一个类似于企查查的人物关系图谱

组件效果

Video_2022-10-19_144424.gif

Vue 代码

<template>
  <div>
    <div style="height:calc(100vh - 50px);">
      <SeeksRelationGraph
        ref="seeksRelationGraph"
        :options="graphOptions"
        :on-node-click="onNodeClick"
        :on-line-click="onLineClick"
      >
        <div @mouseleave="onNodeMouseLeave(node,$event)" @mouseenter="onNodeMouseenter(node,$event)" class="slot_node" slot="node" slot-scope="{node}">
          <div class="node_content">
            {{ node.data.name }}
          </div>
        </div>
      </SeeksRelationGraph>
    </div>
  </div>
</template>

<script>
import SeeksRelationGraph from 'relation-graph'
import tree from "@/utils/tree.js";

export default {
  name: 'erdas',
  components: {SeeksRelationGraph},
  data() {
    return {
      isShowCodePanel: false,
      graphOptions: {
        defaultFocusRootNode: true,//默认选中根节点
        defaultNodeWidth: 120,//默认节点宽度
        defaultNodeHeight: 120,//默认节点高度
        defaultNodeBorderWidth: 0,
        defaultNodeColor: '#3ebde2',//默认圆背景色
        allowSwitchLineShape: true,
        allowSwitchJunctionPoint: true,
        defaultLineShape: 1,
        defaultLineWidth: 1, //默认线条粗细
        'layouts': [
          {
            'label': '中心',
            'layoutName': 'center',
            'layoutClassName': 'seeks-layout-center'
          }
        ],
        defaultJunctionPoint: 'border'
        // 这里可以参考"Graph 图谱"中的参数进行设置
      },
      processed_object: {
        nodes: [], //节点数据
        rootId: '',//rootId
        links: [],//线条数据
      },
    }
  },
  mounted() {
    this.showSeeksGraph()
  },
  methods: {
    getDictLabel(dict, value) {
      return tree.getDictLabel(dict, value)
    },
    onNodeMouseLeave(nodeObject, $event) {
      //遍历节点 恢复样式
      let id = nodeObject.id;
      nodeObject.width = this.graphOptions.defaultNodeWidth;
      nodeObject.height = this.graphOptions.defaultNodeHeight;
      let line_s = this.$refs.seeksRelationGraph.getLines();
      line_s.map(v => {
        if (v.fromNode.id === id || v.toNode.id === id) {
          v.relations.forEach(x => {
            x.lineWidth = this.graphOptions.defaultLineWidth
            x.styleClass = '';
          })
        }
      })
    },
    onNodeMouseenter(nodeObject, $event) {
      //遍历节点 找到归属的线条 加粗线条 放大节点
      let id = nodeObject.id;
      nodeObject.width = this.graphOptions.defaultNodeWidth + 30;
      nodeObject.height = this.graphOptions.defaultNodeHeight + 30;
      let line_s = this.$refs.seeksRelationGraph.getLines();
      line_s.map(v => {
        if (v.fromNode.id === id || v.toNode.id === id) {
          v.relations.forEach(x => {
            x.lineWidth = 3
            x.styleClass = 'cg_line_fake';
          })
        }
      })
    },
    getLineColor(dict, value) {
      return tree.find((dict || []), value, 'dictValue')?.dictColor || value
    },
    showSeeksGraph(query) {
      //关系类型(00表示参股,01表示法人,02表示经理,03表示执行董事,04表示监事,99表示其他) 字典模拟
      let dict_list = [
        {
          dictCode: '0',
          dictValue: '00',
          dictLabel: '参股',
          dictColor: '#f47349',
        },
        {
          dictCode: '01',
          dictValue: '01',
          dictLabel: '法人',
          dictColor: '#d0e3a0',
        },
        {
          dictCode: '02',
          dictValue: '02',
          dictLabel: '经理',
        },
        {
          dictCode: '03',
          dictValue: '03',
          dictLabel: '执行董事',
          dictColor: ' #99cee0',
        },
        {
          dictCode: '04',
          dictValue: '04',
          dictLabel: '监事',
        },
        {
          dictCode: '05',
          dictValue: '99',
          dictLabel: '其他',
        },
      ]
      //模拟 后台请求的数据 根据类型处理颜色
      let colors_bg = {
        '0': '#0183fe',//nodeType为企业时的背景颜色
        '1': '#f25a29',//nodeType为个人时节点的背景颜色
      }
      //mock数据 根据 Yapi文档格式的原数据
      let __mock_json_data = {
        rootId: '2', //根节点
        nodes: [
          {
            nodeCode: '1', nodeType: '1', nodeName: '章泽天', relations: [
              {begin: '1', end: '2', relationType: '01'},
              {begin: '1', end: '2', relationType: '00'},
              {begin: '1', end: '8', relationType: '00'},
              {begin: '1', end: '4', relationType: '00'},
              {begin: '1', end: '3', relationType: '00'},
            ]
          },
          {nodeCode: '2', nodeName: '北京天强坤泰投资管理有限公司', nodeType: '0'},
          {nodeCode: '3', nodeName: '海南三亚天博产业私募基金管理有限公司', nodeType: '0'},
          {nodeCode: '4', nodeName: '三亚天强企业管理合伙企业(有限合伙)', nodeType: '0'},
          {nodeCode: '6', nodeName: '上海京东才奥电子商务有限公司', nodeType: '0'},
          {
            nodeCode: '7', nodeName: '刘强东',nodeType:1, relations: [
              {begin: '7', end: '8', relationType: '00'},
              {begin: '7', end: '6', relationType: '00'},
              {begin: '7', end: '4', relationType: '00'},
              {begin: '7', end: '4', relationType: '01'},
              {begin: '7', end: '3', relationType: '00'},
              {begin: '7', end: '2', relationType: '00'},
              {begin: '7', end: '2', relationType: '01'},
              {begin: '7', end: '2', relationType: '03'},
            ]
          },
          {nodeCode: '8', nodeName: '宿迁天强股权投资合伙企业(有限合伙)', nodeType: '0'},
        ],
      }
      //links数组临时存储
      let links_temp = [];
      //rooId存储
      this.processed_object.rootId = __mock_json_data.rootId;
      //将上面的数据处理成组件需要的数据格式
      this.processed_object.nodes = __mock_json_data.nodes.map(x => {
        x.id = x.nodeCode;
        x.name = x.nodeName;
        x.color = colors_bg[x.nodeType]; //背景色处理
        //根节点处理 宽度放大
        // if (x.nodeCode === __mock_json_data.rootId) {
        //   x.width = 150;
        //   x.height = 150;
        // }
        //将有节点映射关系的节点进行聚集处理成links
        if (x.relations && x.relations.length) {
          x.relations.map(v => {
            v.from = x.nodeCode;
            v.to = v.end;
            v.lineWidth = 1;
            v.text = this.getDictLabel(dict_list, v.relationType)//线条标签名处理
            v.color = this.getLineColor(dict_list, v.relationType) //线条颜色处理
            links_temp.push(v);//插入数据
          });
        }
        x.data = JSON.parse(JSON.stringify(x)); //自定义节点需要
        return x;
      })

      //赋值
      this.processed_object.links = links_temp;
      //不可以直接传入this.processed_object
      let JSON_FORMAT = JSON.parse(JSON.stringify(this.processed_object))
      this.$refs.seeksRelationGraph.setJsonData(JSON_FORMAT, (seeksRGGraph) => {
        // 这些写上当图谱初始化完成后需要执行的代码
      })
    },
    onNodeClick(nodeObject, $event) {
      //重置options
      // this.$refs.seeksRelationGraph.setJsonData(data)
    },
    onLineClick(lineObject, $event) {
      // console.log('onLineClick:', lineObject)
    }
  }
}
</script>

<style lang="scss">

</style>

<style lang="scss" scoped>
::v-deep {
  //线条上的文字大小
  .c-rg-link-text {
    font-size: 18px;
  }
  //线条默认改为虚线
  .c-rg-line{
    stroke-dasharray:5;
  }

  .cg_line_fake{
    stroke-dasharray:none ;
  }

  //整体
  .slot_node {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  //内容
  .node_content{

  }
}
</style>

组件效果