diff --git a/simple-mind-map/example/exampleData.js b/simple-mind-map/example/exampleData.js index ad243813..bea996fa 100644 --- a/simple-mind-map/example/exampleData.js +++ b/simple-mind-map/example/exampleData.js @@ -1,3 +1,19 @@ +const createFullData = () => { + return { + // "image": "http://aliyuncdn.lxqnsys.com/whbm/enJFNMHnedQTYTESGfDkctCp2", + // "imageTitle": "图片名称", + // "imageSize": { + // "width": 1000, + // "height": 563 + // }, + // "icon": ['priority_1'], + // "tag": ["标签1", "标签2"], + // "hyperlink": "http://lxqnsys.com/", + // "hyperlinkTitle": "理想青年实验室", + // "note": "理想青年实验室\n一个有意思的角落" + }; +} + /** * @Author: 王林 * @Date: 2021-04-15 22:23:24 @@ -8,33 +24,162 @@ export default { "data": { "text": "根节点", }, - "children": [{ - "data": { - "text": "二级节点", - "expand": true, - }, - "children": [{ + "children": [ + { "data": { - "text": "子节点", - // "image": "http://aliyuncdn.lxqnsys.com/whbm/enJFNMHnedQTYTESGfDkctCp2", - // "imageTitle": "图片名称", - // "imageSize": { - // "width": 1000, - // "height": 563 - // }, - // "icon": ['priority_1'], - // "tag": ["标签1", "标签2"], - // "hyperlink": "http://lxqnsys.com/", - // "hyperlinkTitle": "理想青年实验室", - // "note": "理想青年实验室\n一个有意思的角落" + "text": "二级节点1", + "expand": true, }, - "children": [] - }, { + "children": [{ + "data": { + "text": "子节点1-1", + ...createFullData() + }, + }, { + "data": { + "text": "子节点1-2", + ...createFullData() + } + },] + }, + { "data": { - "text": "子节点", - } - }] - }] + "text": "二级节点2" + }, + "children": [ + { + "data": { + "text": "子节点2-1", + ...createFullData() + }, + "children": [ + { + "data": { + "text": "子节点2-1-1", + ...createFullData() + } + }, + { + "data": { + "text": "子节点2-1-2", + ...createFullData() + }, + "children": [ + { + "data": { + "text": "子节点2-1-2-1", + ...createFullData() + } + }, + { + "data": { + "text": "子节点2-1-2-2", + ...createFullData() + }, + "children": [ + { + "data": { + "text": "子节点2-1-2-2-1", + ...createFullData() + } + }, + { + "data": { + "text": "子节点2-1-2-2-2", + ...createFullData() + } + }, + { + "data": { + "text": "子节点2-1-2-2-3", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "子节点4-1-2-3", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "子节点2-1-3", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "子节点2-2", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "二级节点3", + }, + "children": [ + { + "data": { + "text": "子节点3-1", + ...createFullData() + } + }, + { + "data": { + "text": "子节点3-2", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "二级节点4", + }, + "children": [ + { + "data": { + "text": "子节点4-1", + ...createFullData() + }, + "children": [ + { + "data": { + "text": "子节点4-1-1", + ...createFullData() + } + }, + { + "data": { + "text": "子节点4-1-2", + ...createFullData() + } + }, + { + "data": { + "text": "子节点4-1-3", + ...createFullData() + } + } + ] + }, + { + "data": { + "text": "子节点4-2", + ...createFullData() + } + } + ] + } + ] }, "theme": { "template": "default", @@ -42,5 +187,7 @@ export default { // 自定义配置... } }, + // "layout": "mindMap", "layout": "logicalStructure" + // "layout": "catalogOrganization" } \ No newline at end of file diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 47f910e4..b04ac4cd 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -5,7 +5,8 @@ import merge from 'deepmerge' import theme from './src/themes' import Style from './src/Style' import KeyCommand from './src/KeyCommand' -import Command from './src/Command'; +import Command from './src/Command' +import BatchExecution from './src/BatchExecution' import { SVG } from '@svgdotjs/svg.js' @@ -52,7 +53,7 @@ class MindMap { // 画笔 this.draw = SVG().addTo(this.el).size(width, height) - + // 节点id this.uid = 0 @@ -85,6 +86,9 @@ class MindMap { draw: this.draw }) + // 批量执行类 + this.batchExecution = new BatchExecution() + // 初始渲染 this.renderer.render() setTimeout(() => { @@ -99,9 +103,11 @@ class MindMap { * @Desc: 渲染 */ render() { - this.draw.clear() - this.initTheme() - this.renderer.render() + this.batchExecution.push('render', () => { + this.draw.clear() + this.initTheme() + this.renderer.render() + }) } /** diff --git a/simple-mind-map/src/BatchExecution.js b/simple-mind-map/src/BatchExecution.js new file mode 100644 index 00000000..9db557d1 --- /dev/null +++ b/simple-mind-map/src/BatchExecution.js @@ -0,0 +1,85 @@ +/** + * @Author: 王林 + * @Date: 2021-06-27 13:16:23 + * @Desc: 在下一个事件循环里执行任务 + */ +const nextTick = function (fn, ctx) { + let pending = false + let timerFunc = null + let handle = () => { + pending = false + ctx ? fn.call(ctx) : fn() + } + // 支持MutationObserver接口的话使用MutationObserver + if (typeof MutationObserver !== 'undefined') { + let counter = 1 + let observer = new MutationObserver(handle) + let textNode = document.createTextNode(counter) + observer.observe(textNode, { + characterData: true// 设为 true 表示监视指定目标节点或子节点树中节点所包含的字符数据的变化 + }) + timerFunc = function () { + counter = (counter + 1) % 2// counter会在0和1两者循环变化 + textNode.data = counter// 节点变化会触发回调handle, + } + } else {// 否则使用定时器 + timerFunc = setTimeout + } + return function (cb, ctx) { + if (pending) return + pending = true + timerFunc(handle, 0) + } +} + + +/** + * @Author: 王林 + * @Date: 2021-06-26 22:40:52 + * @Desc: 批量执行 + */ +class BatchExecution { + /** + * @Author: 王林 + * @Date: 2021-06-26 22:41:41 + * @Desc: 构造函数 + */ + constructor() { + this.has = {} + this.queue = [] + this.nextTick = nextTick(this.flush, this) + } + + /** + * @Author: 王林 + * @Date: 2021-06-27 12:54:04 + * @Desc: 添加任务 + */ + push(name, fn) { + if (this.has[name]) { + return; + } + this.has[name] = true + this.queue.push({ + name, + fn + }) + this.nextTick() + } + + /** + * @Author: 王林 + * @Date: 2021-06-27 13:09:24 + * @Desc: 执行队列 + */ + flush() { + let fns = this.queue.slice(0) + this.queue = [] + fns.forEach(({ name, fn }) => { + this.has[name] = false + fn() + }) + } +} + +export default BatchExecution \ No newline at end of file diff --git a/simple-mind-map/src/Node.js b/simple-mind-map/src/Node.js index 9ccbdf36..ebf03e2f 100644 --- a/simple-mind-map/src/Node.js +++ b/simple-mind-map/src/Node.js @@ -1,6 +1,7 @@ import Style from './Style' import { - resizeImgSize + resizeImgSize, + copyRenderTree } from './utils' import { Image, @@ -62,6 +63,8 @@ class Node { this._textContentItemMargin = 2 // 图片和文字节点的间距 this._blockContentMargin = 5 + // 展开收缩按钮尺寸 + this._expandBtnSize = 20 // 计算节点尺寸 this.refreshSize() } @@ -491,7 +494,7 @@ class Node { * @Desc: 展开收缩按钮 */ renderExpandBtn() { - if (this.children.length <= 0 || this.isRoot) { + if ((!this.nodeData.data.cacheChildren || this.nodeData.data.cacheChildren.length <= 0) && this.children.length <= 0 || this.isRoot) { return; } let g = this.draw.group() @@ -501,8 +504,8 @@ class Node { } else { iconSvg = btnsSvg.close } - let node = SVG(iconSvg).size(20, 20) - let fillNode = new Circle().size(20) + let node = SVG(iconSvg).size(this._expandBtnSize, this._expandBtnSize) + let fillNode = new Circle().size(this._expandBtnSize) this.renderer.layout.renderExpandBtn(this, [node, fillNode]) node.dx(0).dy(-10) fillNode.dx(0).dy(-10) @@ -518,10 +521,21 @@ class Node { }) }) g.click(() => { - // 需要反映到实际数据上 - this.mindMap.execCommand('UPDATE_NODE_DATA', this, { - expand: !this.nodeData.data.expand - }) + // 展开收缩 + let data = {} + let children = [] + if (this.nodeData.data.expand) { + data.expand = false + data.cacheChildren = this.nodeData.children.map((item) => { + return copyRenderTree({}, item); + }) + children = [] + } else { + data.expand = true + children = this.nodeData.data.cacheChildren + data.cacheChildren = [] + } + this.mindMap.execCommand('UPDATE_NODE_DATA', this, data, children) this.mindMap.emit('expand_btn_click', this) }) g.add(fillNode) diff --git a/simple-mind-map/src/Render.js b/simple-mind-map/src/Render.js index b7146b8e..f8fdad03 100644 --- a/simple-mind-map/src/Render.js +++ b/simple-mind-map/src/Render.js @@ -1,11 +1,17 @@ import merge from 'deepmerge' import LogicalStructure from './layouts/LogicalStructure' +import MindMap from './layouts/MindMap' +import CatalogOrganization from './layouts/CatalogOrganization'; import TextEdit from './TextEdit' // 布局列表 const layouts = { + // 逻辑结构图 + logicalStructure: LogicalStructure, // 思维导图 - logicalStructure: LogicalStructure + mindMap: MindMap, + // 目录组织图 + catalogOrganization: CatalogOrganization } /** @@ -146,6 +152,9 @@ class Render { return; } let first = this.activeNodeList[0] + if (!first.nodeData.children) { + first.nodeData.children = [] + } first.nodeData.children.push({ "data": { "text": "分支主题", @@ -184,10 +193,13 @@ class Render { * @Date: 2021-05-04 14:19:48 * @Desc: 更新节点数据 */ - updateNodeData(node, data) { + updateNodeData(node, data, children) { Object.keys(data).forEach((key) => { node.nodeData.data[key] = data[key] }) + if (children) { + node.nodeData.children = children + } this.mindMap.render() } } diff --git a/simple-mind-map/src/TextEdit.js b/simple-mind-map/src/TextEdit.js index 33a65428..fb93573a 100644 --- a/simple-mind-map/src/TextEdit.js +++ b/simple-mind-map/src/TextEdit.js @@ -99,6 +99,7 @@ export default class TextEdit { this.renderer.activeNodeList.forEach((node) => { let str = getStrWithBrFromHtml(this.textEditNode.innerHTML) node.nodeData.data.text = str + console.log(8) this.mindMap.render() }) this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList) diff --git a/simple-mind-map/src/assets/icon_newcreat_classify.png b/simple-mind-map/src/assets/icon_newcreat_classify.png new file mode 100644 index 00000000..6fa0bcf8 Binary files /dev/null and b/simple-mind-map/src/assets/icon_newcreat_classify.png differ diff --git a/simple-mind-map/src/assets/icon_newcreat_mindmap.png b/simple-mind-map/src/assets/icon_newcreat_mindmap.png new file mode 100644 index 00000000..389b5051 Binary files /dev/null and b/simple-mind-map/src/assets/icon_newcreat_mindmap.png differ diff --git a/simple-mind-map/src/assets/icon_newcreat_structure.png b/simple-mind-map/src/assets/icon_newcreat_structure.png new file mode 100644 index 00000000..24f3b15c Binary files /dev/null and b/simple-mind-map/src/assets/icon_newcreat_structure.png differ diff --git a/simple-mind-map/src/assets/icon_newcreat_theright.png b/simple-mind-map/src/assets/icon_newcreat_theright.png new file mode 100644 index 00000000..3889465b Binary files /dev/null and b/simple-mind-map/src/assets/icon_newcreat_theright.png differ diff --git a/simple-mind-map/src/layouts/Base.js b/simple-mind-map/src/layouts/Base.js index d5efe671..35e979d7 100644 --- a/simple-mind-map/src/layouts/Base.js +++ b/simple-mind-map/src/layouts/Base.js @@ -30,6 +30,7 @@ class Base { * @Desc: 计算节点位置 */ doLayout() { + console.log('布局') throw new Error('【computed】方法为必要方法,需要子类进行重写!') } @@ -65,6 +66,48 @@ class Base { } }) } + + /** + * @Author: 王林 + * @Date: 2021-04-11 15:05:01 + * @Desc: 二次贝塞尔曲线 + */ + quadraticCurvePath(x1, y1, x2, y2) { + let cx = x1 + (x2 - x1) * 0.2 + let cy = y1 + (y2 - y1) * 0.8 + return `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` + } + + /** + * @Author: 王林 + * @Date: 2021-04-11 15:05:18 + * @Desc: 三次贝塞尔曲线 + */ + cubicBezierPath(x1, y1, x2, y2) { + let cx1 = x1 + (x2 - x1) / 2 + let cy1 = y1 + let cx2 = x2 - (x2 - x1) / 2 + let cy2 = y2 + return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}` + } + + /** + * @Author: 王林 + * @Date: 2021-06-27 19:00:07 + * @Desc: 获取节点的marginX + */ + getMarginX(layerIndex) { + return layerIndex === 1 ? this.themeConfig.second.marginX : this.themeConfig.node.marginX; + } + + /** + * @Author: 王林 + * @Date: 2021-04-11 15:34:20 + * @Desc: 获取节点的marginY + */ + getMarginY(layerIndex) { + return layerIndex === 1 ? this.themeConfig.second.marginY : this.themeConfig.node.marginY; + } } export default Base \ No newline at end of file diff --git a/simple-mind-map/src/layouts/BubbleChart.js b/simple-mind-map/src/layouts/BubbleChart.js deleted file mode 100644 index 84f73fe9..00000000 --- a/simple-mind-map/src/layouts/BubbleChart.js +++ /dev/null @@ -1,186 +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: 鱼骨图 - */ -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() { - // 计算节点的width、height - this.computedBaseValue() - // 计算节点的left、top - this.computedLeftTopValue() - // 调整节点top - // this.adjustTopValue() - // 调整节点left - // this.adjustLeftValue() - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 09:49:32 - * @Desc: 计算节点的width、height - */ - computedBaseValue() { - walk(this.renderTree, null, (node, parent, isRoot, index, layerIndex) => { - // 设置width、height - let { - children, - ...props - } = node - let newNode = new Node({ - ...props, - mindMap: this.mindMap, - draw: this.draw, - layerIndex - }) - // 计算节点的宽高 - newNode.refreshSize() - // 计算节点的top - if (isRoot) { - newNode.isRoot = true - newNode.left = this.mindMap.width / 2 - newNode.top = this.mindMap.height / 2 - this.root = newNode - } else { - newNode.parent = parent._node - parent._node.addChildren(newNode) - } - node._node = newNode - }, (node) => { - // 遍历完子节点返回时 - }, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 09:59:25 - * @Desc: 计算节点的left、top - */ - computedLeftTopValue() { - let margin = Math.max(this.mindMap.opt.marginX, this.mindMap.opt.marginY) - walk(this.root, null, (node) => { - if (node.children && node.children.length) { - let rad = (360 / node.children.length) * (Math.PI / 180) - let totalRad = 0 - node.children.forEach((item) => { - let r = node.width / 2 + margin + item.width / 2 - item.left = node.left + r * Math.cos(totalRad) - item.top = node.top + r * Math.sin(totalRad) - totalRad += rad - }) - } - }, null, true) - // return - walk(this.root, null, null, (node) => { - if (node.children && node.children.length) { - let minLeft = Infinity, - minTop = Infinity, - maxRight = -Infinity, - maxBottom = -Infinity - node.children.concat([node]).forEach((item) => { - if ((item.left - item.width / 2) < minLeft) { - minLeft = item.left - item.width / 2 - } - if ((item.top - item.width / 2) < minTop) { - minTop = item.top - item.width / 2 - } - if ((item.left + item.width / 2) > maxRight) { - maxRight = item.left + item.width / 2 - } - if ((item.top + item.width / 2) < maxBottom) { - maxBottom = item.top + item.width / 2 - } - }) - let width = Math.max(maxRight - minLeft, maxBottom - minTop) - let difference = width - node.width - this.update(node, difference) - } - }, true) - } - - update(node, difference) { - if (node.parent) { - // console.log(node.text, difference) - let rad = (360 / node.parent.children.length) * (Math.PI / 180) - let totalRad = 0 - node.parent.children.forEach((item) => { - if (item === node) { - item.left += difference * Math.cos(totalRad) - item.top += difference * Math.sin(totalRad) - if (node.children && node.children.length) { - // this.updateChildren(node) - } - } - totalRad += rad - }) - - this.update(node.parent, difference) - } - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-07 11:25:52 - * @Desc: 更新子节点 - */ - updateChildren(node, difference) { - let margin = Math.max(this.mindMap.opt.marginX, this.mindMap.opt.marginY) - walk(node, null, (node) => { - if (node.children && node.children.length) { - let rad = (360 / node.children.length) * (Math.PI / 180) - let totalRad = 0 - node.children.forEach((item) => { - let r = node.width / 2 + margin + item.width / 2 - item.left = node.left + r * Math.cos(totalRad) - item.top = node.top + r * Math.sin(totalRad) - totalRad += rad - }) - } - }, null, true) - } -} - -export default Render \ 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 909aad42..f56a4faf 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -1,105 +1,87 @@ +import Base from './Base'; import { walk -} from '../Utils' +} from '../utils' import Node from '../Node' -import merge from 'deepmerge' /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:07 - * @Desc: 目录组织图 + * @Author: 王林 + * @Date: 2021-04-12 22:25:58 + * @Desc: 目录组织图 * 思路:第一轮只计算节点的宽高,以及某个节点的所有子节点所占的高度之和,以及该节点里所有子节点中宽度最宽是多少、第二轮计算节点的left和top,需要区分二级节点和其他节点,二级节点top相同,一行依次从做向右排开,其他节点的left相同,一列从上往下依次排开 */ -class Render { +class CatalogOrganization extends Base { /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:32 + * @Author: 王林 + * @Date: 2021-04-12 22:26:31 * @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() + super(opt) } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-06 14:04:20 - * @Desc: 计算位置数据 + * @Desc: 布局 */ - computed() { - // 计算节点的width、height + doLayout() { + // 遍历数据计算节点的width、height this.computedBaseValue() // 计算节点的left、top this.computedLeftTopValue() // 调整节点top this.adjustTopValue() // 调整节点left - this.adjustLeftValue() + // this.adjustLeftValue() + + return this.root; } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-08 09:49:32 - * @Desc: 计算节点的width、height + * @Desc: 遍历数据计算节点的width、height */ computedBaseValue() { - walk(this.renderTree, null, (node, parent, isRoot, index) => { - // 设置width、height - let { - children, - ...props - } = node + walk(this.renderTree, null, (cur, parent, isRoot, layerIndex) => { + // 创建节点 let newNode = new Node({ - ...props, + data: cur, + uid: this.mindMap.uid++, + renderer: this.renderer, mindMap: this.mindMap, - draw: this.draw + draw: this.draw, + layerIndex }) - // 计算节点的宽高 - newNode.refreshSize() - // 计算节点的top + // 数据关联实际节点 + 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 { + // 互相收集 newNode.parent = parent._node parent._node.addChildren(newNode) } - node._node = newNode - }, (node) => { - // 遍历完子节点返回时 - // 计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距 - let len = node._node.children.length - if (node._node.isRoot) { - node._node.childrenAreaWidth = len ? node._node.children.reduce((h, cur) => { - return h + cur.width - }, 0) + (len + 1) * this.mindMap.opt.marginX : 0 + }, (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 } - node._node.childrenAreaHeight = len ? node._node.children.reduce((h, cur) => { - return h + cur.height - }, 0) + (len + 1) * this.mindMap.opt.marginY : 0 - }, true) + // 计算子节点所占的高度之和 + cur._node.childrenAreaHeight = len ? cur._node.children.reduce((h, item) => { + return h + item.height + }, 0) + (len + 1) * this.getMarginY(layerIndex) : 0 + }, true, 0) } /** @@ -109,30 +91,79 @@ class Render { * @Desc: 计算节点的left、top */ computedLeftTopValue() { - walk(this.root, null, (node) => { + 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 + this.mindMap.opt.marginX + let totalLeft = left + marginX node.children.forEach((cur) => { // left cur.left = totalLeft - totalLeft += cur.width + this.mindMap.opt.marginX + totalLeft += cur.width + marginX // top - cur.top = node.top + node.height + this.mindMap.opt.marginY + cur.top = node.top + node.height + marginY }) } else { - let totalTop = node.top + node.height + this.mindMap.opt.marginY + let totalTop = node.top + node.height + marginY node.children.forEach((cur) => { - cur.left = node.left + node.width / 5 + this.mindMap.opt.marginX + cur.left = node.left + node.width / 5 cur.top = totalTop - totalTop += cur.height + this.mindMap.opt.marginY + totalTop += cur.height + marginY }) } } }, null, true) } + /** + * javascript comment + * @Author: 王林25 + * @Date: 2021-04-08 10:04:05 + * @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) + } + } + }, null, true) + } + + /** + * javascript comment + * @Author: 王林25 + * @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 @@ -140,10 +171,11 @@ class Render { * @Desc: 调整节点left */ adjustLeftValue() { - walk(this.root, null, (node) => { + 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 + let difference = childrenAreaWidth - node.width - marginX if (difference > 0) { this.updateBrothersLeftValue(node, difference / 2) } @@ -161,7 +193,7 @@ class Render { let widthArr = [] let loop = (node, width) => { if (node.children.length) { - width += node.width / 5 + this.mindMap.opt.marginX + width += node.width / 5 node.children.forEach((item) => { loop(item, width) }) @@ -205,66 +237,60 @@ class Render { } /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 10:04:05 - * @Desc: 调整节点top,该节点之后的节点都往下进行偏移 + * @Author: 王林 + * @Date: 2021-04-11 14:42:48 + * @Desc: 绘制连线,连接该节点到其子节点 */ - adjustTopValue() { - let marginY = this.mindMap.opt.marginY - walk(this.root, null, (node) => { - if (!node.isRoot && !node.parent.isRoot) { - // 判断子节点的areaHeight是否大于该节点自身,大于则需要调整位置 - if (node.children && node.children.length > 0) { - let difference = node.childrenAreaHeight - marginY - this.updateBrothersTopValue(node, difference) - } - } - }, null, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @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) { - this.updateChildren(item.children, 'top', _offset) - } - }) - // 更新父节点的位置 - this.updateBrothersTopValue(node.parent, addHeight) + renderLine(node) { + return []; + if (node.children.length <= 0) { + return []; } + let { + left, + top, + 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) => { + 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 + let y2 = item.top + item.height / 2 + let path = '' + if (node.isRoot) { + path = this.quadraticCurvePath(x1, y1, x2, y2) + } else { + path = this.cubicBezierPath(x1, y1, x2, y2) + } + let line = this.draw.path(path) + lines.push(line) + }) + return lines; } /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-07 11:25:52 - * @Desc: 更新子节点属性 + * @Author: 王林 + * @Date: 2021-04-11 19:54:26 + * @Desc: 渲染按钮 */ - updateChildren(children, prop, offset) { - children.forEach((item) => { - item[prop] += offset - if (item.children && item.children.length) { - this.updateChildren(item.children, prop, offset) - } + renderExpandBtn(node, icons) { + return; + let { + left, + top, + width, + height + } = node + icons.forEach((icon) => { + icon.x(left + width).y(top + height / 2) }) } } -export default Render \ No newline at end of file +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 73c32000..70f096ea 100644 --- a/simple-mind-map/src/layouts/LogicalStructure.js +++ b/simple-mind-map/src/layouts/LogicalStructure.js @@ -147,39 +147,6 @@ class LogicalStructure extends Base { } } - /** - * @Author: 王林 - * @Date: 2021-04-11 15:34:20 - * @Desc: 获取节点的marginY - */ - getMarginY(layerIndex) { - return layerIndex === 1 ? this.themeConfig.second.marginY : this.themeConfig.node.marginY; - } - - /** - * @Author: 王林 - * @Date: 2021-04-11 15:05:01 - * @Desc: 二次贝塞尔曲线 - */ - quadraticCurvePath(x1, y1, x2, y2) { - let cx = x1 + (x2 - x1) * 0.2 - let cy = y1 + (y2 - y1) * 0.8 - return `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` - } - - /** - * @Author: 王林 - * @Date: 2021-04-11 15:05:18 - * @Desc: 三次贝塞尔曲线 - */ - cubicBezierPath(x1, y1, x2, y2) { - let cx1 = x1 + (x2 - x1) / 2 - let cy1 = y1 - let cx2 = x2 - (x2 - x1) / 2 - let cy2 = y2 - return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}` - } - /** * @Author: 王林 * @Date: 2021-04-11 14:42:48 diff --git a/simple-mind-map/src/layouts/MindMap.js b/simple-mind-map/src/layouts/MindMap.js index cba93d07..c471f9a2 100644 --- a/simple-mind-map/src/layouts/MindMap.js +++ b/simple-mind-map/src/layouts/MindMap.js @@ -1,125 +1,131 @@ +import Base from './Base'; import { walk -} from '../Utils' +} from '../utils' import Node from '../Node' -import merge from 'deepmerge' /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:07 - * @Desc: 思维导图 + * @Author: 王林 + * @Date: 2021-04-12 22:25:58 + * @Desc: 思维导图 * 思路:在逻辑结构图的基础上增加一个变量来记录生长方向,向左还是向右,同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可 */ -class Render { +class MindMap extends Base { /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-08 16:25:32 + * @Author: 王林 + * @Date: 2021-04-12 22:26:31 * @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() + super(opt) } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-06 14:04:20 - * @Desc: 计算位置数据 + * @Desc: 布局 */ - computed() { - // 计算节点的left、width、height + doLayout() { + // 遍历数据计算节点的left、width、height this.computedBaseValue() // 计算节点的top this.computedTopValue() // 调整节点top this.adjustTopValue() + return this.root; } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-08 09:49:32 - * @Desc: 计算节点的left、width、height + * @Desc: 遍历数据计算节点的left、width、height */ computedBaseValue() { - walk(this.renderTree, null, (node, parent, isRoot, index) => { - // 生长方向 + walk(this.renderTree, null, (cur, parent, isRoot, layerIndex, index) => { + // 节点生长方向 let dir = '' if (isRoot) { dir = '' - } else if (parent._node.isRoot) { + } else if (parent._node.isRoot) {// 二级节点根据索引来判断显示在左侧还是右侧 dir = index % 2 === 0 ? 'right' : 'left' - } else { + } else {// 三级及以下节点以上级为准 dir = parent._node.dir } - // 设置left、width、height - let { - children, - ...props - } = node + // 创建节点 let newNode = new Node({ - ...props, + data: cur, + uid: this.mindMap.uid++, + renderer: this.renderer, mindMap: this.mindMap, draw: this.draw, - dir + layerIndex }) - // 计算节点的宽高 - newNode.refreshSize() - // 计算节点的left + 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 { - newNode.left = dir === 'right' ? parent._node.left + parent._node.width + this.mindMap.opt.marginX : parent._node.left - this.mindMap.opt.marginX - newNode.width + // 非根节点 + 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) } - node._node = newNode - }, (node) => { + }, (cur, parent, isRoot, layerIndex) => { // 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距 - let len = node._node.children.length - node._node.childrenAreaHeight = len ? node._node.children.reduce((h, cur) => { - return h + cur.height - }, 0) + (len + 1) * this.mindMap.opt.marginY : 0 - }, true) + if (cur.data.expand === false) { + cur._node.leftChildrenAreaHeight = 0 + cur._node.rightChildrenAreaHeight = 0 + return ; + } + let leftLen = 0 + let rightLen = 0 + let leftAreaHeight = 0 + let rightAreaHeight = 0 + cur._node.children.forEach((item) => { + if (item.dir === 'left') { + leftLen++ + leftAreaHeight += item.height + } else { + rightLen++ + rightAreaHeight += item.height + } + }) + cur._node.leftChildrenAreaHeight = leftAreaHeight + (leftLen + 1) * this.getMarginY(layerIndex) + cur._node.rightChildrenAreaHeight = rightAreaHeight + (rightLen + 1) * this.getMarginY(layerIndex) + }, true, 0) } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-08 09:59:25 - * @Desc: 计算节点的top + * @Desc: 遍历节点树计算节点的top */ computedTopValue() { - walk(this.root, null, (node) => { + walk(this.root, null, (node, parent, isRoot, layerIndex) => { if (node.children && node.children.length) { - // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 - let top = node.top + node.height / 2 - node.childrenAreaHeight / 2 - let totalTop = top + this.mindMap.opt.marginY + 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 node.children.forEach((cur) => { - cur.top = totalTop - totalTop += cur.height + this.mindMap.opt.marginY + if (cur.dir === 'left') { + cur.top = leftTotalTop + leftTotalTop += cur.height + marginY + } else { + cur.top = rightTotalTop + rightTotalTop += cur.height + marginY + } }) } }, null, true) @@ -132,12 +138,13 @@ class Render { * @Desc: 调整节点top */ adjustTopValue() { - let margin = this.mindMap.opt.marginY * 2 - walk(this.root, null, (node) => { + walk(this.root, null, (node, parent, isRoot, layerIndex) => { // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 - let difference = node.childrenAreaHeight - margin - node.height - if (difference > 0) { - this.updateBrothers(node, difference / 2) + let h = this.getMarginY(layerIndex) + node.height + let leftDifference = node.leftChildrenAreaHeight - h + let rightDifference = node.rightChildrenAreaHeight - h + if (leftDifference > 0 || rightDifference > 0) { + this.updateBrothers(node, leftDifference / 2, rightDifference / 2) } }, null, true) } @@ -148,7 +155,7 @@ class Render { * @Date: 2021-04-07 14:26:03 * @Desc: 更新兄弟节点的top */ - updateBrothers(node, addHeight) { + updateBrothers(node, leftAddHeight, rightAddHeight) { if (node.parent) { let childrenList = node.parent.children.filter((item) => { return item.dir === node.dir @@ -158,9 +165,11 @@ class Render { }) childrenList.forEach((item, _index) => { let _offset = 0 + let addHeight = item.dir === 'left' ? leftAddHeight : rightAddHeight + // 上面的节点往上移 if (_index < index) { _offset = -addHeight - } else if (_index > index) { + } else if (_index > index) {// 下面的节点往下移 _offset = addHeight } item.top += _offset @@ -170,26 +179,65 @@ class Render { } }) // 更新父节点的位置 - this.updateBrothers(node.parent, addHeight) + this.updateBrothers(node.parent, leftAddHeight, rightAddHeight) } } /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-07 11:25:52 - * @Desc: 更新子节点属性 + * @Author: 王林 + * @Date: 2021-04-11 14:42:48 + * @Desc: 绘制连线,连接该节点到其子节点 */ - updateChildren(children, prop, offset) { - children.forEach((item) => { - item[prop] += offset - if (item.children && item.children.length) { - this.updateChildren(item.children, prop, offset) + renderLine(node) { + if (node.children.length <= 0) { + return []; + } + let { + left, + top, + width, + 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 + let y1 = node.layerIndex === 0 ? top + height / 2 : top + height / 2 + let x2 = item.dir === 'right' ? item.left : item.left + item.width + let y2 = item.top + item.height / 2 + let path = '' + if (node.isRoot) { + path = this.quadraticCurvePath(x1, y1, x2, y2) + } else { + path = this.cubicBezierPath(x1, y1, x2, y2) } + let line = this.draw.path(path) + lines.push(line) }) + return lines; } - + /** + * @Author: 王林 + * @Date: 2021-04-11 19:54:26 + * @Desc: 渲染按钮 + */ + renderExpandBtn(node, icons) { + 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) + }) + } } -export default Render \ No newline at end of file +export default MindMap \ No newline at end of file diff --git a/simple-mind-map/src/layouts/Structure.js b/simple-mind-map/src/layouts/Structure.js deleted file mode 100644 index 2cc8c28c..00000000 --- a/simple-mind-map/src/layouts/Structure.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-12 17:21:04 - * @Desc: 基类 - */ -class Structure { - -} - -export default Structure \ No newline at end of file diff --git a/simple-mind-map/src/layouts/Fishbone.js b/simple-mind-map/src/layouts/_CatalogOrganization.js similarity index 56% rename from simple-mind-map/src/layouts/Fishbone.js rename to simple-mind-map/src/layouts/_CatalogOrganization.js index b42c644b..e2796840 100644 --- a/simple-mind-map/src/layouts/Fishbone.js +++ b/simple-mind-map/src/layouts/_CatalogOrganization.js @@ -8,7 +8,8 @@ import merge from 'deepmerge' * javascript comment * @Author: 王林25 * @Date: 2021-04-08 16:25:07 - * @Desc: 鱼骨图 + * @Desc: 目录组织图 + * 思路:第一轮只计算节点的宽高,以及某个节点的所有子节点所占的高度之和,以及该节点里所有子节点中宽度最宽是多少、第二轮计算节点的left和top,需要区分二级节点和其他节点,二级节点top相同,一行依次从做向右排开,其他节点的left相同,一列从上往下依次排开 */ class Render { /** @@ -50,9 +51,9 @@ class Render { // 计算节点的left、top this.computedLeftTopValue() // 调整节点top - // this.adjustTopValue() + this.adjustTopValue() // 调整节点left - // this.adjustLeftValue() + this.adjustLeftValue() } /** @@ -62,16 +63,7 @@ class Render { * @Desc: 计算节点的width、height */ computedBaseValue() { - walk(this.renderTree, null, (node, parent, isRoot, index, layerIndex) => { - // 生长方向 - let dir = '' - if (isRoot) { - dir = '' - } else if (parent._node.isRoot) { - dir = index % 2 === 0 ? 'up' : 'down' - } else { - dir = parent._node.dir - } + walk(this.renderTree, null, (node, parent, isRoot) => { // 设置width、height let { children, @@ -80,9 +72,7 @@ class Render { let newNode = new Node({ ...props, mindMap: this.mindMap, - draw: this.draw, - dir, - layerIndex + draw: this.draw }) // 计算节点的宽高 newNode.refreshSize() @@ -99,7 +89,13 @@ class Render { node._node = newNode }, (node) => { // 遍历完子节点返回时 + // 计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距 let len = node._node.children.length + if (node._node.isRoot) { + node._node.childrenAreaWidth = len ? node._node.children.reduce((h, cur) => { + return h + cur.width + }, 0) + (len + 1) * this.mindMap.opt.marginX : 0 + } node._node.childrenAreaHeight = len ? node._node.children.reduce((h, cur) => { return h + cur.height }, 0) + (len + 1) * this.mindMap.opt.marginY : 0 @@ -114,126 +110,24 @@ class Render { */ computedLeftTopValue() { walk(this.root, null, (node) => { - // 二级节点 - if (node.isRoot && node.children && node.children.length) { - let totalLeft = node.left + node.width + this.mindMap.opt.marginX - node.children.forEach((item) => { - item.left = totalLeft - item.top = node.top + node.height / 2 - this.mindMap.opt.marginY - item.height - totalLeft += item.width + this.mindMap.opt.marginX - this.computedThirdLevelLeftTopValue(item) - }) - } - }, null, true) - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-13 09:33:04 - * @Desc: 计算三级节点 - */ - computedThirdLevelLeftTopValue(node) { - if (node.children && node.children.length > 0) { - let totalLeft = node.left - let totalTop = node.top - this.mindMap.opt.marginY - node.children.forEach((item) => { - let h = node.height + this.mindMap.opt.marginY - let w = h / Math.tan(70) - item.left = totalLeft + w - totalLeft += w - item.top = totalTop - item.height - totalTop -= this.mindMap.opt.marginY + item.height - this.computedThirdAfterLevelLeftTopValue(item) - }) - } - } - - /** - * javascript comment - * @Author: 王林25 - * @Date: 2021-04-13 09:55:54 - * @Desc: 计算三级以后的节点 - */ - computedThirdAfterLevelLeftTopValue(root) { - let marginY = this.mindMap.opt.marginY - let marginX = this.mindMap.opt.marginX - // 计算left、top - walk(root, null, (node) => { if (node.children && node.children.length) { - let totalTop = node.top + node.height + marginY - node.children.forEach((cur) => { - cur.left = node.left + node.width / 5 + marginX - cur.top = totalTop - totalTop += cur.height + marginY - }) - } - }, null, true) - // 调整top - const updateBrothersTopValue = (node, addHeight) => { - 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 = addHeight - } - item.top += _offset - // 同步更新子节点的位置 - if (item.children && item.children.length) { - this.updateChildren(item.children, 'top', _offset) - } - }) - // 更新父节点的位置 - updateBrothersTopValue(node.parent, addHeight) - } - } - walk(root, null, (node) => { - // 判断子节点的areaHeight是否大于该节点自身,大于则需要调整位置 - if (node.children && node.children.length > 0) { - let difference = node.childrenAreaHeight - marginY - updateBrothersTopValue(node, difference) - } - }, null, true) - // 调整left - const updateBrothersLeftValue = (node, w, h) => { - if (node.parent && node.parent.layerIndex > 0) { - let childrenList = node.parent.children - let index = childrenList.findIndex((item) => { - return item === node - }) - childrenList.forEach((item, _index) => { - let _w = 0 - let _h = 0 - if (_index >= index) { - _w = w - _h = -h - } - console.log(item.text, _w, _h) - item.left += _w - item.top += _h - // 同步更新子节点的位置 - if (item.children && item.children.length) { - this.updateChildren(item.children, 'left', _w) - this.updateChildren(item.children, 'left', _h) - } - }) - // 更新父节点的位置 - updateBrothersLeftValue(node.parent, w, h) - } - } - walk(root, null, (node) => { - if (node.layerIndex > 1) { - let h = node.childrenAreaHeight - marginY - if (h > 0) { - let w = h / Math.tan(70) - console.log(node.text, w, h) - // let childrenAreaWidth = getNodeWidth(node) - // let differenceX = childrenAreaWidth - node.width - // updateBrothersLeftValue(node, w, h) + if (node.isRoot) { + let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 + let totalLeft = left + this.mindMap.opt.marginX + node.children.forEach((cur) => { + // left + cur.left = totalLeft + totalLeft += cur.width + this.mindMap.opt.marginX + // top + cur.top = node.top + node.height + this.mindMap.opt.marginY + }) + } else { + let totalTop = node.top + node.height + this.mindMap.opt.marginY + node.children.forEach((cur) => { + cur.left = node.left + node.width / 5 + this.mindMap.opt.marginX + cur.top = totalTop + totalTop += cur.height + this.mindMap.opt.marginY + }) } } }, null, true) diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/_OrganizationStructure.js similarity index 100% rename from simple-mind-map/src/layouts/OrganizationStructure.js rename to simple-mind-map/src/layouts/_OrganizationStructure.js diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 9588c686..47a4d50e 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -4,15 +4,15 @@ * @Date: 2021-04-06 14:13:17 * @Desc: 深度优先遍历树 */ -export const walk = (root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0) => { - beforeCallback && beforeCallback(root, parent, isRoot, layerIndex) +export const walk = (root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0) => { + beforeCallback && beforeCallback(root, parent, isRoot, layerIndex, index) if (root.children && root.children.length > 0) { let _layerIndex = layerIndex + 1 - root.children.forEach((node) => { - walk(node, root, beforeCallback, afterCallback, false, _layerIndex) + root.children.forEach((node, nodeIndex) => { + walk(node, root, beforeCallback, afterCallback, false, _layerIndex, nodeIndex) }) } - afterCallback && afterCallback(root, parent, isRoot, layerIndex) + afterCallback && afterCallback(root, parent, isRoot, layerIndex, index) } /** @@ -118,10 +118,10 @@ export const simpleDeepClone = (data) => { } /** - * @Author: 王林 - * @Date: 2021-05-04 14:40:11 - * @Desc: 复制渲染树数据 - */ + * @Author: 王林 + * @Date: 2021-05-04 14:40:11 + * @Desc: 复制渲染树数据 + */ export const copyRenderTree = (tree, root) => { tree.data = simpleDeepClone(root.data) tree.children = [] diff --git a/web/src/config/index.js b/web/src/config/index.js index 24650e59..242c65d7 100644 --- a/web/src/config/index.js +++ b/web/src/config/index.js @@ -205,4 +205,9 @@ export const backgroundPositionList = [ name: '中下', value: 'center bottom' } -] \ No newline at end of file +] + +// 数据存储 +export const store = { + sidebarZIndex: 1//侧边栏zIndex +} \ No newline at end of file diff --git a/web/src/pages/Edit/components/BaseStyle.vue b/web/src/pages/Edit/components/BaseStyle.vue index 13d4326c..20f841c6 100644 --- a/web/src/pages/Edit/components/BaseStyle.vue +++ b/web/src/pages/Edit/components/BaseStyle.vue @@ -227,13 +227,18 @@ diff --git a/web/src/pages/Edit/components/Sidebar.vue b/web/src/pages/Edit/components/Sidebar.vue index da4ae4a4..d0ddb6a3 100644 --- a/web/src/pages/Edit/components/Sidebar.vue +++ b/web/src/pages/Edit/components/Sidebar.vue @@ -1,5 +1,10 @@ @@ -43,11 +58,11 @@ export default { border-left: 1px solid #e8e8e8; display: flex; flex-direction: column; - transition: all 0.3s; + transition: all 0.3s; - &.show { - right: 0; - } + &.show { + right: 0; + } .closeBtn { position: absolute; diff --git a/web/src/pages/Edit/components/Structure.vue b/web/src/pages/Edit/components/Structure.vue new file mode 100644 index 00000000..6aaf7001 --- /dev/null +++ b/web/src/pages/Edit/components/Structure.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/web/src/pages/Edit/components/Style.vue b/web/src/pages/Edit/components/Style.vue index 3e0f279c..469df5a2 100644 --- a/web/src/pages/Edit/components/Style.vue +++ b/web/src/pages/Edit/components/Style.vue @@ -261,11 +261,14 @@ export default { }, created() { this.$bus.$on("node_active", (...args) => { - this.activeTab = "normal"; - let activeNodes = args[1]; - this.activeNode = activeNodes[0]; - this.$refs.sidebar.show = activeNodes.length > 0; - this.initNodeStyle(); + this.$refs.sidebar.show = false; + this.$nextTick(() => { + this.activeTab = "normal"; + let activeNodes = args[1]; + this.activeNode = activeNodes[0]; + this.$refs.sidebar.show = activeNodes.length > 0; + this.initNodeStyle(); + }); }); }, methods: { diff --git a/web/src/pages/Edit/components/Theme.vue b/web/src/pages/Edit/components/Theme.vue index 3b87b7a8..403433c6 100644 --- a/web/src/pages/Edit/components/Theme.vue +++ b/web/src/pages/Edit/components/Theme.vue @@ -44,8 +44,11 @@ export default { }, created() { this.$bus.$on("showTheme", () => { - this.theme = this.mindMap.getTheme(); - this.$refs.sidebar.show = true; + this.$refs.sidebar.show = false; + this.$nextTick(() => { + this.theme = this.mindMap.getTheme(); + this.$refs.sidebar.show = true; + }); }); }, methods: { diff --git a/web/src/pages/Edit/components/Toolbar.vue b/web/src/pages/Edit/components/Toolbar.vue index 32efc9fe..1fdc9895 100644 --- a/web/src/pages/Edit/components/Toolbar.vue +++ b/web/src/pages/Edit/components/Toolbar.vue @@ -98,6 +98,10 @@ 主题 +
+ + 结构 +