vue中使用gojs/jointjs的示例代码


Posted in Javascript onAugust 24, 2018

因为公司项目需求,要画出相关业务的流程图,以便客户了解自己身处何处

搜索框输入 “前端流程图插件”,查了很多资料,总结一下有以下几种

flow-chart

代码写法繁琐,不是json就可以解决,效果也比较丑,PASS

darge-d3

github :https://github.com/dagrejs/dagre-d3

效果图

vue中使用gojs/jointjs的示例代码

下载里面的demo,改一下json就可以了

// States 
var states = [ "NEW", "SUBMITTED","FINISHED" ,"FAILED","DELIVER", 
    "CANCELED", "ABOLISHED" , "DELETED","REFUNDING","REFUNDED"];
var map = ['新创建','已提交','已完成','提交失败',"交付中",
    '已取消','废除','已删除','退款中',"已退款"]
// Automatically label each of the nodes
states.forEach(function(state,index) { g.setNode(state, { label: `${map[index]}(${state})`})});

// Set up the edges
g.setEdge("NEW", "FAILED",  { label: "后台接口自动"});
g.setEdge("NEW", "SUBMITTED", { label: "后台接口自动" });
g.setEdge("NEW", "CANCELED", { label: "用户取消订单" });
g.setEdge("SUBMITTED","CANCELED",  { label: "用户取消订单" });
g.setEdge("SUBMITTED", "ABOLISHED", { label: "用户超过48小时未支付,\n系统自动取消"});
g.setEdge("ABOLISHED","DELETED",  { label: "已删除" });
g.setEdge("CANCELED", "DELETED", { label: "已删除"});
g.setEdge("FAILED", "SUBMITTED",  { label: "后台接口自动" });

g.setEdge("SUBMITTED", "DELIVER",  { label: "用户支付" });
g.setEdge("FINISHED", "REFUNDING",  { label: "用户退款" });

g.setEdge("DELIVER", "FINISHED",  { label: "交付完成" });
g.setEdge("REFUNDING", "REFUNDED",  { label: "已退款" });
g.setEdge("REFUNDED", "DELETED",  { label: "已删除" });
g.setEdge("DELIVER", "REFUNDING",  { label: "用户退款" });
g.setEdge("FAILED", "CANCELED",  { label: "用户取消订单" });

不满意的地方:画出来的图是垂直方向的,我要的是水平方向,PASS

gojs

GoJS是一个实现交互类图表(比如流程图,树图,关系图,力导图等等)的JS库。本文将介绍GoJs的精华部分。
因为GoJS依赖于HTML5,所以请保证您的浏览器版本支持HTML5,当然还要加载这个库。

github :https://github.com/NorthwoodsSoftware/GoJS

可以通过npm install gojs -save安装

效果图

vue中使用gojs/jointjs的示例代码

看里面的demo我自己包装了一下

<template>
<div>
 <p style="background-color:#d5d5d5;margin:0;padding:5px;">
 您当前处于 <span class="tip">用户提交资料</span> 步骤 
 下一步等待<span class="tip">供应商接单</span>
 <el-button type="text" v-if="show===false" @click="show=true">展开</el-button>
 <el-button type="text" v-else @click="show=false">收起</el-button>
 
 </p>
 <div id="myDiagramDiv" v-show="show" ></div>
 </div> 
 
</template>
<style scoped>
.tip{
 color:red;
 font-size:0.8em;
 font-weight:bold;
 padding:5px;
}
#myDiagramDiv{
 height: 200px; 
 border: solid 1px #d3d3d3;
}

</style>
<script>
window.go =require('./go.js') 
var $ = go.GraphObject.make;

