前言:

jsplumb 有2个版本一个Toolkit Edition(付费版),另外一个就是Community Edition(社区版本)。Toolkit Edition版本功能集成的比较丰富,社区版本的就差好多,很多功能都没有,需要我们自己去添加,当然了自己添加多多少少有些麻烦,而且也不完善。但是我们还是用Community Edition(社区版本),毕竟不收费,没办法,下边所说的版本默认都是以社区版。

最近公司项目有用到这个流程图,所以也就看到了这个框架,这个框架是英文版本的,地址:https://jsplumbtoolkit.com/community/doc/home.html(可以用浏览器翻译了看)。他的缺陷就是文档不全,api感觉也有点乱,实例交代的也不清楚,github地址是:https://github.com/jsplumb/jsplumb (里面有demo,自己可以下载运行,多动手试试)。如果只是简单的画个图,这个框架是没有什么问题的,demo里也有,但是如果要实现高级的动能呢鞥,还是得多多尝试。此文也是记录一下我自己用到的一些功能,很多我还没用到,用到了在慢慢补充。

 
jsplumb 流程图,常用功能配置记录
jsplumb.png

上图也就是我这次用到的jsplumb实现的功能,连接线能够拖拽生成,也可以删除,编辑label。

1、数据结构

{
  "nodes": [{  //节点集合
    "icon": "el-icon-loading",
    "id": "start",
    "nodeStyle": {
      "top": 100,
      "left": 200
    },
    "text": "开始",
    "type": "circle"
  }, {
    "icon": "el-icon-upload",
    "id": "end",
    "nodeStyle": {
      "top": 300,
      "left": 400
    },
    "text": "结束",
    "type": "circle"
  }] ,
  "connections": [{  //连接线集合
      "sourceId": "start",
      "targetId": "end",
      "label":"编辑"
    }]
}

jsplumb实例里面的数据结构就是这样的,这里我们沿用他的数据结构,你也可以自己定义自己想的数据结构,但是对比起来这个结构是最清晰也最方便的。

2、初始化

jsplumb在DOM渲染完毕之后才会执行,所以需要为jsplumb的执行代码绑定一个ready事件:

jsPlumb.ready(function() { 
    // your jsPlumb related init code goes here
});

jsplumb默认是注册在浏览器窗口的,将整个页面提供给我们作为一个实例,但我们也可以使用getInstance方法建立页面中一个独立的实例:

var _instance = jsPlumb.getInstance();

3、功能实现(允许哪些元素拖拽,允许拆卸连接)

let instance = jsPlumb.getInstance({
                PaintStyle:{ 
                    strokeWidth:2, 
                    stroke:"#567567", 
                }
            })
        //拖拽功能
        var els = document.querySelectorAll(".box");//.box是允许拖拽的元素class类名
        instance.draggable(els,{
           containment:true,
           filter: ".ep",//除去不能拖拽的,这里是个class类名
        });
        //不允许拆卸连接,不设置的话默认是可以的
        instance.importDefaults({ 
          ConnectionsDetachable:false
        });

4、连线监听事件(拖动connection 事件)

        // 监听拖动connection 事件,判断是否有重复链接
        instance.bind("beforeDrop", function(info) {
            // info.connection.getOverlay("label").setLabel(info.connection.id);
            // 判断是否已有该连接
            let isSame = true;
            //下边的forEach循环就是处理数据结构里的connections不能自己跟自己连线。当然你也可以处理其他
            _this.chartData.connections.forEach(item => {
              if ((item.targetId === info.targetId && item.sourceId === info.sourceId) ||  (item.targetId === info.sourceId && item.sourceId === info.targetId)) {
                isSame = false;
              }
            });
            if (isSame) {
                //允许连线后处理的情况
            } else {
              alert("不允许重复连接!");
            }
            return isSame;//这里返回了ture就会自定进行连线。
        });

5、上图实现的完整代码

下边代码就是实现上图的,需要指出的是运用了vue,但是里面掺杂了jquery,和jquery-ui,其实不想用这2个的,但是项目紧,之前项目也用到了,所以就延续了。还有就是上面代码是我自己的测试代码,写的可能有些杂乱,就是测试一个一个功能而写,写的有点乱。

还有一个想说的就是之前想实现,缩放,引入了panzoom.js,流程图也实现了滚动鼠标放大放小,但是有个问题就是滚动鼠标放大放小后如果拖动单个元素或者连线,你就会发现鼠标点对不齐了,这点还没有解决,如果有好的方案,可以告知我下。Toolkit Edition(付费版)的这些功能都有,就不会出现这样的问题。

<template>
  <div id="test6" style="height:100%;position:relative">
      <section id="focal"  style="position:relative;overflow:hidden;width:610px;height:610px;background:#fff;border:1px solid red">
        <div class="parent" id="parent" style="height:100%;">
          <div class="panzoom" id="panzoom" style="border:1px solid blue;width:6000px;height:6000px; transform:translate(-50%, -50%);position:absolute;">
            <div class="box" :id="item.id" :style="{'top':item.nodeStyle.top+'px','left':item.nodeStyle.left+'px'}" v-for="item in chartData.nodes" :key="item.id">
                <i :class="item.icon" class="oldIcon" :title="item.text"></i>
                <i class="el-icon-circle-close" style="display:none" :title="item.text" :id="item.id"></i>
                <div class="ep"></div>
            </div>
          </div>
      </div>
    </section>
    <div class="source">
        <ul>
            <li v-for="(item,index) in list" :id="item.id" :key="index" class="sourceLi" :disabled="true" :data-icon="item.icon" :data-text="item.text" :data-type="item.type">{{item.text}}</li>
        </ul>
    </div>

        <el-dialog
              title="修改label名称"
              :visible.sync="dialogVisible"
              width="30%"
              :before-close="handleClose">
              <el-input v-model="labelName" placeholder="请输入"></el-input>
              <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="changeNote">确 定</el-button>
              </span>
            </el-dialog>
  </div>
</template>
<script>
import ChartNode from "@/components/ChartNode";
export default {
  name: "test6",
  data() {
    return {
        dialogVisible:false,
        labelName:"",
        curSourceId:'',
        curTargetId:'',
        addLabelText:'',//拖拽后生成的连线label文字
        jsp:null,
        myscale:1,
        curScreen:[],//当前屏幕宽高
        chartData: {
            nodes: [],
            connections: [],//{ "targetId": "box2", "sourceId": "box1" }
            props: {},
            screen:[610,610]//提交屏幕宽高
        },
        list: [
          {
            icon: "el-icon-goods",
            text: "伴随车牌",
            type: "circle",
            id:'li1'
          },
          {
            icon: "el-icon-bell",
            text: "常住人口筛选",
            type: "diamond",
            id:"li2"
          },
          {
            icon: "el-icon-date",
            text: "伴随imsi",
            type: "circle",
            id:"li3"
          }
        ]
    };
  },
  mounted() {
  
    let _this = this
    jsPlumb.ready(function() {
        var $section = $('#focal');
        var $panzoom = $section.find('.panzoom').panzoom({ 
             minScale: 0.3,
             maxScale:2,
             eventNamespace: ".panzoom",
             $zoomRange: $(".jtk-endpoint"),
             $set: $section.find('.jtk-overlay'),
             eventsListenerElement: document.querySelector('.box')
        });

        $(document).on('mouseover','.box,.jtk-draggable,.jtk-overlay,.ep',function(){
          $('.panzoom').panzoom("disable");
        })

        $(document).on(

相关文章: