Browse Source

DAG automatic layout (#1497)

* Password verification and v-for add key

* DAG automatic layout
pull/2/head
break60 5 years ago committed by lgcareer
parent
commit
da1afb7a04
  1. 238
      dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
  2. 47
      dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue

238
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js

@ -91,22 +91,232 @@ Dag.prototype.toolbarEvent = function ({ item, code, is }) {
/**
* Echo data display
*/
Dag.prototype.backfill = function () {
jsPlumb.ready(() => {
JSP.init({
dag: this.dag,
instance: this.instance
Dag.prototype.backfill = function (arg) {
if(arg) {
let locationsValue = store.state.dag.locations
let locationsValue1 = store.state.dag.locations
let locationsValue2 = store.state.dag.locations
let arr = []
for (let i in locationsValue1) {
let objs = new Object();
objs.id = i
arr.push(Object.assign(objs,locationsValue1[i])); //Attributes
}
let tmp = []
for(let i in locationsValue2) {
if(locationsValue2[i].targetarr !='' && locationsValue2[i].targetarr.split(',').length>1) {
tmp.push(locationsValue2[i])
}
}
function copy (array) {
let newArray = []
for(let item of array) {
newArray.push(item);
}
return newArray;
}
let newArr = copy(arr)
function getNewArr() {
for(let i= 0; i<newArr.length; i++) {
if(newArr[i].targetarr !='' && newArr[i].targetarr.split(',').length>1) {
newArr[i].targetarr = newArr[i].targetarr.split(',').shift()
}
}
return newArr
}
getNewArr()
/**
* @description Transform flat data into a tree structure
* @param {Array} arr Flat data
* @param {String} pidStr targetarr key name
* @param {String} idStr id key name
* @param {String} childrenStr children key name
*/
function fommat({arrayList, pidStr = 'targetarr', idStr = 'id', childrenStr = 'children'}) {
let listOjb = {}; // Used to store objects of the form {key: obj}
let treeList = []; // An array to store the final tree structure data
// Transform the data into {key: obj} format, which is convenient for the following data processing
for (let i = 0; i < arrayList.length; i++) {
listOjb[arrayList[i][idStr]] = arrayList[i]
}
// Format data based on pid
for (let j = 0; j < arrayList.length; j++) {
// Determine if the parent exists
// let haveParent = arrayList[j].targetarr.split(',').length>1?listOjb[arrayList[j].targetarr.split(',')[0]]:listOjb[arrayList[j][pidStr]]
let haveParent = listOjb[arrayList[j][pidStr]]
if (haveParent) {
// If there is no parent children field, create a children field
!haveParent[childrenStr] && (haveParent[childrenStr] = [])
// Insert child in parent
haveParent[childrenStr].push(arrayList[j])
} else {
// If there is no parent, insert directly into the outermost layer
treeList.push(arrayList[j])
}
}
return treeList
}
let datas = fommat({arrayList: newArr,pidStr: 'targetarr'})
// Count the number of leaf nodes
function getLeafCountTree(json) {
if(!json.children) {
json.colspan = 1;
return 1;
} else {
let leafCount = 0;
for(let i = 0 ; i < json.children.length ; i++){
leafCount = leafCount + getLeafCountTree(json.children[i]);
}
json.colspan = leafCount;
return leafCount;
}
}
// Number of tree node levels
let countTree = getLeafCountTree(datas[0])
function getMaxFloor(treeData) {
let floor = 0
let v = this
let max = 0
function each (data, floor) {
data.forEach(e => {
e.floor = floor
e.x=floor*170
if (floor > max) {
max = floor
}
if (e.children) {
each(e.children, floor + 1)
}
})
}
each(treeData,1)
return max
}
getMaxFloor(datas)
// The last child of each node
let lastchildren = [];
forxh(datas);
function forxh(list) {
for (let i = 0; i < list.length; i++) {
let chlist = list[i];
if (chlist.children) {
forxh(chlist.children);
} else {
lastchildren.push(chlist);
}
}
}
// Get all parent nodes above the leaf node
function treeFindPath (tree, func, path,n) {
if (!tree) return []
for (const data of tree) {
path.push(data.name)
if (func(data)) return path
if (data.children) {
const findChildren = treeFindPath(data.children, func, path,n)
if (findChildren.length) return findChildren
}
path.pop()
}
return []
}
function toLine(data){
return data.reduce((arr, {id, name, targetarr, x, y, children = []}) =>
arr.concat([{id, name, targetarr, x, y}], toLine(children)), [])
return result;
}
let listarr = toLine(datas);
let listarrs = toLine(datas)
let dataObject = {}
for(let i = 0; i<listarrs.length; i++) {
delete(listarrs[i].id)
}
for(let a = 0; a<listarr.length; a++) {
dataObject[listarr[a].id] = listarrs[a]
}
// Comparison function
function createComparisonFunction(propertyName) {
return function (object1,object2) {
let value1 = object1[propertyName];
let value2 = object2[propertyName];
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
};
}
lastchildren = lastchildren.sort(createComparisonFunction('x'))
// Coordinate value of each leaf node
for(let a = 0; a<lastchildren.length; a++) {
dataObject[lastchildren[a].id].y = (a+1)*120
}
for(let i =0 ; i<lastchildren.length; i++) {
let node = treeFindPath(datas, data=> data.targetarr===lastchildren[i].targetarr,[],i+1)
for(let j = 0; j<node.length; j++) {
for(let k= 0; k<listarrs.length; k++) {
if(node[j] == listarrs[k].name) {
listarrs[k].y = (i+1)*120
}
}
}
}
for(let i = 0; i<tmp.length; i++) {
for(let objs in dataObject) {
if(tmp[i].name == dataObject[objs].name) {
dataObject[objs].targetarr = tmp[i].targetarr
}
}
}
for(let a = 0; a<lastchildren.length; a++) {
dataObject[lastchildren[a].id].y = (a+1)*120
}
if(countTree>1) {
dataObject[Object.keys(locationsValue1)[0]].y = (countTree/2)*120+50
}
locationsValue = dataObject
jsPlumb.ready(() => {
JSP.init({
dag: this.dag,
instance: this.instance
})
// Backfill
JSP.jspBackfill({
// connects
connects: _.cloneDeep(store.state.dag.connects),
// Node location information
locations: _.cloneDeep(locationsValue),
// Node data
largeJson: _.cloneDeep(store.state.dag.tasks)
})
})
// Backfill
JSP.jspBackfill({
// connects
connects: _.cloneDeep(store.state.dag.connects),
// Node location information
locations: _.cloneDeep(store.state.dag.locations),
// Node data
largeJson: _.cloneDeep(store.state.dag.tasks)
} else {
jsPlumb.ready(() => {
JSP.init({
dag: this.dag,
instance: this.instance
})
// Backfill
JSP.jspBackfill({
// connects
connects: _.cloneDeep(store.state.dag.connects),
// Node location information
locations: _.cloneDeep(store.state.dag.locations),
// Node data
largeJson: _.cloneDeep(store.state.dag.tasks)
})
})
})
}
}
/**

47
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue

@ -22,6 +22,7 @@
<div class="bar-box roundedRect jtk-draggable jtk-droppable jtk-endpoint-anchor jtk-connected"
:class="v === dagBarId ? 'active' : ''"
:id="v"
:key="v"
v-for="(item,v) in tasksTypeList"
@mousedown="_getDagId(v)">
<div data-toggle="tooltip" :title="item.description">
@ -65,10 +66,12 @@
v-for="(item,$index) in toolOperList"
:class="_operationClass(item)"
:id="item.code"
:key="$index"
@click="_ckOperation(item,$event)">
<i class="iconfont" v-html="item.icon" data-toggle="tooltip" :title="item.description" ></i>
</a>
</div>
<x-button type="text" icon="fa fa-play" @click="dagAutomaticLayout"></x-button>
<x-button
data-toggle="tooltip"
:title="$t('Refresh DAG status')"
@ -142,7 +145,8 @@
isRtTasks: false,
isRefresh: false,
isLoading: false,
taskId: null
taskId: null,
arg: false,
}
},
mixins: [disabledState],
@ -153,9 +157,44 @@
methods: {
...mapActions('dag', ['saveDAGchart', 'updateInstance', 'updateDefinition', 'getTaskState']),
...mapMutations('dag', ['addTasks', 'resetParams', 'setIsEditDag', 'setName']),
init () {
// DAG automatic layout
dagAutomaticLayout() {
$('#canvas').html('')
// Destroy round robin
Dag.init({
dag: this,
instance: jsPlumb.getInstance({
Endpoint: [
'Dot', { radius: 1, cssClass: 'dot-style' }
],
Connector: 'Straight',
PaintStyle: { lineWidth: 2, stroke: '#456' }, // Connection style
ConnectionOverlays: [
[
'Arrow',
{
location: 1,
id: 'arrow',
length: 12,
foldback: 0.8
}
]
],
Container: 'canvas'
})
})
if (this.tasks.length) {
Dag.backfill(true)
} else {
Dag.create()
}
},
init (args) {
if (this.tasks.length) {
Dag.backfill()
Dag.backfill(args)
// Process instances can view status
if (this.type === 'instance') {
this._getTaskState(false).then(res => {})
@ -513,7 +552,7 @@
})
},
mounted () {
this.init()
this.init(this.arg)
},
beforeDestroy () {
this.resetParams()

Loading…
Cancel
Save