博客文章地址:https://lry1994.github.io/stu...
---------------------------------------------更新 2018/8/30----------------------------------------------------------
通過一番實踐,我以爲jointjs很差用了。
不滿意點:javascript
最終採用gojs,上面提到的問題解決方案是:把去掉水印的gojs放在本身的npm服務器上,這樣就能夠npm安裝了!!!
實踐過程當中遇到個問題html
<process-go style="height:250px" v-if="show" :model-data="dataObj.graph" :category="category"> </process-go>
像這樣,用v-if
反覆切換,會報錯Cannot read property 'type' of undefined at Po (go.js?d976:1044)
前端
換成v-show
就不會vue
<process-go style="height:250px" v-show="show" :model-data="dataObj.graph" :category="category"> </process-go>
可是這樣的前提是show初始化是true.若是初始化爲false,沒有報錯,可是圖呈現不出來。
緣由我猜想是:show初始化爲false,組件高度爲0,由於默認畫布就是組件容器,因此畫布高度變成0,圖畫不出。java
最後想出個方法。v-if
和v-show
結合一塊兒使用,加上$once
方法,代碼:node
<process-go style="height:250px" v-if="firstClick" v-show="show" :model-data="dataObj.graph" :category="category"> </process-go>
data(){ return{ show:false, firstClick:false, } } created(){ this.init(); this.$once('firstClick',()=>{ this.firstClick = true }) }, methods:{ init(){...}, look(){//用v-if切換會報錯,只有第一次點擊查看用v-if,其餘用v-show this.$emit('firstClick'); this.show = true; } }
從新封裝了一下gojs 地址:https://github.com/LRY1994/vue-lib/blob/master/src/components/process-go/index.vuegit
-------------------------------------------更新線-----------------------------------------------------------------github
由於公司項目需求,要畫出相關業務的流程圖,以便客戶瞭解本身身處何處npm
搜索框輸入 「前端流程圖插件」,查了不少資料,總結一下有如下幾種json
代碼寫法繁瑣,不是json就能夠解決,效果也比較醜,PASS
github :https://github.com/dagrejs/dagre-d3
效果圖
下載裏面的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
github :https://github.com/NorthwoodsSoftware/GoJS
能夠經過npm install gojs -save
安裝
效果圖
看裏面的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>
不滿意的地方:
這是我本身包裝的代碼地址:https://github.com/LRY1994/vue-lib/tree/master/src/components/process-go
github : https://github.com/clientIO/joint
效果圖
能夠經過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
這個目前看來還算滿意
這個看了官網,不太友好,並且下載只有一個js文件,沒有demo代碼,不知如何下手
https://gojs.net/latest/samples/pageFlow.html
http://www.daviddurman.com/assets/autolayout.js
http://resources.jointjs.com/demos/layout