import datam from './data';
export default{
 mixins:[datam],
 data(){
 return{
  myDiagram:null,
  show:true
 }
 },
 mounted(){
 this.load();
 },
 methods:{
 load(){
  this.init();
  this.addNodeTemplate(this.User);
  this.addNodeTemplate(this.Supplier);
  this.layout();
 },
 layout() {
  this.myDiagram.model = go.Model.fromJson(this.myjson);
  this.myDiagram.layoutDiagram(true);
 },

 getOption(){
  // for conciseness in defining templates

  let options={
  yellowgrad : $(go.Brush, "Linear", { 0: "rgb(254, 201, 0)", 1: "rgb(254, 162, 0)" }),
  greengrad : $(go.Brush, "Linear", { 0: "#98FB98", 1: "#9ACD32" }),
  bluegrad : $(go.Brush, "Linear", { 0: "#B0E0E6", 1: "#87CEEB" }),
  redgrad : $(go.Brush, "Linear", { 0: "#C45245", 1: "#871E1B" }),
  whitegrad : $(go.Brush, "Linear", { 0: "#F0F8FF", 1: "#E6E6FA" }),
  bigfont : "bold 8pt Helvetica, Arial, sans-serif",
  smallfont : "bold 6pt Helvetica, Arial, sans-serif",
  
  }

  return options;
 },

  textStyle(){
  return {
   margin: 6,
   wrap: go.TextBlock.WrapFit,
   textAlign: "center",
   editable: true,
   font: this.getOption()['bigfont']
  }
  },
  init(){
  this.myDiagram =
   $(go.Diagram, "myDiagramDiv",
    {
    isReadOnly: true,
    // have mouse wheel events zoom in and out instead of scroll up and down
    "toolManager.mouseWheelBehavior": go.ToolManager.WheelNone,
    initialAutoScale: go.Diagram.Uniform,
    "linkingTool.direction": go.LinkingTool.ForwardsOnly,
    initialContentAlignment: go.Spot.Center,
    layout: $(go.LayeredDigraphLayout, { isInitial: false, isOngoing: false, layerSpacing: 50 }),
    "undoManager.isEnabled": true
    });
    //默认节点模板
  this.myDiagram.nodeTemplate =
   $(go.Node, "Auto",
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    // define the node's outer shape, which will surround the TextBlock
    $(go.Shape, "Rectangle",
    { fill: this.getOption()['yellowgrad'], stroke: "black",
     portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
     toEndSegmentLength: 50, fromEndSegmentLength: 40 }),
    $(go.TextBlock, "Page",
    { margin: 6,
     font: this.getOption()['bigfont'],
     editable: true },
    new go.Binding("text", "text").makeTwoWay()));
   // replace the default Link template in the linkTemplateMap
   this.myDiagram.linkTemplate =
    $(go.Link, // the whole link panel
     new go.Binding("points").makeTwoWay(),
     { curve: go.Link.Bezier, toShortLength: 15 },
     new go.Binding("curviness", "curviness"),
     $(go.Shape, // the link shape
     { stroke: "#2F4F4F", strokeWidth: 2.5 }),
     $(go.Shape, // the arrowhead
     { toArrow: "kite", fill: "#2F4F4F", stroke: null, scale: 2 })
     );
  },
  /**
  * options:{
  * category
  * shape:RoundedRectangle/Rectangle
  * shapeOptions:{
  * fill:bluegrad/greengrad/yellowgrad/null/redgrad/whitegrad 自定义的
  * stroke: "black",
  * portId:""
  * fromLinkable:true
  * toLinkable:
  * cursor:"pointer"
  * fromEndSegmentLength:40
  * toEndSegmentLength
  * strokeWidth
  * 
  * }
  * textStyle:{
  *  margin: 9,
  *  maxSize: new go.Size(200, NaN),
  *  wrap: go.TextBlock.WrapFit,
  *  editable: true,
  *  textAlign: "center",
  *  font: smallfont 
  * },
  * 
  * }
  */
  addNodeTemplate(options){
  let fill = this.getOption()[options.shapeOptions.fill];
  options.shapeOptions.fill = fill;
  this.myDiagram.nodeTemplateMap.add(options.category,
   $(go.Node, "Auto",
   new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
   $(go.Shape, options.shape,options.shapeOptions),
   $(go.TextBlock, this.textStyle(),
    new go.Binding("text", "text").makeTwoWay())
   ));
  },

 }


}
</script>

不满意的地方:

  1. 免费版gojs是有水印的,百度搜索“gojs如何去水印”有一堆答案,我就不写了。
  2. 因为要自己手动去掉水印,所以我只能手动下载go.js放在我自己的组件目录下,但是这个文件太大了,800+KB,npm run dev 的时候停在这里停了好久。有时候还爆出“......maximun ....500KB”的错误,我也不知道是什么原因,不知道有什么方法,有的话麻烦通知我。
  3. 代码写法有点太繁琐

