Feat:新增改变[思维导图]布局结构行为的插件,使之更符合目前主流思维导图的做法

This commit is contained in:
街角小林
2024-12-09 18:32:54 +08:00
parent 2a76f5a0bc
commit 322975528e
4 changed files with 140 additions and 49 deletions

View File

@@ -172,7 +172,8 @@ export const nodeDataNoStylePropList = [
'customLeft',
'customTop',
'customTextWidth',
'checkbox'
'checkbox',
'dir'
]
// 错误类型

View File

@@ -35,7 +35,14 @@ class MindMap extends Base {
this.renderer.renderTree,
null,
(cur, parent, isRoot, layerIndex, index, ancestors) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex, index, ancestors)
let newNode = this.createNode(
cur,
parent,
isRoot,
layerIndex,
index,
ancestors
)
// 根节点定位在画布中心位置
if (isRoot) {
this.setNodeCenter(newNode)
@@ -47,9 +54,10 @@ class MindMap extends Base {
} else {
// 节点生长方向
newNode.dir =
index % 2 === 0
newNode.getData('dir') ||
(index % 2 === 0
? CONSTANTS.LAYOUT_GROW_DIR.RIGHT
: CONSTANTS.LAYOUT_GROW_DIR.LEFT
: CONSTANTS.LAYOUT_GROW_DIR.LEFT)
}
// 根据生长方向定位到父节点的左侧或右侧
newNode.left =

View File

@@ -0,0 +1,117 @@
import { CONSTANTS } from '../constants/constant'
// 该插件会向节点数据的data中添加dir字段
/*
需要更新数据的情况:
1.实例化时的数据
2.调用setData和updateData方法
3.执行完命令
4.切换结构
*/
class MindMapLayoutPro {
constructor(opt) {
this.opt = opt
this.mindMap = opt.mindMap
this.init()
}
init() {
this.updateNodeTree = this.updateNodeTree.bind(this)
this.afterExecCommand = this.afterExecCommand.bind(this)
this.layoutChange = this.layoutChange.bind(this)
// 处理实例化时传入的数据
if (this.mindMap.opt.data && this.isMindMapLayout()) {
this.updateNodeTree(this.mindMap.opt.data)
}
this.mindMap.on('layout_change', this.layoutChange)
this.mindMap.on('afterExecCommand', this.afterExecCommand)
this.mindMap.on('before_update_data', this.updateNodeTree)
this.mindMap.on('before_set_data', this.updateNodeTree)
}
restore() {
this.mindMap.off('layout_change', this.layoutChange)
this.mindMap.off('afterExecCommand', this.afterExecCommand)
this.mindMap.off('before_update_data', this.updateNodeTree)
this.mindMap.off('before_set_data', this.updateNodeTree)
}
// 监听命令执行后的事件
afterExecCommand(name) {
if (!this.isMindMapLayout()) return
if (
![
'BACK',
'FORWARD',
'INSERT_NODE',
'INSERT_MULTI_NODE',
'INSERT_CHILD_NODE',
'INSERT_MULTI_CHILD_NODE',
'INSERT_PARENT_NODE',
'UP_NODE',
'DOWN_NODE',
'MOVE_UP_ONE_LEVEL',
'INSERT_AFTER',
'INSERT_BEFORE',
'MOVE_NODE_TO',
'REMOVE_NODE',
'REMOVE_CURRENT_NODE',
'PASTE_NODE',
'CUT_NODE'
].includes(name)
)
return
this.updateRenderTree()
}
// 更新布局结构
layoutChange(layout) {
if (layout === CONSTANTS.LAYOUT.MIND_MAP) {
this.updateRenderTree()
}
}
// 更新当前的渲染树
updateRenderTree() {
this.updateNodeTree(this.mindMap.renderer.renderTree)
}
// 更新节点树,修改二级节点的排列位置
updateNodeTree(tree) {
if (!this.isMindMapLayout()) return
const root = tree
const childrenLength = root.children.length
if (childrenLength <= 0) return
const center = Math.ceil(childrenLength / 2)
root.children.forEach((item, index) => {
if (index + 1 <= center) {
item.data.dir = CONSTANTS.LAYOUT_GROW_DIR.RIGHT
} else {
item.data.dir = CONSTANTS.LAYOUT_GROW_DIR.LEFT
}
})
}
// 判断当前是否是思维导图布局结构
isMindMapLayout() {
return this.mindMap.opt.layout === CONSTANTS.LAYOUT.MIND_MAP
}
// 插件被移除前做的事情
beforePluginRemove() {
this.restore()
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.restore()
}
}
MindMapLayoutPro.instanceName = 'mindMapLayoutPro'
export default MindMapLayoutPro

View File

@@ -72,6 +72,7 @@ import Formula from 'simple-mind-map/src/plugins/Formula.js'
import RainbowLines from 'simple-mind-map/src/plugins/RainbowLines.js'
import Demonstrate from 'simple-mind-map/src/plugins/Demonstrate.js'
import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
import MindMapLayoutPro from 'simple-mind-map/src/plugins/MindMapLayoutPro.js'
import Themes from 'simple-mind-map-plugin-themes'
// 协同编辑插件
// import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
@@ -140,16 +141,12 @@ MindMap.usePlugin(MiniMap)
.usePlugin(RainbowLines)
.usePlugin(Demonstrate)
.usePlugin(OuterFrame)
.usePlugin(MindMapLayoutPro)
// .usePlugin(Cooperate) // 协同插件
// 注册主题
Themes.init(MindMap)
/**
* @Author: 王林
* @Date: 2021-06-24 22:56:17
* @Desc: 编辑区域
*/
export default {
name: 'Edit',
components: {
@@ -291,21 +288,13 @@ export default {
}
},
/**
* @Author: 王林
* @Date: 2021-07-03 22:11:37
* @Desc: 获取思维导图数据,实际应该调接口获取
*/
// 获取思维导图数据,实际应该调接口获取
getData() {
let storeData = getData()
this.mindMapData = storeData
},
/**
* @Author: 王林
* @Date: 2021-08-01 10:19:07
* @Desc: 存储数据当数据有变时
*/
// 存储数据当数据有变时
bindSaveEvent() {
this.$bus.$on('data_change', data => {
storeData(data)
@@ -320,21 +309,13 @@ export default {
})
},
/**
* @Author: 王林
* @Date: 2021-08-02 23:19:52
* @Desc: 手动保存
*/
// 手动保存
manualSave() {
let data = this.mindMap.getData(true)
storeConfig(data)
},
/**
* @Author: 王林
* @Date: 2021-04-10 15:01:01
* @Desc: 初始化
*/
// 初始化
init() {
let hasFileURL = this.hasFileURL()
let { root, layout, theme, view, config } = this.mindMapData
@@ -664,11 +645,7 @@ export default {
return /\.(smm|json|xmind|md|xlsx)$/.test(fileURL)
},
/**
* @Author: 王林
* @Date: 2021-08-03 23:01:13
* @Desc: 动态设置思维导图数据
*/
// 动态设置思维导图数据
setData(data) {
this.handleShowLoading()
if (data.root) {
@@ -680,29 +657,17 @@ export default {
this.manualSave()
},
/**
* @Author: 王林
* @Date: 2021-05-05 13:32:11
* @Desc: 重新渲染
*/
// 重新渲染
reRender() {
this.mindMap.reRender()
},
/**
* @Author: 王林
* @Date: 2021-05-04 13:08:28
* @Desc: 执行命令
*/
// 执行命令
execCommand(...args) {
this.mindMap.execCommand(...args)
},
/**
* @Author: 王林
* @Date: 2021-07-01 22:33:02
* @Desc: 导出
*/
// 导出
async export(...args) {
try {
showLoading()