This is an automated email from the ASF dual-hosted git repository.
lgcareer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new a34f829 [Improvement][ui] Refactored dag formatting logic (#3703)
a34f829 is described below
commit a34f8296cc14e143eea86fb9250524d541b2e4f0
Author: elonlo <[email protected]>
AuthorDate: Wed Sep 16 18:04:49 2020 +0800
[Improvement][ui] Refactored dag formatting logic (#3703)
Co-authored-by: dashi <[email protected]>
---
dolphinscheduler-dist/release-docs/LICENSE | 1 +
.../licenses/ui-licenses/LICENSE-dagre | 19 ++
dolphinscheduler-ui/package.json | 1 +
.../src/js/conf/home/pages/dag/_source/dag.js | 212 +++------------------
4 files changed, 45 insertions(+), 188 deletions(-)
diff --git a/dolphinscheduler-dist/release-docs/LICENSE
b/dolphinscheduler-dist/release-docs/LICENSE
index 59da274..707ea5c 100644
--- a/dolphinscheduler-dist/release-docs/LICENSE
+++ b/dolphinscheduler-dist/release-docs/LICENSE
@@ -502,6 +502,7 @@ MIT licenses
vue-router 2.7.0: https://github.com/vuejs/vue-router MIT
vuex 3.0.0: https://github.com/vuejs/vuex MIT
vuex-router-sync 4.1.2: https://github.com/vuejs/vuex-router-sync MIT
+ dagre 0.8.5: https://github.com/dagrejs/dagre MIT
========================================
Apache 2.0 licenses
diff --git
a/dolphinscheduler-dist/release-docs/licenses/ui-licenses/LICENSE-dagre
b/dolphinscheduler-dist/release-docs/licenses/ui-licenses/LICENSE-dagre
new file mode 100644
index 0000000..e3c8f95
--- /dev/null
+++ b/dolphinscheduler-dist/release-docs/licenses/ui-licenses/LICENSE-dagre
@@ -0,0 +1,19 @@
+Copyright (c) 2012-2014 Chris Pettitt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/dolphinscheduler-ui/package.json b/dolphinscheduler-ui/package.json
index a5642c8..9624fa6 100644
--- a/dolphinscheduler-ui/package.json
+++ b/dolphinscheduler-ui/package.json
@@ -20,6 +20,7 @@
"clipboard": "^2.0.1",
"codemirror": "^5.43.0",
"d3": "^3.5.17",
+ "dagre": "^0.8.5",
"dayjs": "^1.7.8",
"echarts": "4.1.0",
"html2canvas": "^0.5.0-beta4",
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
index ff8a452..d7f2f78 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.js
@@ -22,6 +22,7 @@ import { jsPlumb } from 'jsplumb'
import JSP from './plugIn/jsPlumbHandle'
import DownChart from './plugIn/downChart'
import store from '@/conf/home/store'
+import dagre from "dagre"
/**
* Prototype method
@@ -115,202 +116,38 @@ Dag.prototype.toolbarEvent = function ({ item, code, is
}) {
*/
Dag.prototype.backfill = function (arg) {
if (arg) {
- let locationsValue = store.state.dag.locations
- const locationsValue1 = store.state.dag.locations
- const locationsValue2 = store.state.dag.locations
- const arr = []
- for (const i in locationsValue1) {
- const objs = {}
- objs.id = i
- arr.push(Object.assign(objs, locationsValue1[i])) // Attributes
- }
- const tmp = []
- for (const i in locationsValue2) {
- if (locationsValue2[i].targetarr !== '' &&
locationsValue2[i].targetarr.split(',').length > 1) {
- tmp.push(locationsValue2[i])
- }
- }
-
- const copy = function (array) {
- const newArray = []
- for (const item of array) {
- newArray.push(item)
- }
- return newArray
- }
-
- const newArr = copy(arr)
- const getNewArr = function () {
- 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
- */
- const fommat = function ({ arrayList, pidStr = 'targetarr', idStr = 'id',
childrenStr = 'children' }) {
- const listOjb = {} // Used to store objects of the form {key: obj}
- const 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]]
- const 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
- }
- const datas = fommat({ arrayList: newArr, pidStr: 'targetarr' })
- // Count the number of leaf nodes
- const getLeafCountTree = function (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
- const countTree = getLeafCountTree(datas[0])
- const getMaxFloor = function (treeData) {
- 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 = []
- const forxh = function (list) {
- for (let i = 0; i < list.length; i++) {
- const chlist = list[i]
- if (chlist.children) {
- forxh(chlist.children)
- } else {
- lastchildren.push(chlist)
- }
- }
- }
- forxh(datas)
- // Get all parent nodes above the leaf node
- const treeFindPath = function (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 []
- }
- const toLine = function (data) {
- return data.reduce((arrData, { id, name, targetarr, x, y, children = []
}) =>
- arrData.concat([{ id, name, targetarr, x, y }], toLine(children)), [])
- }
- const listarr = toLine(datas)
- const listarrs = toLine(datas)
- const dataObject = {}
- for (let i = 0; i < listarrs.length; i++) {
- delete (listarrs[i].id)
- }
+ const marginX = 100
+ const g = new dagre.graphlib.Graph()
+ g.setGraph({})
+ g.setDefaultEdgeLabel(function () { return {} })
- for (let a = 0; a < listarr.length; a++) {
- dataObject[listarr[a].id] = listarrs[a]
+ for (const i in store.state.dag.locations) {
+ const location = store.state.dag.locations[i]
+ g.setNode(i, { label: i, width: Math.min(location.name.length * 7, 170),
height: 150 })
}
- // Comparison function
- const createComparisonFunction = function (propertyName) {
- return function (object1, object2) {
- const value1 = object1[propertyName]
- const value2 = object2[propertyName]
- if (value1 < value2) {
- return -1
- } else if (value1 > value2) {
- return 1
- } else {
- return 0
- }
- }
+ for (const i in store.state.dag.connects) {
+ const connect = store.state.dag.connects[i]
+ g.setEdge(connect['endPointSourceId'], connect['endPointTargetId'])
}
+ dagre.layout(g)
- 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++) {
- const 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 (const 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
- const self = this
+ const dataObject = {}
+ g.nodes().forEach(function (v) {
+ const node = g.node(v)
+ const obj = {}
+ obj.name = node.label
+ obj.x = node.x + marginX
+ obj.y = node.y
+ dataObject[node.label] = obj
+ })
jsPlumb.ready(() => {
JSP.init({
dag: this.dag,
instance: this.instance,
options: {
onRemoveNodes ($id) {
- self.dag.removeEventModelById($id)
+ this.dag.removeEventModelById($id)
}
}
})
@@ -319,20 +156,19 @@ Dag.prototype.backfill = function (arg) {
// connects
connects: _.cloneDeep(store.state.dag.connects),
// Node location information
- locations: _.cloneDeep(locationsValue),
+ locations: _.cloneDeep(dataObject),
// Node data
largeJson: _.cloneDeep(store.state.dag.tasks)
})
})
} else {
- const self = this
jsPlumb.ready(() => {
JSP.init({
dag: this.dag,
instance: this.instance,
options: {
onRemoveNodes ($id) {
- self.dag.removeEventModelById($id)
+ this.dag.removeEventModelById($id)
}
}
})