这段时间由于业务需要,需要展现动态的流程图。具体实现效果如图所示:

 

jointJS中的线条以及框都是依赖SVG进行的二次开发。建议初学者先学习svg里相关属性,便于在阅读jointJs的API或者demo的时候有更好的理解。

svg学习可参考:http://www.w3school.com.cn/svg/index.asp

jointJS学习可参考:https://www.jointjs.com/

核心代码:

    1.   定义画布:
      var graph = new joint.dia.Graph();
      //定义画布
      var paperWidth = $('#paper').width();  //兼容性考虑这边拿div的长度
          var paper = new joint.dia.Paper({
              el: $('#paper'),
              width: paperWidth-15,
              height: 1000,
              gridSize: 1,
              model: graph,
              elementView: ElementView,
              linkView:LinkView
          });    
    2.   定义连线
          //定义连线
          function link(source, target, label){
              var cell = new joint.shapes.standard.Link({ 
                  source: { id: source.id },
                  target: { id: target.id },
                  labels: [{ position: 0.5, attrs: { text: { text: label || '', 'font-weight': 'bold','font-size': '12px' } } }],
                  router: { name: 'manhattan' },//设置连线弯曲样式 manhattan直角
                  attrs: {
                      '.marker-target': {
                          fill: '#333333',//箭头颜色
                          d: 'M 10 0 L 0 5 L 10 10 z'//箭头样式
                      },
                      line: { 
                           stroke: '#333333', // SVG attribute and value
                          'stroke-width': 0.5//连线粗细
                      }
                  }
              });
              graph.addCell(cell);
              return cell;
          }    

       

    3. 业务需要去掉可移动的属性:
         var ElementView = joint.dia.ElementView.extend({
              pointerdown: function () {
                  this._click = true;
                  joint.dia.ElementView.prototype.pointerdown.apply(this, arguments);
              },
              pointermove: function(evt, x, y) {
                  this._click = false;
              },
              pointerup: function (evt, x, y) {
                 this._click = true;
                  if (this._click) {
                      this.notify('cell:click', evt, x, y); 
                  } else {
                      joint.dia.ElementView.prototype.pointerup.apply(this, arguments);
                  }
              }
          });

       

    4. 定义框的形状
         var state = function(x, y, shape, background, text){
              var cell;
              var textColor;
              if(background=="#009ACD"||background=="#FB9900"||background=="#FB9900" || background=="#EE5C42") {
                  textColor = "white";
                  strokeWidth = "0"
              }else {
                  textColor = "black";
                  strokeWidth = "1"
              }
              
              if(shape==="rect"){
                  cell = new joint.shapes.standard.Rectangle();
                  cell.resize(shapesSize, 40);
                  cell.position(x, y);
                  cell.attr('label/text', text);
                  cell.attr('label/font-size', '14px');
                  cell.attr('label/fill', textColor);
                  cell.attr('body/refPoints', '0,5 10,0 20,5 10,10');
                  cell.attr('body/fill', background);
                  cell.attr('body/strokeWidth', strokeWidth);
                  cell.attr('body/stroke', '#999999');
                  cell.attr('body/rx', '5px');
                  cell.attr('body/ry', '5px');
                  
              }  else if(shape==="rect"){
                  cell = new joint.shapes.basic.Rect({
                      position: { x: x, y: y },//坐标
                      size: { width: shapesSize, height: 40 },//宽高
                      attrs: { 
                          rect: {
                              fill: background,
                              stroke: '#999999',//边框颜色
                              'stroke-width': 1 ,//边框大小
                              rx:'5px',
                              ry: '5px'
                          },
                          text: { text: text,fill:textColor}, //显示文字
                      }
                  });
              } else if(shape==="ellipse"){
                  cell = new joint.shapes.basic.Rect({
                      position: { x: x, y: y },//坐标
                      size: { width: shapesSize, height: 40 },//宽高
                      attrs: { 
                          rect: {
                              fill: background,
                              stroke: '#999999',//边框颜色
                              'stroke-width': strokeWidth,//边框大小
                              rx:'28px',
                              ry: '28px'
                          },
                          text: { text: text,fill:textColor } //显示文字
                      }
                  });
              } else if(shape==="polygon") {
                  cell = new joint.shapes.standard.Polygon();
                  cell.resize(shapesSize, 40);
                  cell.position(x, y);
                  cell.attr('label/text', text);
                  cell.attr('label/font-size', '12px');
                  cell.attr('label/fill', textColor);
      
                  cell.attr('body/refPoints', '0,5 10,0 20,5 10,10');
                  cell.attr('body/fill', background);
                  cell.attr('body/strokeWidth', '1');
              } else if(shape==="circle") {
                  var cell = new joint.shapes.standard.Circle();
                  cell.resize(20, 20);
                  cell.position(x, y);
                  cell.attr('root/title', 'joint.shapes.standard.Circle');
                  cell.attr('label/text', text);
                  cell.attr('label/fill', 'white');
                  cell.attr('body/fill', background);
                  cell.attr('body/strokeWidth', '0');
                  cell.attr('label/fill', textColor);
                  cell.attr('label/font-size', '12px');
              }
              graph.addCell(cell);
              return cell;
          };

       

    5. 弹出框部分(根据jointJS中的demo实例进行部分修改)
          //彈出框propOver部分定義
          joint.shapes.html = {};
          
          joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
              defaults: joint.util.deepSupplement({
                  type: 'html.Element',
                  attrs: {
                      rect: { stroke: 'none', 'fill-opacity': 0 }
                  }
              }, joint.shapes.basic.Rect.prototype.defaults)
          });
          
          var mapFlag = new Map();
          
          joint.shapes.html.ElementView = joint.dia.ElementView.extend({
              template: [
                  '<div class="html-element"><div id="flag" style="display:none;"></div>',
                  '<div class="popover fade right in" style="display: block;">',
                  '<div class="arrow" style="top: 50%;"></div><div class="popover-title card-header"><a href="#" class="title "></a> <span class="arrowImg"><img src="./image/ArrowRight_2.png" class="right-side"  style="margin-left:10px;" /> <img src="./image/ArrowLeft_2.png" class="left-side"/> </span></div>',
                  '<div class="popover-content" style="width:200px">',
                  '<div class="content">',
                  '</div>',
                  '</div>',
                  '</div>',
                  '</div>'
              ].join(''),
      
              initialize: function() {
                  _.bindAll(this, 'updateBox');
                  joint.dia.ElementView.prototype.initialize.apply(this, arguments);
                  this.$box = $(_.template(this.template)());        
                  this.model.on('remove', this.removeBox, this);        
                  this.updateBox();
              },
              render: function() {
                  joint.dia.ElementView.prototype.render.apply(this, arguments);
                  this.paper.$el.prepend(this.$box);
                  this.updateBox();
                  return this;
              },
              updateBox: function() {
                  var bbox = this.model.getBBox();
                  var classBox = "html-element"+this.model.get("id");
                  $(".html-element").each(function(index,tep){
                      var className = String($(this).attr("class"));
                      if(className=="html-element") {
                          $(this).addClass(classBox);
                      }
                  });
                  $("." + classBox + " .popover-title .title").text(this.model.get('title'));
      
                  var index = mapFlag.get("html-element"+this.model.get("id")) || 0 ;  //記錄第幾次
                  
                  var valueSize =  this.model.get('JsonValue').length;
                  if(valueSize>1) {
                      if(index != 0) {
                          $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                          $(".left-side").css("cursor","pointer");
                      }else {
                          $(".left-side").css("cursor","auto");
                          $(".right-side").css("cursor","pointer");
                      }
                      if(index != valueSize-1) {
                          $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                          $(".right-side").css("cursor","pointer");
                      } else {
                          $(".left-side").css("cursor","pointer");
                          $(".right-side").css("cursor","auto");
                      }
                      $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));
      
                  }
                  
                  var JsonValue = this.model.get('JsonValue')[index];
      
                  for(var item in JsonValue){
                      $(".content").append('<span class="labelSpan">'+String(JsonValue[item].name)+'</span>');
                      $(".content").append("<span class='valueSpan'>"+JsonValue[item].value+"</span></br>");
                  }
              
                              
                  $("." + classBox).on("click",(e)=>{
                      e.stopPropagation()
                  });
                      
                  if(this.model.get('title')=="最終理算"){
                      $('.right-side').on('click', (e)=>{
                          e.stopPropagation();
                          index++;
                          if(index > valueSize-1 || index < 0) {
                              index--;
                              return;
                          }
                          mapFlag.set("html-element"+this.model.get("id"),index);
                          JsonValue = this.model.get('JsonValue')[index];
                          $("." + classBox + " .labelSpan").each(function(index,tep){
                              $(this).text(JsonValue[index].name);
                          });    
                  
                          $("." + classBox + " .valueSpan").each(function(index,tep){
                              $(this).text(JsonValue[index].value);
                          });
                          $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));
      
                          
                          $(".right-side").attr('src',"./image/ArrowRight_2.png"); 
                          $(".left-side").attr('src',"./image/Arrowleft_2.png"); 
                          if(valueSize > 1) {
                              if(index != 0) {
                                  $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                                  $(".left-side").css("cursor","pointer");
                              }else {
                                  $(".left-side").css("cursor","auto");
                                  $(".right-side").css("cursor","pointer");
                              }
                              if(index != valueSize-1) {
                                  $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                                  $(".right-side").css("cursor","pointer");
                              } else {
                                  $(".left-side").css("cursor","pointer");
                                  $(".right-side").css("cursor","auto");
                              }
                          }
                      });
                      
                      $('.left-side').on('click', (e)=>{
                          e.stopPropagation();
                          index--;
                          if(index > valueSize-1 || index < 0) {
                              index++;
                              return;
                          }
                          mapFlag.set("html-element"+this.model.get("id"),index);
                          JsonValue = this.model.get('JsonValue')[index];
                          $("." + classBox + " .labelSpan").each(function(index,tep){
                              $(this).text(JsonValue[index].name);
                          });    
                  
                          $("." + classBox + " .valueSpan").each(function(index,tep){
                              $(this).text(JsonValue[index].value);
                          });
                          $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));
      
                          $(".right-side").attr('src',"./image/ArrowRight_2.png"); 
                          $(".left-side").attr('src',"./image/Arrowleft_2.png"); 
                          if(valueSize>1) {
                              if(index != 0) {
                                  $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                                  $(".left-side").css("cursor","pointer");
                              }else {
                                  $(".left-side").css("cursor","auto");
                                  $(".right-side").css("cursor","pointer");
                              }
                              if(index != valueSize-1) {
                                  $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                                  $(".right-side").css("cursor","pointer");
                              } else {
                                  $(".left-side").css("cursor","pointer");
                                  $(".right-side").css("cursor","auto");
                              }
                          }
                      });
                  }
                  
                  this.$box.css({
                      width: bbox.width,
                      height: bbox.height,
                      left: bbox.x,
                      top: bbox.y,
                  });
              },
              removeBox: function(evt) {
                  this.$box.remove();
              },
              
              changeBox: function(evt) {
                  this.$box.remove();
              },
              
          });

       

    6. 定义事件
          paper.on('cell:click', function (e) {        
              let offsetX = $("#"+e.id).offset().left;
              let offsetY = $("#"+e.id).offset().top;
              
              if($("#"+e.id+" title").html()=="joint.shapes.standard.Circle") {
                  return;
              }
              
              var arr = $("#"+e.id+" tspan");
              var tmp="";
              $.each(arr, function(k,v){
                 tmp+=$(v).html();
              });
              
              map.forEach(function (item, key, mapObj) {
                  item.remove();
              });
              map.clear();
              
              var el1;
              if(tmp=="已完成" || tmp=="未完成" || tmp=="未生成" || tmp=="整案結案" || tmp=="代服務簽核?" || tmp=="預估調整?" || tmp=="預估簽核?" || tmp=="免賠簽核?" || tmp=="全部免賠?" || tmp=="賠款決賠簽核?" || tmp=="部分賠付?") {
                  return;
              }
              if(tmp=="立案" || tmp=="分案確認" || tmp=="初次預估" || tmp == "車損查勘") {
                  el1 = new joint.shapes.html.Element({
                      id: e.id,
                      position: { x: offsetX+5, y: offsetY-210 },
                      size: { width: 170, height: 120 },
                      JsonValue:[[{name: "開始時間" , value:'107/07/01'},{name: '結束時間' , value:'107/07/01'},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'}]],
                      title:tmp
                  });
              } else if(tmp=="最終理算") {
                      el1 = new joint.shapes.html.Element({
                      id: e.id,
                      position: { x: offsetX+5, y: offsetY-210 },
                      size: { width: 170, height: 120 },
                      JsonValue:[[{name: "開始時間" , value:'107/07/01'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'},{name: '和解時間' , value: '107/07/04'},{name: '資料補全日' , value: '107/07/04'}],[{name: '開始時間' , value:'107/07/03'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '否'},{name: '處理人員' , value: '張三'},{name: '和解時間' , value: '107/07/04'},{name: '資料補全日' , value: '107/07/04'}]],
                      title:tmp
                  });
              } else {
                  el1 = new joint.shapes.html.Element({
                      id: e.id,
                      position: { x: offsetX+5, y: offsetY-210 },
                      size: { width: 170, height: 120 },
                      JsonValue:[[{name: '開始時間' , value:'107/07/01'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'}]],
                      title:tmp
                  });
              }
              graph.addCell(el1); 
              map.set(e.id,el1);
          });

       

    代码会有部分冗余,没有做过多的修改,只是做demo用,后期因为会封装进react。所以数据结构等暂未考虑!依赖部分网络上有请自行下载,vendor.min.css样式可忽略。全部代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="./css/joint.css" />
    <link rel="stylesheet" type="text/css" href="./css/vendor.min.css" />
    <link rel="stylesheet" type="text/css" href="./css/bootstrap.min.css" />

    <!-- dependencies -->
    <script src="./js/jquery.js"></script>
    <script src="./js/lodash.js"></script>
    <script src="./js/backbone.js"></script>
    <script src="./js/joint.js"></script>
    <script src="./js/bootstrap.min.js"></script>
<style>
        
    .html-element {
        position: absolute;
        pointer-events: auto;
    }

    .html-element .valueSpan {
        padding-left:25px
    }

    .right-side {
        pointer-events: auto;
        float:right
    }
    
    
    .left-side {
        pointer-events: auto;
        float:right
    }
    .html2-margin {
        margin-left:120px;
    }
    
    .card-header {
        margin-bottom: 0;
        background-color: rgba(0,0,0,.03);
        border-bottom: 1px solid rgba(0,0,0,.125);
    }
    
    .card-header h4:before {
        height: 100%;
        transform: scale(0.75);
        width: 5px;
        margin-top: -3px;
    }

    .card-header h4:before {
        content: '';
        width: 4px;
        float: left;
        height: 25px!important;
        background-color: #ff8200;
        margin-right: 10px;
        border-radius: 8px;
    }
    
    .card-header a:before {
        height: 100%;
        transform: scale(0.75);
        width: 5px;
    }

    .card-header a:before {
        content: '';
        width: 4px;
        float: left;
        height: 20px!important;
        background-color: #ff8200;
        margin-right: 8px;
        border-radius: 8px;
    }
    
    .colorBlue {
        width:10px;
        height:10px;
        background-color:#009ACD
    }
    
    .colorBlue {
        width:10px;
        height:10px;
        background-color:#009ACD
    }
    
    .colorBlue {
        width:10px;
        height:10px;
        background-color:#009ACD
    }
    
    .colorOrange {
        width:10px;
        height:10px;
        background-color:#FB9900
    }
    
    .colorGrey {
        width:10px;
        height:10px;
        background-color:#F2F2F2
    }
    
    .finishColor:before{
        content: '';
        width: 12px;
        height: 12px!important;
        background-color: #009ACD;
        margin-right: 20px;
        padding-right: 16px;
    }
    
        
    .finishColor {
        float:right;
        margin-top:40px;
        padding-right:30px;
    }
    
        
    .notFinishColor:before{
        content: '';
        width: 12px;
        height: 12px!important;
        background-color: #FB9900;
        margin-right: 20px;
        padding-right: 16px;
    }
    
    .notFinishColor {
        float:right;
        margin-top:40px;
        padding-right:30px;
    }
    
    .notGenerate:before{
        content: '';
        width: 12px;
        height: 12px!important;
        background-color: #F2F2F2;
        margin-right: 20px;
        padding-right: 16px;
    }
    
    .notGenerate {
        float:right;
        margin-top:40px;
        padding-right:30px;
    }
    
    .arrowImg img {
        float:right
    }
    
    .html-element .labelSpan {
        color: #666;
        display: inline-block;
        width: 42%;
    }
    
    .html-element .valueSpan {
        color: #212529;
    }
    </style>
    
</head>
<body>
    <div class="container" style="width: 100%; max-width: 90%;">
        <div style="height:100px">
        <p class="notGenerate">未開啟</p>
        <p class="notFinishColor">未完成</p>
        <p class="finishColor">已完成</p>

        </div>
        <div class="card card-outline-default">
        <div class="card-header">
            <h4 class="card-title" tabindex="-1">
                賠案號碼:123789123978
            </h4>
        </div>
        <div class="card-block collapse show">
            <div id="paper" class="paper"  onclick="ccc()"></div>
        </div>
        <div>
    </div>
    
</body>


        <!-- code -->
    <script type="text/javascript">
     
    var graph = new joint.dia.Graph();

    //定义连线
    function link(source, target, label){
        var cell = new joint.shapes.standard.Link({ 
            source: { id: source.id },
            target: { id: target.id },
            labels: [{ position: 0.5, attrs: { text: { text: label || '', 'font-weight': 'bold','font-size': '12px' } } }],
            router: { name: 'manhattan' },//设置连线弯曲样式 manhattan直角
            attrs: {
                '.marker-target': {
                    fill: '#333333',//箭头颜色
                    d: 'M 10 0 L 0 5 L 10 10 z'//箭头样式
                },
                line: { 
                     stroke: '#333333', // SVG attribute and value
                    'stroke-width': 0.5//连线粗细
                }
            }
        });
        graph.addCell(cell);
        return cell;
    }    
                    
    var ElementView = joint.dia.ElementView.extend({
        pointerdown: function () {
            this._click = true;
            joint.dia.ElementView.prototype.pointerdown.apply(this, arguments);
        },
        pointermove: function(evt, x, y) {
            this._click = false;
        },
        pointerup: function (evt, x, y) {
           this._click = true;
            if (this._click) {
                this.notify('cell:click', evt, x, y); 
            } else {
                joint.dia.ElementView.prototype.pointerup.apply(this, arguments);
            }
        }
    });
    
    var LinkView = joint.dia.LinkView.extend({
        addVertex: function(evt, x, y) {},
        removeVertex: function(endType) {},
        pointerdown:function(evt, x, y) {}
    });
    
    //定义画布
    var paperWidth = $('#paper').width();
    var paper = new joint.dia.Paper({
        el: $('#paper'),
        width: paperWidth-15,
        height: 1000,
        gridSize: 1,
        model: graph,
        elementView: ElementView,
        linkView:LinkView
    });    
    var shapesSize = paperWidth/12;
    //定義框的形狀
    var state = function(x, y, shape, background, text){
        var cell;
        var textColor;
        if(background=="#009ACD"||background=="#FB9900"||background=="#FB9900" || background=="#EE5C42") {
            textColor = "white";
            strokeWidth = "0"
        }else {
            textColor = "black";
            strokeWidth = "1"
        }
        
        if(shape==="rect"){
            cell = new joint.shapes.standard.Rectangle();
            cell.resize(shapesSize, 40);
            cell.position(x, y);
            cell.attr('label/text', text);
            cell.attr('label/font-size', '14px');
            cell.attr('label/fill', textColor);
            cell.attr('body/refPoints', '0,5 10,0 20,5 10,10');
            cell.attr('body/fill', background);
            cell.attr('body/strokeWidth', strokeWidth);
            cell.attr('body/stroke', '#999999');
            cell.attr('body/rx', '5px');
            cell.attr('body/ry', '5px');
            
        }  else if(shape==="rect"){
            cell = new joint.shapes.basic.Rect({
                position: { x: x, y: y },//坐标
                size: { width: shapesSize, height: 40 },//宽高
                attrs: { 
                    rect: {
                        fill: background,
                        stroke: '#999999',//边框颜色
                        'stroke-width': 1 ,//边框大小
                        rx:'5px',
                        ry: '5px'
                    },
                    text: { text: text,fill:textColor}, //显示文字
                }
            });
        } else if(shape==="ellipse"){
            cell = new joint.shapes.basic.Rect({
                position: { x: x, y: y },//坐标
                size: { width: shapesSize, height: 40 },//宽高
                attrs: { 
                    rect: {
                        fill: background,
                        stroke: '#999999',//边框颜色
                        'stroke-width': strokeWidth,//边框大小
                        rx:'28px',
                        ry: '28px'
                    },
                    text: { text: text,fill:textColor } //显示文字
                }
            });
        } else if(shape==="polygon") {
            cell = new joint.shapes.standard.Polygon();
            cell.resize(shapesSize, 40);
            cell.position(x, y);
            cell.attr('label/text', text);
            cell.attr('label/font-size', '12px');
            cell.attr('label/fill', textColor);

            cell.attr('body/refPoints', '0,5 10,0 20,5 10,10');
            cell.attr('body/fill', background);
            cell.attr('body/strokeWidth', '1');
        } else if(shape==="circle") {
            var cell = new joint.shapes.standard.Circle();
            cell.resize(20, 20);
            cell.position(x, y);
            cell.attr('root/title', 'joint.shapes.standard.Circle');
            cell.attr('label/text', text);
            cell.attr('label/fill', 'white');
            cell.attr('body/fill', background);
            cell.attr('body/strokeWidth', '0');
            cell.attr('label/fill', textColor);
            cell.attr('label/font-size', '12px');
        }
        graph.addCell(cell);
        return cell;
    };
    
    //创建元素
    //定义形状
    var setX = 20;     //初始的x軸位置
    var setY = 20;    //初始的y軸位置
    var addSetX = paperWidth/8; 
    var addSetY = 80;
    
    //leave 1
    //var start = state(setX,setY,"ellipse","#009ACD", "开始");    
    var last = state(setX + addSetX*7,setY,"ellipse","#F2F2F2","整案結案");
    //leave 2
    setY = setY-addSetY
    var state0 = state(setX,setY+addSetY,"ellipse","#009ACD", "立案");
    
    //leave 3
    var state4 = state(setX,setY+addSetY*2,"rect","#009ACD","分案確認");
    link(state0,state4,"");
    
    //leave 4
    setY = setY+shapesSize/2;
    var state5 = state(setX + addSetX*1,setY+addSetY*3,"rect","#009ACD","竊盜查勘");
    link(state4,state5,"").vertices([
        new g.Point(setX+shapesSize/2, setY+addSetY*3+20),
    ]);
    
    //state(setX + addSetX*1+83,setY+addSetY*3-10,"circle","#289DD8", "15");

    var state6 = state(setX + addSetX*2,setY+addSetY*3,"rect","#009ACD","初次預估");    
    link(state5,state6,"")
    var state7 = state(setX + addSetX*3,setY+addSetY*3,"rect","#FB9900","預估調整");
    state(setX + addSetX*3+shapesSize-shapesSize/8,setY+addSetY*3-10,"circle","#EE5C42", "15");
    
    link(state6,state7,"")
    var state8 = state(setX + addSetX*4,setY+addSetY*3,"rect","#FB9900","最終理算");
    link(state7,state8,"")
    var state9 = state(setX + addSetX*5,setY+addSetY*3,"rect","#F2F2F2","賠款決賠");
    link(state8,state9,"")
    var state10 = state(setX + addSetX*6,setY+addSetY*3,"rect","#F2F2F2","錯更簽核");
    link(state10,state9,"")
    link(state10,state8,"").vertices([
        new g.Point(setX + addSetX*6+shapesSize/2, setY+addSetY*3-20),
       new g.Point(setX + addSetX*4+shapesSize/2, setY+addSetY*3-20),
    ]);

    //leave 5
    var state31 = state(setX + addSetX,setY+addSetY*4,"rect","#009ACD","查勘簽核");
    link(state5,state31);
    
    var state11 = state(setX + addSetX*3,setY+addSetY*4,"rect","#F2F2F2","預估簽核");
    link(state7,state11,"");
    var state12 = state(setX + addSetX*4,setY+addSetY*4,"rect","#F2F2F2","免賠簽核");    

    link(state8,state12,"");
    var state13 = state(setX + addSetX*5,setY+addSetY*4,"rect","#F2F2F2","決賠簽核");
    link(state9,state13,"");
    var state14 = state(setX + addSetX*6,setY+addSetY*4,"rect","#F2F2F2","錯誤結次更正");
    link(state13,state14,"");
    link(state14,state10,"");
    //leave 6
    var state15 = state(setX + addSetX,setY+addSetY*5,"rect","#FB9900","損失關閉");
    link(state4,state15,"").vertices([
        new g.Point(setX+shapesSize/2, setY+addSetY*5+20),
    ]);
    
    var state16 = state(setX + addSetX*2,setY+addSetY*5,"rect","#F2F2F2","損失關閉簽核");
    link(state15,state16,"");
    var state17 = state(setX + addSetX*6,setY+addSetY*5,"rect","#F2F2F2","結案");
    link(state16,state17,"");
    link(state12,state17,"").vertices([
        new g.Point(setX+addSetX*4+shapesSize/2, setY+addSetY*5+20),
    ]);
    link(state13,state17,"").vertices([
        new g.Point(setX+addSetX*5+shapesSize/2, setY+addSetY*5+20),
    ]);
    link(state17,last,"").vertices([
        new g.Point(setX+addSetX*7+shapesSize/2, setY+addSetY*5+20),
    ]);

    //leave 8
    var state18 = state(setX + addSetX*1,setY+addSetY*7,"rect","#009ACD","人傷查勘");
    link(state4,state18,"").vertices([
        new g.Point(setX+shapesSize/2, setY+addSetY*7+20),
    ]);
    
    //leave 8
    var state19 = state(setX + addSetX*2,setY+addSetY*7,"rect","#009ACD","初次預估");
    link(state18,state19,"");
    var state20 = state(setX + addSetX*3,setY+addSetY*7,"rect","#FB9900","預估調整");
    link(state19,state20,"");
    var state21 = state(setX + addSetX*4,setY+addSetY*7,"rect","#F2F2F2","最終理算");
    link(state20,state21,"");
    var state22 = state(setX + addSetX*5,setY+addSetY*7,"rect","#F2F2F2","賠款決賠");
    link(state21,state22,"");
    var state23 = state(setX + addSetX*6,setY+addSetY*7,"rect","#F2F2F2","錯更簽核");
    link(state23,state22,"");
    link(state23,state21,"").vertices([
        new g.Point(setX+addSetX*6+shapesSize/2, setY+addSetY*7-20),
        new g.Point(setX+addSetX*4+shapesSize/2, setY+addSetY*7-20)
    ]);

    //leave 8
    var state24 = state(setX + addSetX*3,setY+addSetY*8,"rect","#F2F2F2","預估簽核");
    link(state20,state24,"");
    var state25 = state(setX + addSetX*4,setY+addSetY*8,"rect","#F2F2F2","免賠簽核");
    link(state21,state25,"");
    var state26 = state(setX + addSetX*5,setY+addSetY*8,"rect","#F2F2F2","決賠簽核");
    link(state22,state26,"");
    var state27 = state(setX + addSetX*6,setY+addSetY*8,"rect","#F2F2F2","錯誤結次更正");
    link(state26,state27,"");
    link(state27,state23,"");

    //leave 10
    var state28 = state(setX + addSetX,setY+addSetY*9,"rect","#FB9900","損失關閉");
    link(state4,state28,"").vertices([
        new g.Point(setX+shapesSize/2, setY+addSetY*9+20),
    ]);
    var state29 = state(setX + addSetX*2,setY+addSetY*9,"rect","#F2F2F2","損失關閉簽核");
    link(state28,state29);
    var state30 = state(setX + addSetX*6,setY+addSetY*9,"rect","#F2F2F2","結案");
    link(state29,state30);
    link(state25,state30).vertices([
        new g.Point(setX + addSetX*4+shapesSize/2, setY+addSetY*9+20),
    ]);
    link(state26,state30).vertices([
        new g.Point(setX+addSetX*5+shapesSize/2, setY+addSetY*9+20),
    ]);
    link(state30,last).vertices([
        new g.Point(setX+addSetX*7+shapesSize/2, setY+addSetY*9+20),
    ]);


    //彈出框propOver部分定義
    joint.shapes.html = {};
    
    joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
        defaults: joint.util.deepSupplement({
            type: 'html.Element',
            attrs: {
                rect: { stroke: 'none', 'fill-opacity': 0 }
            }
        }, joint.shapes.basic.Rect.prototype.defaults)
    });
    
    var mapFlag = new Map();
    
    joint.shapes.html.ElementView = joint.dia.ElementView.extend({
        template: [
            '<div class="html-element"><div id="flag" style="display:none;"></div>',
            '<div class="popover fade right in" style="display: block;">',
            '<div class="arrow" style="top: 50%;"></div><div class="popover-title card-header"><a href="#" class="title "></a> <span class="arrowImg"><img src="./image/ArrowRight_2.png" class="right-side"  style="margin-left:10px;" /> <img src="./image/ArrowLeft_2.png" class="left-side"/> </span></div>',
            '<div class="popover-content" style="width:200px">',
            '<div class="content">',
            '</div>',
            '</div>',
            '</div>',
            '</div>'
        ].join(''),

        initialize: function() {
            _.bindAll(this, 'updateBox');
            joint.dia.ElementView.prototype.initialize.apply(this, arguments);
            this.$box = $(_.template(this.template)());        
            this.model.on('remove', this.removeBox, this);        
            this.updateBox();
        },
        render: function() {
            joint.dia.ElementView.prototype.render.apply(this, arguments);
            this.paper.$el.prepend(this.$box);
            this.updateBox();
            return this;
        },
        updateBox: function() {
            var bbox = this.model.getBBox();
            var classBox = "html-element"+this.model.get("id");
            $(".html-element").each(function(index,tep){
                var className = String($(this).attr("class"));
                if(className=="html-element") {
                    $(this).addClass(classBox);
                }
            });
            $("." + classBox + " .popover-title .title").text(this.model.get('title'));

            var index = mapFlag.get("html-element"+this.model.get("id")) || 0 ;  //記錄第幾次
            
            var valueSize =  this.model.get('JsonValue').length;
            if(valueSize>1) {
                if(index != 0) {
                    $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                    $(".left-side").css("cursor","pointer");
                }else {
                    $(".left-side").css("cursor","auto");
                    $(".right-side").css("cursor","pointer");
                }
                if(index != valueSize-1) {
                    $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                    $(".right-side").css("cursor","pointer");
                } else {
                    $(".left-side").css("cursor","pointer");
                    $(".right-side").css("cursor","auto");
                }
                $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));

            }
            
            var JsonValue = this.model.get('JsonValue')[index];

            for(var item in JsonValue){
                $(".content").append('<span class="labelSpan">'+String(JsonValue[item].name)+'</span>');
                $(".content").append("<span class='valueSpan'>"+JsonValue[item].value+"</span></br>");
            }
        
                        
            $("." + classBox).on("click",(e)=>{
                e.stopPropagation()
            });
                
            if(this.model.get('title')=="最終理算"){
                $('.right-side').on('click', (e)=>{
                    e.stopPropagation();
                    index++;
                    if(index > valueSize-1 || index < 0) {
                        index--;
                        return;
                    }
                    mapFlag.set("html-element"+this.model.get("id"),index);
                    JsonValue = this.model.get('JsonValue')[index];
                    $("." + classBox + " .labelSpan").each(function(index,tep){
                        $(this).text(JsonValue[index].name);
                    });    
            
                    $("." + classBox + " .valueSpan").each(function(index,tep){
                        $(this).text(JsonValue[index].value);
                    });
                    $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));

                    
                    $(".right-side").attr('src',"./image/ArrowRight_2.png"); 
                    $(".left-side").attr('src',"./image/Arrowleft_2.png"); 
                    if(valueSize > 1) {
                        if(index != 0) {
                            $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                            $(".left-side").css("cursor","pointer");
                        }else {
                            $(".left-side").css("cursor","auto");
                            $(".right-side").css("cursor","pointer");
                        }
                        if(index != valueSize-1) {
                            $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                            $(".right-side").css("cursor","pointer");
                        } else {
                            $(".left-side").css("cursor","pointer");
                            $(".right-side").css("cursor","auto");
                        }
                    }
                });
                
                $('.left-side').on('click', (e)=>{
                    e.stopPropagation();
                    index--;
                    if(index > valueSize-1 || index < 0) {
                        index++;
                        return;
                    }
                    mapFlag.set("html-element"+this.model.get("id"),index);
                    JsonValue = this.model.get('JsonValue')[index];
                    $("." + classBox + " .labelSpan").each(function(index,tep){
                        $(this).text(JsonValue[index].name);
                    });    
            
                    $("." + classBox + " .valueSpan").each(function(index,tep){
                        $(this).text(JsonValue[index].value);
                    });
                    $("." + classBox + " .popover-title .title").text(this.model.get('title')+"-00"+(index+1));

                    $(".right-side").attr('src',"./image/ArrowRight_2.png"); 
                    $(".left-side").attr('src',"./image/Arrowleft_2.png"); 
                    if(valueSize>1) {
                        if(index != 0) {
                            $(".left-side").attr('src',"./image/Arrowleft_1.png"); 
                            $(".left-side").css("cursor","pointer");
                        }else {
                            $(".left-side").css("cursor","auto");
                            $(".right-side").css("cursor","pointer");
                        }
                        if(index != valueSize-1) {
                            $(".right-side").attr('src',"./image/ArrowRight_1.png"); 
                            $(".right-side").css("cursor","pointer");
                        } else {
                            $(".left-side").css("cursor","pointer");
                            $(".right-side").css("cursor","auto");
                        }
                    }
                });
            }
            
            this.$box.css({
                width: bbox.width,
                height: bbox.height,
                left: bbox.x,
                top: bbox.y,
            });
        },
        removeBox: function(evt) {
            this.$box.remove();
        },
        
        changeBox: function(evt) {
            this.$box.remove();
        },
        
    });
    
    //彈出部分定義
    joint.shapes.html2 = {};
    
    joint.shapes.html2.Element = joint.shapes.basic.Rect.extend({
        defaults: joint.util.deepSupplement({
            type: 'html2.Element',
            attrs: {
                rect: { stroke: 'none', 'fill-opacity': 0 }
            }
        }, joint.shapes.basic.Rect.prototype.defaults)
    });
    
    joint.shapes.html2.ElementView = joint.dia.ElementView.extend({
        template: [
            '<div class="container html2-margin">',
            '<div class="card card-outline-default" style="margin-top: 200px;">',
                '<div class="card-header" style="padding:5px;"><span><h4 class="card-title" tabindex="-1">賠案號碼:123789123978</h4></span></div>',
                '<div class="card-block collapse show">',
                    '<div style="height:250px"></div>',
                '</div>',
                '</div>',
            '</div>'
        ].join(''),

        initialize: function() {
            _.bindAll(this, 'updateBox');
            joint.dia.ElementView.prototype.initialize.apply(this, arguments);
            this.$box = $(_.template(this.template)());    

            this.updateBox();
        },
        render: function() {
            joint.dia.ElementView.prototype.render.apply(this, arguments);
            this.paper.$el.prepend(this.$box);
            this.updateBox();
            return this;
        },
        updateBox: function() {
            let width = paperWidth*0.8 + "px";
            $(".html2-margin .card-outline-default").css('width',width);
            let maginleft = paperWidth/12+20+"px"
            $(".html2-margin").css('margin-left',maginleft);
            var bbox = this.model.getBBox();    
            this.model.get("title");
            this.$box.find(".card-header h4").text(this.model.get("title"));
            this.$box.find(".card-outline-default").css("margin-top",this.model.get("top"));
            this.$box.css({
                width: bbox.width,
                height: bbox.height,
                left: bbox.x,
                top: bbox.y,
            });
        },
        removeBox: function(evt) {
            this.$box.remove();
        }
    });

    var html2 = new joint.shapes.html2.Element({
        title:"本車財損:PCE-0234",
        top:"135px"
    });
    
    var html3 = new joint.shapes.html2.Element({
        title:"人傷查勘:江志軍",
        top:"455px"
    });

    graph.addCell(html2); 
    graph.addCell(html3); 

        
    //给所有元素添加点击事件
    var map = new Map();
    paper.on('cell:click', function (e) {        
        let offsetX = $("#"+e.id).offset().left;
        let offsetY = $("#"+e.id).offset().top;
        
        if($("#"+e.id+" title").html()=="joint.shapes.standard.Circle") {
            return;
        }
        
        var arr = $("#"+e.id+" tspan");
        var tmp="";
        $.each(arr, function(k,v){
           tmp+=$(v).html();
        });
        
        map.forEach(function (item, key, mapObj) {
            item.remove();
        });
        map.clear();
        
        var el1;
        if(tmp=="已完成" || tmp=="未完成" || tmp=="未生成" || tmp=="整案結案" || tmp=="代服務簽核?" || tmp=="預估調整?" || tmp=="預估簽核?" || tmp=="免賠簽核?" || tmp=="全部免賠?" || tmp=="賠款決賠簽核?" || tmp=="部分賠付?") {
            return;
        }
        if(tmp=="立案" || tmp=="分案確認" || tmp=="初次預估" || tmp == "車損查勘") {
            el1 = new joint.shapes.html.Element({
                id: e.id,
                position: { x: offsetX+5, y: offsetY-210 },
                size: { width: 170, height: 120 },
                JsonValue:[[{name: "開始時間" , value:'107/07/01'},{name: '結束時間' , value:'107/07/01'},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'}]],
                title:tmp
            });
        } else if(tmp=="最終理算") {
                el1 = new joint.shapes.html.Element({
                id: e.id,
                position: { x: offsetX+5, y: offsetY-210 },
                size: { width: 170, height: 120 },
                JsonValue:[[{name: "開始時間" , value:'107/07/01'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'},{name: '和解時間' , value: '107/07/04'},{name: '資料補全日' , value: '107/07/04'}],[{name: '開始時間' , value:'107/07/03'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '否'},{name: '處理人員' , value: '張三'},{name: '和解時間' , value: '107/07/04'},{name: '資料補全日' , value: '107/07/04'}]],
                title:tmp
            });
        } else {
            el1 = new joint.shapes.html.Element({
                id: e.id,
                position: { x: offsetX+5, y: offsetY-210 },
                size: { width: 170, height: 120 },
                JsonValue:[[{name: '開始時間' , value:'107/07/01'},{name: '結束時間' , value:''},{name:'是否逾期' , value: '是'},{name: '處理人員' , value: '張三'}]],
                title:tmp
            });
        }
        graph.addCell(el1); 
        map.set(e.id,el1);
    });

    function ccc() {
        map.forEach(function (item, key, mapObj) {
            item.remove();
        });
        map.clear();
    }
    
 </script>
    




</html>
View Code