阅读 358

bpmn.js鼠标右键菜单选择节点

因公司需求节点可以自定义且节点非常多,如果将所有节点放在左侧菜单中会非常难以定位需要的task

故设计右键幕布空白处弹出节点选择菜单

菜单定位

image.png首先我们给canvas的父级节点加一个id

document.getElementById('content').oncontextmenu=function(ev){
  _this.actionName = ''
  let clintX = ev.clientX;  //ev获取的只是屏幕可视范围的x,y值
  let clintY = ev.clientY;
  // let scollTop = document.documentElement.scrollTop|| document.body.scrollTop;   //当有下拉条的时候必须加上当前屏幕不可视范围的left,和top值
  // let scollLeft = document.documentElement.scrollLeft || document.body.scrollLeft

  _this.mouse.x = clintX
  _this.mouse.y = clintY

  document.getElementById('actionMenu').style.left=(clintX - 200)+'px';
  document.getElementById('actionMenu').style.top=(clintY - 68)+'px';
  document.getElementById('actionMenu').style.display='block';
  return false;    //屏蔽右键菜单
}复制代码

然后监听幕布右键菜单事件弹出节点列表  这里通过右键时的鼠标坐标来定位菜单位置 然后将鼠标坐标保存起来用于点击task节点后的定位

菜单内容

image.png

管理节点的页面,task可以自定义task的图标和颜色image.png

菜单样式

image.png

点击task

addAction(item,event){
  //先隐藏task菜单
  document.getElementById('actionMenu').style.display='none';
  this.$nextTick(e =>{
    let elementRegistry = this.bpmnModeler.get('elementRegistry')
    const elementFactory = this.bpmnModeler.get("elementFactory")
    const modeling = this.bpmnModeler.get("modeling")
    const canvas = this.bpmnModeler.get("canvas")
    const rootElement =canvas.getRootElement()
    let x_canvas
    let y_canvas
    if (canvas._cachedViewbox){
      this.cachedViewbox = canvas._cachedViewbox
      x_canvas = canvas._cachedViewbox.x
      y_canvas = canvas._cachedViewbox.y
    } else {
      x_canvas = this.cachedViewbox.x
      y_canvas = this.cachedViewbox.y
    }
    //此处考虑到如果图有缩放 那么鼠标在中id为content的div中的坐标就和鼠标在幕布中的坐标不同了 所以通过缩放值计算缩放后的坐标
    let x = x_canvas + (this.mouse.x / canvas.zoom())
    let y = y_canvas + (this.mouse.y / canvas.zoom())
    //创建节点
    let branchShape = elementFactory.createShape({
      type: "bpmn:Task",
      id: 'element_id_'+ new Date().getTime()
    })
    branchShape.businessObject.name = item.actionName
    branchShape.businessObject.actionId = item.id
    modeling.createShape(
      branchShape,
      {
        x: x,
        y: y
      },
      rootElement
    )
  })
},复制代码

显示效果

foky1-p6spt.gif

渲染

通过 businessObject 中 自定义字段判断task需要显示什么图标什么颜色

drawShape(parentNode, element) {
  const shape = this.bpmnRenderer.drawShape(parentNode, element);
  const type = element.type; // 获取到类型
  // 所有节点都会走这个函数,所以此时只限制,需要自定义的才去自定义,否则仍显示bpmn默认图标
  const businessObject = getBusinessObject(element);
  const { actionId } = businessObject;
  if (customElements.includes(type) && actionId) {

    let tasks = JSON.parse(sessionStorage.getItem('tasks'))
    let task = tasks.find(e =>{
      return e.id === actionId
    })

    const {url, attr} = customConfig[task.icon];
    const customIcon = svgCreate('image', {...attr, href: url});
    element['width'] = 56;
    element['height'] = 56;
    svgAppend(parentNode, customIcon);

    let textNode = parentNode.childNodes[1]
    console.log(textNode)

    textNode.childNodes.forEach(e =>{
      // e.setAttribute('y',parseInt(e.getAttribute('y')) + 52)
      e.style.display = 'none'
    })

    // 下方为更改节点名称位置
    if (element.businessObject.name) {
      const text = svgCreate('text', {
        x: attr.x + 26,
        y: attr.y + attr.height + 20, //位置可以随意调,我理解此时的attr.y 是此时元素的左上角纵坐标
        'font-size': '12',
        'text-anchor': 'middle',
        'dominant-baseline':'middle'
      });
      text.innerHTML = element.businessObject.name;
      svgAppend(parentNode, text);
    }

    if (!element.businessObject.name){
      element.businessObject.name = task.actionName
    }

    //修改边框颜色
    if(task.color){
      shape.style.setProperty('fill', task.color)
    }
    return customIcon;
  }
  return shape;
}


作者:围_城
链接:https://juejin.cn/post/7025521883822948366

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