[Improvement][ui] Refactored dag formatting logic (#3703)
Co-authored-by: dashi <dashi@fordeal.com>
This commit is contained in:
parent
ec350fbc29
commit
a34f8296cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 marginX = 100
|
||||
const g = new dagre.graphlib.Graph()
|
||||
g.setGraph({})
|
||||
g.setDefaultEdgeLabel(function () { return {} })
|
||||
|
||||
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 })
|
||||
}
|
||||
|
||||
const copy = function (array) {
|
||||
const newArray = []
|
||||
for (const item of array) {
|
||||
newArray.push(item)
|
||||
}
|
||||
return newArray
|
||||
for (const i in store.state.dag.connects) {
|
||||
const connect = store.state.dag.connects[i]
|
||||
g.setEdge(connect['endPointSourceId'], connect['endPointTargetId'])
|
||||
}
|
||||
dagre.layout(g)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for (let a = 0; a < listarr.length; a++) {
|
||||
dataObject[listarr[a].id] = listarrs[a]
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue