vue2+@antv/x6@1.x版本+element-ui实现节点/边contextMenu右键菜单和tooltip提示框

contextMenu右键菜单
代码如下(示例):

<template>
  <div class="graph-container">
    <div ref="graph" id="graph" />
  </div>
</template>

<script>
import Vue from 'vue'
import { Graph, ToolsView } from '@antv/x6'
import { DropdownItem } from 'element-ui'

class ContextMenuTool extends ToolsView.ToolItem {
  knob = null
  timer = null
  dropdownMenuDom = null
  dropdownMenuComp = null

  render() {
    if (!this.knob) {
      this.knob = ToolsView.createElement('div', false)
      this.knob.style.position = 'absolute'
      this.dropdownMenuDom = ToolsView.createElement('div', false)
      this.knob.appendChild(this.dropdownMenuDom)
      this.container.appendChild(this.knob)
    }
    return this
  }

  toggleContextMenu(visible) {
    if (this.dropdownMenuComp) {
    	this.dropdownMenuComp.$destroy()
    	this.knob.innerHTML = ''
    	this.knob.appendChild(this.dropdownMenuDom)
    	this.dropdownMenuComp = null
    }
    document.removeEventListener('mousedown', this.onMouseDown)

    if (visible) {
      const that = this
      this.dropdownMenuComp = new Vue({
      	el: this.dropdownMenuDom,
      	render() {
      		return (
      			<ul
      				class='el-dropdown-menu el-popper'
      				x-placement='bottom-end'
      				style='width: max-content; z-index: 1000; border-radius: 4px'
    			>
    				{that.options.menu.map(it => <DropdownItem><span onClick={that.handleClick}>{it.label}</span></DropdownItem>)}
    			</ul>
      		)
      	}
      })
      document.addEventListener('mousedown', this.onMouseDown)
    }
  }

  handleClick = (e) => {
  	console.log(e.target.innerText, this)
  }

  updatePosition(e) {
    const style = this.knob.style
    if (e) {
      const pos = this.graph.clientToGraph(e.clientX, e.clientY)
      style.left = `${pos.x}px`
      style.top = `${pos.y}px`
    } else {
      style.left = '-1000px'
      style.top = '-1000px'
    }
  }

  onMouseDown = () => {
    this.timer = setTimeout(() => {
      this.updatePosition()
      this.toggleContextMenu(false)
    }, 200)
  }

  onContextMenu({ e }) {
    if (this.timer) {
      clearTimeout(this.timer)
      this.timer = 0
    }
    this.updatePosition(e)
    this.toggleContextMenu(true)
  }

  delegateEvents() {
    this.cellView.on('cell:contextmenu', this.onContextMenu, this)
    return super.delegateEvents()
  }

  onRemove() {
    this.cellView.off('cell:contextmenu', this.onContextMenu, this)
  }
}

ContextMenuTool.config({
  tagName: 'div',
  isSVGElement: false,
})

Graph.registerNodeTool('contextmenu', ContextMenuTool, true)
// Graph.registerEdgeTool('contextmenu', ContextMenuTool, true)

export default {
  data() {
    return {
      graphData: {
        nodes: [{
          id: 'node1',
          x: 40,
          y: 40,
          width: 80,
          height: 40,
          label: 'hello',
          tools: [{
            name: 'contextmenu',
            args: {
              menu: [
              	{ label: '跳过' },
              	{ label: '重执行' },
              	{ label: '结束' }
              ]
            }
          }]
        }, {
          id: 'node2',
          x: 160,
          y: 180,
          width: 80,
          height: 40,
          label: 'world',
          tools: [{
            name: 'contextmenu',
            args: {
              menu: [
              	{ label: '跳过' },
              	{ label: '重执行' },
              	{ label: '结束' }
              ]
            }
          }]
        }],
        // 边
        edges: [{
          source: 'node1', // String,必须,起始节点 id
          target: 'node2', // String,必须,目标节点 id
        }]
      }
    }
  },
  mounted() {
    const graph = new Graph({
      container: this.$refs.graph,
      autoResize: true,
      grid: true
    })
    graph.fromJSON(this.graphData)
    graph.centerContent()
  }
}
</script>

