Loading dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js +224 −14 Original line number Diff line number Diff line Loading @@ -91,7 +91,216 @@ Dag.prototype.toolbarEvent = function ({ item, code, is }) { /** * Echo data display */ Dag.prototype.backfill = function () { 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) }) }) } else { jsPlumb.ready(() => { JSP.init({ dag: this.dag, Loading @@ -108,6 +317,7 @@ Dag.prototype.backfill = function () { }) }) } } /** * Get dag storage format data Loading dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue +43 −4 Original line number Diff line number Diff line Loading @@ -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"> Loading Loading @@ -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')" Loading Loading @@ -142,7 +145,8 @@ isRtTasks: false, isRefresh: false, isLoading: false, taskId: null taskId: null, arg: false, } }, mixins: [disabledState], Loading @@ -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 => {}) Loading Loading @@ -513,7 +552,7 @@ }) }, mounted () { this.init() this.init(this.arg) }, beforeDestroy () { this.resetParams() Loading Loading
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js +224 −14 Original line number Diff line number Diff line Loading @@ -91,7 +91,216 @@ Dag.prototype.toolbarEvent = function ({ item, code, is }) { /** * Echo data display */ Dag.prototype.backfill = function () { 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) }) }) } else { jsPlumb.ready(() => { JSP.init({ dag: this.dag, Loading @@ -108,6 +317,7 @@ Dag.prototype.backfill = function () { }) }) } } /** * Get dag storage format data Loading
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue +43 −4 Original line number Diff line number Diff line Loading @@ -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"> Loading Loading @@ -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')" Loading Loading @@ -142,7 +145,8 @@ isRtTasks: false, isRefresh: false, isLoading: false, taskId: null taskId: null, arg: false, } }, mixins: [disabledState], Loading @@ -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 => {}) Loading Loading @@ -513,7 +552,7 @@ }) }, mounted () { this.init() this.init(this.arg) }, beforeDestroy () { this.resetParams() Loading