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 相关文章推荐
自适应图片大小的弹出窗口
Jul 27 Javascript
jQuery 遍历- 关于closest() 的方法介绍以及与parents()的方法区别分析
Apr 26 Javascript
pace.js页面加载进度条插件
Sep 29 Javascript
jQuery实现仿QQ在线客服效果的滚动层代码
Oct 15 Javascript
酷炫jQuery全屏3D焦点图动画效果
Mar 22 Javascript
jQuery的框架介绍
May 11 Javascript
基于BootStrap Metronic开发框架经验小结【三】下拉列表Select2插件的使用
May 12 Javascript
41个Web开发者必须收藏的JavaScript实用技巧
Jul 22 Javascript
vue element-ui table表格滚动加载方法
Mar 02 Javascript
vue2.0 实现页面导航提示引导的方法
Mar 13 Javascript
微信小程序中使用自定义图标(阿里icon)的方法
Aug 20 Javascript
js 执行上下文和作用域的相关总结
Feb 08 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
给初学者的30条PHP最佳实践(荒野无灯)
2011/08/02 PHP
2014年最新推荐的10款 PHP 开发框架
2014/08/01 PHP
cssQuery()的下载与使用方法
2007/01/12 Javascript
jQuery CSS()方法改变现有的CSS样式表
2014/09/09 Javascript
nodejs中转换URL字符串与查询字符串详解
2014/11/26 NodeJs
js实现禁止中文输入的方法
2015/01/14 Javascript
深入学习js瀑布流布局
2016/10/14 Javascript
angular中的cookie读写方法
2017/08/02 Javascript
Vue项目引进ElementUI组件的方法
2018/11/11 Javascript
nodejs和react实现即时通讯简易聊天室功能
2019/08/21 NodeJs
JS+JQuery实现无缝连接轮播图
2020/12/30 jQuery
理解生产者消费者模型及在Python编程中的运用实例
2016/06/26 Python
解决Python requests 报错方法集锦
2017/03/19 Python
Windows下安装python2和python3多版本教程
2017/03/30 Python
java中两个byte数组实现合并的示例
2018/05/09 Python
python实现对输入的密文加密
2019/03/20 Python
Python中sys模块功能与用法实例详解
2020/02/26 Python
Python3之乱码\xe6\x97\xa0\xe6\xb3\x95处理方式
2020/05/11 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
2020/06/04 Python
如何在pycharm中安装第三方包
2020/10/27 Python
使用CSS3编写类似iOS中的复选框及带开关的按钮
2016/04/11 HTML / CSS
以实惠的价格轻松租车,免费取消:Easyrentcars
2019/07/16 全球购物
初中生自我评价
2014/02/01 职场文书
运动会通讯稿500字
2014/02/20 职场文书
文案策划求职信
2014/03/18 职场文书
学生个人自我鉴定范文
2014/03/28 职场文书
班级标语大全
2014/06/21 职场文书
12.4全国法制宣传日活动总结
2014/11/01 职场文书
八月一日观后感
2015/06/10 职场文书
有关朝花夕拾的读书笔记
2015/06/29 职场文书
2015年暑假生活总结
2015/07/13 职场文书
贷款担保书范本
2015/09/22 职场文书
如何将numpy二维数组中的np.nan值替换为指定的值
2021/05/14 Python
html+css实现分层金字塔的实例
2021/06/02 HTML / CSS
Oracle数据库中通用的函数实例详解
2022/03/25 Oracle
win10怎么设置右下角图标不折叠?Win10设置右下角图标不折叠的方法
2022/07/15 数码科技