in dolphinscheduler-ui/src/views/projects/workflow/definition/tree/use-d3-tree/tree.ts [160:338]
Tree.prototype.treeUpdate = function (source) {
const tasksStateObj = this.tasksStateObj
const tasksType = {}
this.taskTypeNodeOptions.map((v) => {
tasksType[v.taskType] = {
color: v.color
}
})
return new Promise((resolve) => {
const tasks = this.tasks
const height = Math.max(
500,
tasks.length * this.config.barHeight +
this.config.margin.top +
this.config.margin.bottom
)
d3.select('.tree-svg')
.transition()
.duration(this.duration)
.attr('height', height)
tasks.forEach((n, i) => {
n.x = i * this.config.barHeight
})
const task = this.svg.selectAll('g.node').data(tasks, (d) => {
return d.id || (d.id = ++this.i)
})
const nodeEnter = task
.enter()
.append('g')
.attr('class', this.nodesClass)
.attr('transform', () => 'translate(' + source.y0 + ',' + source.x0 + ')')
.style('opacity', 1e-6)
// Node circle
nodeEnter
.append('circle')
.attr('r', this.config.barHeight / 3)
.attr('class', 'task')
.attr('title', (d) => {
return d.data.type ? d.data.type : ''
})
.attr('height', this.config.barHeight)
.attr('width', (d) => this.config.barWidth - d.y)
.style('fill', (d) =>
d.data.type ? tasksType[d.data.type]?.color : '#fff'
)
.attr('task_id', (d) => {
return d.data.uuid
})
.on('click', this.treeToggles)
.on('mouseover', (e, d) => {
self.treeTooltip(d.data.type, e)
})
.on('mouseout', () => {
self.removeTooltip()
})
// Node text
nodeEnter
.append('text')
.attr('dy', 3.5)
.attr('dx', this.config.barHeight / 2)
.text((d) => {
return d.data.name
})
.style('fill', 'var(--n-title-text-color)')
const translateRatio =
this.config.nodesMax > 10 ? (this.config.nodesMax > 20 ? 10 : 30) : 60
// Right node information
nodeEnter
.append('g')
.attr('class', 'stateboxes')
.attr(
'transform',
(d) =>
'translate(' + (this.config.nodesMax * translateRatio - d.y) + ',0)'
)
.selectAll('rect')
.data((d) => d.data.instances)
.enter()
.append('rect')
.on('click', () => {
this.removeTooltip()
})
.attr('class', 'state')
.style(
'fill',
(d) => (d.state && tasksStateObj[d.state].color) || '#ffffff'
)
.attr('rx', (d) => (d.type ? 0 : 12))
.attr('ry', (d) => (d.type ? 0 : 12))
.style('shape-rendering', (d) => (d.type ? 'crispEdges' : 'auto'))
.attr(
'x',
(d, i) => i * (this.config.squareSize + this.config.squarePading)
)
.attr('y', -(this.config.squareSize / 2))
.attr('width', 10)
.attr('height', 10)
.on('mouseover', (e, d) => {
self.treeTooltip(rtInstancesTooltip(d, tasksStateObj), e)
})
.on('mouseout', () => {
self.removeTooltip()
})
// Convert nodes to their new location。
nodeEnter
.transition()
.duration(this.duration)
.attr('transform', (d) => 'translate(' + d.y + ',' + d.x + ')')
.style('opacity', 1)
// Node line
task
.transition()
.duration(this.duration)
.attr('class', this.nodesClass)
.attr('transform', (d) => 'translate(' + d.y + ',' + d.x + ')')
.style('opacity', 1)
// Convert the exit node to the new location of the parent node。
task
.exit()
.transition()
.duration(this.duration)
.attr('transform', () => 'translate(' + source.y + ',' + source.x + ')')
.style('opacity', 1e-6)
.remove()
// Update link
const link = this.svg
.selectAll('path.link')
.data(this.links, (d) => d.target.id)
// Enter any new links in the previous location of the parent node。
link
.enter()
.insert('path', 'g')
.attr('class', 'link')
.attr('d', () => {
const o = { x: source.x0, y: source.y0 }
return this.diagonal({ source: o, target: o })
})
.transition()
.duration(this.duration)
.attr('d', this.diagonal)
// Transition link
link.transition().duration(this.duration).attr('d', this.diagonal)
// Convert the exit node to the new location of the parent node
link
.exit()
.transition()
.duration(this.duration)
.attr('d', () => {
const o = { x: source.x, y: source.y }
return this.diagonal({ source: o, target: o })
})
.remove()
// Hide the old position for a transition.
tasks.forEach((d) => {
d.x0 = d.x
d.y0 = d.y
})
resolve()
})
}