效果图

目前已完成功能:

  • 加载左侧列表菜单
  • 加载右侧表单数据,并根据连接类型进行对应的连线
  • 用户操作功能, 包括连线;连线条件判断;修改连线属性;左侧菜单拖动模型到右侧区域;鼠标滚轮缩放右侧区域,鼠标拖拽移动背景等
  • 保存功能,每次连线、新建模型请求接口保存属性,还有保存按钮可以保存当前全部数据

计划新功能:

计划在右下角增加缩略图,可以点击缩略图的位置,移动大背景图

功能代码:

右侧画布内的模型拖拽:

vm.jsplumb.draggable(document.querySelectorAll('.model'), {
        // 设置拖拽区域不超过父级
        containment: 'parent',
        stop: function (e){
        // 拖拽后改变位置,修改本地数据
        }
});

左侧菜单拖拽模型到右侧,需要绑定两个事件,一个拖拽事件,一个在右侧区域放置事件

1. 左侧菜单拖拽事件

vm.jsplumb.draggable(document.querySelectorAll('.left-sub-title'), {
        helper: 'clone',
        scope: 'ss',
        drag: function (e){
          vm.isDragging = true;
          // 在鼠标拖拽处创建一个元素, 设置元素和拖拽模型拥有相同名称,并使元素随鼠标拖拽移动
          vm.showName = e.el.textContent;
          vm.$refs.controlNode.style.left = e.el.style.left;
          vm.$refs.controlNode.style.top = e.el.style.top;
        },
        stop: function () {
            vm.isDragging = false;
        }
      })

2. 右侧放置事件

// 右侧区域放置事件,设置相同的scope
vm.jsplumb.droppable('points', {
        scope: 'ss',
        drop: function (event){
          // 计算放置位置
          let leftP = ((event.e.x - event.drag.el.offsetWidth) / event.drop.el.offsetWidth).toFixed(2) * 100;
          let topP = (event.e.y / event.drop.el.offsetHeight).toFixed(2) * 100;
          //.... 请求接口数据
          vm.isDragging = false;
          vm.showName = '';
          vm.$nextTick(() => {
            vm.addNew();
          });
        }
      })
addNew(){
      // 为新的模型添加事件
      let lastIndex = Object.keys(vm.data.formMap).length - 1
      let lastNode = vm.data.formMap[Object.keys(vm.data.formMap)[lastIndex]];
      vm.jsplumb.draggable(document.querySelectorAll('.point')[lastIndex], {
        containment: 'points',
        // 拖拽后改变位置,把x, y坐标存入数据(我是用了百分比)
        stop: function (e){
          vm.data.formMap[e.el.id].x = (e.pos[0] / e.el.parentNode.offsetWidth).toFixed(2) * 100;
          vm.data.formMap[e.el.id].y = (e.pos[1] / e.el.parentNode.offsetHeight).toFixed(2) * 100;
        }
      });
      // 每行添加anchor连线点
      vm.jsplumb.batch(() => {
        for (const m in lastNode.fieldMap){
          vm.jsplumb.makeSource(Object.keys(vm.data.formMap)[lastIndex] + '-' + m, {
            anchor: ["Continuous", { faces: ["left", "right"] }],
            endpoint: 'Dot',
          });
          vm.jsplumb.makeTarget(Object.keys(vm.data.formMap)[lastIndex] + '-' + m, {
            anchor: ["Continuous", { faces: ["left", "right"] }],
            allowLoopback: false
          });
        }
      })
    }

给每行添加anchor锚点时,要给每个描点设置id,这样后面的连线才能正确连接。

然后是加载右侧数据,因为用的Vue,所以不用在下面疯狂创建元素了,直接v-for写在template里,只需要后面绑定事件即可,绑定事件代码和上面addNew是一致的,只不过后面需要添加连线:

vm.jsplumb.connect({
                  source: targetLines[line].formId + '-' + targetLines[line].fieldId,
                  target: targetLines[line].targetFormId + '-' + targetLines[line].targetFieldId,
                  paintStyle: { strokeWidth: 1, stroke: targetLines[line].lineType === 1 ? '#409EFF' : '#67C23A' },
                  hoverPaintStyle: { stroke: targetLines[line].lineType === 1 ? '#66b1ff' : '#85ce61', strokeWidth: 3 },
                  overlays: [
                    [
                      "Arrow",
                      {
                        location: 1,
                        visible: true,
                        width: 11,
                        length: 11,
                        id: "ARROW",
                      }
                    ], [
                      "Label",
                      {
                        location: 0.5,
                        label: targetLines[line].lineType === 1 ? '关联' : '推送',
                        visible: true,
                        id: "label",
                        cssClass: "aLabel",
                      }
                    ]]
                });

循环没放出来,jsplumb.connect 就是连线操作,soure填写起点的锚点id,target为终点锚点id,overlays可以设置连线属性,包括箭头位置样式和文字说明。

连线事件(beforeDrop 和 connection):

vm.jsplumb.bind('beforeDrop', function (conn){
// 根据conn的sourceId和targetId判断是否满足连线条件
// 代码.....
// 最后return 为 false 则不会连线        
});
vm.jsplumb.bind("connection", function (connInfo, originalEvent){
// 调用接口,保存连线
});

点击连线可以修改连线样式:

// 点击连线事件
vm.jsplumb.bind('click', function (conn, originalEvent){
    // 点击连线弹出窗口进行修改操作       
    vm.editTable(conn);
});
// 弹出修改弹窗
editTable(conn){
    let vm = this;
    vm.editVisible = true;
    // 连线属性设置
    vm.currentConn = conn;
},
// 保存操作
tableChange(){
    // 保存修改后连线
    this.editVisible = false;
    // 修改连线文字说明
    this.currentConn.getOverlay("label").setLabel(this.tableForm.lineType === 1 ? '关联' : '推送');
    // 修改连线颜色
    this.currentConn.setPaintStyle({ strokeWidth: 1, stroke: this.tableForm.lineType === 2 ? "#67C23A" : '#409EFF' });
    this.currentConn.setHoverPaintStyle({
      strokeWidth: 3,
      stroke: this.tableForm.lineType === 2 ? "#85ce61" : '#66b1ff'
   });
    // 更新本地数据。。。
      
},

鼠标滚轮缩放以及可拖拽画布:

mounted(){
    jsPlumb.ready(() => {
      // 初始化模型,进行添加事件、增加锚点、初始化连线
    });
    // 鼠标滚路事件
    document.onmousewheel = (e) => {
      if (e.target.id === 'points-parent' || e.target.id === 'points'){
        this.setZoom(e);
      }
    }
},
computed: {
    calZoom(e){
      if (e > 0){
        this.zoom += 0.1
      }else if (e < 0){
        this.zoom -= 0.1
      }
}

this.zoom 是html元素画布的动态 scale 属性:

 "-webkit-transform": `scale(${this.zoom)})`,

需要注意的问题:

如果初始化jsplumb实例的时候设置了ConnectionOverlays的label文字,在进行connect连线操作室如果想要动态改变文字,不能在connect方法里设置overlay的label属性,需要在方法外(也就是连线后设置):

this.jsplumb.connect({...}).getOverlay('label的id').setLabel('新的label文字')

 

Logo

前往低代码交流专区

更多推荐