@antv/g6 的使用

383 阅读3分钟

20240228-102825.gif

<template>
  <div id="G6index" ref="G6index">
    <div class="G6indexBox">
      <div class="container" id="container"></div>
    </div>
  </div>
</template>

<script>
import G6 from '@antv/g6'
export default {
  name: 'G6index',
  data() {
    return {
      data: {
        nodes: [
          {
            id: 'node1',
            label: 'Circle1'
          },
          {
            id: 'node2',
            label: 'Circle2'
          },
          {
            id: 'node3',
            label: 'Circle3'
          },
          {
            id: 'node4',
            label: 'Circle4'
          },
          {
            id: 'node5',
            label: 'Circle5'
          },
          {
            id: 'node6',
            label: 'Circle6'
          }
        ],
        edges: [
          {
            source: 'node1',
            target: 'node2'
          },
          {
            source: 'node2',
            target: 'node3'
          },
          {
            source: 'node3',
            target: 'node4'
          },
          {
            source: 'node4',
            target: 'node5'
          },
          {
            source: 'node5',
            target: 'node6'
          },
          {
            source: 'node6',
            target: 'node1'
          },
          {
            source: 'node1',
            target: 'node3'
          }
        ]
      },
      graph: null
    }
  },
  mounted() {
    const that = this
    // 实例化 Menu 插件
    const menu = new G6.Menu({
      offsetX: 6,
      offsetX: 10,
      itemTypes: ['node'],
      getContent(e) {
        const outDiv = document.createElement('div')
        outDiv.style.width = '180px'
        outDiv.innerHTML = `
          <div class="G6menu">
            <div class="G6menu-edit" id="startEdit">开启编辑模式</div>
          </div>
        `
        return outDiv
      },
      handleMenuClick(target, item) {
        if (target.id === 'startEdit') {
          that.graph.off('node:mouseover')
          that.graph.off('node:mouseout')
          that.graph.off('edge:mouseover')
          that.graph.off('edge:mouseout')
          that.graph.setMode('addEdge')
        }
      }
    })
    G6.registerBehavior('click-add-edge', {
      // Set the events and the corresponding responsing function for this behavior
      getEvents() {
        return {
          'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
          mousemove: 'onMousemove' // The event is mousemove, the responsing function is onMousemove
        }
      },
      // 节点的响应函数:在getEvents中定义的点击
      onClick(ev) {
        const self = this
        const node = ev.item
        const graph = self.graph
        // The position where the mouse clicks
        const point = { x: ev.x, y: ev.y }
        const model = node.getModel()
        if (self.addingEdge && self.edge) {
          // 添加边,起始节点为当前节点,结束节点为鼠标单击的当前节点
          const edgeModel = self.edge.getModel()
          const arrNode = node
            .getEdges()
            .filter(
              item =>
                (item.getModel().target == model.id &&
                  item.getModel().source == edgeModel.source) ||
                (item.getModel().source == model.id && item.getModel().target == edgeModel.source)
            )
          if (arrNode.length) {
            self.graph.removeItem(self.edge)
            self.edge = null
            self.addingEdge = false
            that.$message.error('已存在该边')
            return
          }
          graph.updateItem(self.edge, {
            target: model.id
          })

          self.edge = null
          self.addingEdge = false
        } else {
          self.edge = graph.addItem('edge', {
            source: model.id,
            target: model.id
          })
          self.addingEdge = true
        }
      },
      onMousemove(ev) {
        const self = this
        // 鼠标单击的当前位置
        const point = { x: ev.x, y: ev.y }
        if (self.addingEdge && self.edge) {
          // 通过鼠标单击将结束节点更新为当前节点
          self.graph.updateItem(self.edge, {
            target: point
          })
        }
      }
    })
    setTimeout(() => {
      this.graph = new G6.Graph({
        container: 'container',
        fitView: true, // 是否开启画布自适应。开启后图自动适配画布大小。
        fitViewPadding: 20, // [number, number, number, number] 图适应画布留白 padding
        defaultNode: {
          size: [30, 30],
          style: {
            lineWidth: 2, // 描边粗细
            fill: '#DEE9FF', // 填充色
            stroke: '#5B8FF9' // 描边颜色
          },
          labelCfg: {
            position: 'bottom', // 文字位置
            offset: 10, // 距离
            style: {
              fill: '#666' // 文字颜色
            }
          }
        },
        defaultEdge: {
          style: {
            endArrow: true,
            lineWidth: 1, // 边的粗细
            stroke: '#e2e2e2', // 边的颜色
            lineAppendWidth: 2 // 边响应鼠标事件时的检测宽度
          }
        },
        nodeStateStyles: {
          hoverActive: {
            lineWidth: 5, // 描边粗细
            stroke: '#00ffcc', // 描边颜色
            opacity: 1
          },
          inHoverActive: {
            opacity: 0.2
          },
          select: {
            lineWidth: 5, // 描边粗细
            stroke: '#00ffcc', // 描边颜色
            opacity: 1
          },
          inSelect: {
            opacity: 0.2
          }
        },
        edgeStateStyles: {
          hoverActive: {
            lineWidth: 2, // 边的粗细
            stroke: '#ceaf13', // 边的颜色
            opacity: 1
          },
          inHoverActive: {
            opacity: 0.2
          },
          select: {
            lineWidth: 2, // 边的粗细
            stroke: '#ceaf13', // 边的颜色
            opacity: 1
          },
          inSelect: {
            opacity: 0.2
          }
        },
        modes: {
          default: ['drag-node', 'drag-canvas', 'zoom-canvas'],
          addEdge: ['click-add-edge', 'click-select']
        },
        plugins: [menu], // 配置 Menu 插件
        layout: {
          type: 'circular' // 环形布局
        }
      })
      this.graph.data(this.data)
      this.getOn()
      this.graph.on('node:dblclick', e => {})
      this.graph.on('dblclick', item => {
        if (item.shape) return
        this.graph.setMode('default')
        this.clearAllStats({ shape: null })
        this.getOn()
        // const arr = this.graph.save()
        // console.log(
        //   arr.nodes,
        //   arr.edges.map(item => {
        //     return {
        //       source: item.source,
        //       target: item.target
        //     }
        //   })
        // )
      })

      // this.graph.on('node:click', e => {
      //   const item = e.item
      //   this.graph.setAutoPaint(false)
      //   // 所有节点全部隐藏
      //   this.graph.getNodes().forEach(node => {
      //     this.graph.setItemState(node, 'inSelect', true)
      //   })
      //   // 所有边全部隐藏
      //   this.graph.getEdges().forEach(node => {
      //     this.graph.setItemState(node, 'inSelect', true)
      //   })
      //   // 获取当前节点关联的所有边
      //   item.getEdges().forEach(edge => {
      //     // 获取其源和目标
      //     const nodeSource = edge.getSource()
      //     const nodeTarget = edge.getTarget()
      //     // 所有边显示
      //     this.graph.setItemState(edge, 'inSelect', false)
      //     this.graph.setItemState(edge, 'select', true)
      //     // 所有与之相连的节点显示
      //     this.graph.setItemState(nodeSource, 'inSelect', false)
      //     this.graph.setItemState(nodeSource, 'select', true)
      //     this.graph.setItemState(nodeTarget, 'inSelect', false)
      //     this.graph.setItemState(nodeTarget, 'select', true)
      //   })
      //   this.graph.paint()
      //   this.graph.setAutoPaint(true)
      // })
      // this.graph.on('click', this.clearAllStats)
      this.graph.render()
    }, 3000)
  },
  methods: {
    clearAllStats(item) {
      if (item.shape) return
      this.graph.setAutoPaint(false)
      this.graph.getNodes().forEach(node => {
        this.graph.clearItemStates(node)
      })
      this.graph.getEdges().forEach(edge => {
        this.graph.clearItemStates(edge)
      })
      this.graph.paint()
      this.graph.setAutoPaint(true)
    },
    nodeClearAllStats() {
      this.graph.setAutoPaint(false)
      // 所有节点全部隐藏
      this.graph.getNodes().forEach(node => {
        this.graph.clearItemStates(node, 'inHoverActive')
        this.graph.clearItemStates(node, 'hoverActive')
      })
      // 所有边全部隐藏
      this.graph.getEdges().forEach(node => {
        this.graph.clearItemStates(node, 'inHoverActive')
        this.graph.clearItemStates(node, 'hoverActive')
      })
      this.graph.paint()
      this.graph.setAutoPaint(true)
    },

    // 绑定监听事件
    getOn() {
      this.graph.on('node:mouseover', this.nodeOn)
      this.graph.on('node:mouseout', this.nodeClearAllStats)

      this.graph.on('edge:mouseover', this.edgeOn)
      this.graph.on('edge:mouseout', this.nodeClearAllStats)
    },
    // node
    nodeOn(e) {
      const item = e.item
      this.graph.setAutoPaint(false)
      // 所有节点全部隐藏
      this.graph.getNodes().forEach(node => {
        this.graph.setItemState(node, 'inHoverActive', true)
      })
      // 所有边全部隐藏
      this.graph.getEdges().forEach(node => {
        this.graph.setItemState(node, 'inHoverActive', true)
      })
      const nodeModel = item.getModel()
      // 获取当前节点关联的所有边
      item.getEdges().forEach(edge => {
        // 获取其边目标
        if (edge.getModel().source != nodeModel.id) return
        // 所有目标边显示
        this.graph.setItemState(edge, 'inHoverActive', false)
        this.graph.setItemState(edge, 'hoverActive', true)
        // 获取其源和目标
        const nodeSource = edge.getSource()
        const nodeTarget = edge.getTarget()
        // 所有与之相连的节点显示
        this.graph.setItemState(nodeSource, 'inHoverActive', false)
        this.graph.setItemState(nodeSource, 'hoverActive', true)
        this.graph.setItemState(nodeTarget, 'inHoverActive', false)
        this.graph.setItemState(nodeTarget, 'hoverActive', true)
      })
      this.graph.paint()
      this.graph.setAutoPaint(true)
    },
    // edge
    edgeOn(e) {
      const item = e.item
      this.graph.setAutoPaint(false)
      // 所有节点全部隐藏
      this.graph.getNodes().forEach(node => {
        this.graph.setItemState(node, 'inHoverActive', true)
      })
      // 所有边全部隐藏
      this.graph.getEdges().forEach(node => {
        this.graph.setItemState(node, 'inHoverActive', true)
      })
      // 获取其源和目标
      const nodeSource = item.getSource()
      const nodeTarget = item.getTarget()
      // 当前边显示
      this.graph.setItemState(item, 'inHoverActive', false)
      this.graph.setItemState(item, 'hoverActive', true)
      // 所有与之相连的节点显示
      this.graph.setItemState(nodeSource, 'inHoverActive', false)
      this.graph.setItemState(nodeSource, 'hoverActive', true)
      this.graph.setItemState(nodeTarget, 'inHoverActive', false)
      this.graph.setItemState(nodeTarget, 'hoverActive', true)
      this.graph.paint()
      this.graph.setAutoPaint(true)
    },

    afteradditem(e) {
      if (e.item) {
        const nodeModel = e.item.getModel()
        // 所有边
        const arrNode = this.graph
          .getEdges()
          .filter(
            node =>
              (node.getModel().target == nodeModel.target &&
                node.getModel().source == nodeModel.source) ||
              (node.getModel().target == nodeModel.source &&
                node.getModel().source == nodeModel.target)
          )
        console.log(arrNode, 1221)
      }
    }
  }
}
</script>

<style lang="scss">
#G6index {
  width: 100%;
  height: 100%;
  .G6menu {
    &-edit {
      height: 30px;
      line-height: 30px;
      text-align: center;
      cursor: pointer;
      &:hover {
        background: rgba(24, 144, 255, 0.1);
        color: #1890ff;
      }
    }
  }
  .G6indexBox {
    width: 100%;
    height: 100%;
    padding: 20px;
    box-sizing: border-box;
    .container {
      width: 100%;
      height: 100%;
    }
  }
}
</style>