这是我自己包装的代码地址:https://github.com/LRY1994/vue-lib/tree/master/src/components/process-go

jointjs

相比Dagre-D3和jsPlumb,JointJS的API很详细,代码量少,连接线有多种选择,封装了多种常用的形状,而且能画的图很多,官方也给了一些demo可以参考。

github : https://github.com/clientIO/joint

效果图

vue中使用gojs/jointjs的示例代码

可以通过npm install jointjs -save安装

参照了很多demo和文档,用的是矩形,但是可以设置圆角的度数变成椭圆形,其他形状我就无力了。

可以自定义矩形的样式和矩形框里面的文字样式

//data.vue
<script>
export default {
 data(){
  var userClass = {//这个要参照SVG属性
   /**shapeStyle
    * fill:填充的背景颜色
    stroke: 边框颜色
    strokeWidth: 边框宽度
    rx: 圆角
    ry: 
    */
   shapeStyle:{//矩形样式
    fill:{
     type: 'linearGradient',
     stops: [
      {offset: '0%', color: '#98FB98'},
      {offset: '100%', color: '#9ACD32'}
     ],
    },
    rx:150,
    ry:15
   },
   /**
    * textStyle
    * fontWeight
    * fontSize
    * 
    */
   textStyle:{//文本样式
    fontWeight:'bold'
   } 
  };
  return{
   graphData :{
    node:{
     '100':{text:'用户提交资料',category:userClass},
     '101':{text:'用户完善资料',category:userClass},
     '102':{text:'用户确认完成',category:userClass},
     '103':{text:'用户撤销',category:userClass},

     '200':{text:'供应商驳回'},
     '201':{text:'供应商接单'},
     '202':{text:'供应商完工'},
     '203':{text:'等待供应商处理'},

     '300':{text:'系统交付出错'}    
    },
    edge :{//每个点都要写
     '100': ['200','201','103'], 
     '101': ['201'],
     '102':[],
     '103': ['100'],

     '200': ['101'],    
     '201': ['202','300'],
     '202': ['102'],    
     '203': ['102'], 

     '300': ['203'],
    
    },
   }
  }
 }
}
</script>
<template>
<div id="container">
 <p style="background-color:#EEEEEE;margin:0;padding:5px;font-size:0.9em">
 您当前处于 <span class="tip">用户提交资料</span> 步骤 
 下一步等待<span class="tip">供应商接单</span>
 <el-button type="text" v-if="show===false" @click="show=true">展开</el-button>
 <el-button type="text" v-else @click="show=false">收起</el-button>
 
 </p>
 <div id="myholder" v-show="show"></div>
</div>
</template>
<script>
window.joint=require('jointjs');
var Shape = joint.dia.Element.define('default.Rectangle', {  
  attrs: { 
   rect: {
    refWidth: '100%',
    refHeight: '100%',
    //下面这些可以自己设置
    fill:{
     type: 'linearGradient',
     stops: [
      {offset: '0%', color: '#B0E0E6'},//渐变开始
      {offset: '100%', color: '#F0F8FF'}//渐变结束
     ]
    },
    stroke: '#B0E0E6',
    strokeWidth: 1,
    rx: 5,//圆角
    ry: 5
   },
   text: {
    refX: '50%',
    refY: '50%',        
    textVerticalAnchor: 'middle',
    textAnchor: 'middle',
    fontSize: 10   
   }
   }     
 }, 
 {
   markup: '<rect/><text/>',
   setText: function(text) {     
   return this.attr('text/text', text || '');
  },
  setShapeStyle:function(shapeStyle){
   let newstyle = Object.assign({},this.attr('rect'),shapeStyle);
   return this.attr('rect',newstyle)
  },
  
  setTextStyle:function(textStyle){
   let newstyle = Object.assign({},this.attr('text'),textStyle);
   return this.attr('text',newstyle)
  }
 }
);

