原文首發於個人博客,歡迎點擊查看得到更好的閱讀體驗~css
最新版本html
請關注G6官方的github倉庫github.com/antvis/g6vue
2.x版本後,能夠經過
npm install
直接安裝使用了node
相關資源下載git
最近我司項目中須要加入流程圖製做功能,因而乎百度各類找可視化繪製拓撲圖的輪子,大部分都是國外的,看文檔太吃力,不過好在最終讓我發現了AntV G6流程圖圖表庫,最新版爲2.0,不過編輯器在2.0版本尚未進行開源,因此只能退而求其次,使用了1.2.8版本。但願2.0版本的編輯器儘早開源,在交互方面1.2.8版本仍是差了一些。github
該組件並**
非開箱即食
**,須要根據本身的業務進行修改,右側屬性表單部分若是有時間考慮改成插槽形式,方便之後複用~npm
v3.0.1
v2.4.5
v1.2.8
在index.html
中進行了全局引用json
<script src="./static/plugin/g6.min.js"></script>
複製代碼
仿照2.0版本的編輯器將G6做爲了一個組件使用,代碼:api
<template>
<div id="flowChart">
<div class="operating">
<div class="btn-group">
<div class="btn" @click="addCircle" title="起始節點">
<i class="iconfont icon-circle-oeps"></i>
</div>
<div class="btn" @click="addRect" title="常規節點">
<i class="iconfont icon-square-oeps"></i>
</div>
<div class="btn" @click="addRhombus" title="條件節點">
<i class="iconfont icon-square-ling"></i>
</div>
</div>
<div class="btn-group">
<div class="btn" @click="addLine" title="直線">
<i class="iconfont icon-zhixian"></i>
</div>
<div class="btn" @click="addSmooth" title="曲線">
<i class="iconfont icon-quxian"></i>
</div>
<div class="btn" @click="addArrowLine" title="箭頭直線">
<i class="iconfont icon-jiantouzhixian"></i>
</div>
<div class="btn" @click="addArrowSmooth" title="箭頭曲線">
<i class="iconfont icon-jiantouquxian"></i>
</div>
</div>
<div class="btn-group">
<div class="btn" @click="changeMode('edit')" title="選擇模式">
<i class="iconfont icon-chose"></i>
</div>
<div class="btn" @click="changeMode('drag')" title="拖拽模式">
<i class="iconfont icon-move"></i>
</div>
</div>
<div class="btn-group">
<div class="btn" @click="del" style="margin-top: 5px;" title="刪除">
<i class="el-icon-delete"></i>
</div>
<div class="btn" @click="save" title="保存">
<i class="iconfont icon-baocun"></i>
</div>
</div>
<div class="btn-group">
<el-input size="mini" v-model="workflowName" placeholder="請輸入流圖名稱..."></el-input>
</div>
</div>
<div class="info">
<div class="title">
<span>{{infoTitle}}屬性</span>
</div>
<div class="content">
<el-checkbox v-if="isBlank === true" v-model="checked">網格對齊</el-checkbox>
<el-form v-else label-position="left" label-width="60px">
<el-form-item v-if="isNode !== true" label="動做">
<el-select v-model="action" size="mini" filterable placeholder="綁定動做" value="">
<el-option
v-for="item in actionList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select>
</el-form-item> <!-- 線-->
<el-form-item v-if="isNode === true" label="名稱">
<el-input size="mini" v-model="name"></el-input>
</el-form-item>
<el-form-item v-if="isNode === true" label="功能">
<el-select v-model="func" size="mini" filterable placeholder="綁定功能" value="">
<el-option
v-for="item in funcList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="isNode === true" label="帳號">
<el-select v-model="account" size="mini" filterable multiple
collapse-tags placeholder="綁定帳號" value="">
<el-option
v-for="item in accountList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="isNode === true" label="流圖">
<el-select v-model="workflow" size="mini" filterable clearable placeholder="綁定流圖" value="">
<el-option
v-for="item in workflowList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="isNode === true" label="類型">
<el-select v-model="nodeType" size="mini" filterable placeholder="請選擇類型" value="">
<el-option
v-for="item in nodeTypeList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="顏色">
<el-color-picker v-model="color"></el-color-picker>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
export default {
name: "index",
components: {},
mounted() {
this.initG6();
},
props: {
actionList: {
type: Array, default: []
},
funcList: {
type: Array, default: []
},
accountList: {
type: Array, default: []
},
workflowList: {
type: Array, default: []
},
nodeTypeList: {
type: Array, default: () => {
return [
{id: 0, label: '普通節點'},
{id: 1, label: '入口節點'},
{id: 2, label: '出口節點'}
]
}
}
},
data() {
return {
action: '',
name: '',
func: '',
account: '',
workflow: '',
nodeType: 0,
color: '',
net: '',
Util: '',
workflowName: '',
activation: '', //當前激活的節點
isNode: false, //當前是節點
isBlank: true, //當前是空白區
checked: true, //網格對齊
infoTitle: '畫布',//屬性標題
oldColor: '', //獲取節點自己顏色
type: '', //有值爲編輯狀態
}
},
methods: {
initG6() {
let self = this;
self.Util = G6.Util;
let grid;
if (self.checked) {
grid = {
forceAlign: true, // 是否支持網格對齊
cell: 25, // 網格大小
};
} else {
grid = null;
}
self.net = new G6.Net({
id: 'flowChart', // 容器ID
mode: 'edit',
grid: grid,
/*width: 500, // 畫布寬*/
height: 800 // 畫布高
});
/*self.net.tooltip({
title: '信息', // @type {String} 標題
split: ':', // @type {String} 分割符號
dx: 0, // @type {Number} 水平偏移
dy: 0 // @type {Number} 豎直偏移
});*/
/**
*點擊空白處
*/
self.net.on('click', (ev) => {
if (!self.Util.isNull(ev.item)) {
self.isBlank = false
} else {
self.isBlank = true;
self.infoTitle = '畫布'
}
});
/**
*點擊節點
*/
self.net.on('itemclick', function (ev) {
self.isNode = self.Util.isNode(ev.item); //是否爲Node
self.activation = ev.item;
if (self.isNode) {
/* 激活節點後節點名稱input聚焦*/
self.$nextTick(()=>{
self.$refs.inputFocus.$el.querySelector('input').focus();
});
self.infoTitle = '節點';
self.name = ev.item.get('model').label;
self.func = ev.item.get('model').func;
self.account = ev.item.get('model').account || [];
self.workflow = ev.item.get('model').workflow;
self.nodeType = ev.item.get('model').nodeType;
} else {
self.infoTitle = '邊';
self.action = ev.item.get('model').action;
}
self.color = self.oldColor;
});
/**
* 鼠標移入移出事件改變顏色
*/
self.net.on('itemmouseenter', ev => {
const item = ev.item;
self.oldColor = item.get('model').color; //獲取節點顏色
self.net.update(item, {
color: '#108EE9',
});
self.net.refresh();
});
self.net.on('itemmouseleave', ev => {
const item = ev.item;
self.net.update(item, {
color: self.oldColor
});
self.net.refresh();
});
/**
* 提示信息
*/
/* self.net.node().tooltip(['label', 'func', 'role', 'color']);
self.net.edge().tooltip(['label', 'color']);*/
/**
* 渲染
*/
/*self.net.source(self.nodes, self.edges);*/ //加載資源數據
self.net.render();
},
addCircle() {
this.net.beginAdd('node', {
shape: 'circle',
nodeType: 0
})
},//添加起始節點
addRect() {
this.net.beginAdd('node', {
shape: 'rect',
nodeType: 0
})
},//添加常規節點
addRhombus() {
this.net.beginAdd('node', {
shape: 'rhombus',
nodeType: 0
})
}, //添加條件節點
addLine() {
this.net.beginAdd('edge', {
shape: 'line'
});
}, //添加直線
addSmooth() {
this.net.beginAdd('edge', {
shape: 'smooth'
})
}, //添加曲線
addArrowSmooth() {
this.net.beginAdd('edge', {
shape: 'smoothArrow'
})
}, //添加箭頭曲線
addArrowLine() {
this.net.beginAdd('edge', {
shape: 'arrow'
});
}, //添加箭頭直線
addPolyLine() {
this.net.beginAdd('edge', {
shape: 'polyLineFlow'
});
}, //添加折線
changeMode(mode) {
this.net.changeMode(mode)
}, //拖拽與編輯模式的切換
del() {
this.net.del()
},//刪除
save() {
/* 驗證流圖名稱*/
if (this.workflowName !== '') {
let data = this.net.save();
if (data.source.nodes.length === 0) {
this.$message({type: 'error', message: '流圖內容不能爲空'});
return false
}
/* 驗證節點名稱*/
for (let item of data.source.nodes) {
if (item.label === '' || item.label === null || item.label === undefined) {
this.$message({type: 'error', message: '節點名稱不能爲空'});
return false
}
}
data.source['name'] = this.workflowName;
/*let json = JSON.stringify(data, null, 2);*/
this.$emit('saveData', data.source, this.type);
} else {
this.$message({type: 'error', message: '流圖名稱不能爲空'})
}
/*console.log(saveData, json);*/
},//保存
update() {
if (this.activation.get('type') === 'node') {
this.net.update(this.activation, {
label: this.name,
func: this.func,
account: this.account,
workflow: this.workflow,
nodeType: this.nodeType,
color: this.color
});
} else {
/* 根據ID取出label*/
let label = this.actionList.map(item => {
if (item.id === this.action) {
return item.label
}
}).join('');
this.net.update(this.activation, {
label: label,
color: this.color,
action: this.action
});
}
}, //更新節點
clearView() {
this.type = '';
this.workflowName = '';
this.net.changeData()
}, //清空視圖
source(nodes, edges, name, type) {
this.type = type;
this.workflowName = name;
this.net.changeData(nodes, edges)
}, //更新數據
},
watch: {
/**
* 監聽輸入框
*/
action: function () {
this.update()
},
name: function () {
this.update()
},
func: function () {
this.update()
},
account: function () {
this.update()
},
workflow: function () {
this.update()
},
nodeType: function () {
this.update()
},
color: function () {
this.update()
},
/**
* 網格切換
*/
checked: function () {
let _saveData = this.net.save();
this.net.destroy(); //銷燬畫布
this.initG6();
this.net.read(_saveData);
this.net.render()
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
#flowChart {
border: 1px solid #ebeef5;
position: relative;
overflow: hidden;
}
.operating {
position: absolute;
z-index: 99;
background-color: #ffffff;
padding: 20px 10px;
box-shadow: 1px 1px 4px 0 #0a0a0a2e;
}
.info {
position: absolute;
right: 0;
z-index: 99;
box-shadow: 1px 1px 4px 0 #0a0a0a2e;
.title {
height: 40px;
padding-left: 10px;
border-top: 1px solid #DCE3E8;
border-bottom: 1px solid #DCE3E8;
border-left: 1px solid #DCE3E8;
background: rgb(235, 238, 242);
line-height: 40px;
span {
font-size: 14px;
}
}
.content {
background: rgba(247, 249, 251, 0.45);
width: 200px;
height: 800px;
border-left: 1px solid #E6E9ED;
padding: 10px;
}
}
.btn-group {
border-right: 1px solid #efefef;
display: inline-block;
padding-left: 10px;
padding-right: 14px;
&:last-of-type {
border-right: 0;
}
.btn {
display: inline-block;
margin: 2px;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
cursor: pointer;
border: 1px solid rgba(233, 233, 233, 0);
i {
font-size: 20px;
}
&:hover {
border: 1px solid #E9E9E9;
color: #767A85;
border-radius: 2px;
background: #FAFAFE;
}
}
.el-form-item {
margin-bottom: 0 !important;
}
}
</style>
複製代碼
參數 | 說明 | 類型 | 可選值 | 默認值 |
---|---|---|---|---|
actionList | 動做數據 | Array | —— | [] |
funcList | 功能數據 | Array | —— | [] |
accountList | 帳號數據 | Array | —— | [] |
workflowList | 流圖數據 | Array | —— | [] |
nodeTypeList | 節點類型數據 | Array | —— | [{id: 0, label: '普通節點'},{id: 1, label: '入口節點'},{id: 2, label: '出口節點'}] |
全部屬性接收的數據格式須要與
nodeTypeList
的默認值相同bash
事件名 | 說明 | 參數 |
---|---|---|
saveData | 當用戶手動點擊保存觸發事件 | source,type |
參數
type
可爲空,在此項目中主要用來區分新建
與編輯
方法名 | 說明 | 參數 |
---|---|---|
clearView | 清空當前視圖 | —— |
source | 渲染數據 | nodes, edges, name, type |
參數
type
與事件中相同,參數name
的做用是用來取流圖名