JointJS流程图的绘制方法


Posted in Javascript onDecember 03, 2018

最近项目上需要用流程图来做问题定界分析,之前有同事用jsPlumb做过,但是阅读代码后觉得比较麻烦,所以自己又找了一圈,找到一个叫Dagre-D3的开源类库,画出来的效果如下图,Dagre-D3最大的优点就是可以实现自动布局,你只需要put数据就可以了,但是缺点就是自动布局后的连线会比较乱,而且连线不是横平竖直的,对于流程图不复杂的还好,稍微复杂点画出来的连线就没法看。最后还是被pass了。

jsPlumb地址:https://jsplumbtoolkit.com

Dagre-D3 Git地址:https://github.com/cpettitt/dagre-d3

JointJS流程图的绘制方法

后面经过一番百度,最终决定用JointJS,官网:www.jointjs.com,相比Dagre-D3和jsPlumb,JointJS的API很详细,代码量少,连接线有多种选择,封装了多种常用的形状,而且能画的图很多,官方也给了一些demo可以参考。下面是我用JointJS画出来的流程图:

JointJS流程图的绘制方法

依赖:在官网的下载页面都能找到

<link rel="stylesheet" type="text/css" href="joint.css" />
<script src="jquery.min.js"></script>
<script src="lodash.min.js"></script>
<script src="backbone-min.js"></script>
<script src="joint.js"></script>

我的demo里还引用了bootstrap的依赖用来显示模态框

html代码

<body>
 <div id="paper" class="paper"></div>
 
 <div class="modal fade searchpanel" id="detailModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
 <div class="modal-dialog" role="document">
 <div class="modal-content">
  <div class="modal-header">
  <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  <h4 class="modal-title" id="modalTitle">详细信息</h4>
  </div>
  <div class="modal-body">

  </div>
  <div class="modal-footer">
  <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
  </div>
 </div>
 </div>
 </div>
</body>

js代码

首先是定义画板和画布,这里重写了ElementView和LinkView,目的是为了让画出来的流程图不能被删除和编辑

