From 747a781ad8bf74561b401fc16df5f85c387aa9df Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Tue, 28 Mar 2023 19:35:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=B3=A8=E9=87=8A=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E7=A9=BA=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/Drag.js | 8 - simple-mind-map/src/Render.js | 51 -- .../src/layouts/CatalogOrganization.js | 772 +++++++++--------- .../src/layouts/LogicalStructure.js | 13 - simple-mind-map/src/layouts/MindMap.js | 12 - .../src/layouts/OrganizationStructure.js | 11 - 6 files changed, 386 insertions(+), 481 deletions(-) diff --git a/simple-mind-map/src/Drag.js b/simple-mind-map/src/Drag.js index 287cb989..75ff5089 100644 --- a/simple-mind-map/src/Drag.js +++ b/simple-mind-map/src/Drag.js @@ -5,7 +5,6 @@ import Base from './layouts/Base' class Drag extends Base { // 构造函数 - constructor({ mindMap }) { super(mindMap.renderer) this.mindMap = mindMap @@ -14,7 +13,6 @@ class Drag extends Base { } // 复位 - reset() { // 当前拖拽节点 this.node = null @@ -48,7 +46,6 @@ class Drag extends Base { } // 绑定事件 - bindEvent() { this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this) this.mindMap.on('node_mousedown', (node, e) => { @@ -98,7 +95,6 @@ class Drag extends Base { } // 鼠标松开事件 - onMouseup(e) { if (!this.isMousedown) { return @@ -141,7 +137,6 @@ class Drag extends Base { } // 创建克隆节点 - createCloneNode() { if (!this.clone) { // 节点 @@ -163,7 +158,6 @@ class Drag extends Base { } // 移除克隆节点 - removeCloneNode() { if (!this.clone) { return @@ -174,7 +168,6 @@ class Drag extends Base { } // 拖动中 - onMove(x, y) { if (!this.isMousedown) { return @@ -201,7 +194,6 @@ class Drag extends Base { } // 检测重叠节点 - checkOverlapNode() { if (!this.drawTransform) { return diff --git a/simple-mind-map/src/Render.js b/simple-mind-map/src/Render.js index 32406cc6..85399d78 100644 --- a/simple-mind-map/src/Render.js +++ b/simple-mind-map/src/Render.js @@ -24,7 +24,6 @@ const layouts = { class Render { // 构造函数 - constructor(opt = {}) { this.opt = opt this.mindMap = opt.mindMap @@ -51,7 +50,6 @@ class Render { } // 设置布局结构 - setLayout() { this.layout = new ( layouts[this.mindMap.opt.layout] @@ -61,7 +59,6 @@ class Render { } // 绑定事件 - bindEvent() { // 点击事件 this.mindMap.on('draw_click', () => { @@ -73,7 +70,6 @@ class Render { } // 注册命令 - registerCommands() { // 全选 this.selectAll = this.selectAll.bind(this) @@ -175,7 +171,6 @@ class Render { } // 注册快捷键 - registerShortcutKeys() { // 插入下级节点 this.mindMap.keyCommand.addShortcut('Tab', () => { @@ -220,7 +215,6 @@ class Render { } // 开启文字编辑,会禁用回车键和删除键相关快捷键防止冲突 - startTextEdit() { this.mindMap.keyCommand.save() // this.mindMap.keyCommand.removeShortcut('Del|Backspace') @@ -229,7 +223,6 @@ class Render { } // 结束文字编辑,会恢复回车键和删除键相关快捷键 - endTextEdit() { this.mindMap.keyCommand.restore() // this.mindMap.keyCommand.addShortcut('Del|Backspace', this.removeNodeWrap) @@ -238,7 +231,6 @@ class Render { } // 渲染 - render(callback = () => {}) { if (this.reRender) { this.clearActive() @@ -254,7 +246,6 @@ class Render { } // 清除当前激活的节点 - clearActive() { this.activeNodeList.forEach(item => { this.setNodeActive(item, false) @@ -263,7 +254,6 @@ class Render { } // 清除当前所有激活节点,并会触发事件 - clearAllActive() { if (this.activeNodeList.length <= 0) { return @@ -273,7 +263,6 @@ class Render { } // 添加节点到激活列表里 - addActiveNode(node) { let index = this.findActiveNodeIndex(node) if (index === -1) { @@ -282,7 +271,6 @@ class Render { } // 在激活列表里移除某个节点 - removeActiveNode(node) { let index = this.findActiveNodeIndex(node) if (index === -1) { @@ -292,7 +280,6 @@ class Render { } // 检索某个节点在激活列表里的索引 - findActiveNodeIndex(node) { return this.activeNodeList.findIndex(item => { return item === node @@ -300,7 +287,6 @@ class Render { } // 获取节点在同级里的索引位置 - getNodeIndex(node) { return node.parent ? node.parent.children.findIndex(item => { @@ -310,7 +296,6 @@ class Render { } // 全选 - selectAll() { walk( this.root, @@ -332,7 +317,6 @@ class Render { } // 回退 - back(step) { this.clearAllActive() let data = this.mindMap.command.back(step) @@ -343,7 +327,6 @@ class Render { } // 前进 - forward(step) { this.clearAllActive() let data = this.mindMap.command.forward(step) @@ -360,7 +343,6 @@ class Render { } // 插入同级节点,多个节点只会操作第一个节点 - insertNode(openEdit = true, appointNodes = [], appointData = null) { appointNodes = this.formatAppointNodes(appointNodes) if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) { @@ -391,7 +373,6 @@ class Render { } // 插入子节点 - insertChildNode(openEdit = true, appointNodes = [], appointData = null) { appointNodes = this.formatAppointNodes(appointNodes) if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) { @@ -426,7 +407,6 @@ class Render { } // 上移节点,多个节点只会操作第一个节点 - upNode() { if (this.activeNodeList.length <= 0) { return @@ -454,7 +434,6 @@ class Render { } // 下移节点,多个节点只会操作第一个节点 - downNode() { if (this.activeNodeList.length <= 0) { return @@ -482,7 +461,6 @@ class Render { } // 将节点移动到另一个节点的前面 - insertBefore(node, exist) { if (node.isRoot) { return @@ -521,7 +499,6 @@ class Render { } // 将节点移动到另一个节点的后面 - insertAfter(node, exist) { if (node.isRoot) { return @@ -561,7 +538,6 @@ class Render { } // 移除节点 - removeNode(appointNodes = []) { appointNodes = this.formatAppointNodes(appointNodes) if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) { @@ -603,7 +579,6 @@ class Render { } // 移除某个指定节点 - removeOneNode(node) { let index = this.getNodeIndex(node) node.remove() @@ -612,7 +587,6 @@ class Render { } // 复制节点,多个节点只会操作第一个节点 - copyNode() { if (this.activeNodeList.length <= 0) { return @@ -621,7 +595,6 @@ class Render { } // 剪切节点,多个节点只会操作第一个节点 - cutNode(callback) { if (this.activeNodeList.length <= 0) { return @@ -641,7 +614,6 @@ class Render { } // 移动一个节点作为另一个节点的子节点 - moveNodeTo(node, toNode) { if (node.isRoot) { return @@ -658,7 +630,6 @@ class Render { } // 粘贴节点到节点 - pasteNode(data) { if (this.activeNodeList.length <= 0) { return @@ -670,7 +641,6 @@ class Render { } // 设置节点样式 - setNodeStyle(node, prop, value, isActive) { let data = {} if (isActive) { @@ -702,7 +672,6 @@ class Render { } // 设置节点是否激活 - setNodeActive(node, active) { this.setNodeData(node, { isActive: active @@ -711,7 +680,6 @@ class Render { } // 设置节点是否展开 - setNodeExpand(node, expand) { this.setNodeData(node, { expand @@ -735,7 +703,6 @@ class Render { } // 展开所有 - expandAllNode() { walk( this.renderTree, @@ -754,7 +721,6 @@ class Render { } // 收起所有 - unexpandAllNode() { walk( this.renderTree, @@ -774,7 +740,6 @@ class Render { } // 展开到指定层级 - expandToLevel(level) { walk( this.renderTree, @@ -792,7 +757,6 @@ class Render { } // 切换激活节点的展开状态 - toggleActiveExpand() { this.activeNodeList.forEach(node => { if (node.nodeData.children.length <= 0) { @@ -803,7 +767,6 @@ class Render { } // 切换节点展开状态 - toggleNodeExpand(node) { this.mindMap.execCommand( 'SET_NODE_EXPAND', @@ -813,7 +776,6 @@ class Render { } // 设置节点文本 - setNodeText(node, text, richText) { this.setNodeDataRender(node, { text, @@ -822,7 +784,6 @@ class Render { } // 设置节点图片 - setNodeImage(node, { url, title, width, height }) { this.setNodeDataRender(node, { image: url, @@ -835,7 +796,6 @@ class Render { } // 设置节点图标 - setNodeIcon(node, icons) { this.setNodeDataRender(node, { icon: icons @@ -843,7 +803,6 @@ class Render { } // 设置节点超链接 - setNodeHyperlink(node, link, title = '') { this.setNodeDataRender(node, { hyperlink: link, @@ -852,7 +811,6 @@ class Render { } // 设置节点备注 - setNodeNote(node, note) { this.setNodeDataRender(node, { note @@ -860,7 +818,6 @@ class Render { } // 设置节点标签 - setNodeTag(node, tag) { this.setNodeDataRender(node, { tag @@ -868,7 +825,6 @@ class Render { } // 添加节点概要 - addGeneralization(data) { if (this.activeNodeList.length <= 0) { return @@ -888,7 +844,6 @@ class Render { } // 删除节点概要 - removeGeneralization() { if (this.activeNodeList.length <= 0) { return @@ -906,7 +861,6 @@ class Render { } // 设置节点自定义位置 - setNodeCustomPosition(node, left = undefined, top = undefined) { let nodeList = [node] || this.activeNodeList nodeList.forEach(item => { @@ -918,7 +872,6 @@ class Render { } // 一键整理布局,即去除自定义位置 - resetLayout() { walk( this.root, @@ -940,7 +893,6 @@ class Render { } // 设置节点形状 - setNodeShape(node, shape) { if (!shape || !shapeList.includes(shape)) { return @@ -952,7 +904,6 @@ class Render { } // 更新节点数据 - setNodeData(node, data) { Object.keys(data).forEach(key => { node.nodeData.data[key] = data[key] @@ -960,7 +911,6 @@ class Render { } // 设置节点数据,并判断是否渲染 - setNodeDataRender(node, data) { this.setNodeData(node, data) let changed = node.getSize() @@ -975,7 +925,6 @@ class Render { } // 移动节点到画布中心 - moveNodeToCenter(node) { let halfWidth = this.mindMap.width / 2 let halfHeight = this.mindMap.height / 2 diff --git a/simple-mind-map/src/layouts/CatalogOrganization.js b/simple-mind-map/src/layouts/CatalogOrganization.js index 0b102655..4cf06569 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -1,386 +1,386 @@ -import Base from './Base' -import { walk, asyncRun } from '../utils' - -// 目录组织图 -class CatalogOrganization extends Base { - // 构造函数 - constructor(opt = {}) { - super(opt) - } - - // 布局 - doLayout(callback) { - let task = [ - () => { - this.computedBaseValue() - }, - () => { - this.computedLeftTopValue() - }, - () => { - this.adjustLeftTopValue() - }, - () => { - callback(this.root) - } - ] - asyncRun(task) - } - - // 遍历数据计算节点的left、width、height - computedBaseValue() { - walk( - this.renderer.renderTree, - null, - (cur, parent, isRoot, layerIndex) => { - let newNode = this.createNode(cur, parent, isRoot, layerIndex) - // 根节点定位在画布中心位置 - if (isRoot) { - this.setNodeCenter(newNode) - } else { - // 非根节点 - if (parent._node.isRoot) { - newNode.top = - parent._node.top + - parent._node.height + - this.getMarginX(layerIndex) - } - } - if (!cur.data.expand) { - return true - } - }, - (cur, parent, isRoot, layerIndex) => { - if (isRoot) { - let len = cur.data.expand === false ? 0 : cur._node.children.length - cur._node.childrenAreaWidth = len - ? cur._node.children.reduce((h, item) => { - return h + item.width - }, 0) + - (len + 1) * this.getMarginX(layerIndex + 1) - : 0 - } - }, - true, - 0 - ) - } - - // 遍历节点树计算节点的left、top - computedLeftTopValue() { - walk( - this.root, - null, - (node, parent, isRoot, layerIndex) => { - if ( - node.nodeData.data.expand && - node.children && - node.children.length - ) { - let marginX = this.getMarginX(layerIndex + 1) - let marginY = this.getMarginY(layerIndex + 1) - if (isRoot) { - let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 - let totalLeft = left + marginX - node.children.forEach(cur => { - cur.left = totalLeft - totalLeft += cur.width + marginX - }) - } else { - let totalTop = node.top + node.height + marginY + node.expandBtnSize - node.children.forEach(cur => { - cur.left = node.left + node.width * 0.5 - cur.top = totalTop - totalTop += cur.height + marginY + node.expandBtnSize - }) - } - } - }, - null, - true - ) - } - - // 调整节点left、top - adjustLeftTopValue() { - walk( - this.root, - null, - (node, parent, isRoot, layerIndex) => { - if (!node.nodeData.data.expand) { - return - } - // 调整left - if (parent && parent.isRoot) { - let areaWidth = this.getNodeAreaWidth(node) - let difference = areaWidth - node.width - if (difference > 0) { - this.updateBrothersLeft(node, difference / 2) - } - } - // 调整top - let len = node.children.length - if (parent && !parent.isRoot && len > 0) { - let marginY = this.getMarginY(layerIndex + 1) - let totalHeight = - node.children.reduce((h, item) => { - return h + item.height - }, 0) + - (len + 1) * marginY + - len * node.expandBtnSize - this.updateBrothersTop(node, totalHeight) - } - }, - null, - true - ) - } - - // 递归计算节点的宽度 - getNodeAreaWidth(node) { - let widthArr = [] - let loop = (node, width) => { - if (node.children.length) { - width += node.width / 2 - node.children.forEach(item => { - loop(item, width) - }) - } else { - width += node.width - widthArr.push(width) - } - } - loop(node, 0) - return Math.max(...widthArr) - } - - // 调整兄弟节点的left - updateBrothersLeft(node, addWidth) { - if (node.parent) { - let childrenList = node.parent.children - let index = childrenList.findIndex(item => { - return item === node - }) - // 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称 - if ( - (index === 0 || index === childrenList.length - 1) && - childrenList.length > 1 - ) { - let _offset = index === 0 ? -addWidth : addWidth - node.left += _offset - if ( - node.children && - node.children.length && - !node.hasCustomPosition() - ) { - this.updateChildren(node.children, 'left', _offset) - } - } - childrenList.forEach((item, _index) => { - if (item.hasCustomPosition()) { - // 适配自定义位置 - return - } - let _offset = 0 - if (_index < index) { - // 左边的节点往左移 - _offset = -addWidth - } else if (_index > index) { - // 右边的节点往右移 - _offset = addWidth - } - item.left += _offset - // 同步更新子节点的位置 - if (item.children && item.children.length) { - this.updateChildren(item.children, 'left', _offset) - } - }) - // 更新父节点的位置 - this.updateBrothersLeft(node.parent, addWidth) - } - } - - // 调整兄弟节点的top - updateBrothersTop(node, addHeight) { - if (node.parent && !node.parent.isRoot) { - let childrenList = node.parent.children - let index = childrenList.findIndex(item => { - return item === node - }) - childrenList.forEach((item, _index) => { - if (item.hasCustomPosition()) { - // 适配自定义位置 - return - } - let _offset = 0 - // 下面的节点往下移 - if (_index > index) { - _offset = addHeight - } - item.top += _offset - // 同步更新子节点的位置 - if (item.children && item.children.length) { - this.updateChildren(item.children, 'top', _offset) - } - }) - // 更新父节点的位置 - this.updateBrothersTop(node.parent, addHeight) - } - } - - // 绘制连线,连接该节点到其子节点 - renderLine(node, lines, style) { - if (node.children.length <= 0) { - return [] - } - let { left, top, width, height, expandBtnSize } = node - let len = node.children.length - let marginX = this.getMarginX(node.layerIndex + 1) - if (node.isRoot) { - // 根节点 - let x1 = left + width / 2 - let y1 = top + height - let s1 = marginX * 0.7 - let minx = Infinity - let maxx = -Infinity - node.children.forEach((item, index) => { - let x2 = item.left + item.width / 2 - let y2 = item.top - if (x2 < minx) { - minx = x2 - } - if (x2 > maxx) { - maxx = x2 - } - // 节点使用横线风格,需要额外渲染横线 - let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle - ? ` L ${item.left},${y2} L ${item.left + item.width},${y2}` - : '' - let path = - `M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` + - nodeUseLineStylePath - // 竖线 - lines[index].plot(path) - style && style(lines[index], item) - }) - minx = Math.min(minx, x1) - maxx = Math.max(maxx, x1) - // 父节点的竖线 - let line1 = this.draw.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() - node.style.line(lin2) - lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`) - node._lines.push(lin2) - style && style(lin2, node) - } - } else { - // 非根节点 - let y1 = top + height - let maxy = -Infinity - let x2 = node.left + node.width * 0.3 - node.children.forEach((item, index) => { - // 为了适配自定义位置,下面做了各种位置的兼容 - let y2 = item.top + item.height / 2 - if (y2 > maxy) { - maxy = y2 - } - // 水平线 - let path = '' - let _left = item.left - let _isLeft = item.left + item.width < x2 - let _isXCenter = false - if (_isLeft) { - // 水平位置在父节点左边 - _left = item.left + item.width - } else if (item.left < x2 && item.left + item.width > x2) { - // 水平位置在父节点之间 - _isXCenter = true - y2 = item.top - maxy = y2 - } - if (y2 > top && y2 < y1) { - // 自定义位置的情况:垂直位置节点在父节点之间 - path = `M ${ - _isLeft ? node.left : node.left + node.width - },${y2} L ${_left},${y2}` - } else if (y2 < y1) { - // 自定义位置的情况:垂直位置节点在父节点上面 - if (_isXCenter) { - y2 = item.top + item.height - _left = x2 - } - path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}` - } else { - if (_isXCenter) { - _left = x2 - } - path = `M ${x2},${y2} L ${_left},${y2}` - } - // 节点使用横线风格,需要额外渲染横线 - let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle - ? ` L ${_left},${y2 - item.height / 2} L ${_left},${ - y2 + item.height / 2 - }` - : '' - path += nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) - }) - // 竖线 - if (len > 0) { - let lin2 = this.draw.path() - expandBtnSize = len > 0 ? expandBtnSize : 0 - node.style.line(lin2) - if (maxy < y1 + expandBtnSize) { - lin2.hide() - } else { - lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`) - lin2.show() - } - node._lines.push(lin2) - style && style(lin2, node) - } - } - } - - // 渲染按钮 - renderExpandBtn(node, btn) { - let { width, height, expandBtnSize, isRoot } = node - if (!isRoot) { - let { translateX, translateY } = btn.transform() - btn.translate( - width * 0.3 - expandBtnSize / 2 - translateX, - height + expandBtnSize / 2 - translateY - ) - } - } - - // 创建概要节点 - renderGeneralization(node, gLine, gNode) { - let { - top, - bottom, - right, - generalizationLineMargin, - generalizationNodeMargin - } = this.getNodeBoundaries(node, 'h') - let x1 = right + generalizationLineMargin - let y1 = top - let x2 = right + generalizationLineMargin - let y2 = bottom - let cx = x1 + 20 - let cy = y1 + (y2 - y1) / 2 - let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` - gLine.plot(path) - gNode.left = right + generalizationNodeMargin - gNode.top = top + (bottom - top - gNode.height) / 2 - } -} - -export default CatalogOrganization +import Base from './Base' +import { walk, asyncRun } from '../utils' + +// 目录组织图 +class CatalogOrganization extends Base { + // 构造函数 + constructor(opt = {}) { + super(opt) + } + + // 布局 + doLayout(callback) { + let task = [ + () => { + this.computedBaseValue() + }, + () => { + this.computedLeftTopValue() + }, + () => { + this.adjustLeftTopValue() + }, + () => { + callback(this.root) + } + ] + asyncRun(task) + } + + // 遍历数据计算节点的left、width、height + computedBaseValue() { + walk( + this.renderer.renderTree, + null, + (cur, parent, isRoot, layerIndex) => { + let newNode = this.createNode(cur, parent, isRoot, layerIndex) + // 根节点定位在画布中心位置 + if (isRoot) { + this.setNodeCenter(newNode) + } else { + // 非根节点 + if (parent._node.isRoot) { + newNode.top = + parent._node.top + + parent._node.height + + this.getMarginX(layerIndex) + } + } + if (!cur.data.expand) { + return true + } + }, + (cur, parent, isRoot, layerIndex) => { + if (isRoot) { + let len = cur.data.expand === false ? 0 : cur._node.children.length + cur._node.childrenAreaWidth = len + ? cur._node.children.reduce((h, item) => { + return h + item.width + }, 0) + + (len + 1) * this.getMarginX(layerIndex + 1) + : 0 + } + }, + true, + 0 + ) + } + + // 遍历节点树计算节点的left、top + computedLeftTopValue() { + walk( + this.root, + null, + (node, parent, isRoot, layerIndex) => { + if ( + node.nodeData.data.expand && + node.children && + node.children.length + ) { + let marginX = this.getMarginX(layerIndex + 1) + let marginY = this.getMarginY(layerIndex + 1) + if (isRoot) { + let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 + let totalLeft = left + marginX + node.children.forEach(cur => { + cur.left = totalLeft + totalLeft += cur.width + marginX + }) + } else { + let totalTop = node.top + node.height + marginY + node.expandBtnSize + node.children.forEach(cur => { + cur.left = node.left + node.width * 0.5 + cur.top = totalTop + totalTop += cur.height + marginY + node.expandBtnSize + }) + } + } + }, + null, + true + ) + } + + // 调整节点left、top + adjustLeftTopValue() { + walk( + this.root, + null, + (node, parent, isRoot, layerIndex) => { + if (!node.nodeData.data.expand) { + return + } + // 调整left + if (parent && parent.isRoot) { + let areaWidth = this.getNodeAreaWidth(node) + let difference = areaWidth - node.width + if (difference > 0) { + this.updateBrothersLeft(node, difference / 2) + } + } + // 调整top + let len = node.children.length + if (parent && !parent.isRoot && len > 0) { + let marginY = this.getMarginY(layerIndex + 1) + let totalHeight = + node.children.reduce((h, item) => { + return h + item.height + }, 0) + + (len + 1) * marginY + + len * node.expandBtnSize + this.updateBrothersTop(node, totalHeight) + } + }, + null, + true + ) + } + + // 递归计算节点的宽度 + getNodeAreaWidth(node) { + let widthArr = [] + let loop = (node, width) => { + if (node.children.length) { + width += node.width / 2 + node.children.forEach(item => { + loop(item, width) + }) + } else { + width += node.width + widthArr.push(width) + } + } + loop(node, 0) + return Math.max(...widthArr) + } + + // 调整兄弟节点的left + updateBrothersLeft(node, addWidth) { + if (node.parent) { + let childrenList = node.parent.children + let index = childrenList.findIndex(item => { + return item === node + }) + // 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称 + if ( + (index === 0 || index === childrenList.length - 1) && + childrenList.length > 1 + ) { + let _offset = index === 0 ? -addWidth : addWidth + node.left += _offset + if ( + node.children && + node.children.length && + !node.hasCustomPosition() + ) { + this.updateChildren(node.children, 'left', _offset) + } + } + childrenList.forEach((item, _index) => { + if (item.hasCustomPosition()) { + // 适配自定义位置 + return + } + let _offset = 0 + if (_index < index) { + // 左边的节点往左移 + _offset = -addWidth + } else if (_index > index) { + // 右边的节点往右移 + _offset = addWidth + } + item.left += _offset + // 同步更新子节点的位置 + if (item.children && item.children.length) { + this.updateChildren(item.children, 'left', _offset) + } + }) + // 更新父节点的位置 + this.updateBrothersLeft(node.parent, addWidth) + } + } + + // 调整兄弟节点的top + updateBrothersTop(node, addHeight) { + if (node.parent && !node.parent.isRoot) { + let childrenList = node.parent.children + let index = childrenList.findIndex(item => { + return item === node + }) + childrenList.forEach((item, _index) => { + if (item.hasCustomPosition()) { + // 适配自定义位置 + return + } + let _offset = 0 + // 下面的节点往下移 + if (_index > index) { + _offset = addHeight + } + item.top += _offset + // 同步更新子节点的位置 + if (item.children && item.children.length) { + this.updateChildren(item.children, 'top', _offset) + } + }) + // 更新父节点的位置 + this.updateBrothersTop(node.parent, addHeight) + } + } + + // 绘制连线,连接该节点到其子节点 + renderLine(node, lines, style) { + if (node.children.length <= 0) { + return [] + } + let { left, top, width, height, expandBtnSize } = node + let len = node.children.length + let marginX = this.getMarginX(node.layerIndex + 1) + if (node.isRoot) { + // 根节点 + let x1 = left + width / 2 + let y1 = top + height + let s1 = marginX * 0.7 + let minx = Infinity + let maxx = -Infinity + node.children.forEach((item, index) => { + let x2 = item.left + item.width / 2 + let y2 = item.top + if (x2 < minx) { + minx = x2 + } + if (x2 > maxx) { + maxx = x2 + } + // 节点使用横线风格,需要额外渲染横线 + let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle + ? ` L ${item.left},${y2} L ${item.left + item.width},${y2}` + : '' + let path = + `M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` + + nodeUseLineStylePath + // 竖线 + lines[index].plot(path) + style && style(lines[index], item) + }) + minx = Math.min(minx, x1) + maxx = Math.max(maxx, x1) + // 父节点的竖线 + let line1 = this.draw.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() + node.style.line(lin2) + lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`) + node._lines.push(lin2) + style && style(lin2, node) + } + } else { + // 非根节点 + let y1 = top + height + let maxy = -Infinity + let x2 = node.left + node.width * 0.3 + node.children.forEach((item, index) => { + // 为了适配自定义位置,下面做了各种位置的兼容 + let y2 = item.top + item.height / 2 + if (y2 > maxy) { + maxy = y2 + } + // 水平线 + let path = '' + let _left = item.left + let _isLeft = item.left + item.width < x2 + let _isXCenter = false + if (_isLeft) { + // 水平位置在父节点左边 + _left = item.left + item.width + } else if (item.left < x2 && item.left + item.width > x2) { + // 水平位置在父节点之间 + _isXCenter = true + y2 = item.top + maxy = y2 + } + if (y2 > top && y2 < y1) { + // 自定义位置的情况:垂直位置节点在父节点之间 + path = `M ${ + _isLeft ? node.left : node.left + node.width + },${y2} L ${_left},${y2}` + } else if (y2 < y1) { + // 自定义位置的情况:垂直位置节点在父节点上面 + if (_isXCenter) { + y2 = item.top + item.height + _left = x2 + } + path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}` + } else { + if (_isXCenter) { + _left = x2 + } + path = `M ${x2},${y2} L ${_left},${y2}` + } + // 节点使用横线风格,需要额外渲染横线 + let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle + ? ` L ${_left},${y2 - item.height / 2} L ${_left},${ + y2 + item.height / 2 + }` + : '' + path += nodeUseLineStylePath + lines[index].plot(path) + style && style(lines[index], item) + }) + // 竖线 + if (len > 0) { + let lin2 = this.draw.path() + expandBtnSize = len > 0 ? expandBtnSize : 0 + node.style.line(lin2) + if (maxy < y1 + expandBtnSize) { + lin2.hide() + } else { + lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`) + lin2.show() + } + node._lines.push(lin2) + style && style(lin2, node) + } + } + } + + // 渲染按钮 + renderExpandBtn(node, btn) { + let { width, height, expandBtnSize, isRoot } = node + if (!isRoot) { + let { translateX, translateY } = btn.transform() + btn.translate( + width * 0.3 - expandBtnSize / 2 - translateX, + height + expandBtnSize / 2 - translateY + ) + } + } + + // 创建概要节点 + renderGeneralization(node, gLine, gNode) { + let { + top, + bottom, + right, + generalizationLineMargin, + generalizationNodeMargin + } = this.getNodeBoundaries(node, 'h') + let x1 = right + generalizationLineMargin + let y1 = top + let x2 = right + generalizationLineMargin + let y2 = bottom + let cx = x1 + 20 + let cy = y1 + (y2 - y1) / 2 + let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + gLine.plot(path) + gNode.left = right + generalizationNodeMargin + gNode.top = top + (bottom - top - gNode.height) / 2 + } +} + +export default CatalogOrganization diff --git a/simple-mind-map/src/layouts/LogicalStructure.js b/simple-mind-map/src/layouts/LogicalStructure.js index 5b28fa0d..a9ed8ff2 100644 --- a/simple-mind-map/src/layouts/LogicalStructure.js +++ b/simple-mind-map/src/layouts/LogicalStructure.js @@ -2,16 +2,13 @@ import Base from './Base' import { walk, asyncRun } from '../utils' // 逻辑结构图 - class LogicalStructure extends Base { // 构造函数 - constructor(opt = {}) { super(opt) } // 布局 - doLayout(callback) { let task = [ () => { @@ -31,7 +28,6 @@ class LogicalStructure extends Base { } // 遍历数据计算节点的left、width、height - computedBaseValue() { walk( this.renderer.renderTree, @@ -67,7 +63,6 @@ class LogicalStructure extends Base { } // 遍历节点树计算节点的top - computedTopValue() { walk( this.root, @@ -94,7 +89,6 @@ class LogicalStructure extends Base { } // 调整节点top - adjustTopValue() { walk( this.root, @@ -118,7 +112,6 @@ class LogicalStructure extends Base { } // 更新兄弟节点的top - updateBrothers(node, addHeight) { if (node.parent) { let childrenList = node.parent.children @@ -150,7 +143,6 @@ class LogicalStructure extends Base { } // 绘制连线,连接该节点到其子节点 - renderLine(node, lines, style, lineStyle) { if (lineStyle === 'curve') { this.renderLineCurve(node, lines, style) @@ -162,7 +154,6 @@ class LogicalStructure extends Base { } // 直线风格连线 - renderLineStraight(node, lines, style) { if (node.children.length <= 0) { return [] @@ -192,7 +183,6 @@ class LogicalStructure extends Base { } // 直连风格 - renderLineDirect(node, lines, style) { if (node.children.length <= 0) { return [] @@ -218,7 +208,6 @@ class LogicalStructure extends Base { } // 曲线风格连线 - renderLineCurve(node, lines, style) { if (node.children.length <= 0) { return [] @@ -249,7 +238,6 @@ class LogicalStructure extends Base { } // 渲染按钮 - renderExpandBtn(node, btn) { let { width, height } = node let { translateX, translateY } = btn.transform() @@ -264,7 +252,6 @@ class LogicalStructure extends Base { } // 创建概要节点 - renderGeneralization(node, gLine, gNode) { let { top, diff --git a/simple-mind-map/src/layouts/MindMap.js b/simple-mind-map/src/layouts/MindMap.js index 87e6ced3..384c301a 100644 --- a/simple-mind-map/src/layouts/MindMap.js +++ b/simple-mind-map/src/layouts/MindMap.js @@ -2,7 +2,6 @@ import Base from './Base' import { walk, asyncRun } from '../utils' // 思维导图 - class MindMap extends Base { // 构造函数 // 在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可 @@ -11,7 +10,6 @@ class MindMap extends Base { } // 布局 - doLayout(callback) { let task = [ () => { @@ -31,7 +29,6 @@ class MindMap extends Base { } // 遍历数据计算节点的left、width、height - computedBaseValue() { walk( this.renderer.renderTree, @@ -96,7 +93,6 @@ class MindMap extends Base { } // 遍历节点树计算节点的top - computedTopValue() { walk( this.root, @@ -129,7 +125,6 @@ class MindMap extends Base { } // 调整节点top - adjustTopValue() { walk( this.root, @@ -152,7 +147,6 @@ class MindMap extends Base { } // 更新兄弟节点的top - updateBrothers(node, leftAddHeight, rightAddHeight) { if (node.parent) { // 过滤出和自己同方向的节点 @@ -188,7 +182,6 @@ class MindMap extends Base { } // 绘制连线,连接该节点到其子节点 - renderLine(node, lines, style, lineStyle) { if (lineStyle === 'curve') { this.renderLineCurve(node, lines, style) @@ -200,7 +193,6 @@ class MindMap extends Base { } // 直线风格连线 - renderLineStraight(node, lines, style) { if (node.children.length <= 0) { return [] @@ -238,7 +230,6 @@ class MindMap extends Base { } // 直连风格 - renderLineDirect(node, lines, style) { if (node.children.length <= 0) { return [] @@ -273,7 +264,6 @@ class MindMap extends Base { } // 曲线风格连线 - renderLineCurve(node, lines, style) { if (node.children.length <= 0) { return [] @@ -313,7 +303,6 @@ class MindMap extends Base { } // 渲染按钮 - renderExpandBtn(node, btn) { let { width, height, expandBtnSize } = node let { translateX, translateY } = btn.transform() @@ -327,7 +316,6 @@ class MindMap extends Base { } // 创建概要节点 - renderGeneralization(node, gLine, gNode) { let isLeft = node.dir === 'left' let { diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/OrganizationStructure.js index 4c2dc460..36a26a84 100644 --- a/simple-mind-map/src/layouts/OrganizationStructure.js +++ b/simple-mind-map/src/layouts/OrganizationStructure.js @@ -5,13 +5,11 @@ import { walk, asyncRun } from '../utils' // 和逻辑结构图基本一样,只是方向变成向下生长,所以先计算节点的top,后计算节点的left、最后调整节点的left即可 class OrganizationStructure extends Base { // 构造函数 - constructor(opt = {}) { super(opt) } // 布局 - doLayout(callback) { let task = [ () => { @@ -31,7 +29,6 @@ class OrganizationStructure extends Base { } // 遍历数据计算节点的left、width、height - computedBaseValue() { walk( this.renderer.renderTree, @@ -67,7 +64,6 @@ class OrganizationStructure extends Base { } // 遍历节点树计算节点的left - computedLeftValue() { walk( this.root, @@ -94,7 +90,6 @@ class OrganizationStructure extends Base { } // 调整节点left - adjustLeftValue() { walk( this.root, @@ -118,7 +113,6 @@ class OrganizationStructure extends Base { } // 更新兄弟节点的left - updateBrothers(node, addWidth) { if (node.parent) { let childrenList = node.parent.children @@ -150,7 +144,6 @@ class OrganizationStructure extends Base { } // 绘制连线,连接该节点到其子节点 - renderLine(node, lines, style, lineStyle) { if (lineStyle === 'direct') { this.renderLineDirect(node, lines, style) @@ -160,7 +153,6 @@ class OrganizationStructure extends Base { } // 直连风格 - renderLineDirect(node, lines, style) { if (node.children.length <= 0) { return [] @@ -182,7 +174,6 @@ class OrganizationStructure extends Base { } // 直线风格连线 - renderLineStraight(node, lines, style) { if (node.children.length <= 0) { return [] @@ -232,7 +223,6 @@ class OrganizationStructure extends Base { } // 渲染按钮 - renderExpandBtn(node, btn) { let { width, height, expandBtnSize } = node let { translateX, translateY } = btn.transform() @@ -243,7 +233,6 @@ class OrganizationStructure extends Base { } // 创建概要节点 - renderGeneralization(node, gLine, gNode) { let { bottom,