From 2d8643015ff795db7d0a7bfd073ba826ed03b275 Mon Sep 17 00:00:00 2001 From: wanglin <1013335014@qq.com> Date: Sun, 31 Jul 2022 10:28:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A6=82=E8=A6=81=E5=BC=80=E5=8F=91=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/example/exampleData.js | 67 ++++++++++++++- simple-mind-map/src/Drag.js | 2 +- simple-mind-map/src/Node.js | 80 +++++++++++++++++- simple-mind-map/src/Render.js | 57 ++++++++++++- simple-mind-map/src/Style.js | 11 +++ simple-mind-map/src/layouts/Base.js | 42 +++++++++ .../src/layouts/CatalogOrganization.js | 20 +++++ .../src/layouts/LogicalStructure.js | 20 +++++ simple-mind-map/src/layouts/MindMap.js | 23 +++++ .../src/layouts/OrganizationStructure.js | 20 +++++ simple-mind-map/src/themes/default.js | 26 ++++++ simple-mind-map/src/themes/minions.js | 13 +++ simple-mind-map/src/utils/index.js | 2 +- web/src/.DS_Store | Bin 6148 -> 6148 bytes web/src/assets/.DS_Store | Bin 6148 -> 6148 bytes web/src/assets/icon-font/demo_index.html | 29 ++++++- web/src/assets/icon-font/iconfont.css | 10 ++- web/src/assets/icon-font/iconfont.js | 2 +- web/src/assets/icon-font/iconfont.json | 7 ++ web/src/assets/icon-font/iconfont.ttf | Bin 10732 -> 11004 bytes web/src/assets/icon-font/iconfont.woff | Bin 6640 -> 6732 bytes web/src/assets/icon-font/iconfont.woff2 | Bin 5620 -> 5680 bytes web/src/pages/Edit/components/BaseStyle.vue | 48 +++++++++++ web/src/pages/Edit/components/NodeIcon.vue | 1 - web/src/pages/Edit/components/Toolbar.vue | 19 ++++- 25 files changed, 483 insertions(+), 16 deletions(-) diff --git a/simple-mind-map/example/exampleData.js b/simple-mind-map/example/exampleData.js index f0fab061..7c7fd82e 100644 --- a/simple-mind-map/example/exampleData.js +++ b/simple-mind-map/example/exampleData.js @@ -864,6 +864,70 @@ const data4 = { } } +// 带概要 +const data5 = { + "root": { + "data": { + "text": "根节点" + }, + "children": [ + { + "data": { + "text": "二级节点", + "generalization": { + "text": "概要", + } + }, + "children": [ + { + "data": { + "text": "子节点" + }, + "children": [] + }, + { + "data": { + "text": "子节点" + }, + "children": [] + }, + { + "data": { + "text": "子节点" + }, + "children": [] + }, + { + "data": { + "text": "子节点" + }, + "children": [] + } + ] + }, + { + "data": { + "text": "二级节点2" + }, + "children": [ + { + "data": { + "text": "子节点" + }, + "children": [] + }, + { + "data": { + "text": "子节点" + }, + "children": [] + } + ] + } + ] + } +} + const rootData = { "root": { "data": { @@ -876,8 +940,9 @@ const rootData = { export default { // ...data1, // ...data2, - ...data3, + // ...data3, // ...data4, + ...data5, // ...rootData, "theme": { "template": "minions", diff --git a/simple-mind-map/src/Drag.js b/simple-mind-map/src/Drag.js index 70ee60dd..85561405 100644 --- a/simple-mind-map/src/Drag.js +++ b/simple-mind-map/src/Drag.js @@ -71,7 +71,7 @@ class Drag extends Base { bindEvent() { this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this) this.mindMap.on('node_mousedown', (node, e) => { - if (this.mindMap.opt.readonly) { + if (this.mindMap.opt.readonly || node.isGeneralization) { return } if (e.which !== 1 || node.isRoot) { diff --git a/simple-mind-map/src/Node.js b/simple-mind-map/src/Node.js index 22c9da04..4c39ed58 100644 --- a/simple-mind-map/src/Node.js +++ b/simple-mind-map/src/Node.js @@ -45,6 +45,9 @@ class Node { this.style = new Style(this, this.themeConfig) // 是否是根节点 this.isRoot = opt.isRoot === undefined ? false : opt.isRoot + // 是否是概要节点 + this.isGeneralization = opt.isGeneralization === undefined ? false : opt.isGeneralization + this.generalizationBelongNode = null // 节点层级 this.layerIndex = opt.layerIndex === undefined ? 0 : opt.layerIndex // 节点宽 @@ -73,6 +76,8 @@ class Node { this.noteEl = null this._expandBtn = null this._lines = [] + this._generalizationLine = null + this._generalizationNode = null // 尺寸信息 this._rectInfo = { imgContentWidth: 0, @@ -153,6 +158,7 @@ class Node { this._hyperlinkData = this.createHyperlinkNode() this._tagData = this.createTagNode() this._noteData = this.createNoteNode() + this.createGeneralizationNode() } /** @@ -584,7 +590,7 @@ class Node { }) // 右键菜单事件 this.group.on('contextmenu', (e) => { - if (this.mindMap.opt.readonly) { + if (this.mindMap.opt.readonly || this.isGeneralization) { return } e.stopPropagation() @@ -646,6 +652,7 @@ class Node { } else { this.updateExpandBtnPos() } + this.renderGeneralization() let t = this.group.transform() if (!layout) { this.group.animate(300).translate(this.left - t.translateX, this.top - t.translateY) @@ -690,6 +697,7 @@ class Node { this.removeAllEvent() this.removeAllNode() this.removeLine() + this.removeGeneralization() // 子节点 if (this.children && this.children.length) { asyncRun(this.children.map((item) => { @@ -728,7 +736,10 @@ class Node { * @Date: 2021-11-23 18:39:14 * @Desc: 显示节点 */ - show() { + show() { + if (!this.group) { + return; + } this.group.show() if (this.parent) { let index = this.parent.children.indexOf(this) @@ -786,6 +797,71 @@ class Node { this._lines = [] } + /** + * @Author: 王林 + * @Date: 2022-07-31 09:41:28 + * @Desc: 创建概要节点 + */ + createGeneralizationNode() { + if (this.isGeneralization || !this.nodeData.data.generalization) { + return + } + if (!this._generalizationLine) { + this._generalizationLine = this.draw.path() + } + if (!this._generalizationNode) { + this._generalizationNode = new Node({ + data: { + data: this.nodeData.data.generalization + }, + uid: this.mindMap.uid++, + renderer: this.renderer, + mindMap: this.mindMap, + draw: this.draw, + isGeneralization: true + }) + this._generalizationNode.generalizationBelongNode = this + if (this.nodeData.data.generalization.isActive) { + this.renderer.addActiveNode(this._generalizationNode) + } + } + } + + /** + * @Author: 王林 + * @Date: 2022-07-30 08:35:51 + * @Desc: 创建概要节点 + */ + renderGeneralization() { + if (this.isGeneralization) { + return + } + if (this.nodeData.data.expand === false || !this.nodeData.data.generalization) { + this.removeGeneralization() + return + } + this.createGeneralizationNode() + this.renderer.layout.renderGeneralization(this, this._generalizationLine, this._generalizationNode) + this.style.generalizationLine(this._generalizationLine) + this._generalizationNode.render() + } + + /** + * @Author: 王林 + * @Date: 2022-07-30 13:11:27 + * @Desc: 删除概要节点 + */ + removeGeneralization() { + if (this._generalizationLine) { + this._generalizationLine.remove() + this._generalizationLine = null + } + if (this._generalizationNode) { + this._generalizationNode.remove() + this._generalizationNode = null + } + } + /** * @Author: 王林 * @Date: 2021-07-10 17:59:14 diff --git a/simple-mind-map/src/Render.js b/simple-mind-map/src/Render.js index 4dc67703..ad92f279 100644 --- a/simple-mind-map/src/Render.js +++ b/simple-mind-map/src/Render.js @@ -163,6 +163,12 @@ class Render { // 设置节点标签 this.setNodeTag = this.setNodeTag.bind(this) this.mindMap.command.add('SET_NODE_TAG', this.setNodeTag) + // 添加节点概要 + this.addGeneralization = this.addGeneralization.bind(this) + this.mindMap.command.add('ADD_GENERALIZATION', this.addGeneralization) + // 删除节点概要 + this.removeGeneralization = this.removeGeneralization.bind(this) + this.mindMap.command.add('REMOVE_GENERALIZATION', this.removeGeneralization) } /** @@ -579,7 +585,14 @@ class Render { } for (let i = 0; i < this.activeNodeList.length; i++) { let node = this.activeNodeList[i] - if (node.isRoot) { + if (node.isGeneralization) { + // 删除概要节点 + this.setNodeData(node.generalizationBelongNode, { + generalization: null + }) + this.removeActiveNode(node) + i-- + } else if (node.isRoot) { node.children.forEach((child) => { child.remove() }) @@ -855,6 +868,48 @@ class Render { }) } + /** + * @Author: 王林 + * @Date: 2022-07-30 20:52:42 + * @Desc: 添加节点概要 + */ + addGeneralization(data) { + if (this.activeNodeList.length <= 0) { + return + } + this.activeNodeList.forEach((node) => { + if (node.nodeData.data.generalization) { + return + } + this.setNodeData(node, { + generalization: data || { + text: '概要' + } + }) + }) + this.mindMap.render() + } + + /** + * @Author: 王林 + * @Date: 2022-07-30 21:16:33 + * @Desc: 删除节点概要 + */ + removeGeneralization() { + if (this.activeNodeList.length <= 0) { + return + } + this.activeNodeList.forEach((node) => { + if (!node.nodeData.data.generalization) { + return + } + this.setNodeData(node, { + generalization: null + }) + }) + this.mindMap.render() + } + /** * @Author: 王林 * @Date: 2021-05-04 14:19:48 diff --git a/simple-mind-map/src/Style.js b/simple-mind-map/src/Style.js index 3d47b892..31096475 100644 --- a/simple-mind-map/src/Style.js +++ b/simple-mind-map/src/Style.js @@ -50,6 +50,8 @@ class Style { let defaultConfig = this.themeConfig.node if (root || rootProp.includes(prop)) {// 直接使用最外层样式 defaultConfig = this.themeConfig + } else if (this.ctx.isGeneralization) {// 概要节点 + defaultConfig = this.themeConfig.generalization } else if (this.ctx.layerIndex === 0) {// 根节点 defaultConfig = this.themeConfig.root } else if (this.ctx.layerIndex === 1) {// 二级节点 @@ -154,6 +156,15 @@ class Style { node.stroke({ width: this.merge('lineWidth', true), color: this.merge('lineColor', true) }).fill({ color: 'none' }) } + /** + * @Author: 王林 + * @Date: 2022-07-30 16:19:03 + * @Desc: 概要连线 + */ + generalizationLine(node) { + node.stroke({ width: this.merge('generalizationLineWidth', true), color: this.merge('generalizationLineColor', true) }).fill({ color: 'none' }) + } + /** * @Author: 王林 * @Date: 2021-04-11 20:03:59 diff --git a/simple-mind-map/src/layouts/Base.js b/simple-mind-map/src/layouts/Base.js index c8478e32..483a3ff2 100644 --- a/simple-mind-map/src/layouts/Base.js +++ b/simple-mind-map/src/layouts/Base.js @@ -1,4 +1,7 @@ import Node from '../Node' +import { + walk, +} from '../utils' /** * @Author: 王林 @@ -49,6 +52,13 @@ class Base { throw new Error('【renderExpandBtn】方法为必要方法,需要子类进行重写!') } + /** + * @Author: 王林 + * @Date: 2022-07-30 22:49:28 + * @Desc: 概要节点 + */ + renderGeneralization() {} + /** * @Author: 王林 * @Date: 2021-07-10 21:30:54 @@ -156,6 +166,38 @@ class Base { getMarginY(layerIndex) { return layerIndex === 1 ? this.mindMap.themeConfig.second.marginY : this.mindMap.themeConfig.node.marginY; } + + /** + * @Author: 王林 + * @Date: 2022-07-31 09:14:03 + * @Desc: 获取节点的边界值 + */ + getNodeBoundaries(node) { + let top = Infinity + let bottom = -Infinity + let left = Infinity + let right = -Infinity + walk(node, null, (root) => { + if (root.top < top) { + top = root.top + } + if (root.top + root.height > bottom) { + bottom = root.top + root.height + } + if (root.left < left) { + left = root.left + } + if (root.left + root.width > right) { + right = root.left + root.width + } + }, null, true) + return { + left, + right, + top, + bottom + }; + } } export default Base \ No newline at end of file diff --git a/simple-mind-map/src/layouts/CatalogOrganization.js b/simple-mind-map/src/layouts/CatalogOrganization.js index 66d15967..75895ceb 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -310,6 +310,26 @@ class CatalogOrganization extends Base { btn.translate(width * 0.3 - expandBtnSize / 2 - translateX, height + expandBtnSize / 2 - translateY) } } + + /** + * @Author: 王林 + * @Date: 2022-07-30 08:30:35 + * @Desc: 创建概要节点 + */ + renderGeneralization(node, gLine, gNode) { + let { top, bottom, right } = this.getNodeBoundaries(node) + let space = 20 + let x1 = right + let y1 = top + let x2 = right + let y2 = bottom + let cx = x1 + space + let cy = y1 + (y2 - y1) / 2 + let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + gLine.plot(path) + gNode.left = right + space + gNode.top = top + (bottom - top - gNode.height) / 2 + } } export default CatalogOrganization \ No newline at end of file diff --git a/simple-mind-map/src/layouts/LogicalStructure.js b/simple-mind-map/src/layouts/LogicalStructure.js index 1bd0e540..4953bc7b 100644 --- a/simple-mind-map/src/layouts/LogicalStructure.js +++ b/simple-mind-map/src/layouts/LogicalStructure.js @@ -188,6 +188,26 @@ class LogicalStructure extends Base { } = btn.transform() btn.translate(width - translateX, height / 2 - translateY) } + + /** + * @Author: 王林 + * @Date: 2022-07-30 08:30:35 + * @Desc: 创建概要节点 + */ + renderGeneralization(node, gLine, gNode) { + let { top, bottom, right } = this.getNodeBoundaries(node) + let space = 20 + let x1 = right + let y1 = top + let x2 = right + let y2 = bottom + let cx = x1 + space + let cy = y1 + (y2 - y1) / 2 + let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + gLine.plot(path) + gNode.left = right + space + gNode.top = top + (bottom - top - gNode.height) / 2 + } } export default LogicalStructure \ No newline at end of file diff --git a/simple-mind-map/src/layouts/MindMap.js b/simple-mind-map/src/layouts/MindMap.js index 72ae43f2..86ac410b 100644 --- a/simple-mind-map/src/layouts/MindMap.js +++ b/simple-mind-map/src/layouts/MindMap.js @@ -224,6 +224,29 @@ class MindMap extends Base { let y = height / 2 - translateY btn.translate(x, y) } + + /** + * @Author: 王林 + * @Date: 2022-07-30 08:30:35 + * @Desc: 创建概要节点 + */ + renderGeneralization(node, gLine, gNode) { + let { top, bottom, left, right } = this.getNodeBoundaries(node) + let isLeft = node.dir === 'left' + let space = 20 + let x = isLeft ? left : right + space = (isLeft ? -space : space) + let x1 = x + let y1 = top + let x2 = x + let y2 = bottom + let cx = x1 + space + let cy = y1 + (y2 - y1) / 2 + let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + gLine.plot(path) + gNode.left = x + space - (isLeft ? gNode.width : 0) + gNode.top = top + (bottom - top - gNode.height) / 2 + } } export default MindMap \ No newline at end of file diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/OrganizationStructure.js index 04b2c7b5..828ea22e 100644 --- a/simple-mind-map/src/layouts/OrganizationStructure.js +++ b/simple-mind-map/src/layouts/OrganizationStructure.js @@ -206,6 +206,26 @@ class OrganizationStructure extends Base { } = btn.transform() btn.translate(width / 2 - expandBtnSize / 2 - translateX, height + expandBtnSize / 2 - translateY) } + + /** + * @Author: 王林 + * @Date: 2022-07-30 08:30:35 + * @Desc: 创建概要节点 + */ + renderGeneralization(node, gLine, gNode) { + let { bottom, left, right } = this.getNodeBoundaries(node) + let space = 20 + let x1 = left + let y1 = bottom + let x2 = right + let y2 = bottom + let cx = left + (right - left) / 2 + let cy = bottom + space + let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + gLine.plot(path) + gNode.top = bottom + space + gNode.left = left + (right - left - gNode.width) / 2 + } } export default OrganizationStructure \ No newline at end of file diff --git a/simple-mind-map/src/themes/default.js b/simple-mind-map/src/themes/default.js index 8f82c633..c9225905 100644 --- a/simple-mind-map/src/themes/default.js +++ b/simple-mind-map/src/themes/default.js @@ -17,6 +17,10 @@ export default { lineWidth: 1, // 连线的颜色 lineColor: '#549688', + // 概要连线的粗细 + generalizationLineWidth: 1, + // 概要连线的颜色 + generalizationLineColor: '#549688', // 背景颜色 backgroundColor: '#fafafa', // 背景图片 @@ -86,5 +90,27 @@ export default { borderWidth: 3, borderDasharray: 'none', } + }, + // 概要节点样式 + generalization: { + marginX: 100, + marginY: 40, + fillColor: '#fff', + fontFamily: '微软雅黑, Microsoft YaHei', + color: '#565656', + fontSize: 16, + fontWeight: 'noraml', + fontStyle: 'normal', + lineHeight: 1.5, + borderColor: '#549688', + borderWidth: 1, + borderDasharray: 'none', + borderRadius: 5, + textDecoration: 'none', + active: { + borderColor: 'rgb(57, 80, 96)', + borderWidth: 3, + borderDasharray: 'none', + } } } \ No newline at end of file diff --git a/simple-mind-map/src/themes/minions.js b/simple-mind-map/src/themes/minions.js index 647e5793..635f115a 100644 --- a/simple-mind-map/src/themes/minions.js +++ b/simple-mind-map/src/themes/minions.js @@ -10,6 +10,10 @@ export default merge(defaultTheme, { // 连线的颜色 lineColor: 'rgb(51, 51, 51)', lineWidth: 3, + // 概要连线的粗细 + generalizationLineWidth: 3, + // 概要连线的颜色 + generalizationLineColor: '#222', // 背景颜色 backgroundColor: 'rgb(248, 215, 49)', // 根节点样式 @@ -39,5 +43,14 @@ export default merge(defaultTheme, { active: { borderColor: 'rgb(55, 165, 255)' } + }, + // 概要节点样式 + generalization: { + borderColor: '#222', + borderWidth: 3, + color: '#222', + active: { + borderColor: 'rgb(55, 165, 255)' + } } }) \ No newline at end of file diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 04a6dc24..8834226b 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -229,7 +229,7 @@ export const asyncRun = (taskList, callback = () => {}) => { let index = 0 let len = taskList.length if (len <= 0) { - return + return callback() } let loop = () => { if (index >= len) { diff --git a/web/src/.DS_Store b/web/src/.DS_Store index 8b8ab42e581a8a4664d6861ecf41d97f3c530844..1a810436fe2bdfa16fa0dcd28c62fb4599640efe 100644 GIT binary patch delta 71 zcmZoMXffEJ&ct|fvIbLwrbKnMk%gI#f{~eNt&T#qxw(Okf{C$NZ7nBM8XF_ge bRdr2m-OR}snB*B}ZT`R{#=4oE<1aq|<~S9~ delta 70 zcmZoMXffEJ&ct|PvIbLwhInUW8x|xmRA3p%nFBOCU diff --git a/web/src/assets/.DS_Store b/web/src/assets/.DS_Store index 3f852d15516f0a6f43b739fd5572e7828eb83c5e..6855e40808d7d407843d4fdedec19bb014bfb581 100644 GIT binary patch delta 75 zcmZoMXffEJ%fxtcvK~`|rbKnMk%gI#f{~eNt&T#qxw(Okf{C$NZ7nBM8XF_ge fRdr2m-OS0?nB*B}O)g*-+swoKi)AxA$6tN`KiwAi delta 74 zcmZoMXffEJ%fxtMvK~`|hIn
    +
  • + +
    概要总览
    +
    &#xe609;
    +
  • +
  • 全选
    @@ -258,9 +264,9 @@
    @font-face {
       font-family: 'iconfont';
    -  src: url('iconfont.woff2?t=1628093007325') format('woff2'),
    -       url('iconfont.woff?t=1628093007325') format('woff'),
    -       url('iconfont.ttf?t=1628093007325') format('truetype');
    +  src: url('iconfont.woff2?t=1659185196536') format('woff2'),
    +       url('iconfont.woff?t=1659185196536') format('woff'),
    +       url('iconfont.ttf?t=1659185196536') format('truetype');
     }
     

    第二步:定义使用 iconfont 的样式

    @@ -286,6 +292,15 @@
      +
    • + +
      + 概括总览 +
      +
      .icongaikuozonglan +
      +
    • +
    • @@ -592,6 +607,14 @@
        +
      • + +
        概括总览
        +
        #icongaikuozonglan
        +
      • +
      + +
      概要的连线
      +
      +
      + 颜色 + + + + +
      +
      + 粗细 + + + + +
      +
      节点内边距
      @@ -259,6 +303,8 @@ export default { backgroundColor: "", lineColor: "", lineWidth: "", + generalizationLineWidth: "", + generalizationLineColor: "", paddingX: 0, paddingY: 0, imgMaxWidth: 0, @@ -291,6 +337,8 @@ export default { "backgroundColor", "lineWidth", "lineColor", + "generalizationLineWidth", + "generalizationLineColor", "paddingX", "paddingY", "imgMaxWidth", diff --git a/web/src/pages/Edit/components/NodeIcon.vue b/web/src/pages/Edit/components/NodeIcon.vue index c1063f45..8488bd0a 100644 --- a/web/src/pages/Edit/components/NodeIcon.vue +++ b/web/src/pages/Edit/components/NodeIcon.vue @@ -50,7 +50,6 @@ export default { } else { this.iconList = []; } - console.log(this.iconList, nodeIconList); }); this.$bus.$on("showNodeIcon", () => { this.dialogVisible = true; diff --git a/web/src/pages/Edit/components/Toolbar.vue b/web/src/pages/Edit/components/Toolbar.vue index 24e33355..436c04c9 100644 --- a/web/src/pages/Edit/components/Toolbar.vue +++ b/web/src/pages/Edit/components/Toolbar.vue @@ -26,7 +26,7 @@
      @@ -36,7 +36,7 @@
      @@ -103,6 +103,16 @@ 标签
      +
      + + 概要 +
      @@ -188,6 +198,11 @@ export default { return node.isRoot; }); }, + hasGeneralization() { + return this.activeNodes.find((node) => { + return node.isGeneralization; + }); + } }, created() { this.$bus.$on("mode_change", (mode) => {