[VUE2]基于vue-workflow-chart的DEG图组件
vue-workflow-chart调用
<workflow-chart
:style='size'
:transitions='transitions'
:states='states'
:stateSemantics='stateSemantics'
:orientation="isHorizontal ? 'horizontal' : 'vertical'"
@state-click="onStateClick($event)"
@transition-click="onLabelClicked('transition', $event)"
@sizeChange='sizeChanged'
/>
官方demo
<template>
<div id="app">
<workflow-chart
:transitions="transitions"
:states="states" />
</div>
</template>
<script>
import WorkflowChart from 'vue-workflow-chart';
export default {
name: "App",
components: {
WorkflowChart,
},
data: () => ({
states: [{
"id": "state_1",
"label": "State 1",
}, {
"id": "state_2",
"label": "State 2",
}],
transitions: [{
"id": "transition_1",
"label": "this is a transition",
"target": "state_2",
"source": "state_1",
}],
}),
};
</script>
自定义组件效果
主要是重写了一下样式,自定义每个节点里的图片,达到workflow DEG图的效果。
自定义组件调用
<Workflow :nodeData='nodeData' :isHorizontal='isHorizontal' @clickNode='clickNode' v-dragScroll />
自定义组件代码
<template>
<div class='hzs-workflow-chart-box' ref='box'>
<workflow-chart
:style='size'
:transitions='transitions'
:states='states'
:stateSemantics='stateSemantics'
:orientation="isHorizontal ? 'horizontal' : 'vertical'"
@state-click="onStateClick($event)"
@transition-click="onLabelClicked('transition', $event)"
@sizeChange='sizeChanged'
/>
</div>
</template>
<script>
import WorkflowChart from 'vue-workflow-chart'
const phaseToClass = {
Succeeded: 'succeeded',
Running: 'running',
Pending: 'pending',
Omitted: 'omitted',
Failed: 'failed'
}
export default {
name: 'Workflow',
components: {
WorkflowChart
},
props: {
nodeData: {
type: Object,
default: () => ({})
},
isHorizontal: {
type: Boolean,
default: false
}
},
watch: {
nodeData: {
handler: function(newVal) {
console.log('检测到有新的节点数据')
console.log(newVal)
this.composeChartData(newVal.status.nodes)
setTimeout(this.dealWordPosition)
},
deep: true
}
},
data: () => ({
states: [],
transitions: [],
stateSemantics: [],
size: { width: '0px', height: '0px' }
}),
methods: {
onStateClick(e) {
console.log('点击了节点')
console.log(e)
this.$emit('clickNode', e)
},
addData() {
for (let i = 0; i < 100; i++) {
this.states.push({
id: `node${i}`,
label: `node${i}`
})
}
for (let i = 0; i < 50; i++) {
this.transitions.push({
'label': '',
'source': `node${i}`,
'target': `node${i + 1}`
})
}
for (let i = 50; i < 100; i++) {
this.transitions.push({
'label': '',
'source': `node${i - 50}`,
'target': `node${i}`
})
}
},
sizeChanged(size) {
this.size = {
width: `${size.width}px`,
height: `${size.height}px`
}
},
// 组装成图的数据
composeChartData(dataObj) {
if (!dataObj || JSON.stringify(dataObj) === '{}' || dataObj.length < 1) {
return
}
let nodeList = []
let lineList = []
let stateSemanticList = []
Object.keys(dataObj).forEach((key) => {
let node = dataObj[key]
console.log(node)
// 放入节点
nodeList.push({
'id': node.id,
'label': node.displayName
})
// 放入节点状态信息
stateSemanticList.push({
'id': node.id,
'classname': phaseToClass[node.phase]
})
// 放入连线的情况
if (node.children && node.children.length > 0) {
node.children.forEach((child, index) => {
lineList.push({
'id': `${node.id}-${index}`,
'target': child,
'source': node.id
})
})
}
})
console.log('组装出来的数据')
console.log(nodeList)
console.log(lineList)
this.states = nodeList
this.transitions = lineList
this.stateSemantics = stateSemanticList
},
getMaxHeight() {
let maxHeight = 0
let nodeList = document.getElementsByClassName('vue-workflow-chart-state')
for (let i = 0; i < nodeList.length; i++) {
if (nodeList[i].style.top) {
let top = +nodeList[i].style.top.split('px')[0]
if (top > maxHeight) {
maxHeight = top
}
}
}
console.log(this.$refs.box)
},
// 调整文字位置
dealWordPosition() {
let nodeList = document.getElementsByClassName('vue-workflow-chart-state')
for (let i = 0; i < nodeList.length; i++) {
// console.log(nodeList[i])
let label = nodeList[i].innerText
let element = document.createElement('p')
element.innerText = label
element.className = 'vue-workflow-chart-state-text'
nodeList[i].innerText = ''
nodeList[i].appendChild(element)
}
},
onLabelClicked(type, id) {
console.log('点击了节点')
alert(`Clicked on ${type} with id: ${id}`)
}
},
created() {
// this.addData()
// this.composeChartData(this.nodeData.status.nodes)
},
mounted() {
//
// this.getMaxHeight()
}
}
</script>
<style lang='less'>
@import '~vue-workflow-chart/dist/vue-workflow-chart.css';
.hzs-workflow-chart-box {
min-height: 800px;
//border: 1px solid black;
overflow: auto;
//margin-left: 50px;
position: relative;
.vue-workflow-chart-state {
padding: 0;
margin: 0;
z-index: 999;
//border: 2px solid black;
border-radius: 50%;
width: 60px;
height: 60px;
overflow: visible;
color: black;
font-size: 8px;
//background-color: white;
//position: relative;
//font-weight: 500;
//flex-wrap: nowrap;
//display: flex;
//justify-content: flex-end;
//background-image: url("/img/success.svg");
background-position: center;
background-origin: content-box;
background-attachment: local;
background-size: 100%;
//background-size: cover;
background-repeat: no-repeat;
p {
position: absolute;
left: 30px;
top: 55px;
width: 150px;
transform: translate(-50%);
}
}
.vue-workflow-chart-state-delete {
color: white;
background: red;
}
.vue-workflow-chart-state-succeeded {
//color: white;
//background: green;
//background: #00FF00 url("/img/success.svg") no-repeat fixed top;
//background-image: url("/img/success.svg");
background-image: url("/img/success.svg");
}
.vue-workflow-chart-state-running {
background-image: url("/img/loading.gif");
}
.vue-workflow-chart-state-pending {
background-image: url("/img/wait.svg");
//background-size: cover;
//background: gray;
}
.vue-workflow-chart-state-omitted {
background-image: url("/img/ignore.svg");
//background-size: cover;
}
.vue-workflow-chart-state-failed {
background-image: url("/img/fail.svg");
//background-size: cover;
}
.vue-workflow-chart-transition-arrow-delete {
fill: red;
}
.vue-workflow-chart-transition-path-delete {
stroke: red;
}
}
</style>
文章评论