From 88fa6225ebb52cebc3b2192eff9821a5c5b8694a Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 11 Oct 2023 11:36:34 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E4=BC=98=E5=8C=96=E7=94=BB?= =?UTF-8?q?=E5=B8=83DOM=E7=BB=93=E6=9E=84=EF=BC=8C=E5=B0=86=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E3=80=81=E8=BF=9E=E7=BA=BF=E3=80=81=E5=85=B3=E8=81=94?= =?UTF-8?q?=E7=BA=BF=E5=88=86=E5=B1=82=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/index.js | 48 +++++++++++++++++-- .../src/constants/defaultOptions.js | 5 +- simple-mind-map/src/core/render/Render.js | 10 ---- simple-mind-map/src/core/render/node/Node.js | 10 ++-- .../core/render/node/nodeGeneralization.js | 5 +- simple-mind-map/src/layouts/Base.js | 1 + .../src/layouts/CatalogOrganization.js | 6 +-- simple-mind-map/src/layouts/Fishbone.js | 6 +-- simple-mind-map/src/layouts/FishboneBottom.js | 2 +- simple-mind-map/src/layouts/FishboneTop.js | 2 +- .../src/layouts/OrganizationStructure.js | 4 +- simple-mind-map/src/layouts/Timeline.js | 2 +- .../src/plugins/AssociativeLine.js | 28 +++++++++-- simple-mind-map/src/plugins/Drag.js | 6 +-- .../associativeLineControls.js | 6 +-- .../associativeLine/associativeLineText.js | 2 +- 16 files changed, 97 insertions(+), 46 deletions(-) diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 6dc77fd2..45b9180e 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -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) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index d7cc00fb..1f5d91ef 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -209,5 +209,8 @@ export const defaultOpt = { cooperateStyle: { avatarSize: 22,// 头像大小 fontSize: 12,// 如果是文字头像,那么文字的大小 - } + }, + // 关联线是否始终显示在节点上层 + // false:即创建关联线和激活关联线时处于最顶层,其他情况下处于节点下方 + associativeLineIsAlwaysAboveNode: true } diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js index 713c3066..f954e08d 100644 --- a/simple-mind-map/src/core/render/Render.js +++ b/simple-mind-map/src/core/render/Render.js @@ -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() - } } // 粘贴节点到节点 diff --git a/simple-mind-map/src/core/render/node/Node.js b/simple-mind-map/src/core/render/node/Node.js index 9df52019..b4aef24b 100644 --- a/simple-mind-map/src/core/render/node/Node.js +++ b/simple-mind-map/src/core/render/node/Node.js @@ -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) { // 删除多余的线 diff --git a/simple-mind-map/src/core/render/node/nodeGeneralization.js b/simple-mind-map/src/core/render/node/nodeGeneralization.js index 3459e0e2..3ab1cc5f 100644 --- a/simple-mind-map/src/core/render/node/nodeGeneralization.js +++ b/simple-mind-map/src/core/render/node/nodeGeneralization.js @@ -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() } diff --git a/simple-mind-map/src/layouts/Base.js b/simple-mind-map/src/layouts/Base.js index a446acfb..64abca4e 100644 --- a/simple-mind-map/src/layouts/Base.js +++ b/simple-mind-map/src/layouts/Base.js @@ -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) diff --git a/simple-mind-map/src/layouts/CatalogOrganization.js b/simple-mind-map/src/layouts/CatalogOrganization.js index 0162434c..3037d7e7 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -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) { diff --git a/simple-mind-map/src/layouts/Fishbone.js b/simple-mind-map/src/layouts/Fishbone.js index fff92a49..e8892d3d 100644 --- a/simple-mind-map/src/layouts/Fishbone.js +++ b/simple-mind-map/src/layouts/Fishbone.js @@ -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) diff --git a/simple-mind-map/src/layouts/FishboneBottom.js b/simple-mind-map/src/layouts/FishboneBottom.js index c267d62e..295e0363 100644 --- a/simple-mind-map/src/layouts/FishboneBottom.js +++ b/simple-mind-map/src/layouts/FishboneBottom.js @@ -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) { diff --git a/simple-mind-map/src/layouts/FishboneTop.js b/simple-mind-map/src/layouts/FishboneTop.js index fb31e5e6..0d5f9567 100644 --- a/simple-mind-map/src/layouts/FishboneTop.js +++ b/simple-mind-map/src/layouts/FishboneTop.js @@ -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 ( diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/OrganizationStructure.js index ba41a454..4b3a148a 100644 --- a/simple-mind-map/src/layouts/OrganizationStructure.js +++ b/simple-mind-map/src/layouts/OrganizationStructure.js @@ -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) diff --git a/simple-mind-map/src/layouts/Timeline.js b/simple-mind-map/src/layouts/Timeline.js index ee1c0f9b..fea32841 100644 --- a/simple-mind-map/src/layouts/Timeline.js +++ b/simple-mind-map/src/layouts/Timeline.js @@ -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 && diff --git a/simple-mind-map/src/plugins/AssociativeLine.js b/simple-mind-map/src/plugins/AssociativeLine.js index 51fc51ee..a7773043 100644 --- a/simple-mind-map/src/plugins/AssociativeLine.js +++ b/simple-mind-map/src/plugins/AssociativeLine.js @@ -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' diff --git a/simple-mind-map/src/plugins/Drag.js b/simple-mind-map/src/plugins/Drag.js index 53d2a1a5..a8162ab4 100644 --- a/simple-mind-map/src/plugins/Drag.js +++ b/simple-mind-map/src/plugins/Drag.js @@ -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 }) // 当前被拖拽的节点的临时设置 diff --git a/simple-mind-map/src/plugins/associativeLine/associativeLineControls.js b/simple-mind-map/src/plugins/associativeLine/associativeLineControls.js index a35b4d7c..fbd93d24 100644 --- a/simple-mind-map/src/plugins/associativeLine/associativeLineControls.js +++ b/simple-mind-map/src/plugins/associativeLine/associativeLineControls.js @@ -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' }) diff --git a/simple-mind-map/src/plugins/associativeLine/associativeLineText.js b/simple-mind-map/src/plugins/associativeLine/associativeLineText.js index 201077f0..3bd77ae3 100644 --- a/simple-mind-map/src/plugins/associativeLine/associativeLineText.js +++ b/simple-mind-map/src/plugins/associativeLine/associativeLineText.js @@ -7,7 +7,7 @@ import { // 创建文字节点 function createText(data) { - let g = this.draw.group() + let g = this.associativeLineDraw.group() const setActive = () => { if ( !this.activeLine ||