var Link = joint.dia.Link.define('default.Link', {
  attrs: {
   '.connection': {
    stroke: '#2F4F4F',//线
    strokeWidth: 1,
    pointerEvents: 'none',
    targetMarker: {//箭头
     type: 'path',
     fill: '#2F4F4F',//填充颜色
     stroke: '#2F4F4F',//边框颜色
     strokeWidth:'1',
     d: 'M 2 -2 0 0 2 2 z'//形状
    }
   }
  },
  connector: {
   name: 'rounded'
  },
  z: -1,
  weight: 1,
  minLen: 1,
  labelPosition: 'c',
  labelOffset: 10,
  labelSize: {
   width: 50,
   height: 30
  },
  labels: [{
   markup: '<rect/><text/>',
   attrs: {
    text: {
     fill: 'gray',
     textAnchor: 'middle',
     refY: 5,
     refY2: '-50%',
     fontSize: 10,
     cursor: 'pointer'
    },
    // rect: {
    //  fill: 'lightgray',
    //  stroke: 'gray',
    //  strokeWidth: 2,
    //  refWidth: '100%',
    //  refHeight: '100%',
    //  refX: '-50%',
    //  refY: '-50%',
    //  rx: 5,
    //  ry: 5
    // }
   },
   size: {
    width: 50, height: 10
   }
  }]

 }, {
  markup: '<path class="connection"/><g class="labels"/>',
  
  connect: function(sourceId, targetId) {
   return this.set({
    source: { id: sourceId },
    target: { id: targetId }
   });
  },

  setLabelText: function(text) {
   return this.prop('labels/0/attrs/text/text', text || '');
  }
 });



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) {}
});


export default { 
 data(){
  return{
   graph:null,
   paper:null,
   show:true
  }  
 },
 props:{
  graphData:{
   type:Object,
   required:true
  }
 },
 mounted(){
  let w = document.getElementById('container').width ; 
  this.graph = new joint.dia.Graph;
  this.paper = new joint.dia.Paper({
   el: document.getElementById('myholder'),
   width: w,
   height: 250,   
   model: this.graph,
   elementView: ElementView,//禁止拖拽
   linkView:LinkView//禁止拖拽
  });
  this.layout();
 },
 methods:{
  getWidthandHeight(label){
   let maxLineLength = _.max(label.split('\n'), function(l) { return l.length; }).length,

   // Compute width/height of the rectangle based on the number
   // of lines in the label and the letter size. 0.6 * letterSize is
   // an approximation of the monospace font letter width.
    letterSize = 8,
    width = 2 * (letterSize * (0.6 * maxLineLength + 1)),
    height = 2 * ((label.split('\n').length + 1) * letterSize);
   return {width,height}
  },
  getLayoutOptions() {
   return {
    // setVertices: false,
    // setLabels: false,
    // ranker:'longer-path',//'tight-tree'/'network-simplex',
    rankDir: 'LR',
    align: 'UR',
    rankSep:0,
    edgeSep:0,
    nodeSep:0,
   };
  },
  buildGraphFromAdjacencyList(adjacencyList) {
   let elements = [],links = [],obj,size,node;
   const _this=this;
   const map=this.graphData.node;

   Object.keys(adjacencyList).forEach(function(parentId) {
    // Add element

    obj =map[parentId];
    size = _this.getWidthandHeight(obj.text);
    node =new Shape({id:parentId,size:size}).setText(obj.text);

    if(obj.category&&obj.category.shapeStyle){
     node = node.setShapeStyle(obj.category.shapeStyle);
    }
    if(obj.category&&obj.category.textStyle){
     node = node.setTextStyle(obj.category.textStyle);
    }

    elements.push(node);
    
    // Add links
    adjacencyList[parentId].forEach(function(childId) {
     links.push(
      new Link().connect(parentId, childId)// .setLabelText(parentLabel + '-' + childLabel)           
     );
    });
   });

   return elements.concat(links);
  },
  layout() {   
   let cells = this.buildGraphFromAdjacencyList(this.graphData.edge); 
   this.graph.resetCells(cells);
   joint.layout.DirectedGraph.layout(this.graph, this.getLayoutOptions());
  },
 }
}
</script>

<style>
#myholder {
 border: 1px solid lightgray;
 margin-bottom:20px;
 padding-left:20px
}
.tip{
 color:#9ACD32;
 font-size:0.9em;
 font-weight:bold;
 padding:5px;
}
</style>

这是我自己包装的代码地址:https://github.com/LRY1994/vue-lib/tree/master/src/components/process-joint

