mind-map/web/src/pages/Edit/components/Edit.vue

1006 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div
class="editContainer"
@dragenter.stop.prevent="onDragenter"
@dragleave.stop.prevent
@dragover.stop.prevent
@drop.stop.prevent
>
<div
class="mindMapContainer"
id="mindMapContainer"
ref="mindMapContainer"
></div>
<Count :mindMap="mindMap" v-if="!isZenMode"></Count>
<Navigator v-if="mindMap" :mindMap="mindMap"></Navigator>
<NavigatorToolbar :mindMap="mindMap" v-if="!isZenMode"></NavigatorToolbar>
<OutlineSidebar :mindMap="mindMap"></OutlineSidebar>
<Style v-if="!isZenMode"></Style>
<BaseStyle
:data="mindMapData"
:configData="mindMapConfig"
:mindMap="mindMap"
></BaseStyle>
<AssociativeLineStyle
v-if="mindMap"
:mindMap="mindMap"
></AssociativeLineStyle>
<Theme v-if="mindMap" :data="mindMapData" :mindMap="mindMap"></Theme>
<Structure :mindMap="mindMap"></Structure>
<ShortcutKey></ShortcutKey>
<Contextmenu v-if="mindMap" :mindMap="mindMap"></Contextmenu>
<RichTextToolbar v-if="mindMap" :mindMap="mindMap"></RichTextToolbar>
<NodeNoteContentShow
v-if="mindMap"
:mindMap="mindMap"
></NodeNoteContentShow>
<NodeAttachment v-if="mindMap" :mindMap="mindMap"></NodeAttachment>
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
<Search v-if="mindMap" :mindMap="mindMap"></Search>
<NodeIconSidebar v-if="mindMap" :mindMap="mindMap"></NodeIconSidebar>
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
<SourceCodeEdit v-if="mindMap" :mindMap="mindMap"></SourceCodeEdit>
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
<Setting :configData="mindMapConfig" :mindMap="mindMap"></Setting>
<NodeImgPlacementToolbar
v-if="mindMap"
:mindMap="mindMap"
></NodeImgPlacementToolbar>
<AiCreate v-if="mindMap && enableAi" :mindMap="mindMap"></AiCreate>
<AiChat v-if="enableAi"></AiChat>
<div
class="dragMask"
v-if="showDragMask"
@dragleave.stop.prevent="onDragleave"
@dragover.stop.prevent
@drop.stop.prevent="onDrop"
>
<div class="dragTip">{{ $t('edit.dragTip') }}</div>
</div>
</div>
</template>
<script>
import MindMap from 'simple-mind-map'
import MiniMap from 'simple-mind-map/src/plugins/MiniMap.js'
import Watermark from 'simple-mind-map/src/plugins/Watermark.js'
import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF.js'
import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind.js'
import Export from 'simple-mind-map/src/plugins/Export.js'
import Drag from 'simple-mind-map/src/plugins/Drag.js'
import Select from 'simple-mind-map/src/plugins/Select.js'
import RichText from 'simple-mind-map/src/plugins/RichText.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
import Painter from 'simple-mind-map/src/plugins/Painter.js'
import ScrollbarPlugin from 'simple-mind-map/src/plugins/Scrollbar.js'
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'
// 以下插件为付费插件详情请查看开发文档。依次为手绘风格插件、标记插件、编号插件、Freemind软件格式导入导出插件、Excel软件格式导入导出插件、待办插件、节点连线流动效果插件、动量效果插件
import HandDrawnLikeStyle from 'simple-mind-map-plugin-handdrawnlikestyle'
import Notation from 'simple-mind-map-plugin-notation'
import Numbers from 'simple-mind-map-plugin-numbers'
import Freemind from 'simple-mind-map-plugin-freemind'
import Excel from 'simple-mind-map-plugin-excel'
import Checkbox from 'simple-mind-map-plugin-checkbox'
import LineFlow from 'simple-mind-map-plugin-lineflow'
import Momentum from 'simple-mind-map-plugin-momentum'
// npm link simple-mind-map-plugin-excel simple-mind-map-plugin-freemind simple-mind-map-plugin-numbers simple-mind-map-plugin-notation simple-mind-map-plugin-handdrawnlikestyle simple-mind-map-plugin-checkbox simple-mind-map simple-mind-map-plugin-themes simple-mind-map-plugin-lineflow simple-mind-map-plugin-momentum
import OutlineSidebar from './OutlineSidebar.vue'
import Style from './Style.vue'
import BaseStyle from './BaseStyle.vue'
import Theme from './Theme.vue'
import Structure from './Structure.vue'
import Count from './Count.vue'
import NavigatorToolbar from './NavigatorToolbar.vue'
import ShortcutKey from './ShortcutKey.vue'
import Contextmenu from './Contextmenu.vue'
import RichTextToolbar from './RichTextToolbar.vue'
import NodeNoteContentShow from './NodeNoteContentShow.vue'
import { getData, getConfig, storeData } from '@/api'
import Navigator from './Navigator.vue'
import NodeImgPreview from './NodeImgPreview.vue'
import SidebarTrigger from './SidebarTrigger.vue'
import { mapState } from 'vuex'
import icon from '@/config/icon'
import CustomNodeContent from './CustomNodeContent.vue'
import Color from './Color.vue'
import Vue from 'vue'
import router from '../../../router'
import store from '../../../store'
import i18n from '../../../i18n'
import Search from './Search.vue'
import NodeIconSidebar from './NodeIconSidebar.vue'
import NodeIconToolbar from './NodeIconToolbar.vue'
import OutlineEdit from './OutlineEdit.vue'
import { showLoading, hideLoading } from '@/utils/loading'
import handleClipboardText from '@/utils/handleClipboardText'
import Scrollbar from './Scrollbar.vue'
import exampleData from 'simple-mind-map/example/exampleData'
import FormulaSidebar from './FormulaSidebar.vue'
import SourceCodeEdit from './SourceCodeEdit.vue'
import NodeAttachment from './NodeAttachment.vue'
import NodeOuterFrame from './NodeOuterFrame.vue'
import NodeTagStyle from './NodeTagStyle.vue'
import Setting from './Setting.vue'
import AssociativeLineStyle from './AssociativeLineStyle.vue'
import NodeImgPlacementToolbar from './NodeImgPlacementToolbar.vue'
import AiCreate from './AiCreate.vue'
import AiChat from './AiChat.vue'
// 注册插件
MindMap.usePlugin(MiniMap)
.usePlugin(Watermark)
.usePlugin(Drag)
.usePlugin(KeyboardNavigation)
.usePlugin(ExportPDF)
.usePlugin(ExportXMind)
.usePlugin(Export)
.usePlugin(Select)
.usePlugin(AssociativeLine)
.usePlugin(NodeImgAdjust)
.usePlugin(TouchEvent)
.usePlugin(SearchPlugin)
.usePlugin(Painter)
.usePlugin(Formula)
.usePlugin(RainbowLines)
.usePlugin(Demonstrate)
.usePlugin(OuterFrame)
.usePlugin(MindMapLayoutPro)
// .usePlugin(Cooperate) // 协同插件
// 注册主题
Themes.init(MindMap)
export default {
components: {
OutlineSidebar,
Style,
BaseStyle,
Theme,
Structure,
Count,
NavigatorToolbar,
ShortcutKey,
Contextmenu,
RichTextToolbar,
NodeNoteContentShow,
Navigator,
NodeImgPreview,
SidebarTrigger,
Search,
NodeIconSidebar,
NodeIconToolbar,
OutlineEdit,
Scrollbar,
FormulaSidebar,
SourceCodeEdit,
NodeAttachment,
NodeOuterFrame,
NodeTagStyle,
Setting,
AssociativeLineStyle,
NodeImgPlacementToolbar,
AiCreate,
AiChat
},
data() {
return {
enableShowLoading: true,
mindMap: null,
mindMapData: null,
mindMapConfig: {},
prevImg: '',
storeConfigTimer: null,
showDragMask: false
}
},
computed: {
...mapState({
isZenMode: state => state.localConfig.isZenMode,
openNodeRichText: state => state.localConfig.openNodeRichText,
isShowScrollbar: state => state.localConfig.isShowScrollbar,
enableDragImport: state => state.localConfig.enableDragImport,
useLeftKeySelectionRightKeyDrag: state =>
state.localConfig.useLeftKeySelectionRightKeyDrag,
isUseHandDrawnLikeStyle: state =>
state.localConfig.isUseHandDrawnLikeStyle,
isUseMomentum: state => state.localConfig.isUseMomentum,
extraTextOnExport: state => state.extraTextOnExport,
isDragOutlineTreeNode: state => state.isDragOutlineTreeNode,
enableAi: state => state.localConfig.enableAi
})
},
watch: {
openNodeRichText() {
if (this.openNodeRichText) {
this.addRichTextPlugin()
} else {
this.removeRichTextPlugin()
}
},
isShowScrollbar() {
if (this.isShowScrollbar) {
this.addScrollbarPlugin()
} else {
this.removeScrollbarPlugin()
}
},
isUseHandDrawnLikeStyle() {
if (this.isUseHandDrawnLikeStyle) {
this.addHandDrawnLikeStylePlugin()
} else {
this.removeHandDrawnLikeStylePlugin()
}
},
isUseMomentum() {
if (this.isUseMomentum) {
this.addMomentumPlugin()
} else {
this.removeMomentumPlugin()
}
}
},
mounted() {
showLoading()
// this.showNewFeatureInfo()
this.getData()
this.init()
this.$bus.$on('execCommand', this.execCommand)
this.$bus.$on('paddingChange', this.onPaddingChange)
this.$bus.$on('export', this.export)
this.$bus.$on('setData', this.setData)
this.$bus.$on('startTextEdit', this.handleStartTextEdit)
this.$bus.$on('endTextEdit', this.handleEndTextEdit)
this.$bus.$on('createAssociativeLine', this.handleCreateLineFromActiveNode)
this.$bus.$on('startPainter', this.handleStartPainter)
this.$bus.$on('node_tree_render_end', this.handleHideLoading)
this.$bus.$on('showLoading', this.handleShowLoading)
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
this.$bus.$off('execCommand', this.execCommand)
this.$bus.$off('paddingChange', this.onPaddingChange)
this.$bus.$off('export', this.export)
this.$bus.$off('setData', this.setData)
this.$bus.$off('startTextEdit', this.handleStartTextEdit)
this.$bus.$off('endTextEdit', this.handleEndTextEdit)
this.$bus.$off('createAssociativeLine', this.handleCreateLineFromActiveNode)
this.$bus.$off('startPainter', this.handleStartPainter)
this.$bus.$off('node_tree_render_end', this.handleHideLoading)
this.$bus.$off('showLoading', this.handleShowLoading)
window.removeEventListener('resize', this.handleResize)
this.mindMap.destroy()
},
methods: {
handleStartTextEdit() {
this.mindMap.renderer.startTextEdit()
},
handleEndTextEdit() {
this.mindMap.renderer.endTextEdit()
},
handleCreateLineFromActiveNode() {
this.mindMap.associativeLine.createLineFromActiveNode()
},
handleStartPainter() {
this.mindMap.painter.startPainter()
},
handleResize() {
this.mindMap.resize()
},
// 显示loading
handleShowLoading() {
this.enableShowLoading = true
showLoading()
},
// 渲染结束后关闭loading
handleHideLoading() {
if (this.enableShowLoading) {
this.enableShowLoading = false
hideLoading()
}
},
// 获取思维导图数据,实际应该调接口获取
getData() {
this.mindMapData = getData()
this.mindMapConfig = getConfig() || {}
},
// 存储数据当数据有变时
bindSaveEvent() {
this.$bus.$on('data_change', data => {
storeData({ root: data })
})
this.$bus.$on('view_data_change', data => {
clearTimeout(this.storeConfigTimer)
this.storeConfigTimer = setTimeout(() => {
storeData({
view: data
})
}, 300)
})
},
// 手动保存
manualSave() {
storeData(this.mindMap.getData(true))
},
// 初始化
init() {
let hasFileURL = this.hasFileURL()
let { root, layout, theme, view } = this.mindMapData
const config = this.mindMapConfig
// 如果url中存在要打开的文件那么思维导图数据、主题、布局都使用默认的
if (hasFileURL) {
root = {
data: {
text: this.$t('edit.root')
},
children: []
}
layout = exampleData.layout
theme = exampleData.theme
view = null
}
this.mindMap = new MindMap({
el: this.$refs.mindMapContainer,
data: root,
fit: false,
layout: layout,
theme: theme.template,
themeConfig: theme.config,
viewData: view,
nodeTextEditZIndex: 1000,
nodeNoteTooltipZIndex: 1000,
customNoteContentShow: {
show: (content, left, top, node) => {
this.$bus.$emit('showNoteContent', content, left, top, node)
},
hide: () => {
// this.$bus.$emit('hideNoteContent')
}
},
openRealtimeRenderOnNodeTextEdit: true,
enableAutoEnterTextEditWhenKeydown: true,
...(config || {}),
iconList: [...icon],
useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
customInnerElsAppendTo: null,
customHandleClipboardText: handleClipboardText,
defaultNodeImage: require('../../../assets/img/图片加载失败.svg'),
initRootNodePosition: ['center', 'center'],
handleIsSplitByWrapOnPasteCreateNewNode: () => {
return this.$confirm(
this.$t('edit.splitByWrap'),
this.$t('edit.tip'),
{
confirmButtonText: this.$t('edit.yes'),
cancelButtonText: this.$t('edit.no'),
type: 'warning'
}
)
},
errorHandler: (code, err) => {
console.error(err)
switch (code) {
case 'export_error':
this.$message.error(this.$t('edit.exportError'))
break
default:
break
}
},
addContentToFooter: () => {
const text = this.extraTextOnExport.trim()
if (!text) return null
const el = document.createElement('div')
el.className = 'footer'
el.innerHTML = text
const cssText = `
.footer {
width: 100%;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
color: #979797;
}
`
return {
el,
cssText,
height: 30
}
},
expandBtnNumHandler: num => {
return num >= 100 ? '…' : num
},
beforeDeleteNodeImg: node => {
return new Promise(resolve => {
this.$confirm(
this.$t('edit.deleteNodeImgTip'),
this.$t('edit.tip'),
{
confirmButtonText: this.$t('edit.yes'),
cancelButtonText: this.$t('edit.no'),
type: 'warning'
}
)
.then(() => {
resolve(false)
})
.catch(() => {
resolve(true)
})
})
}
// createNodePrefixContent: node => {
// const el = document.createElement('div')
// el.style.width = '50px'
// el.style.height = '50px'
// el.style.background = 'red'
// return {
// el,
// width: 50,
// height: 50
// }
// },
// createNodePostfixContent: node => {
// const domparser = new DOMParser()
// const doc = domparser.parseFromString(
// '<b style="background-color: rgb(214, 239, 214);">白日依山尽</b>',
// 'text/html'
// )
// const el = doc.querySelector('b')
// return {
// el,
// width: 50,
// height: 50
// }
// },
// addContentToHeader: () => {
// const el = document.createElement('div')
// el.className = 'footer'
// el.innerHTML = '理想青年实验室'
// const cssText = `
// .header {
// width: 100%;
// height: 50px;
// background: #f5f5f5;
// display: flex;
// justify-content: center;
// align-items: center
// }
// `
// return {
// el,
// cssText,
// height: 50
// }
// },
// beforeShortcutRun: (key, activeNodeList) => {
// console.log(key, activeNodeList)
// // 阻止删除快捷键行为
// if (key === 'Backspace') {
// return true
// }
// }
// handleNodePasteImg: img => {
// console.log(img)
// return new Promise(resolve => {
// setTimeout(() => {
// resolve({
// url: require('../../../assets/img/themes/autumn.jpg'),
// size: {
// width: 100,
// height: 100
// }
// })
// }, 200)
// })
// }
// isUseCustomNodeContent: true,
// 示例1组件里用到了router、store、i18n等实例化vue组件时需要用到的东西
// customCreateNodeContent: (node) => {
// let el = document.createElement('div')
// let Comp = Vue.extend(Color)
// let comp = new Comp({
// router,
// store,
// i18n
// })
// comp.$mount(el)
// return comp.$el
// },
// 示例2组件里没有用到示例1的东西
// customCreateNodeContent: (node) => {
// let el = document.createElement('div')
// let Comp = Vue.extend(CustomNodeContent)
// let comp = new Comp({
// propsData: {
// html: node.nodeData.data.text
// }
// })
// comp.$mount(el)
// return comp.$el
// },
// 示例3普通元素
// customCreateNodeContent: node => {
// let el = document.createElement('div')
// el.style.cssText = `
// width: 203px;
// height: 78px;
// opacity: 0.8;
// background-image: linear-gradient(0deg, rgba(53,130,172,0.06) 0%, rgba(24,75,116,0.06) 100%);
// box-shadow: inset 0 1px 15px 0 rgba(119,196,255,0.40);
// border-radius: 2px;
// display: flex;
// justify-content: center;
// align-items: center;
// `
// el.innerHTML = `
// ${node.nodeData.data.text}
// <img crossOrigin="anonymous" src="/img/cactus.jpg" />
// `
// return el
// }
})
this.loadPlugins()
this.mindMap.keyCommand.addShortcut('Control+s', () => {
this.manualSave()
})
// 转发事件
;[
'node_active',
'data_change',
'view_data_change',
'back_forward',
'node_contextmenu',
'node_click',
'draw_click',
'expand_btn_click',
'svg_mousedown',
'mouseup',
'mode_change',
'node_tree_render_end',
'rich_text_selection_change',
'transforming-dom-to-images',
'generalization_node_contextmenu',
'painter_start',
'painter_end',
'scrollbar_change',
'scale',
'translate',
'node_attachmentClick',
'node_attachmentContextmenu',
'demonstrate_jump',
'exit_demonstrate',
'node_note_dblclick',
'node_mousedown'
].forEach(event => {
this.mindMap.on(event, (...args) => {
this.$bus.$emit(event, ...args)
})
})
this.bindSaveEvent()
this.testDynamicCreateNodes()
// 如果应用被接管,那么抛出事件传递思维导图实例
if (window.takeOverApp) {
this.$bus.$emit('app_inited', this.mindMap)
}
// 解析url中的文件
if (hasFileURL) {
this.$bus.$emit('handle_file_url')
}
// api/index.js文件使用
// 当正在编辑本地文件时通过该方法获取最新数据
Vue.prototype.getCurrentData = () => {
const fullData = this.mindMap.getData(true)
return { ...fullData }
}
// 协同测试
this.cooperateTest()
// 销毁
// setTimeout(() => {
// console.log('销毁')
// this.mindMap.destroy()
// }, 10000)
// 测试
// setTimeout(() => {
// console.log(this.mindMap.renderer.root.getRect())
// console.log(this.mindMap.renderer.root.getRectInSvg())
// }, 5000);
// setTimeout(() => {
// this.mindMap.renderer.renderTree.data.fillColor = 'red'
// this.mindMap.render()
// this.mindMap.reRender()
// this.mindMap.render()
// }, 5000)
},
// 加载相关插件
loadPlugins() {
if (this.openNodeRichText) this.addRichTextPlugin()
if (this.isShowScrollbar) this.addScrollbarPlugin()
if (typeof HandDrawnLikeStyle !== 'undefined') {
this.$store.commit('setSupportHandDrawnLikeStyle', true)
if (this.isUseHandDrawnLikeStyle) this.addHandDrawnLikeStylePlugin()
}
if (typeof Momentum !== 'undefined') {
this.$store.commit('setSupportMomentum', true)
if (this.isUseMomentum) this.addMomentumPlugin()
}
if (typeof Notation !== 'undefined') {
this.mindMap.addPlugin(Notation)
this.$store.commit('setSupportMark', true)
}
if (typeof Numbers !== 'undefined') {
this.mindMap.addPlugin(Numbers)
this.$store.commit('setSupportNumbers', true)
}
if (typeof Freemind !== 'undefined') {
this.mindMap.addPlugin(Freemind)
this.$store.commit('setSupportFreemind', true)
Vue.prototype.Freemind = Freemind
}
if (typeof Excel !== 'undefined') {
this.mindMap.addPlugin(Excel)
this.$store.commit('setSupportExcel', true)
Vue.prototype.Excel = Excel
}
if (typeof Checkbox !== 'undefined') {
this.mindMap.addPlugin(Checkbox)
this.$store.commit('setSupportCheckbox', true)
}
if (typeof LineFlow !== 'undefined') {
this.mindMap.addPlugin(LineFlow)
this.$store.commit('setSupportLineFlow', true)
}
},
// url中是否存在要打开的文件
hasFileURL() {
const fileURL = this.$route.query.fileURL
if (!fileURL) return false
return /\.(smm|json|xmind|md|xlsx)$/.test(fileURL)
},
// 动态设置思维导图数据
setData(data) {
this.handleShowLoading()
let rootNodeData = null
if (data.root) {
this.mindMap.setFullData(data)
rootNodeData = data.root
} else {
this.mindMap.setData(data)
rootNodeData = data
}
this.mindMap.view.reset()
this.manualSave()
// 如果导入的是富文本内容,那么自动开启富文本模式
if (rootNodeData.data.richText && !this.openNodeRichText) {
this.$bus.$emit('toggleOpenNodeRichText', true)
this.$notify.info({
title: this.$t('edit.tip'),
message: this.$t('edit.autoOpenNodeRichTextTip')
})
}
},
// 重新渲染
reRender() {
this.mindMap.reRender()
},
// 执行命令
execCommand(...args) {
this.mindMap.execCommand(...args)
},
// 导出
async export(...args) {
try {
showLoading()
await this.mindMap.export(...args)
hideLoading()
} catch (error) {
console.log(error)
hideLoading()
}
},
// 修改导出内边距
onPaddingChange(data) {
this.mindMap.updateConfig(data)
},
// 显示新特性提示
showNewFeatureInfo() {
let showed = localStorage.getItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1')
if (!showed) {
this.$notify.info({
title: this.$t('edit.newFeatureNoticeTitle'),
message: this.$t('edit.newFeatureNoticeMessage'),
duration: 0,
onClose: () => {
localStorage.setItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1', true)
}
})
}
},
// 加载节点富文本编辑插件
addRichTextPlugin() {
if (!this.mindMap) return
this.mindMap.addPlugin(RichText)
},
// 移除节点富文本编辑插件
removeRichTextPlugin() {
this.mindMap.removePlugin(RichText)
},
// 加载滚动条插件
addScrollbarPlugin() {
if (!this.mindMap) return
this.mindMap.addPlugin(ScrollbarPlugin)
},
// 移除滚动条插件
removeScrollbarPlugin() {
this.mindMap.removePlugin(ScrollbarPlugin)
},
// 加载手绘风格插件
addHandDrawnLikeStylePlugin() {
try {
if (!this.mindMap) return
this.mindMap.addPlugin(HandDrawnLikeStyle)
this.mindMap.reRender()
} catch (error) {
console.log('手绘风格插件不存在')
}
},
// 移除手绘风格插件
removeHandDrawnLikeStylePlugin() {
try {
this.mindMap.removePlugin(HandDrawnLikeStyle)
this.mindMap.reRender()
} catch (error) {
console.log('手绘风格插件不存在')
}
},
// 加载动量效果插件
addMomentumPlugin() {
try {
if (!this.mindMap) return
this.mindMap.addPlugin(Momentum)
} catch (error) {
console.log('动量效果插件不存在')
}
},
// 移除动量效果插件
removeMomentumPlugin() {
try {
this.mindMap.removePlugin(Momentum)
} catch (error) {
console.log('动量效果插件不存在')
}
},
// 测试动态插入节点
testDynamicCreateNodes() {
// return
setTimeout(() => {
// 动态给指定节点添加子节点
// this.mindMap.execCommand(
// 'INSERT_CHILD_NODE',
// false,
// null,
// {
// text: '自定义内容'
// },
// [
// {
// data: {
// text: '自定义子节点'
// }
// }
// ]
// )
// 动态给指定节点添加同级节点
// this.mindMap.execCommand(
// 'INSERT_NODE',
// false,
// null,
// {
// text: '自定义内容'
// },
// [
// {
// data: {
// text: '自定义同级节点'
// },
// children: [
// {
// data: {
// text: '自定义同级节点2'
// },
// children: []
// }
// ]
// }
// ]
// )
// 动态插入多个子节点
// this.mindMap.execCommand('INSERT_MULTI_CHILD_NODE', null, [
// {
// data: {
// text: '自定义节点1'
// },
// children: [
// {
// data: {
// text: '自定义节点1-1'
// },
// children: []
// }
// ]
// },
// {
// data: {
// text: '自定义节点2'
// },
// children: [
// {
// data: {
// text: '自定义节点2-1'
// },
// children: []
// }
// ]
// }
// ])
// 动态插入多个同级节点
// this.mindMap.execCommand('INSERT_MULTI_NODE', null, [
// {
// data: {
// text: '自定义节点1'
// },
// children: [
// {
// data: {
// text: '自定义节点1-1'
// },
// children: []
// }
// ]
// },
// {
// data: {
// text: '自定义节点2'
// },
// children: [
// {
// data: {
// text: '自定义节点2-1'
// },
// children: []
// }
// ]
// }
// ])
// 动态删除指定节点
// this.mindMap.execCommand('REMOVE_NODE', this.mindMap.renderer.root.children[0])
}, 5000)
},
// 协同测试
cooperateTest() {
if (this.mindMap.cooperate && this.$route.query.userName) {
this.mindMap.cooperate.setProvider(null, {
roomName: 'demo-room',
signalingList: ['ws://localhost:4444']
})
this.mindMap.cooperate.setUserInfo({
id: Math.random(),
name: this.$route.query.userName,
color: ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399'][
Math.floor(Math.random() * 5)
],
avatar:
Math.random() > 0.5
? 'https://img0.baidu.com/it/u=4270674549,2416627993&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1696006800&t=4d32871d14a7224a4591d0c3c7a97311'
: ''
})
}
},
// 拖拽文件到页面导入
onDragenter() {
if (!this.enableDragImport || this.isDragOutlineTreeNode) return
this.showDragMask = true
},
onDragleave() {
this.showDragMask = false
},
onDrop(e) {
if (!this.enableDragImport) return
this.showDragMask = false
const dt = e.dataTransfer
const file = dt.files && dt.files[0]
if (!file) return
this.$bus.$emit('importFile', file)
}
}
}
</script>
<style lang="less" scoped>
.editContainer {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
.dragMask {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 3999;
.dragTip {
pointer-events: none;
font-weight: bold;
}
}
.mindMapContainer {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
// left: 100px;
// top: 100px;
// right: 100px;
// bottom: 100px;
}
}
</style>