vue插件——relation-graph——实现关系图功能——技能提升

最近在写后台管理系统时,遇到一个需求,就是要实现关系图:
如下图所示:
vue插件——relation-graph——实现关系图功能——技能提升_第1张图片
在前年写天眼查功能时,我也遇到过这种需求,不过当时不知道可以用插件来实现,因此功能并未完全开发:

vue插件——relation-graph——实现关系图功能——技能提升_第2张图片
直接上代码:

1.安装

1.1Npm 方式

npm i relation-graph

1.2Yarn方式

yarn add relation-graph

2.使用

<template>
   <div>
     <div style="height:calc(100vh - 50px);">
        <RelationGraph ref="seeksRelationGraph" :options="graphOptions" :on-node-click="onNodeClick" :on-line-click="onLineClick" />
     </div>
   </div>
 </template>

 <script>
 import RelationGraph from 'relation-graph'
 export default {
   name: 'Demo',
   components: { RelationGraph },
   data() {
     return {
       graphOptions: {
         allowSwitchLineShape: true,
         allowSwitchJunctionPoint: true,
         defaultJunctionPoint: 'border'
         // 这里可以参考"Graph 图谱"中的参数进行设置:http://relation-graph.com/#/docs/graph
       }
     }
   },
   mounted() {
     this.showSeeksGraph()
   },
   methods: {
     showSeeksGraph() {
       var __graph_json_data = {
         rootId: 'a',
         nodes: [
            // node配置选项:http://relation-graph.com/#/docs/node
            // node支持通过插槽slot完全自定义,示例:http://relation-graph.com/#/demo/adv-slot
           { id: 'a', text: 'A', borderColor: 'yellow' },
           { id: 'b', text: 'B', color: '#43a2f1', fontColor: 'yellow' },
           { id: 'c', text: 'C', nodeShape: 1, width: 80, height: 60 },
           { id: 'e', text: 'E', nodeShape: 0, width: 150, height: 150 }
         ],
         lines: [
            // link配置选项:http://relation-graph.com/#/docs/link
           { from: 'a', to: 'b', text: '关系1', color: '#43a2f1' },
           { from: 'a', to: 'c', text: '关系2' },
           { from: 'a', to: 'e', text: '关系3' },
           { from: 'b', to: 'e', color: '#67C23A' }
         ]
       }
       this.$refs.seeksRelationGraph.setJsonData(__graph_json_data, (seeksRGGraph) => {
         // Called when the relation-graph is completed 
       })
     },
     onNodeClick(nodeObject, $event) {
       console.log('onNodeClick:', nodeObject)
     },
     onLineClick(linkObject, $event) {
       console.log('onLineClick:', linkObject)
     }
   }
 }
 </script>

3.如果要需要展示鼠标移入后展示节点细节,则可以用下面的方式

<template>
  <a-spin :spinning="loading">
    <div
      style="height: calc(100vh - 130px); border: 1px solid #ebebeb"
      ref="myPage"
    >
      <RelationGraph
        ref="seeksRelationGraph"
        :options="graphOptions"
        :on-node-click="onNodeClick"
        :on-line-click="onLineClick"
      >
        <div
          slot="node"
          slot-scope="{ node }"
          style="height: 100%"
          @mouseover="showNodeTips(node, $event)"
          @mouseout="hideNodeTips(node, $event)"
        >
          <div
            style="
              border-radius: 50%;
              cursor: pointer;
              word-break: break-all;
              display: flex;
              justify-content: center;
              align-items: center;
              color: #fff;
              height: 100%;
              font-size: 12px;
              overflow: hidden;
            "
          >
            {{
              node.text &&
              node.text
                .replace('https://www.', '')
                .replace('http://www.', '')
                .replace('.com', '')
                .replace('.html', '')
                .split('/').length > 1
                ? node.text
                    .replace('https://www.', '')
                    .replace('http://www.', '')
                    .replace('.com', '')
                    .replace('.html', '')
                    .split('/')[
                    node.text
                      .replace('https://www.', '')
                      .replace('http://www.', '')
                      .replace('.com', '')
                      .replace('.html', '')
                      .split('/').length - 1
                  ]||node.text
                    .replace('https://www.', '')
                    .replace('http://www.', '')
                    .replace('.com', '')
                    .replace('.html', '')
                    .split('/')[
                    node.text
                      .replace('https://www.', '')
                      .replace('http://www.', '')
                      .replace('.com', '')
                      .replace('.html', '')
                      .split('/').length - 2
                  ]
                : node.text
            }}
          </div>
        </div>
        <!-- <div
          slot="bottomPanel"
          style="
            border-top: #efefef solid 1px;
            height: 60px;
            line-height: 60px;
            text-align: center;
            font-size: 18px;
            background-color: #ffffff;
          "
        >
          这里是底部插槽 slot="bottomPanel",可以自定义这里的内容
        </div> -->
      </RelationGraph>
    </div>
    <div
      v-if="isShowNodeTipsPanel"
      :style="{
        left: nodeMenuPanelPosition.x + 'px',
        top: nodeMenuPanelPosition.y + 'px',
      }"
      style="
        z-index: 999;
        padding: 10px;
        background-color: #ffffff;
        border: #eeeeee solid 1px;
        box-shadow: 0px 0px 8px #cccccc;
        position: absolute;
      "
    >
      <div
        style="
          line-height: 25px;
          padding-left: 10px;
          color: #888888;
          font-size: 12px;
        "
      >
        节点名称:{{ currentNode.text }}
      </div>
    </div>
  </a-spin>