这个目前看来还算满意

jsplumb

这个看了官网,不太友好,而且下载只有一个js文件,没有demo代码,不知如何下手

参考资料:

https://gojs.net/latest/samples/pageFlow.html
http://www.daviddurman.com/assets/autolayout.js
http://resources.jointjs.com/demos/layout

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

Javascript 相关文章推荐
jquery的选择器的使用技巧之如何选择input框
Sep 22 Javascript
JavaScript中Number.NEGATIVE_INFINITY值的使用详解
Jun 05 Javascript
轻松学习jQuery插件EasyUI EasyUI创建树形网络(1)
Nov 30 Javascript
javascript匀速运动实现方法分析
Jan 08 Javascript
浅析js绑定事件的常用方法
May 15 Javascript
Centos7 中安装 Node.js v4.4.4
Nov 03 Javascript
微信小程序 页面跳转和数据传递实例详解
Jan 19 Javascript
如何理解Vue的.sync修饰符的使用
Aug 17 Javascript
JS使用Prim算法和Kruskal算法实现最小生成树
Jan 17 Javascript
微信小程序3D轮播实现代码
Sep 19 Javascript
详解Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸总结
May 28 Javascript
JavaScript 去重和重复次数统计
Mar 31 Javascript
vue操作下拉选择器获取选择的数据的id方法
Aug 24 #Javascript
浅谈Vue组件及组件的注册方法
Aug 24 #Javascript
JavaScript中this关键字用法实例分析
Aug 24 #Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
Aug 24 #Javascript
JavaScript原型链与继承操作实例总结
Aug 24 #Javascript
element-ui循环显示radio控件信息的方法
Aug 24 #Javascript
vue-cli2打包前和打包后的css前缀不一致的问题解决
Aug 24 #Javascript
You might like
php基础知识:类与对象(2) 自动加载对象
2006/12/13 PHP
检测png图片是否完整的php代码
2010/09/06 PHP
优化PHP代码技巧的小结
2013/06/02 PHP
php实现文件下载(支持中文文名)
2013/12/04 PHP
PHP实现支付宝即时到账功能
2016/12/21 PHP
PHP实现将多个文件中的内容合并为新文件的方法示例
2017/06/10 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
JQuery拖拽元素改变大小尺寸实现代码
2012/12/10 Javascript
ScrollDown的基本操作示例
2013/06/09 Javascript
javascript for-in有序遍历json数据并探讨各个浏览器差异
2015/11/30 Javascript
深入浅析JavaScript中的scrollTop
2016/07/11 Javascript
AngularJS实现单独作用域内的数据操作
2016/09/05 Javascript
nodejs使用express创建一个简单web应用
2017/03/31 NodeJs
js实现鼠标拖拽多选功能示例
2017/08/01 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
JS实现鼠标按下拖拽效果
2020/07/23 Javascript
使用Python脚本在Linux下实现部分Bash Shell的教程
2015/04/17 Python
python实现TCP服务器端与客户端的方法详解
2015/04/30 Python
Python使用Tkinter实现机器人走迷宫
2018/01/22 Python
numpy.ndarray 交换多维数组(矩阵)的行/列方法
2018/08/02 Python
python使用Matplotlib画饼图
2018/09/25 Python
Python元组常见操作示例
2019/02/19 Python
在python中用print()输出多个格式化参数的方法
2019/07/16 Python
Python的缺点和劣势分析
2019/11/19 Python
python numpy实现多次循环读取文件 等间隔过滤数据示例
2020/03/14 Python
一款基于css3和jquery实现的动画显示弹出层按钮教程
2015/01/04 HTML / CSS
html5小程序飞入购物车(抛物线绘制运动轨迹点)
2020/10/19 HTML / CSS
印度电子产品购物网站:Vijay Sales
2021/02/16 全球购物
资深地理教师自我评价
2013/09/21 职场文书
关于中国梦的演讲稿
2014/04/23 职场文书
2015年大学团支部工作总结
2015/05/13 职场文书
2016年党员学习廉政准则心得体会
2016/01/20 职场文书
《刷子李》教学反思
2016/02/20 职场文书
详解MongoDB的条件查询和排序
2021/06/23 MongoDB
再谈python_tkinter弹出对话框创建
2022/03/20 Python
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android