<style lang="scss" scoped>
.graph-container {
  width: 100%;
  height: 100%;
  display: flex;
  #graph {  
    flex: 1
  }
}
</style>

tooltip提示框
代码如下(示例):

<template>
  <div class="graph-container">
    <div ref="graph" id="graph" />
  </div>
</template>

<script>
import Vue from 'vue'
import { Graph, ToolsView } from '@antv/x6'
import { Tooltip } from 'element-ui'

class TooltipTool extends ToolsView.ToolItem {
  knob = null
  tooltipDom = null
  tooltipComp = null

  render() {
    if (!this.knob) {
      this.knob = ToolsView.createElement('div', false)
      this.knob.style.position = 'absolute'
      this.tooltipDom = ToolsView.createElement('div', false)
      this.knob.appendChild(this.tooltipDom)
      this.container.appendChild(this.knob)
    }
    return this
  }

  toggleTooltip(visible) {
    if (this.tooltipComp) {
      this.tooltipComp.$destroy()
      this.knob.innerHTML = ''
      this.knob.appendChild(this.tooltipDom)
      this.tooltipComp = null
    }

    if (visible) {
      const that = this
      this.tooltipComp = new Vue({
        el: this.tooltipDom,
        render() {
          return (
          	// 假如遇到effect不生效,就用style去调样式
            <Tooltip value={true} effect='dark'>
              <div />
              <div slot="content" style={{
                color: '#fff',
                backgroundColor: 'rgb(0, 0, 0, .7)',
                padding: '10px',
                borderRadius: '4px'
              }}>
                标题:{that.options.content}
              </div>
            </Tooltip>
          )
        }
      })
    }
  }

  updatePosition(e) {
    const style = this.knob.style
    if (e) {
      const p = this.graph.clientToGraph(e.clientX, e.clientY)
      style.display = 'block'
      style.left = `${p.x}px`
      style.top = `${p.y}px`
    } else {
      style.display = 'none'
      style.left = '-1000px'
      style.top = '-1000px'
    }
  }

  onMosueEnter({ e }) {
    this.updatePosition(e)
    this.toggleTooltip(true)
  }

  onMouseLeave() {
    this.updatePosition()
    this.toggleTooltip(false)
  }

  onMouseMove() {
    this.updatePosition()
    this.toggleTooltip(false)
  }

  delegateEvents() {
    this.cellView.on('cell:mouseenter', this.onMosueEnter, this)
    this.cellView.on('cell:mouseleave', this.onMouseLeave, this)
    this.cellView.on('cell:mousemove', this.onMouseMove, this)
    return super.delegateEvents()
  }

  onRemove() {
    this.toggleTooltip(false)  
    this.cellView.off('cell:mouseenter', this.onMosueEnter, this)
    this.cellView.off('cell:mouseleave', this.onMouseLeave, this)
    this.cellView.off('cell:mousemove', this.onMouseMove, this)
  }
}

TooltipTool.config({
  tagName: 'div',
  isSVGElement: false,
})

Graph.registerNodeTool('tooltip', TooltipTool, true)
// Graph.registerEdgeTool('tooltip', TooltipTool, true)

export default {
  data() {
    return {
      graphData: {
        nodes: [{
          id: 'node1',
          x: 40,
          y: 40,
          width: 80,
          height: 40,
          label: 'hello',
          tools: [{
            name: 'tooltip',
            args: {
              content: '测试tooltip'
            }
          }]
        }, {
          id: 'node2',
          x: 160,
          y: 180,
          width: 80,
          height: 40,
          label: 'world',
          tools: [{
            name: 'tooltip',
            args: {
              content: '测试tooltip'
            }
          }]
        }],
        // 边
        edges: [{
          source: 'node1', // String,必须,起始节点 id
          target: 'node2', // String,必须,目标节点 id
        }]
      }
    }
  },
  mounted() {
    const graph = new Graph({
      container: this.$refs.graph,
      autoResize: true,
      grid: true
    })
    graph.fromJSON(this.graphData)
    graph.centerContent()
  }
}
</script>

<style lang="scss" scoped>
.graph-container {
  width: 100%;
  height: 100%;
  display: flex;
  #graph {  
    flex: 1
  }
}
</style>
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leungwanghoi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值