</template>
<script>
import RelationGraph from 'relation-graph';
import { getRelationship } from '@/services/statistics';
export default {
  components: { RelationGraph },
  data() {
    return {
      loading: false,
      data: [],
      activeKey: '',
      src: '',
      isShowCodePanel: false,
      isShowNodeTipsPanel: false,
      nodeMenuPanelPosition: { x: 0, y: 0 },
      currentNode: {},
      graphOptions: {
        allowSwitchLineShape: true,
        allowSwitchJunctionPoint: true,
        layouts: [
          {
            label: '中心',
            layoutName: 'force', //布局方式(tree树状布局/center中心布局/force自动布局)
            layoutClassName: 'seeks-layout-center', //当使用这个布局时,会将此样式添加到图谱上
            defaultJunctionPoint: 'border', //默认的连线与节点接触的方式
            defaultNodeShape: 0, //默认的节点形状,0:圆形;1:矩形
            defaultLineShape: 1, //默认的线条样式(1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6)
            centerOffset_y: 130, //根节点y坐标偏移量(针对项目配置单位为px)
            min_per_width: 150, //节点距离限制:节点之间横向距离最小值
            min_per_height: 180, //节点距离限制:节点之间纵向距离最小值
          },
        ],
        defaultNodeShape: 0, //默认的节点形状,0:圆形;1:矩形
        defaultExpandHolderPosition: 'bottom', //节点展开关闭的按钮位置
        defaultLineShape: 1, //默认的线条样式(1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6)
        defaultJunctionPoint: 'tb', //默认的连线与节点接触的方式(border:边缘/ltrb:上下左右/tb:上下/lr:左右)当布局为树状布局时应使用tb或者lr,这样才会好看
        defaultNodeBorderWidth: 0.2, //节点边框粗细
        defaultcolor: 'rgba(0, 186, 189, 1)', //默认的线条颜色
        defaultNodeColor: 'rgba(0, 206, 209, 1)', //默认的节点背景颜色
        defaultNodeWidth: '80', //节点宽度
        defaultNodeHeight: '80', //节点高度
        defaultFocusRootNode: false, //默认为根节点添加一个被选中的样式
        moveToCenterWhenResize: true, //当图谱的大小发生变化时,是否重新让图谱的内容看起来居中
        // 这里可以参考"Graph 图谱"中的参数进行设置
      },
    };
  },
  activated() {
    this.showSeeksGraph();
  },
  methods: {
    showNodeTips(nodeObject, $event) {
      this.currentNode = nodeObject;
      const _base_position = this.$refs.myPage.getBoundingClientRect();
      this.isShowNodeTipsPanel = true;
      this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x + 10;
      this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y + 10;
    },
    hideNodeTips(nodeObject, $event) {
      this.isShowNodeTipsPanel = false;
    },
    callback(val) {
      this.activeKey = val;
      this.showSeeksGraph();
    },
    showSeeksGraph() {
      getRelationship().then((res) => {
        let nodes = res.node_list || [];
        let links = res.edge_list || [];
        var __graph_json_data = {
          rootId: '0',
          nodes: nodes,
          links: links,
        };
        // 以上数据中的node和link可以参考"Node节点"和"Link关系"中的参数进行配置
        this.$refs.seeksRelationGraph.setJsonData(
          __graph_json_data,
          (graphInstance) => {
            // Called when the relation-graph is completed
            setTimeout(() => {
              graphInstance.stopAutoLayout();
            }, 1000);
          }
        );
      });
    },
    onNodeClick(nodeObject, $event) {
      const allLinks = this.$refs.seeksRelationGraph.getLinks();
      allLinks.forEach((link) => {
        // 还原所有样式
        link.relations.forEach((line) => {
          if (line.data.orignColor) {
            line.color = line.data.orignColor;
          }
          if (line.data.orignFontColor) {
            line.fontColor = line.data.orignColor;
          }
          if (line.data.orignLineWidth) {
            line.lineWidth = line.data.orignLineWidth;
          }
        });
      });
      // 让与{nodeObject}相关的所有连线高亮
      allLinks
        .filter(
          (link) => link.fromNode === nodeObject || link.toNode === nodeObject
        )
        .forEach((link) => {
          link.relations.forEach((line) => {
            line.data.orignColor = line.color;
            line.data.orignFontColor = line.fontColor || line.color;
            line.data.orignLineWidth = line.lineWidth || 1;
            line.color = '#ff0000';
            line.fontColor = '#ff0000';
            line.lineWidth = 3;
          });
        });
      // 有时候更改一些属性后,并不能马上同步到视图,这需要以下方法让视图强制根据数据同步到最新
      this.$refs.seeksRelationGraph.getInstance().dataUpdated();
    },
    onLineClick(lineObject, $event) {
      console.log('onLineClick:', lineObject);
      // this.$notify({
      //   title: '点击连线:',
      //   type: 'success',
      //   message: '点击了线:' + linkObject.fromNode.text + ' to ' + linkObject.toNode.text
      // });
    },
  },
};
</script>
<style lang="less" scoped>
.c-my-node2 {
  border: none;
  background-position: center center;
  background-size: 100%;
  height: 74px;
  width: 74px;
  border-radius: 40px;
}
.c-node-name2 {
  width: 160px;
  margin-left: -40px;
  text-align: center;
  margin-top: 85px;
  position: absolute;
}
.c-node-menu-item {
  line-height: 30px;
  padding-left: 10px;
  cursor: pointer;
  color: #444444;
  font-size: 14px;
  border-top: #efefef solid 1px;
}
.c-node-menu-item:hover {
  background-color: rgba(66, 187, 66, 0.2);
}
</style>

你可能感兴趣的:(relationn-graph,vue插件关系图,关系图,vue.js,javascript,前端)