mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-21 10:27:44 +08:00
Feat:优化画布DOM结构,将节点、连线、关联线分层渲染
This commit is contained in:
parent
7ec720823f
commit
88fa6225eb
@ -48,8 +48,7 @@ class MindMap {
|
||||
this.addCss()
|
||||
|
||||
// 画布
|
||||
this.svg = SVG().addTo(this.el).size(this.width, this.height)
|
||||
this.draw = this.svg.group()
|
||||
this.initContainer()
|
||||
|
||||
// 初始化主题
|
||||
this.initTheme()
|
||||
@ -79,8 +78,7 @@ class MindMap {
|
||||
|
||||
// 视图操作类
|
||||
this.view = new View({
|
||||
mindMap: this,
|
||||
draw: this.draw
|
||||
mindMap: this
|
||||
})
|
||||
|
||||
// 批量执行类
|
||||
@ -111,6 +109,46 @@ class MindMap {
|
||||
return opt
|
||||
}
|
||||
|
||||
// 创建容器元素
|
||||
initContainer() {
|
||||
const { associativeLineIsAlwaysAboveNode } = this.opt
|
||||
// 节点关联线容器
|
||||
const createAssociativeLineDraw = () => {
|
||||
this.associativeLineDraw = this.draw.group()
|
||||
this.associativeLineDraw.addClass('smm-associative-line-container')
|
||||
}
|
||||
// 画布
|
||||
this.svg = SVG().addTo(this.el).size(this.width, this.height)
|
||||
// 容器
|
||||
this.draw = this.svg.group()
|
||||
this.draw.addClass('smm-container')
|
||||
// 节点连线容器
|
||||
this.lineDraw = this.draw.group()
|
||||
this.lineDraw.addClass('smm-line-container')
|
||||
// 默认处于节点下方
|
||||
if (!associativeLineIsAlwaysAboveNode) {
|
||||
createAssociativeLineDraw()
|
||||
}
|
||||
// 节点容器
|
||||
this.nodeDraw = this.draw.group()
|
||||
this.nodeDraw.addClass('smm-node-container')
|
||||
// 关联线始终处于节点上方
|
||||
if (associativeLineIsAlwaysAboveNode) {
|
||||
createAssociativeLineDraw()
|
||||
}
|
||||
// 其他内容的容器
|
||||
this.otherDraw = this.draw.group()
|
||||
this.otherDraw.addClass('smm-other-container')
|
||||
}
|
||||
|
||||
// 清空各容器
|
||||
clearDraw() {
|
||||
this.lineDraw.clear()
|
||||
this.associativeLineDraw.clear()
|
||||
this.nodeDraw.clear()
|
||||
this.otherDraw.clear()
|
||||
}
|
||||
|
||||
// 添加必要的css样式到页面
|
||||
addCss() {
|
||||
this.cssEl = document.createElement('style')
|
||||
@ -136,7 +174,7 @@ class MindMap {
|
||||
// 重新渲染
|
||||
reRender(callback, source = '') {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.draw.clear()
|
||||
this.clearDraw()
|
||||
this.initTheme()
|
||||
this.renderer.reRender = true
|
||||
this.renderer.render(callback, source)
|
||||
|
||||
@ -209,5 +209,8 @@ export const defaultOpt = {
|
||||
cooperateStyle: {
|
||||
avatarSize: 22,// 头像大小
|
||||
fontSize: 12,// 如果是文字头像,那么文字的大小
|
||||
}
|
||||
},
|
||||
// 关联线是否始终显示在节点上层
|
||||
// false:即创建关联线和激活关联线时处于最顶层,其他情况下处于节点下方
|
||||
associativeLineIsAlwaysAboveNode: true
|
||||
}
|
||||
|
||||
@ -52,7 +52,6 @@ class Render {
|
||||
this.opt = opt
|
||||
this.mindMap = opt.mindMap
|
||||
this.themeConfig = this.mindMap.themeConfig
|
||||
this.draw = this.mindMap.draw
|
||||
// 渲染树,操作过程中修改的都是这里的数据
|
||||
this.renderTree = merge({}, this.mindMap.opt.data || {})
|
||||
// 是否重新渲染
|
||||
@ -624,9 +623,6 @@ class Render {
|
||||
node.nodeData.children.push(newNode)
|
||||
// 插入子节点时自动展开子节点
|
||||
node.nodeData.data.expand = true
|
||||
if (node.isRoot) {
|
||||
node.destroy()
|
||||
}
|
||||
})
|
||||
// 如果同时对多个节点插入子节点,需要清除原来激活的节点
|
||||
if (handleMultiNodes || !openEdit) {
|
||||
@ -663,9 +659,6 @@ class Render {
|
||||
node.nodeData.children.push(...childList)
|
||||
// 插入子节点时自动展开子节点
|
||||
node.nodeData.data.expand = true
|
||||
if (node.isRoot) {
|
||||
node.destroy()
|
||||
}
|
||||
})
|
||||
this.clearActive()
|
||||
this.mindMap.render()
|
||||
@ -1057,9 +1050,6 @@ class Render {
|
||||
})
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
this.mindMap.render()
|
||||
if (toNode.isRoot) {
|
||||
toNode.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// 粘贴节点到节点
|
||||
|
||||
@ -22,7 +22,9 @@ class Node {
|
||||
// 渲染实例
|
||||
this.renderer = opt.renderer
|
||||
// 渲染器
|
||||
this.draw = opt.draw || null
|
||||
this.draw = this.mindMap.draw
|
||||
this.nodeDraw = this.mindMap.nodeDraw
|
||||
this.lineDraw = this.mindMap.lineDraw
|
||||
// 样式实例
|
||||
this.style = new Style(this)
|
||||
// 形状实例
|
||||
@ -613,11 +615,11 @@ class Node {
|
||||
cursor: 'default'
|
||||
})
|
||||
this.bindGroupEvent()
|
||||
this.draw.add(this.group)
|
||||
this.nodeDraw.add(this.group)
|
||||
this.layout()
|
||||
this.update()
|
||||
} else {
|
||||
this.draw.add(this.group)
|
||||
this.nodeDraw.add(this.group)
|
||||
if (this.needLayout) {
|
||||
this.needLayout = false
|
||||
this.layout()
|
||||
@ -788,7 +790,7 @@ class Node {
|
||||
if (childrenLen > this._lines.length) {
|
||||
// 创建缺少的线
|
||||
new Array(childrenLen - this._lines.length).fill(0).forEach(() => {
|
||||
this._lines.push(this.draw.path())
|
||||
this._lines.push(this.lineDraw.path())
|
||||
})
|
||||
} else if (childrenLen < this._lines.length) {
|
||||
// 删除多余的线
|
||||
|
||||
@ -12,7 +12,7 @@ function createGeneralizationNode() {
|
||||
return
|
||||
}
|
||||
if (!this._generalizationLine) {
|
||||
this._generalizationLine = this.draw.path()
|
||||
this._generalizationLine = this.lineDraw.path()
|
||||
}
|
||||
if (!this._generalizationNode) {
|
||||
this._generalizationNode = new Node({
|
||||
@ -22,7 +22,6 @@ function createGeneralizationNode() {
|
||||
uid: createUid(),
|
||||
renderer: this.renderer,
|
||||
mindMap: this.mindMap,
|
||||
draw: this.draw,
|
||||
isGeneralization: true
|
||||
})
|
||||
this._generalizationNodeWidth = this._generalizationNode.width
|
||||
@ -79,7 +78,7 @@ function removeGeneralization() {
|
||||
}
|
||||
// hack修复当激活一个节点时创建概要,然后立即激活创建的概要节点后会重复创建概要节点并且无法删除的问题
|
||||
if (this.generalizationBelongNode) {
|
||||
this.draw
|
||||
this.nodeDraw
|
||||
.find('.generalization_' + this.generalizationBelongNode.uid)
|
||||
.remove()
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ class Base {
|
||||
this.mindMap = renderer.mindMap
|
||||
// 绘图对象
|
||||
this.draw = this.mindMap.draw
|
||||
this.lineDraw = this.mindMap.lineDraw
|
||||
// 根节点
|
||||
this.root = null
|
||||
this.lru = new Lru(this.mindMap.opt.maxNodeCacheCount)
|
||||
|
||||
@ -247,14 +247,14 @@ class CatalogOrganization extends Base {
|
||||
minx = Math.min(minx, x1)
|
||||
maxx = Math.max(maxx, x1)
|
||||
// 父节点的竖线
|
||||
let line1 = this.draw.path()
|
||||
let line1 = this.lineDraw.path()
|
||||
node.style.line(line1)
|
||||
line1.plot(`M ${x1},${y1} L ${x1},${y1 + s1}`)
|
||||
node._lines.push(line1)
|
||||
style && style(line1, node)
|
||||
// 水平线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
let lin2 = this.lineDraw.path()
|
||||
node.style.line(lin2)
|
||||
lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`)
|
||||
node._lines.push(lin2)
|
||||
@ -315,7 +315,7 @@ class CatalogOrganization extends Base {
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
let lin2 = this.lineDraw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
node.style.line(lin2)
|
||||
if (maxy < y1 + expandBtnSize) {
|
||||
|
||||
@ -252,7 +252,7 @@ class Fishbone extends Base {
|
||||
let nodeLineX = item.left
|
||||
let offset = node.height / 2 + marginY
|
||||
let offsetX = offset / Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
if (this.checkIsTop(item)) {
|
||||
line.plot(
|
||||
`M ${nodeLineX - offsetX},${item.top + item.height + offset} L ${
|
||||
@ -273,7 +273,7 @@ class Fishbone extends Base {
|
||||
// 从根节点出发的水平线
|
||||
let nodeHalfTop = node.top + node.height / 2
|
||||
let offset = node.height / 2 + this.getMarginY(node.layerIndex + 1)
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
line.plot(
|
||||
`M ${node.left + node.width},${nodeHalfTop} L ${
|
||||
maxx - offset / Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
@ -308,7 +308,7 @@ class Fishbone extends Base {
|
||||
})
|
||||
// 斜线
|
||||
if (len >= 0) {
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
let lineLength = maxx - node.left - node.width * this.indent
|
||||
lineLength = Math.max(lineLength, 0)
|
||||
|
||||
@ -307,7 +307,7 @@ class Fishbone extends Base {
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
let lineLength = maxx - node.left - node.width * 0.3
|
||||
if (node.parent && node.parent.isRoot) {
|
||||
|
||||
@ -276,7 +276,7 @@ class Fishbone extends Base {
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
let lineLength = maxx - node.left - node.width * 0.3
|
||||
if (
|
||||
|
||||
@ -218,7 +218,7 @@ class OrganizationStructure extends Base {
|
||||
minx = Math.min(x1, minx)
|
||||
maxx = Math.max(x1, maxx)
|
||||
// 父节点的竖线
|
||||
let line1 = this.draw.path()
|
||||
let line1 = this.lineDraw.path()
|
||||
node.style.line(line1)
|
||||
expandBtnSize = len > 0 && !isRoot ? expandBtnSize : 0
|
||||
line1.plot(`M ${x1},${y1 + expandBtnSize} L ${x1},${y1 + s1}`)
|
||||
@ -226,7 +226,7 @@ class OrganizationStructure extends Base {
|
||||
style && style(line1, node)
|
||||
// 水平线
|
||||
if (len > 0) {
|
||||
let lin2 = this.draw.path()
|
||||
let lin2 = this.lineDraw.path()
|
||||
node.style.line(lin2)
|
||||
lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`)
|
||||
node._lines.push(lin2)
|
||||
|
||||
@ -275,7 +275,7 @@ class Timeline extends Base {
|
||||
})
|
||||
// 竖线
|
||||
if (len > 0) {
|
||||
let line = this.draw.path()
|
||||
let line = this.lineDraw.path()
|
||||
expandBtnSize = len > 0 ? expandBtnSize : 0
|
||||
if (
|
||||
node.parent &&
|
||||
|
||||
@ -15,7 +15,7 @@ import associativeLineTextMethods from './associativeLine/associativeLineText'
|
||||
class AssociativeLine {
|
||||
constructor(opt = {}) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.draw = this.mindMap.draw
|
||||
this.associativeLineDraw = this.mindMap.associativeLineDraw
|
||||
// 当前所有连接线
|
||||
this.lineList = []
|
||||
// 当前激活的连接线
|
||||
@ -98,7 +98,7 @@ class AssociativeLine {
|
||||
|
||||
// 创建箭头
|
||||
createMarker() {
|
||||
return this.draw.marker(20, 20, add => {
|
||||
return this.associativeLineDraw.marker(20, 20, add => {
|
||||
add.ref(12, 5)
|
||||
add.size(10, 10)
|
||||
add.attr('orient', 'auto-start-reverse')
|
||||
@ -194,7 +194,7 @@ class AssociativeLine {
|
||||
toNode
|
||||
)
|
||||
// 虚线
|
||||
let path = this.draw.path()
|
||||
let path = this.associativeLineDraw.path()
|
||||
path
|
||||
.stroke({
|
||||
width: associativeLineWidth,
|
||||
@ -205,7 +205,7 @@ class AssociativeLine {
|
||||
path.plot(pathStr)
|
||||
path.marker('end', this.marker)
|
||||
// 不可见的点击线
|
||||
let clickPath = this.draw.path()
|
||||
let clickPath = this.associativeLineDraw.path()
|
||||
clickPath
|
||||
.stroke({ width: associativeLineActiveWidth, color: 'transparent' })
|
||||
.fill({ color: 'none' })
|
||||
@ -276,6 +276,7 @@ class AssociativeLine {
|
||||
controlPoints[1]
|
||||
)
|
||||
this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
|
||||
this.front()
|
||||
}
|
||||
|
||||
// 移除所有连接线
|
||||
@ -300,9 +301,10 @@ class AssociativeLine {
|
||||
let { associativeLineWidth, associativeLineColor } =
|
||||
this.mindMap.themeConfig
|
||||
if (this.isCreatingLine || !fromNode) return
|
||||
this.front()
|
||||
this.isCreatingLine = true
|
||||
this.creatingStartNode = fromNode
|
||||
this.creatingLine = this.draw.path()
|
||||
this.creatingLine = this.associativeLineDraw.path()
|
||||
this.creatingLine
|
||||
.stroke({
|
||||
width: associativeLineWidth,
|
||||
@ -357,6 +359,7 @@ class AssociativeLine {
|
||||
height
|
||||
}
|
||||
}
|
||||
|
||||
// 检测当前移动到的目标节点
|
||||
checkOverlapNode(x, y) {
|
||||
this.overlapNode = null
|
||||
@ -391,6 +394,7 @@ class AssociativeLine {
|
||||
this.creatingLine.remove()
|
||||
this.creatingLine = null
|
||||
this.overlapNode = null
|
||||
this.back()
|
||||
}
|
||||
|
||||
// 添加连接线
|
||||
@ -500,6 +504,7 @@ class AssociativeLine {
|
||||
}
|
||||
this.activeLine = null
|
||||
this.removeControls()
|
||||
this.back()
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,6 +531,19 @@ class AssociativeLine {
|
||||
this.showControls()
|
||||
this.isNodeDragging = false
|
||||
}
|
||||
|
||||
// 关联线顶层显示
|
||||
front() {
|
||||
if (this.mindMap.opt.associativeLineIsAlwaysAboveNode) return
|
||||
this.associativeLineDraw.front()
|
||||
}
|
||||
|
||||
// 关联线回到原有层级
|
||||
back() {
|
||||
if (this.mindMap.opt.associativeLineIsAlwaysAboveNode) return
|
||||
this.associativeLineDraw.back() // 最底层
|
||||
this.associativeLineDraw.forward() // 连线层上面
|
||||
}
|
||||
}
|
||||
|
||||
AssociativeLine.instanceName = 'associativeLine'
|
||||
|
||||
@ -261,7 +261,7 @@ class Drag extends Base {
|
||||
const lineColor = node.style.merge('lineColor', true)
|
||||
// 如果当前被拖拽的节点数量大于1,那么创建一个矩形示意
|
||||
if (this.beingDragNodeList.length > 1) {
|
||||
this.clone = this.draw
|
||||
this.clone = this.mindMap.otherDraw
|
||||
.rect()
|
||||
.size(rectWidth, rectHeight)
|
||||
.radius(rectHeight / 2)
|
||||
@ -278,12 +278,12 @@ class Drag extends Base {
|
||||
if (expandEl) {
|
||||
expandEl.remove()
|
||||
}
|
||||
this.mindMap.draw.add(this.clone)
|
||||
this.mindMap.otherDraw.add(this.clone)
|
||||
}
|
||||
this.clone.opacity(dragOpacityConfig.cloneNodeOpacity)
|
||||
this.clone.css('z-index', 99999)
|
||||
// 同级位置提示元素
|
||||
this.placeholder = this.draw.rect().fill({
|
||||
this.placeholder = this.mindMap.otherDraw.rect().fill({
|
||||
color: dragPlaceholderRectFill || lineColor
|
||||
})
|
||||
// 当前被拖拽的节点的临时设置
|
||||
|
||||
@ -9,10 +9,10 @@ import {
|
||||
function createControlNodes() {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
// 连线
|
||||
this.controlLine1 = this.draw
|
||||
this.controlLine1 = this.associativeLineDraw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
this.controlLine2 = this.draw
|
||||
this.controlLine2 = this.associativeLineDraw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
// 控制点
|
||||
@ -23,7 +23,7 @@ function createControlNodes() {
|
||||
// 创建控制点
|
||||
function createOneControlNode(pointKey) {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
return this.draw
|
||||
return this.associativeLineDraw
|
||||
.circle(this.controlPointDiameter)
|
||||
.stroke({ color: associativeLineActiveColor })
|
||||
.fill({ color: '#fff' })
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
|
||||
// 创建文字节点
|
||||
function createText(data) {
|
||||
let g = this.draw.group()
|
||||
let g = this.associativeLineDraw.group()
|
||||
const setActive = () => {
|
||||
if (
|
||||
!this.activeLine ||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user