From a798a40fab0cc0028ed23d3b2c626588e12cfaaa Mon Sep 17 00:00:00 2001 From: wanglin <1013335014@qq.com> Date: Fri, 16 Jul 2021 13:42:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/Command.js | 24 ++- simple-mind-map/src/Event.js | 11 ++ simple-mind-map/src/Node.js | 10 +- simple-mind-map/src/Render.js | 130 +++++++++++++--- simple-mind-map/src/utils/index.js | 17 ++ web/src/pages/Edit/components/Contextmenu.vue | 146 ++++++++++++++---- web/src/pages/Edit/components/Edit.vue | 4 +- 7 files changed, 290 insertions(+), 52 deletions(-) diff --git a/simple-mind-map/src/Command.js b/simple-mind-map/src/Command.js index 300f9eef..0ec3549b 100644 --- a/simple-mind-map/src/Command.js +++ b/simple-mind-map/src/Command.js @@ -30,7 +30,7 @@ class Command { fn(...args) }) if (name === 'BACK' || name === 'FORWARD') { - return ; + return; } this.addHistory() } @@ -49,6 +49,28 @@ class Command { ] } + /** + * @Author: 王林 + * @Date: 2021-07-15 23:02:41 + * @Desc: 移除命令 + */ + remove(name, fn) { + if (!this.commands[name]) { + return + } + if (!fn) { + this.commands[name] = [] + delete this.commands[name] + } else { + let index = this.commands[name].find((item) => { + return item === fn; + }) + if (index !== -1) { + this.commands[name].splice(index, 1) + } + } + } + /** * @Author: 王林 * @Date: 2021-05-04 14:35:43 diff --git a/simple-mind-map/src/Event.js b/simple-mind-map/src/Event.js index cca50593..a11197c3 100644 --- a/simple-mind-map/src/Event.js +++ b/simple-mind-map/src/Event.js @@ -47,6 +47,7 @@ class Event extends EventEmitter { this.onMouseup = this.onMouseup.bind(this) this.onMousewheel = this.onMousewheel.bind(this) this.onContextmenu = this.onContextmenu.bind(this) + this.onSvgMousedown = this.onSvgMousedown.bind(this) } /** @@ -58,6 +59,7 @@ class Event extends EventEmitter { bind() { this.mindMap.svg.on('click', this.onDrawClick) this.mindMap.el.addEventListener('mousedown', this.onMousedown) + this.mindMap.svg.on('mousedown', this.onSvgMousedown) window.addEventListener('mousemove', this.onMousemove) window.addEventListener('mouseup', this.onMouseup) // 兼容火狐浏览器 @@ -93,6 +95,15 @@ class Event extends EventEmitter { this.emit('draw_click', e) } + /** + * @Author: 王林 + * @Date: 2021-07-16 13:37:30 + * @Desc: svg画布的鼠标按下事件 + */ + onSvgMousedown(e) { + this.emit('svg_mousedown', e) + } + /** * javascript comment * @Author: 王林25 diff --git a/simple-mind-map/src/Node.js b/simple-mind-map/src/Node.js index ba606ac8..c1a792b5 100644 --- a/simple-mind-map/src/Node.js +++ b/simple-mind-map/src/Node.js @@ -165,7 +165,7 @@ class Node { this._expandBtn.off(['mouseover', 'mouseout', 'click']) } if (this.group) { - this.group.off(['click', 'dblclick', 'contextmenu']) + this.group.off(['click', 'dblclick', 'contextmenu', 'mousedown', 'mouseup']) } } @@ -551,6 +551,14 @@ class Node { this.mindMap.emit('node_click', this) this.active(e) }) + this.group.on('mousedown', (e) => { + e.stopPropagation() + this.mindMap.emit('node_mousedown', this) + }) + this.group.on('mouseup', (e) => { + e.stopPropagation() + this.mindMap.emit('node_mouseup', this) + }) // 双击事件 this.group.on('dblclick', (e) => { e.stopPropagation() diff --git a/simple-mind-map/src/Render.js b/simple-mind-map/src/Render.js index 370007fd..52e1f268 100644 --- a/simple-mind-map/src/Render.js +++ b/simple-mind-map/src/Render.js @@ -1,9 +1,10 @@ import merge from 'deepmerge' import LogicalStructure from './layouts/LogicalStructure' import MindMap from './layouts/MindMap' -import CatalogOrganization from './layouts/CatalogOrganization'; +import CatalogOrganization from './layouts/CatalogOrganization' import OrganizationStructure from './layouts/OrganizationStructure' import TextEdit from './TextEdit' +import { copyNodeTree, simpleDeepClone, walk } from './utils' // 布局列表 const layouts = { @@ -62,7 +63,7 @@ class Render { * @Desc: 设置布局结构 */ setLayout() { - this.layout = new(layouts[this.mindMap.opt.layout] ? layouts[this.mindMap.opt.layout] : layouts.logicalStructure)(this) + this.layout = new (layouts[this.mindMap.opt.layout] ? layouts[this.mindMap.opt.layout] : layouts.logicalStructure)(this) } /** @@ -108,9 +109,12 @@ class Render { // 删除节点 this.removeNode = this.removeNode.bind(this) this.mindMap.command.add('REMOVE_NODE', this.removeNode) - // 复制节点 - this.copyNode = this.copyNode.bind(this) - this.mindMap.command.add('COPY_NODE', this.copyNode) + // 粘贴节点 + this.pasteNode = this.pasteNode.bind(this) + this.mindMap.command.add('PASTE_NODE', this.pasteNode) + // 剪切节点 + this.cutNode = this.cutNode.bind(this) + this.mindMap.command.add('CUT_NODE', this.cutNode) // 修改节点样式 this.setNodeStyle = this.setNodeStyle.bind(this) this.mindMap.command.add('SET_NODE_STYLE', this.setNodeStyle) @@ -123,6 +127,12 @@ class Render { // 切换节点是否展开 this.setNodeExpand = this.setNodeExpand.bind(this) this.mindMap.command.add('SET_NODE_EXPAND', this.setNodeExpand) + // 展开所有节点 + this.expandAllNode = this.expandAllNode.bind(this) + this.mindMap.command.add('EXPAND_ALL', this.expandAllNode) + // 收起所有节点 + this.unexpandAllNode = this.unexpandAllNode.bind(this) + this.mindMap.command.add('UNEXPAND_ALL', this.unexpandAllNode) // 设置节点数据 this.setNodeData = this.setNodeData.bind(this) this.mindMap.command.add('SET_NODE_DATA', this.setNodeData) @@ -222,6 +232,9 @@ class Render { */ removeActiveNode(node) { let index = this.findActiveNodeIndex(node) + if (index === -1) { + return + } this.activeNodeList.splice(index, 1) } @@ -232,7 +245,7 @@ class Render { */ findActiveNodeIndex(node) { return this.activeNodeList.findIndex((item) => { - return item === node; + return item === node }) } @@ -281,7 +294,7 @@ class Render { */ insertNode() { if (this.activeNodeList.length <= 0) { - return; + return } let first = this.activeNodeList[0] if (first.isRoot) { @@ -306,7 +319,7 @@ class Render { */ insertChildNode() { if (this.activeNodeList.length <= 0) { - return; + return } this.activeNodeList.forEach((node, index) => { if (!node.nodeData.children) { @@ -344,7 +357,7 @@ class Render { let parent = node.parent let childList = parent.children let index = childList.findIndex((item) => { - return item === node; + return item === node }) if (index === -1 || index === 0) { return @@ -375,7 +388,7 @@ class Render { let parent = node.parent let childList = parent.children let index = childList.findIndex((item) => { - return item === node; + return item === node }) if (index === -1 || index === childList.length - 1) { return @@ -397,7 +410,7 @@ class Render { */ removeNode() { if (this.activeNodeList.length <= 0) { - return; + return } for (let i = 0; i < this.activeNodeList.length; i++) { let node = this.activeNodeList[i] @@ -410,10 +423,7 @@ class Render { break } else { this.removeActiveNode(node) - let index = this.getNodeIndex(node) - node.remove() - node.parent.children.splice(index, 1) - node.parent.nodeData.children.splice(index, 1) + this.removeOneNode(node) i-- } } @@ -421,18 +431,67 @@ class Render { this.mindMap.render() } + /** + * @Author: 王林 + * @Date: 2021-07-15 22:46:27 + * @Desc: 移除某个指定节点 + */ + removeOneNode(node) { + let index = this.getNodeIndex(node) + node.remove() + node.parent.children.splice(index, 1) + node.parent.nodeData.children.splice(index, 1) + } + /** * javascript comment * @Author: 王林25 * @Date: 2021-07-15 09:53:23 - * @Desc: 复制节点 + * @Desc: 复制节点,多个节点只会操作第一个节点 */ copyNode() { if (this.activeNodeList.length <= 0) { - return; + return } - let copyData = [] - + return copyNodeTree({}, this.activeNodeList[0]) + } + + /** + * @Author: 王林 + * @Date: 2021-07-15 22:36:45 + * @Desc: 剪切节点,多个节点只会操作第一个节点 + */ + cutNode(callback) { + if (this.activeNodeList.length <= 0) { + return + } + let node = this.activeNodeList[0] + if (node.isRoot) { + return null + } + let copyData = copyNodeTree({}, node) + this.removeActiveNode(node) + this.removeOneNode(node) + this.mindMap.emit('node_active', null, this.activeNodeList) + this.mindMap.render() + if (callback && typeof callback === 'function') { + callback(copyData) + } + } + + /** + * @Author: 王林 + * @Date: 2021-07-15 20:09:39 + * @Desc: 粘贴节点到节点 + */ + pasteNode(data) { + if (this.activeNodeList.length <= 0) { + return + } + this.activeNodeList.forEach((item) => { + item.nodeData.children.push(simpleDeepClone(data)) + }) + this.mindMap.render() } /** @@ -494,6 +553,39 @@ class Render { this.mindMap.render() } + /** + * @Author: 王林 + * @Date: 2021-07-15 23:23:37 + * @Desc: 展开所有 + */ + expandAllNode() { + walk(this.renderTree, null, (node) => { + if (!node.data.expand) { + node.data.expand = true + } + }, null, true, 0, 0) + this.mindMap.render() + this.root.children.forEach((item) => { + item.updateExpandBtnNode() + }) + } + + /** + * @Author: 王林 + * @Date: 2021-07-15 23:27:14 + * @Desc: 收起所有 + */ + unexpandAllNode() { + this.root.children.forEach((item) => { + this.setNodeExpand(item, false) + }) + walk(this.renderTree, null, (node, parent, isRoot) => { + if (!isRoot) { + node.data.expand = false + } + }, null, true, 0, 0) + } + /** * @Author: 王林 * @Date: 2021-07-11 17:15:33 diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index b67aec30..a0cc9ef5 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -136,6 +136,23 @@ export const copyRenderTree = (tree, root) => { return tree; } +/** + * @Author: 王林 + * @Date: 2021-05-04 14:40:11 + * @Desc: 复制节点树数据 + */ +export const copyNodeTree = (tree, root) => { + tree.data = simpleDeepClone(root.nodeData.data) + tree.data.isActive = false + tree.children = [] + if (root.children && root.children.length > 0) { + root.children.forEach((item, index) => { + tree.children[index] = copyNodeTree({}, item) + }) + } + return tree; +} + /** * @Author: 王林 * @Date: 2021-07-04 09:08:43 diff --git a/web/src/pages/Edit/components/Contextmenu.vue b/web/src/pages/Edit/components/Contextmenu.vue index 7be42fe0..7aaa1ff9 100644 --- a/web/src/pages/Edit/components/Contextmenu.vue +++ b/web/src/pages/Edit/components/Contextmenu.vue @@ -4,32 +4,45 @@ v-if="isShow" :style="{ left: left + 'px', top: top + 'px' }" > -