鱼骨结构开发中:完成上方鱼骨图
This commit is contained in:
parent
965ab8151e
commit
940c60f23d
@ -157,6 +157,19 @@ class Base {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新子节点多个属性
|
||||||
|
updateChildrenPro(children, props) {
|
||||||
|
children.forEach(item => {
|
||||||
|
Object.keys(props).forEach((prop) => {
|
||||||
|
item[prop] += props[prop]
|
||||||
|
})
|
||||||
|
if (item.children && item.children.length && !item.hasCustomPosition()) {
|
||||||
|
// 适配自定义位置
|
||||||
|
this.updateChildrenPro(item.children, props)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 二次贝塞尔曲线
|
// 二次贝塞尔曲线
|
||||||
quadraticCurvePath(x1, y1, x2, y2) {
|
quadraticCurvePath(x1, y1, x2, y2) {
|
||||||
let cx = x1 + (x2 - x1) * 0.2
|
let cx = x1 + (x2 - x1) * 0.2
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import Base from './Base'
|
|||||||
import { walk, asyncRun } from '../utils'
|
import { walk, asyncRun } from '../utils'
|
||||||
import { CONSTANTS } from '../utils/constant'
|
import { CONSTANTS } from '../utils/constant'
|
||||||
|
|
||||||
const degToRad = (deg) => {
|
const degToRad = deg => {
|
||||||
return Math.PI / 180 * deg
|
return (Math.PI / 180) * deg
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鱼骨图
|
// 鱼骨图
|
||||||
@ -37,33 +37,30 @@ class Fishbone extends Base {
|
|||||||
walk(
|
walk(
|
||||||
this.renderer.renderTree,
|
this.renderer.renderTree,
|
||||||
null,
|
null,
|
||||||
(cur, parent, isRoot, layerIndex, index) => {
|
(node, parent, isRoot, layerIndex, index) => {
|
||||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
// 创建节点
|
||||||
|
let newNode = this.createNode(node, parent, isRoot, layerIndex)
|
||||||
// 根节点定位在画布中心位置
|
// 根节点定位在画布中心位置
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
this.setNodeCenter(newNode)
|
this.setNodeCenter(newNode)
|
||||||
} else {
|
} else {
|
||||||
// 非根节点
|
// 非根节点
|
||||||
// 三级及以下节点以上级为准
|
// 三级及以下节点以上级方向为准
|
||||||
if (parent._node.dir) {
|
if (parent._node.dir) {
|
||||||
newNode.dir = parent._node.dir
|
newNode.dir = parent._node.dir
|
||||||
} else {
|
} else {
|
||||||
// 节点生长方向
|
// 节点生长方向
|
||||||
newNode.dir =
|
newNode.dir =
|
||||||
index % 2 === 0
|
index % 2 === 0
|
||||||
? CONSTANTS.TIMELINE_DIR.BOTTOM
|
? CONSTANTS.TIMELINE_DIR.TOP
|
||||||
: CONSTANTS.TIMELINE_DIR.TOP
|
: CONSTANTS.TIMELINE_DIR.BOTTOM
|
||||||
}
|
}
|
||||||
// 计算二级节点的top值
|
// 计算二级节点的top值
|
||||||
if (parent._node.isRoot) {
|
if (parent._node.isRoot) {
|
||||||
newNode.top =
|
newNode.top = parent._node.top - newNode.height
|
||||||
parent._node.top +
|
|
||||||
(cur._node.height > parent._node.height
|
|
||||||
? -(cur._node.height - parent._node.height) / 2
|
|
||||||
: (parent._node.height - cur._node.height) / 2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cur.data.expand) {
|
if (!node.data.expand) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -79,50 +76,27 @@ class Fishbone extends Base {
|
|||||||
this.root,
|
this.root,
|
||||||
null,
|
null,
|
||||||
(node, parent, isRoot, layerIndex, index) => {
|
(node, parent, isRoot, layerIndex, index) => {
|
||||||
if (
|
if (node.isRoot) {
|
||||||
node.nodeData.data.expand &&
|
let totalLeft = node.left + node.width
|
||||||
node.children &&
|
node.children.forEach(item => {
|
||||||
node.children.length
|
item.left = totalLeft
|
||||||
) {
|
totalLeft += item.width
|
||||||
if (isRoot) {
|
})
|
||||||
let left = node.left + node.width
|
}
|
||||||
let topTotalLeft = left
|
if (layerIndex >= 1 && node.children) {
|
||||||
let bottomTotalLeft = left
|
// 遍历三级及以下节点的子节点
|
||||||
node.children.forEach((cur) => {
|
let startLeft = node.left + node.width * 0.5
|
||||||
if (cur.dir === 'top') {
|
let totalTop =
|
||||||
cur.left = topTotalLeft
|
node.top +
|
||||||
topTotalLeft += cur.width
|
node.height +
|
||||||
} else {
|
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||||
cur.left = bottomTotalLeft
|
node.children.forEach(item => {
|
||||||
bottomTotalLeft += cur.width
|
item.left = startLeft
|
||||||
}
|
item.top += totalTop
|
||||||
})
|
totalTop +=
|
||||||
} else {
|
item.height +
|
||||||
if (node.dir === 'top' || node.layerIndex < 2) {
|
(this.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||||
let totalTop =
|
})
|
||||||
node.top +
|
|
||||||
node.height +
|
|
||||||
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
|
||||||
node.children.forEach(cur => {
|
|
||||||
cur.left = node.left + node.width * 0.5
|
|
||||||
cur.top = totalTop
|
|
||||||
totalTop +=
|
|
||||||
cur.height +
|
|
||||||
(this.getNodeActChildrenLength(cur) > 0 ? cur.expandBtnSize : 0)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let totalTop =
|
|
||||||
node.top -
|
|
||||||
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
|
||||||
node.children.forEach(cur => {
|
|
||||||
cur.left = node.left + node.width * 0.5
|
|
||||||
cur.top = totalTop - cur.height
|
|
||||||
totalTop -=
|
|
||||||
cur.height +
|
|
||||||
(this.getNodeActChildrenLength(cur) > 0 ? cur.expandBtnSize : 0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
@ -139,79 +113,56 @@ class Fishbone extends Base {
|
|||||||
if (!node.nodeData.data.expand) {
|
if (!node.nodeData.data.expand) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 调整left
|
|
||||||
if (node.isRoot) {
|
|
||||||
this.updateBrothersLeft(node)
|
|
||||||
}
|
|
||||||
// 调整top
|
// 调整top
|
||||||
let len = node.children.length
|
let len = node.children.length
|
||||||
|
// 调整三级及以下节点的top
|
||||||
if (parent && !parent.isRoot && len > 0) {
|
if (parent && !parent.isRoot && len > 0) {
|
||||||
let totalHeight =
|
let totalHeight = node.children.reduce((h, item) => {
|
||||||
node.children.reduce((h, item) => {
|
return (
|
||||||
return (
|
h +
|
||||||
h +
|
item.height +
|
||||||
item.height +
|
(this.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||||
(this.getNodeActChildrenLength(item) > 0
|
)
|
||||||
? item.expandBtnSize
|
}, 0)
|
||||||
: 0)
|
this.updateBrothersTop(node, totalHeight)
|
||||||
)
|
|
||||||
}, 0)
|
|
||||||
this.updateBrothersTop(node, node.dir !== 'top' && node.layerIndex > 2 ? -totalHeight : totalHeight)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(node, parent) => {
|
(node, parent) => {
|
||||||
if (
|
// 将二级节点的子节点移到上方
|
||||||
parent &&
|
if (parent && parent.isRoot) {
|
||||||
parent.isRoot &&
|
|
||||||
node.dir === CONSTANTS.TIMELINE_DIR.TOP
|
|
||||||
) {
|
|
||||||
// 遍历二级节点的子节点
|
// 遍历二级节点的子节点
|
||||||
|
let totalHeight = 0
|
||||||
node.children.forEach(item => {
|
node.children.forEach(item => {
|
||||||
let totalHeight = this.getNodeAreaHeight(item)
|
// 调整top
|
||||||
|
let nodeTotalHeight = this.getNodeAreaHeight(item)
|
||||||
let _top = item.top
|
let _top = item.top
|
||||||
item.top =
|
item.top =
|
||||||
node.top - (item.top - node.top) - totalHeight + node.height
|
node.top - (item.top - node.top) - nodeTotalHeight + node.height
|
||||||
this.updateChildren(item.children, 'top', item.top - _top)
|
// 调整left
|
||||||
|
let offsetLeft =
|
||||||
|
(nodeTotalHeight + totalHeight) / Math.tan(degToRad(45))
|
||||||
|
item.left += offsetLeft
|
||||||
|
totalHeight += nodeTotalHeight
|
||||||
|
// 同步更新后代节点
|
||||||
|
this.updateChildrenPro(item.children, {
|
||||||
|
top: item.top - _top,
|
||||||
|
left: offsetLeft
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (
|
// 调整二级节点的子节点的left值
|
||||||
parent &&
|
if (node.isRoot) {
|
||||||
parent.isRoot &&
|
let totalLeft = 0
|
||||||
node.dir === CONSTANTS.TIMELINE_DIR.BOTTOM
|
|
||||||
) {
|
|
||||||
// 遍历二级节点的子节点
|
|
||||||
node.children.forEach(item => {
|
node.children.forEach(item => {
|
||||||
let totalHeight = this.getNodeAreaHeight(item)
|
item.left += totalLeft
|
||||||
let _top = item.top
|
this.updateChildren(item.children, 'left', totalLeft)
|
||||||
item.top += totalHeight
|
let { left, right } = this.getNodeBoundaries(item, 'h')
|
||||||
this.updateChildren(item.children, 'top', item.top - _top)
|
totalLeft += right - left
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
walk(
|
|
||||||
this.root,
|
|
||||||
null,
|
|
||||||
(node, parent, isRoot, layerIndex) => {
|
|
||||||
if (!node.nodeData.data.expand) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 调整left
|
|
||||||
if (node.layerIndex === 1) {
|
|
||||||
let totalHeight = 0
|
|
||||||
node.children.forEach((item) => {
|
|
||||||
let h = this.getNodeAreaHeight(item)
|
|
||||||
let x = (h + totalHeight) / Math.tan(degToRad(45))
|
|
||||||
totalHeight += h
|
|
||||||
item.left += x
|
|
||||||
this.updateChildren(item.children, 'left', x)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归计算节点的宽度
|
// 递归计算节点的宽度
|
||||||
@ -320,8 +271,12 @@ class Fishbone extends Base {
|
|||||||
// 当前节点为非根节点
|
// 当前节点为非根节点
|
||||||
let maxy = -Infinity
|
let maxy = -Infinity
|
||||||
let miny = Infinity
|
let miny = Infinity
|
||||||
|
let maxx = -Infinity
|
||||||
let x = node.left + node.width * 0.3
|
let x = node.left + node.width * 0.3
|
||||||
node.children.forEach((item, index) => {
|
node.children.forEach((item, index) => {
|
||||||
|
if (item.left > maxx) {
|
||||||
|
maxx = item.left
|
||||||
|
}
|
||||||
let y = item.top + item.height / 2
|
let y = item.top + item.height / 2
|
||||||
if (y > maxy) {
|
if (y > maxy) {
|
||||||
maxy = y
|
maxy = y
|
||||||
@ -340,15 +295,29 @@ class Fishbone extends Base {
|
|||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
let line = this.draw.path()
|
let line = this.draw.path()
|
||||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||||
|
let lineLength = maxx - node.left - node.width * 0.3
|
||||||
if (
|
if (
|
||||||
node.parent &&
|
node.parent &&
|
||||||
node.parent.isRoot &&
|
node.parent.isRoot &&
|
||||||
node.dir === CONSTANTS.TIMELINE_DIR.TOP
|
node.dir === CONSTANTS.TIMELINE_DIR.TOP
|
||||||
) {
|
) {
|
||||||
line.plot(`M ${x},${top} L ${x + 1000},${top - Math.tan(degToRad(45)) * 1000}`)
|
line.plot(
|
||||||
|
`M ${x},${top} L ${x + lineLength},${
|
||||||
|
top - Math.tan(degToRad(45)) * lineLength
|
||||||
|
}`
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (node.parent && node.parent.isRoot) {
|
if (node.parent && node.parent.isRoot) {
|
||||||
line.plot(`M ${x},${top + height + expandBtnSize} L ${x + 1000},${top + Math.tan(degToRad(45)) * 1000}`)
|
line.plot(
|
||||||
|
`M ${x},${top} L ${x + lineLength},${
|
||||||
|
top - Math.tan(degToRad(45)) * lineLength
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
// line.plot(
|
||||||
|
// `M ${x},${top + height + expandBtnSize} L ${x + 1000},${
|
||||||
|
// top + Math.tan(degToRad(45)) * 1000
|
||||||
|
// }`
|
||||||
|
// )
|
||||||
} else {
|
} else {
|
||||||
line.plot(`M ${x},${top + height + expandBtnSize} L ${x},${maxy}`)
|
line.plot(`M ${x},${top + height + expandBtnSize} L ${x},${maxy}`)
|
||||||
}
|
}
|
||||||
@ -365,11 +334,7 @@ class Fishbone extends Base {
|
|||||||
let { width, height, expandBtnSize, isRoot } = node
|
let { width, height, expandBtnSize, isRoot } = node
|
||||||
if (!isRoot) {
|
if (!isRoot) {
|
||||||
let { translateX, translateY } = btn.transform()
|
let { translateX, translateY } = btn.transform()
|
||||||
if (
|
if (node.parent && node.parent.isRoot) {
|
||||||
node.parent &&
|
|
||||||
node.parent.isRoot &&
|
|
||||||
node.dir === CONSTANTS.TIMELINE_DIR.TOP
|
|
||||||
) {
|
|
||||||
btn.translate(
|
btn.translate(
|
||||||
width * 0.3 - expandBtnSize / 2 - translateX,
|
width * 0.3 - expandBtnSize / 2 - translateX,
|
||||||
-expandBtnSize / 2 - translateY
|
-expandBtnSize / 2 - translateY
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user