diff --git a/simple-mind-map/example/exampleData.js b/simple-mind-map/example/exampleData.js index 5362a8f8..d1e23677 100644 --- a/simple-mind-map/example/exampleData.js +++ b/simple-mind-map/example/exampleData.js @@ -785,8 +785,8 @@ const data3 = { export default { // ...data1, - // ...data2, - ...data3, + ...data2, + // ...data3, "theme": { "template": "default", "config": { @@ -794,6 +794,7 @@ export default { } }, // "layout": "mindMap", - "layout": "logicalStructure" - // "layout": "catalogOrganization" + // "layout": "logicalStructure" + "layout": "catalogOrganization" + // "layout": "organizationStructure" } \ No newline at end of file diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 95b39f71..5e9d2a55 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -123,7 +123,7 @@ class MindMap { */ handleOpt(opt) { // 检查布局配置 - if (!['logicalStructure'].includes(opt.layout)) { + if (!['logicalStructure', 'mindMap', 'catalogOrganization', 'organizationStructure'].includes(opt.layout)) { opt.layout = 'logicalStructure' } // 检查主题配置 diff --git a/simple-mind-map/src/Node.js b/simple-mind-map/src/Node.js index 4a6950db..ecc3b685 100644 --- a/simple-mind-map/src/Node.js +++ b/simple-mind-map/src/Node.js @@ -85,6 +85,8 @@ class Node { this._expandBtnSize = this.mindMap.opt.expandBtnSize // 初始渲染 this._initRender = true + // 更新的时候的钩子 + this.updateHooks = [] // 初始化 this.createNodeData() this.getSize() @@ -485,7 +487,7 @@ class Node { // 创建组 this.group = new G() this.draw.add(this.group) - this.update(false) + this.update(true) // 节点矩形 this.style.rect(this.group.rect(width, height)) // 图片节点 @@ -595,7 +597,7 @@ class Node { * @Date: 2021-07-04 22:47:01 * @Desc: 更新节点 */ - update(animate = true) { + update(layout = false) { if (!this.group) { return } @@ -603,11 +605,15 @@ class Node { if (this._expandBtn && this.nodeData.children.length <= 0) { this.removeExpandBtn() } else if (!this._expandBtn && this.nodeData.children.length > 0) {// 需要添加展开收缩按钮 - this.renderExpandBtn() } + if (!layout) { + this.updateHooks.forEach((hook) => { + hook(this) + }) + } let t = this.group.transform() - if (animate) { + if (!layout) { this.group.animate(300).translate(this.left - t.translateX, this.top - t.translateY) } else { this.group.translate(this.left - t.translateX, this.top - t.translateY) @@ -637,18 +643,6 @@ class Node { item.render() } })) - // let index = 0 - // let loop = () => { - // if (index >= this.children.length) { - // return - // } - // this.children[index].render() - // setTimeout(() => { - // index++ - // loop() - // }, 0) - // } - // loop() } } @@ -669,18 +663,6 @@ class Node { item.remove() } })) - // let index = 0 - // let loop = () => { - // if (index >= this.children.length) { - // return - // } - // this.children[index].remove() - // setTimeout(() => { - // index++ - // loop() - // }, 0) - // } - // loop() } } @@ -749,6 +731,20 @@ class Node { this._expandBtn.add(fillNode).add(node) } + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-07-12 18:18:13 + * @Desc: 更新展开收缩按钮位置 + */ + updateExpandBtnPos() { + if (!this._expandBtn) { + return + } + console.log('更新') + this.renderer.layout.renderExpandBtn(this, this._expandBtn) + } + /** * @Author: 王林 * @Date: 2021-04-11 19:47:01 diff --git a/simple-mind-map/src/Render.js b/simple-mind-map/src/Render.js index 368fc1d2..1aca04ec 100644 --- a/simple-mind-map/src/Render.js +++ b/simple-mind-map/src/Render.js @@ -2,6 +2,7 @@ import merge from 'deepmerge' import LogicalStructure from './layouts/LogicalStructure' import MindMap from './layouts/MindMap' import CatalogOrganization from './layouts/CatalogOrganization'; +import OrganizationStructure from './layouts/OrganizationStructure' import TextEdit from './TextEdit' // 布局列表 @@ -11,7 +12,9 @@ const layouts = { // 思维导图 mindMap: MindMap, // 目录组织图 - catalogOrganization: CatalogOrganization + catalogOrganization: CatalogOrganization, + // 组织结构图 + organizationStructure: OrganizationStructure } /** diff --git a/simple-mind-map/src/layouts/CatalogOrganization.js b/simple-mind-map/src/layouts/CatalogOrganization.js index f56a4faf..fc5511f1 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -1,14 +1,13 @@ import Base from './Base'; import { - walk + walk, + asyncRun } from '../utils' -import Node from '../Node' /** * @Author: 王林 * @Date: 2021-04-12 22:25:58 * @Desc: 目录组织图 - * 思路:第一轮只计算节点的宽高,以及某个节点的所有子节点所占的高度之和,以及该节点里所有子节点中宽度最宽是多少、第二轮计算节点的left和top,需要区分二级节点和其他节点,二级节点top相同,一行依次从做向右排开,其他节点的left相同,一列从上往下依次排开 */ class CatalogOrganization extends Base { /** @@ -26,61 +25,46 @@ class CatalogOrganization extends Base { * @Date: 2021-04-06 14:04:20 * @Desc: 布局 */ - doLayout() { - // 遍历数据计算节点的width、height - this.computedBaseValue() - // 计算节点的left、top - this.computedLeftTopValue() - // 调整节点top - this.adjustTopValue() - // 调整节点left - // this.adjustLeftValue() - - return this.root; + doLayout(callback) { + let task = [() => { + this.computedBaseValue() + }, () => { + this.computedLeftValue() + }, () => { + // this.adjustTopValue() + }, () => { + callback(this.root) + }] + asyncRun(task) } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-08 09:49:32 - * @Desc: 遍历数据计算节点的width、height + * @Desc: 遍历数据计算节点的left、width、height */ computedBaseValue() { - walk(this.renderTree, null, (cur, parent, isRoot, layerIndex) => { - // 创建节点 - let newNode = new Node({ - data: cur, - uid: this.mindMap.uid++, - renderer: this.renderer, - mindMap: this.mindMap, - draw: this.draw, - layerIndex - }) - // 数据关联实际节点 - cur._node = newNode + walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex) => { + let newNode = this.createNode(cur, parent, isRoot, layerIndex) // 根节点定位在画布中心位置 if (isRoot) { - newNode.isRoot = true newNode.left = (this.mindMap.width - newNode.width) / 2 newNode.top = (this.mindMap.height - newNode.height) / 2 - this.root = newNode } else { - // 互相收集 - newNode.parent = parent._node - parent._node.addChildren(newNode) + // 非根节点 + // 定位到父节点下方 + newNode.top = parent._node.top + parent._node.height + this.getMarginX(layerIndex) + } + if (!cur.data.expand) { + return true; } }, (cur, parent, isRoot, layerIndex) => { - // 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距 - let len = cur._node.children.length - if (isRoot) {// 计算二级节点所占的宽度之和 - cur._node.childrenAreaWidth = len ? cur._node.children.reduce((h, item) => { - return h + item.width - }, 0) + (len + 1) * this.getMarginX(layerIndex) : 0 - } - // 计算子节点所占的高度之和 - cur._node.childrenAreaHeight = len ? cur._node.children.reduce((h, item) => { - return h + item.height - }, 0) + (len + 1) * this.getMarginY(layerIndex) : 0 + // 返回时计算节点的areaWidth和areaHeight,也就是子节点所占的高度之和,包括外边距 + 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.getMarginY(layerIndex + 1) : 0 }, true, 0) } @@ -88,31 +72,19 @@ class CatalogOrganization extends Base { * javascript comment * @Author: 王林25 * @Date: 2021-04-08 09:59:25 - * @Desc: 计算节点的left、top + * @Desc: 遍历节点树计算节点的left */ - computedLeftTopValue() { + computedLeftValue() { walk(this.root, null, (node, parent, isRoot, layerIndex) => { - let marginX = this.getMarginX(layerIndex) - let marginY = this.getMarginY(layerIndex) - if (node.children && node.children.length) { - if (node.isRoot) { - let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 - let totalLeft = left + marginX - node.children.forEach((cur) => { - // left - cur.left = totalLeft - totalLeft += cur.width + marginX - // top - cur.top = node.top + node.height + marginY - }) - } else { - let totalTop = node.top + node.height + marginY - node.children.forEach((cur) => { - cur.left = node.left + node.width / 5 - cur.top = totalTop - totalTop += cur.height + marginY - }) - } + if (node.nodeData.data.expand && node.children && node.children.length) { + let marginX = this.getMarginY(layerIndex + 1) + // 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半 + 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 + }) } }, null, true) } @@ -121,17 +93,17 @@ class CatalogOrganization extends Base { * javascript comment * @Author: 王林25 * @Date: 2021-04-08 10:04:05 - * @Desc: 调整节点top,该节点之后的节点都往下进行偏移 + * @Desc: 调整节点top */ adjustTopValue() { walk(this.root, null, (node, parent, isRoot, layerIndex) => { - let marginY = this.getMarginY(layerIndex) - if (!node.isRoot && !node.parent.isRoot) { - // 判断子节点的areaHeight是否大于该节点自身,大于则需要调整位置 - if (node.children && node.children.length > 0) { - let difference = node.childrenAreaHeight - marginY - this.updateBrothersTopValue(node, difference) - } + if (!node.nodeData.data.expand) { + return; + } + // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 + let difference = node.childrenAreaHeight - this.getMarginY(layerIndex + 1) * 2 - node.height + if (difference > 0) { + this.updateBrothers(node, difference / 2) } }, null, true) } @@ -142,77 +114,7 @@ class CatalogOrganization extends Base { * @Date: 2021-04-07 14:26:03 * @Desc: 更新兄弟节点的top */ - updateBrothersTopValue(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) => { - let _offset = 0 - if (_index > index) { - _offset = addHeight - } - item.top += _offset - // 同步更新子节点的位置 - if (item.children && item.children.length && _offset > 0) { - this.updateChildren(item.children, 'top', _offset) - } - }) - // 更新父节点的位置 - this.updateBrothersTopValue(node.parent, addHeight) - } - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-12 17:07:29 - * @Desc: 调整节点left - */ - adjustLeftValue() { - walk(this.root, null, (node, parent, isRoot, layerIndex) => { - let marginX = this.getMarginY(layerIndex) - if (node.parent && node.parent.isRoot) { - let childrenAreaWidth = this.getNodeWidth(node) - let difference = childrenAreaWidth - node.width - marginX - if (difference > 0) { - this.updateBrothersLeftValue(node, difference / 2) - } - } - }, null, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-12 18:55:03 - * @Desc: 计算节点的宽度,包括子节点 - */ - getNodeWidth(node) { - let widthArr = [] - let loop = (node, width) => { - if (node.children.length) { - width += node.width / 5 - node.children.forEach((item) => { - loop(item, width) - }) - } else { - width += node.width - widthArr.push(width) - } - } - loop(node, 0) - return Math.max(...widthArr) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-12 18:21:46 - * @Desc: 调整兄弟节点的left - */ - updateBrothersLeftValue(node, addWidth) { + updateBrothers(node, addHeight) { if (node.parent) { let childrenList = node.parent.children let index = childrenList.findIndex((item) => { @@ -220,19 +122,20 @@ class CatalogOrganization extends Base { }) childrenList.forEach((item, _index) => { let _offset = 0 - if (_index > index) { - _offset = addWidth - } else { - _offset = -addWidth + // 上面的节点往上移 + if (_index < index) { + _offset = -addHeight + } else if (_index > index) { // 下面的节点往下移 + _offset = addHeight } - item.left += _offset + item.top += _offset // 同步更新子节点的位置 if (item.children && item.children.length) { - this.updateChildren(item.children, 'left', _offset) + this.updateChildren(item.children, 'top', _offset) } }) // 更新父节点的位置 - this.updateBrothersLeftValue(node.parent, addWidth) + this.updateBrothers(node.parent, addHeight) } } @@ -241,8 +144,8 @@ class CatalogOrganization extends Base { * @Date: 2021-04-11 14:42:48 * @Desc: 绘制连线,连接该节点到其子节点 */ - renderLine(node) { - return []; + renderLine(node, lines) { + return if (node.children.length <= 0) { return []; } @@ -252,12 +155,7 @@ class CatalogOrganization extends Base { width, height } = node - let lines = [] - if (!node.isRoot) { - let line = this.draw.line(left + width, top + height / 2, left + width + 20, top + height / 2) - lines.push(line) - } - node.children.forEach((item) => { + node.children.forEach((item, index) => { let x1 = node.layerIndex === 0 ? left + width / 2 : left + width + 20 let y1 = node.layerIndex === 0 ? top + height / 2 : top + height / 2 let x2 = item.left @@ -268,10 +166,8 @@ class CatalogOrganization extends Base { } else { path = this.cubicBezierPath(x1, y1, x2, y2) } - let line = this.draw.path(path) - lines.push(line) + lines[index].plot(path) }) - return lines; } /** @@ -279,17 +175,13 @@ class CatalogOrganization extends Base { * @Date: 2021-04-11 19:54:26 * @Desc: 渲染按钮 */ - renderExpandBtn(node, icons) { - return; + renderExpandBtn(node, btn) { + return let { - left, - top, width, height } = node - icons.forEach((icon) => { - icon.x(left + width).y(top + height / 2) - }) + btn.translate(width, height / 2) } } diff --git a/simple-mind-map/src/layouts/LogicalStructure.js b/simple-mind-map/src/layouts/LogicalStructure.js index 682b87c5..45932e20 100644 --- a/simple-mind-map/src/layouts/LogicalStructure.js +++ b/simple-mind-map/src/layouts/LogicalStructure.js @@ -101,7 +101,7 @@ class LogicalStructure extends Base { return; } // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 - let difference = node.childrenAreaHeight - this.getMarginY(layerIndex + 1) - node.height + let difference = node.childrenAreaHeight - this.getMarginY(layerIndex + 1) * 2 - node.height if (difference > 0) { this.updateBrothers(node, difference / 2) } diff --git a/simple-mind-map/src/layouts/MindMap.js b/simple-mind-map/src/layouts/MindMap.js index c471f9a2..068be7d6 100644 --- a/simple-mind-map/src/layouts/MindMap.js +++ b/simple-mind-map/src/layouts/MindMap.js @@ -1,14 +1,14 @@ import Base from './Base'; import { - walk + walk, + asyncRun } from '../utils' -import Node from '../Node' /** * @Author: 王林 * @Date: 2021-04-12 22:25:58 * @Desc: 思维导图 - * 思路:在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可 + * 在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可 */ class MindMap extends Base { /** @@ -26,14 +26,17 @@ class MindMap extends Base { * @Date: 2021-04-06 14:04:20 * @Desc: 布局 */ - doLayout() { - // 遍历数据计算节点的left、width、height - this.computedBaseValue() - // 计算节点的top - this.computedTopValue() - // 调整节点top - this.adjustTopValue() - return this.root; + doLayout(callback) { + let task = [() => { + this.computedBaseValue() + }, () => { + this.computedTopValue() + }, () => { + this.adjustTopValue() + }, () => { + callback(this.root) + }] + asyncRun(task) } /** @@ -43,65 +46,55 @@ class MindMap extends Base { * @Desc: 遍历数据计算节点的left、width、height */ computedBaseValue() { - walk(this.renderTree, null, (cur, parent, isRoot, layerIndex, index) => { - // 节点生长方向 - let dir = '' - if (isRoot) { - dir = '' - } else if (parent._node.isRoot) {// 二级节点根据索引来判断显示在左侧还是右侧 - dir = index % 2 === 0 ? 'right' : 'left' - } else {// 三级及以下节点以上级为准 - dir = parent._node.dir + walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex, index) => { + let newNode = this.createNode(cur, parent, isRoot, layerIndex) + // 更新时展开收缩按钮位置可能会变化,需要更新 + if (newNode.updateHooks.length <= 0) { + newNode.updateHooks.push((node) => { + node.updateExpandBtnPos() + }) } - // 创建节点 - let newNode = new Node({ - data: cur, - uid: this.mindMap.uid++, - renderer: this.renderer, - mindMap: this.mindMap, - draw: this.draw, - layerIndex - }) - newNode.dir = dir - // 数据关联实际节点 - cur._node = newNode // 根节点定位在画布中心位置 if (isRoot) { - newNode.isRoot = true newNode.left = (this.mindMap.width - newNode.width) / 2 newNode.top = (this.mindMap.height - newNode.height) / 2 - this.root = newNode } else { // 非根节点 - let marginX = layerIndex === 1 ? this.themeConfig.second.marginX : this.themeConfig.node.marginX - // 根据生长方向定位到父节点的左侧还是右侧 - newNode.left = dir === 'right' ? parent._node.left + parent._node.width + marginX : parent._node.left - newNode.width - marginX - // 互相收集 - newNode.parent = parent._node - parent._node.addChildren(newNode) + // 三级及以下节点以上级为准 + if (parent._node.dir) { + newNode.dir = parent._node.dir + } else { // 节点生长方向 + newNode.dir = index % 2 === 0 ? 'right' : 'left' + } + // 根据生长方向定位到父节点的左侧或右侧 + newNode.left = newNode.dir === 'right' ? parent._node.left + parent._node.width + this.getMarginX(layerIndex) : parent._node.left - this.getMarginX(layerIndex) - newNode.width + } + if (!cur.data.expand) { + return true; } }, (cur, parent, isRoot, layerIndex) => { - // 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距 - if (cur.data.expand === false) { + // 返回时计算节点的leftChildrenAreaHeight和rightChildrenAreaHeight,也就是左侧和右侧子节点所占的高度之和,包括外边距 + if (!cur.data.expand) { cur._node.leftChildrenAreaHeight = 0 cur._node.rightChildrenAreaHeight = 0 - return ; + return } + // 理论上只有根节点是存在两个方向的子节点的,其他节点的子节点一定全都是同方向,但是为了逻辑统一,就不按特殊处理的方式来写了 let leftLen = 0 let rightLen = 0 - let leftAreaHeight = 0 - let rightAreaHeight = 0 + let leftChildrenAreaHeight = 0 + let rightChildrenAreaHeight = 0 cur._node.children.forEach((item) => { if (item.dir === 'left') { leftLen++ - leftAreaHeight += item.height + leftChildrenAreaHeight += item.height } else { rightLen++ - rightAreaHeight += item.height + rightChildrenAreaHeight += item.height } }) - cur._node.leftChildrenAreaHeight = leftAreaHeight + (leftLen + 1) * this.getMarginY(layerIndex) - cur._node.rightChildrenAreaHeight = rightAreaHeight + (rightLen + 1) * this.getMarginY(layerIndex) + cur._node.leftChildrenAreaHeight = leftChildrenAreaHeight + (leftLen + 1) * this.getMarginY(layerIndex + 1) + cur._node.rightChildrenAreaHeight = rightChildrenAreaHeight + (rightLen + 1) * this.getMarginY(layerIndex + 1) }, true, 0) } @@ -113,11 +106,12 @@ class MindMap extends Base { */ computedTopValue() { walk(this.root, null, (node, parent, isRoot, layerIndex) => { - if (node.children && node.children.length) { - let marginY = this.getMarginY(layerIndex) - let top = node.top + node.height / 2 - let leftTotalTop = top - node.leftChildrenAreaHeight / 2 + marginY - let rightTotalTop = top - node.rightChildrenAreaHeight / 2 + marginY + if (node.nodeData.data.expand && node.children && node.children.length) { + let marginY = this.getMarginY(layerIndex + 1) + let baseTop = node.top + node.height / 2 + marginY + // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 + let leftTotalTop = baseTop - node.leftChildrenAreaHeight / 2 + let rightTotalTop = baseTop - node.rightChildrenAreaHeight / 2 node.children.forEach((cur) => { if (cur.dir === 'left') { cur.top = leftTotalTop @@ -139,10 +133,13 @@ class MindMap extends Base { */ adjustTopValue() { walk(this.root, null, (node, parent, isRoot, layerIndex) => { + if (!node.nodeData.data.expand) { + return; + } // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 - let h = this.getMarginY(layerIndex) + node.height - let leftDifference = node.leftChildrenAreaHeight - h - let rightDifference = node.rightChildrenAreaHeight - h + let base = this.getMarginY(layerIndex + 1) * 2 + node.height + let leftDifference = node.leftChildrenAreaHeight - base + let rightDifference = node.rightChildrenAreaHeight - base if (leftDifference > 0 || rightDifference > 0) { this.updateBrothers(node, leftDifference / 2, rightDifference / 2) } @@ -157,6 +154,7 @@ class MindMap extends Base { */ updateBrothers(node, leftAddHeight, rightAddHeight) { if (node.parent) { + // 过滤出和自己同方向的节点 let childrenList = node.parent.children.filter((item) => { return item.dir === node.dir }) @@ -169,7 +167,7 @@ class MindMap extends Base { // 上面的节点往上移 if (_index < index) { _offset = -addHeight - } else if (_index > index) {// 下面的节点往下移 + } else if (_index > index) { // 下面的节点往下移 _offset = addHeight } item.top += _offset @@ -188,7 +186,7 @@ class MindMap extends Base { * @Date: 2021-04-11 14:42:48 * @Desc: 绘制连线,连接该节点到其子节点 */ - renderLine(node) { + renderLine(node, lines) { if (node.children.length <= 0) { return []; } @@ -199,15 +197,10 @@ class MindMap extends Base { height, _expandBtnSize } = node - let lines = [] - // if (!node.isRoot) { - // let line = this.draw.line(left + width, top + height / 2, left + width + 20, top + height / 2) - // lines.push(line) - // } - node.children.forEach((item) => { - let x1 = node.layerIndex === 0 ? left + width / 2 : item.dir === 'right' ? left + width + _expandBtnSize : left - _expandBtnSize + node.children.forEach((item, index) => { + let x1 = node.layerIndex === 0 ? left + width / 2 : item.dir === 'left' ? left - _expandBtnSize : left + width + 20 let y1 = node.layerIndex === 0 ? top + height / 2 : top + height / 2 - let x2 = item.dir === 'right' ? item.left : item.left + item.width + let x2 = item.dir === 'left' ? item.left + item.width : item.left let y2 = item.top + item.height / 2 let path = '' if (node.isRoot) { @@ -215,10 +208,8 @@ class MindMap extends Base { } else { path = this.cubicBezierPath(x1, y1, x2, y2) } - let line = this.draw.path(path) - lines.push(line) + lines[index].plot(path) }) - return lines; } /** @@ -226,17 +217,19 @@ class MindMap extends Base { * @Date: 2021-04-11 19:54:26 * @Desc: 渲染按钮 */ - renderExpandBtn(node, icons) { + renderExpandBtn(node, btn) { let { - left, - top, width, height, _expandBtnSize } = node - icons.forEach((icon) => { - node.dir === 'right' ? icon.x(left + width).y(top + height / 2) : icon.x(left - _expandBtnSize).y(top + height / 2) - }) + let { + translateX, + translateY + } = btn.transform() + let x = (node.dir === 'left' ? 0 - _expandBtnSize : width) - translateX + let y = height / 2 - translateY + btn.translate(x, y) } } diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/OrganizationStructure.js new file mode 100644 index 00000000..8f32c8be --- /dev/null +++ b/simple-mind-map/src/layouts/OrganizationStructure.js @@ -0,0 +1,208 @@ +import Base from './Base'; +import { + walk, + asyncRun +} from '../utils' + +/** + * @Author: 王林 + * @Date: 2021-04-12 22:25:58 + * @Desc: 组织结构图 + * 和逻辑结构图基本一样,只是方向变成向下生长,所以先计算节点的top,后计算节点的left、最后调整节点的left即可 + */ +class OrganizationStructure extends Base { + /** + * @Author: 王林 + * @Date: 2021-04-12 22:26:31 + * @Desc: 构造函数 + */ + constructor(opt = {}) { + super(opt) + } + + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-06 14:04:20 + * @Desc: 布局 + */ + doLayout(callback) { + let task = [() => { + this.computedBaseValue() + }, () => { + this.computedLeftValue() + }, () => { + this.adjustLeftValue() + }, () => { + callback(this.root) + }] + asyncRun(task) + } + + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-08 09:49:32 + * @Desc: 遍历数据计算节点的left、width、height + */ + computedBaseValue() { + walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex) => { + let newNode = this.createNode(cur, parent, isRoot, layerIndex) + // 根节点定位在画布中心位置 + if (isRoot) { + newNode.left = (this.mindMap.width - newNode.width) / 2 + newNode.top = (this.mindMap.height - newNode.height) / 2 + } else { + // 非根节点 + // 定位到父节点下方 + newNode.top = parent._node.top + parent._node.height + this.getMarginX(layerIndex) + } + if (!cur.data.expand) { + return true; + } + }, (cur, parent, isRoot, layerIndex) => { + // 返回时计算节点的areaWidth,也就是子节点所占的宽度之和,包括外边距 + 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.getMarginY(layerIndex + 1) : 0 + }, true, 0) + } + + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-08 09:59:25 + * @Desc: 遍历节点树计算节点的left + */ + computedLeftValue() { + walk(this.root, null, (node, parent, isRoot, layerIndex) => { + if (node.nodeData.data.expand && node.children && node.children.length) { + let marginX = this.getMarginY(layerIndex + 1) + // 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半 + 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 + }) + } + }, null, true) + } + + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-08 10:04:05 + * @Desc: 调整节点left + */ + adjustLeftValue() { + walk(this.root, null, (node, parent, isRoot, layerIndex) => { + if (!node.nodeData.data.expand) { + return; + } + // 判断子节点所占的宽度之和是否大于该节点自身,大于则需要调整位置 + let difference = node.childrenAreaWidth - this.getMarginY(layerIndex + 1) * 2 - node.width + if (difference > 0) { + this.updateBrothers(node, difference / 2) + } + }, null, true) + } + + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-07 14:26:03 + * @Desc: 更新兄弟节点的left + */ + updateBrothers(node, addWidth) { + if (node.parent) { + let childrenList = node.parent.children + let index = childrenList.findIndex((item) => { + return item === node + }) + childrenList.forEach((item, _index) => { + 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.updateBrothers(node.parent, addWidth) + } + } + + /** + * @Author: 王林 + * @Date: 2021-04-11 14:42:48 + * @Desc: 绘制连线,连接该节点到其子节点 + */ + renderLine(node, lines) { + if (node.children.length <= 0) { + return []; + } + let { + left, + top, + width, + height, + _expandBtnSize, + isRoot + } = node + let x1 = left + width / 2 + let y1 = top + height + let marginX = this.getMarginX(node.layerIndex + 1) + let s1 = marginX * 0.7 + let minx = 0 + let maxx = 0 + let len = node.children.length + node.children.forEach((item, index) => { + let x2 = item.left +item.width / 2 + let y2 = item.top + if (index === 0) { + minx = x2 + } else if (index >= len - 1) { + maxx = x2 + } + let path = `M ${x2},${y1 + s1} L ${x2},${y2}` + lines[index].plot(path) + }) + // 父节点的竖线 + let line1 = this.draw.path() + node.style.line(line1) + _expandBtnSize = len > 0 && !isRoot ? _expandBtnSize : 0 + line1.plot(`M ${x1},${y1 + _expandBtnSize} L ${x1},${y1 + s1}`) + node._lines.push(line1) + // 水平线 + if (len > 1) { + let lin2 = this.draw.path() + node.style.line(lin2) + lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`) + node._lines.push(lin2) + } + } + + /** + * @Author: 王林 + * @Date: 2021-04-11 19:54:26 + * @Desc: 渲染按钮 + */ + renderExpandBtn(node, btn) { + let { + width, + height, + _expandBtnSize + } = node + btn.translate(width / 2 - _expandBtnSize / 2, height + _expandBtnSize / 2) + } +} + +export default OrganizationStructure \ No newline at end of file diff --git a/simple-mind-map/src/layouts/_OrganizationStructure.js b/simple-mind-map/src/layouts/_OrganizationStructure.js deleted file mode 100644 index 123b2c68..00000000 --- a/simple-mind-map/src/layouts/_OrganizationStructure.js +++ /dev/null @@ -1,183 +0,0 @@ -import { - walk -} from '../Utils' -import Node from '../Node' -import merge from 'deepmerge' - -/** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:07 - * @Desc: 组织结构图 - * 思路:和逻辑结构图基本一样,只是方向变成向下生长,所以先计算节点的top,后计算节点的left、最后调整节点的left即可 - */ -class Render { - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:32 - * @Desc: 构造函数 - */ - constructor(opt = {}) { - this.opt = opt - this.mindMap = opt.mindMap - this.draw = this.mindMap.draw - // 渲染树 - this.renderTree = merge({}, this.mindMap.opt.data || {}) - // 根节点 - this.root = null - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:27:55 - * @Desc: 渲染 - */ - render() { - this.computed() - this.root.render() - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-06 14:04:20 - * @Desc: 计算位置数据 - */ - computed() { - // 计算节点的top、width、height - this.computedBaseValue() - // 计算节点的left - this.computedLeftValue() - // 调整节点left - this.adjustLeftValue() - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 09:49:32 - * @Desc: 计算节点的top、width、height - */ - computedBaseValue() { - walk(this.renderTree, null, (node, parent, isRoot, index) => { - // 设置top、width、height - let { - children, - ...props - } = node - let newNode = new Node({ - ...props, - mindMap: this.mindMap, - draw: this.draw - }) - // 计算节点的宽高 - newNode.getSize() - // 计算节点的top - if (isRoot) { - newNode.isRoot = true - newNode.left = (this.mindMap.width - newNode.width) / 2 - newNode.top = (this.mindMap.height - newNode.height) / 2 - this.root = newNode - } else { - newNode.top = parent._node.top + parent._node.height + this.mindMap.opt.marginY - newNode.parent = parent._node - parent._node.addChildren(newNode) - } - node._node = newNode - }, (node) => { - // 返回时计算节点的areaWidth,也就是子节点所占的宽度之和,包括外边距 - let len = node._node.children.length - node._node.childrenAreaWidth = len ? node._node.children.reduce((h, cur) => { - return h + cur.width - }, 0) + (len + 1) * this.mindMap.opt.marginX : 0 - }, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 09:59:25 - * @Desc: 计算节点的left - */ - computedLeftValue() { - walk(this.root, null, (node) => { - if (node.children && node.children.length) { - // 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半 - let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 - let totalLeft = left + this.mindMap.opt.marginX - node.children.forEach((cur) => { - cur.left = totalLeft - totalLeft += cur.width + this.mindMap.opt.marginX - }) - } - }, null, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 10:04:05 - * @Desc: 调整节点left - */ - adjustLeftValue() { - let margin = this.mindMap.opt.marginX * 2 - walk(this.root, null, (node) => { - // 判断子节点所占的宽度之和是否大于该节点自身,大于则需要调整位置 - let difference = node.childrenAreaWidth - margin - node.width - if (difference > 0) { - this.updateBrothers(node, difference / 2) - } - }, null, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-07 14:26:03 - * @Desc: 更新兄弟节点的left - */ - updateBrothers(node, addWidth) { - if (node.parent) { - let childrenList = node.parent.children - let index = childrenList.findIndex((item) => { - return item === node - }) - childrenList.forEach((item, _index) => { - 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.updateBrothers(node.parent, addWidth) - } - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-07 11:25:52 - * @Desc: 更新子节点属性 - */ - updateChildren(children, prop, offset) { - children.forEach((item) => { - item[prop] += offset - if (item.children && item.children.length) { - this.updateChildren(item.children, prop, offset) - } - }) - } - - -} - -export default Render \ No newline at end of file diff --git a/web/src/pages/Edit/components/Toolbar.vue b/web/src/pages/Edit/components/Toolbar.vue index 5261f9e0..2fda80dd 100644 --- a/web/src/pages/Edit/components/Toolbar.vue +++ b/web/src/pages/Edit/components/Toolbar.vue @@ -186,7 +186,6 @@ export default { this.activeNodes = args[1]; }); this.$bus.$on("back_forward", (index, len) => { - console.log(index, len) this.backEnd = index <= 0 this.forwardEnd = index >= len - 1 });