var graph = new joint.dia.Graph();

 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;
  joint.dia.ElementView.prototype.pointermove.apply(this, arguments);
 },
 pointerup: function (evt, x, y) {
  if (this._click) {
  // triggers an event on the paper and the element itself
  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 paper = new joint.dia.Paper({
 el: $('#paper'),
 width: 1200,
 height: 600,
 gridSize: 1,
 model: graph,
 elementView: ElementView,
 linkView:LinkView
 });
 //paper.$el.css('pointer-events', 'none')//去除默认样式,使所有事件不可用

然后我写了两个函数分别用来创建形状和连线,这样写可以减少代码量,官方的demo也大都是这样写的

//定义形状
 var state = function(x, y, shape, background, text){
 var cell;
 if(shape==="rect"){
  cell = new joint.shapes.basic.Rect({
  position: { x: x, y: y },//坐标
  size: { width: 140, height: 40 },//宽高
  attrs: { 
   rect: {
   fill: {
    type: 'linearGradient',
    stops: [
    { offset: '0%', color: background },//渐变开始
    { offset: '100%', color: '#fe8550' }//渐变结束
    ],
    attrs: { x1: '0%', y1: '0%', x2: '0%', y2: '100%' }
   },
   stroke: background,//边框颜色
   'stroke-width': 1//边框大小
   },
   text: { text: text } //显示文字
  }
  });
 } else if(shape==="ellipse"){
  cell = new joint.shapes.basic.Ellipse({
  position: { x: x, y: y },//坐标
  size: { width: 140, height: 40 },//宽高
  attrs: { 
   ellipse: {
   fill: {
    type: 'linearGradient',
    stops: [
    { offset: '0%', color: background },//渐变开始
    { offset: '100%', color: '#FFFFFF' }//渐变结束
    ],
    attrs: { x1: '0%', y1: '0%', x2: '0%', y2: '100%' }
   },
   stroke: background,//边框颜色
   'stroke-width': 1//边框大小
   },
   text: { text: text } //显示文字
  }
  });
 }
 graph.addCell(cell);
 return cell;
 };
 
 //定义连线
 function link(source, target, label){
 var cell = new joint.dia.Link({ 
  source: { id: source.id },
  target: { id: target.id },
  labels: [{ position: 0.5, attrs: { text: { text: label || '', 'font-weight': 'bold' } } }],
  router: { name: 'manhattan' },//设置连线弯曲样式 manhattan直角
  attrs: {
  '.connection': {
   stroke: '#333333',//连线颜色
   'stroke-width': 2//连线粗细
  },
  '.marker-target': {
   fill: '#333333',//箭头颜色
   d: 'M 10 0 L 0 5 L 10 10 z'//箭头样式
  }
  }
 });
 graph.addCell(cell);
 return cell;
 }

最后就是我们实际的业务代码了,这里我们可以整理一下数据结构,把数据定义成json格式,然后写一个函数通过json直接生成流程图,当然坐标需要寻找规律自己计算一下

//创建元素
 var start = state(500,100,"ellipse","#00FFFF", "视频播放成功率");
 var state1 = state(500,200,"rect","#f7a07b", "GET响应成功率");
 var state2 = state(400,300,"rect","#f7a07b", "HTTP错误码分析");
 var state3 = state(600,300,"rect","#f7a07b", joint.util.breakText("TCP异常和其他原因",{width:80}));
 var state4 = state(400,400,"rect","#f7a07b", "4XX、5XX分析");
 var state5 = state(600,400,"rect","#f7a07b", "接口以上分析");
 var state6 = state(750,400,"rect","#f7a07b", "接口以下分析");
 
//创建连线
 link(start, state1, "");
 link(state1, state2, "≥70%");
 link(state1, state3, "<70%");
 link(state2, state4, "");
 link(state3, state5, "是");
 link(state3, state6, "否");
 
 //给所有元素添加点击事件
 paper.on('cell:click', function (e) {
 $("#detailModal .modal-body").html("");
 var arr = $("#"+e.id+" tspan");
 if(arr.length===1){
  $("#detailModal .modal-body").append($(arr).html());
  $("#detailModal").modal();
 } else{
  var tmp="";
  $.each(arr, function(k,v){
  tmp+=$(v).html();
  });
  $("#detailModal .modal-body").append(tmp);
  $("#detailModal").modal();
 }
 
 });

后面是给每个元素(不包含连线)添加了一个点击事件,弹出一个模态框,显示当前点击的内容。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Extjs中常用表单介绍与应用
Jun 07 Javascript
JS无法捕获滚动条上的mouse up事件的原因猜想
Mar 21 Javascript
input禁止键盘及中文输入,但可以点击
Feb 13 Javascript
给js文件传参数(详解)
Jul 13 Javascript
jQuery中each()方法用法实例
Dec 27 Javascript
Node.js服务器环境下使用Mock.js拦截AJAX请求的教程
May 23 Javascript
js 获取范围内的随机数实例代码
Aug 02 Javascript
JS声明式函数与赋值式函数实例分析
Dec 13 Javascript
bootstrap datetimepicker实现秒钟选择下拉框
Jan 05 Javascript
在Vue.js中使用Mixins的方法
Sep 12 Javascript
vue控制多行文字展开收起的实现示例
Oct 11 Javascript
Vue实现todo应用的示例
Feb 20 Vue.js
微信小程序之事件交互操作实例分析
Dec 03 #Javascript
vue-better-scroll 的使用实例代码详解
Dec 03 #Javascript
Vue项目中使用better-scroll实现一个轮播图自动播放功能
Dec 03 #Javascript
Vue.js 图标选择组件实践详解
Dec 03 #Javascript
vue-music 使用better-scroll遇到轮播图不能自动轮播问题
Dec 03 #Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
Dec 03 #Javascript
利用jquery和BootStrap实现动态滚动条效果
Dec 03 #jQuery
You might like
推荐php模板技术[转]
2007/01/04 PHP
php判断是否为json格式的方法
2014/03/04 PHP
php中操作memcached缓存进行增删改查数据的实现代码
2014/08/15 PHP
php中debug_backtrace、debug_print_backtrace和匿名函数用法实例
2014/12/01 PHP
memcache一致性hash的php实现方法
2015/03/05 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
破除一些网站复制、右键限制
2006/11/04 Javascript
JS解密入门之凭直觉解
2008/06/25 Javascript
JavaScript 给汉字排序实例代码
2008/06/28 Javascript
javascript的tab切换原理与效果实现方法
2015/01/10 Javascript
jQuery实现ajax调用WCF服务的方法(附带demo下载)
2015/12/04 Javascript
javascript表单事件处理方法详解
2016/05/15 Javascript
jQuery height()、innerHeight()、outerHeight()函数的区别详解
2016/05/23 Javascript
Jquery和BigFileUpload实现大文件上传及进度条显示
2016/06/27 Javascript
js中常用的Math方法总结
2017/01/12 Javascript
详解微信小程序 template添加绑定事件
2017/06/23 Javascript
vue中使用input[type=&quot;file&quot;]实现文件上传功能
2018/09/10 Javascript
[31:33]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS DT 第一场
2014/05/23 DOTA
Python二分法搜索算法实例分析
2015/05/11 Python
python使用两种发邮件的方式smtp和outlook示例
2017/06/02 Python
使用python实现ANN
2017/12/20 Python
python中实现字符串翻转的方法
2018/07/11 Python
Flask框架URL管理操作示例【基于@app.route】
2018/07/23 Python
python脚本实现音频m4a格式转成MP3格式的实例代码
2019/10/09 Python
浅谈cv2.imread()和keras.preprocessing中的image.load_img()区别
2020/06/12 Python
django ObjectDoesNotExist 和 DoesNotExist的用法
2020/07/09 Python
python调用win32接口进行截图的示例
2020/11/11 Python
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
新加坡交友网站:be2新加坡
2019/04/10 全球购物
Java中compareTo和compare的区别
2016/04/12 面试题
母亲追悼会答谢词
2014/01/27 职场文书
终止解除劳动合同证明书
2015/06/17 职场文书
法制工作总结2015
2015/07/23 职场文书
出纳2015年度工作总结范文
2015/10/14 职场文书
接触艺术对孩子学习思维有益
2019/08/06 职场文书
mysql通过group by分组取最大时间对应数据的两种有效方法
2022/09/23 MySQL