vue中使用gojs/jointjs的示例代碼
因為公司項目需求,要畫出相關(guān)業(yè)務(wù)的流程圖,以便客戶了解自己身處何處
搜索框輸入 “前端流程圖插件”,查了很多資料,總結(jié)一下有以下幾種
flow-chart
代碼寫法繁瑣,不是json就可以解決,效果也比較丑,PASS
darge-d3
github :https://github.com/dagrejs/dagre-d3
效果圖

下載里面的demo,改一下json就可以了
// States
var states = [ "NEW", "SUBMITTED","FINISHED" ,"FAILED","DELIVER",
"CANCELED", "ABOLISHED" , "DELETED","REFUNDING","REFUNDED"];
var map = ['新創(chuàng)建','已提交','已完成','提交失敗',"交付中",
'已取消','廢除','已刪除','退款中',"已退款"]
// 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系統(tǒng)自動取消"});
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是一個實現(xiàn)交互類圖表(比如流程圖,樹圖,關(guān)系圖,力導(dǎo)圖等等)的JS庫。本文將介紹GoJs的精華部分。
因為GoJS依賴于HTML5,所以請保證您的瀏覽器版本支持HTML5,當(dāng)然還要加載這個庫。
github :https://github.com/NorthwoodsSoftware/GoJS
可以通過npm install gojs -save安裝
效果圖

看里面的demo我自己包裝了一下
<template>
<div>
<p style="background-color:#d5d5d5;margin:0;padding:5px;">
您當(dāng)前處于 <span class="tip">用戶提交資料</span> 步驟
下一步等待<span class="tip">供應(yīng)商接單</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
});
//默認節(jié)點模板
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>
不滿意的地方:
- 免費版gojs是有水印的,百度搜索“gojs如何去水印”有一堆答案,我就不寫了。
- 因為要自己手動去掉水印,所以我只能手動下載go.js放在我自己的組件目錄下,但是這個文件太大了,800+KB,npm run dev 的時候停在這里停了好久。有時候還爆出“......maximun ....500KB”的錯誤,我也不知道是什么原因,不知道有什么方法,有的話麻煩通知我。
- 代碼寫法有點太繁瑣
這是我自己包裝的代碼地址: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
效果圖

可以通過npm install jointjs -save安裝
參照了很多demo和文檔,用的是矩形,但是可以設(shè)置圓角的度數(shù)變成橢圓形,其他形狀我就無力了。
可以自定義矩形的樣式和矩形框里面的文字樣式
//data.vue
<script>
export default {
data(){
var userClass = {//這個要參照SVG屬性
/**shapeStyle
* fill:填充的背景顏色
stroke: 邊框顏色
strokeWidth: 邊框?qū)挾?
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:'供應(yīng)商駁回'},
'201':{text:'供應(yīng)商接單'},
'202':{text:'供應(yīng)商完工'},
'203':{text:'等待供應(yīng)商處理'},
'300':{text:'系統(tǒng)交付出錯'}
},
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"> 您當(dāng)前處于 <span class="tip">用戶提交資料</span> 步驟 下一步等待<span class="tip">供應(yīng)商接單</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%',
//下面這些可以自己設(shè)置
fill:{
type: 'linearGradient',
stops: [
{offset: '0%', color: '#B0E0E6'},//漸變開始
{offset: '100%', color: '#F0F8FF'}//漸變結(jié)束
]
},
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
這個看了官網(wǎng),不太友好,而且下載只有一個js文件,沒有demo代碼,不知如何下手
參考資料:
https://gojs.net/latest/samples/pageFlow.html
http://www.daviddurman.com/assets/autolayout.js
http://resources.jointjs.com/demos/layout
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue實現(xiàn)pdf導(dǎo)出解決生成canvas模糊等問題(推薦)
最近公司項目需要,利用vue實現(xiàn)pdf導(dǎo)出,從而保存到本地打印出來,說起來好像也很容易,具體要怎么實現(xiàn)呢?下面小編給大家?guī)砹藇ue實現(xiàn)pdf導(dǎo)出解決生成canvas模糊等問題,需要的朋友參考下吧2018-10-10
解決Vue項目中Emitted value instead of an 
這篇文章主要介紹了解決Vue項目中Emitted value instead of an instance of Error問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Electron中打包應(yīng)用程序及相關(guān)報錯問題的解決
這篇文章主要介紹了Electron中打包應(yīng)用程序及相關(guān)報錯問題的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
Vue實現(xiàn)遠程獲取路由與頁面刷新導(dǎo)致404錯誤的解決
這篇文章主要介紹了Vue實現(xiàn)遠程獲取路由與頁面刷新導(dǎo)致404錯誤的解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01
3分鐘了解vue數(shù)據(jù)劫持的原理實現(xiàn)
這篇文章主要介紹了3分鐘了解vue數(shù)據(jù)劫持的原理實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

