Merge branch 'feature' into main

This commit is contained in:
wanglin2 2023-04-21 10:08:11 +08:00
commit cf16937160
34 changed files with 937 additions and 67 deletions

File diff suppressed because one or more lines are too long

View File

@ -101,7 +101,9 @@ const defaultOpt = {
// 节点备注浮层的z-index
nodeNoteTooltipZIndex: 3000,
// 是否在点击了画布外的区域时结束节点文本的编辑状态
isEndNodeTextEditOnClickOuter: true
isEndNodeTextEditOnClickOuter: true,
// 最大历史记录数
maxHistoryCount: 1000
}
// 思维导图

View File

@ -1,6 +1,6 @@
{
"name": "simple-mind-map",
"version": "0.5.5-fix.2",
"version": "0.5.6",
"description": "一个简单的web在线思维导图",
"authors": [
{

View File

@ -84,6 +84,10 @@ class Command {
// 删除当前历史指针后面的数据
this.history = this.history.slice(0, this.activeHistoryIndex + 1)
this.history.push(simpleDeepClone(data))
// 历史记录数超过最大数量
if (this.history.length > this.mindMap.opt.maxHistoryCount) {
this.history.shift()
}
this.activeHistoryIndex = this.history.length - 1
this.mindMap.emit('data_change', this.removeDataUid(data))
this.mindMap.emit(

View File

@ -389,7 +389,7 @@ class Node {
// 右键菜单事件
this.group.on('contextmenu', e => {
// 按住ctrl键点击鼠标左键不知为何触发的是contextmenu事件
if (this.mindMap.opt.readonly || this.isGeneralization || e.ctrlKey) {
if (this.mindMap.opt.readonly || e.ctrlKey) {// || this.isGeneralization
return
}
e.stopPropagation()

View File

@ -250,6 +250,7 @@ class Render {
// 渲染
render(callback = () => {}, source) {
let t = Date.now()
// 如果当前还没有渲染完毕,不再触发渲染
if (this.isRendering) {
// 等待当前渲染完毕后再进行一次渲染
@ -281,7 +282,7 @@ class Render {
// 更新根节点
this.root = root
// 渲染节点
this.root.render(() => {
const onEnd = () => {
this.isRendering = false
this.mindMap.emit('node_tree_render_end')
callback && callback()
@ -289,6 +290,18 @@ class Render {
this.hasWaitRendering = false
this.render(callback, source)
}
}
let { enableNodeTransitionMove, nodeTransitionMoveDuration } =
this.mindMap.opt
this.root.render(() => {
let dur = Date.now() - t
if (enableNodeTransitionMove && dur <= nodeTransitionMoveDuration) {
setTimeout(() => {
onEnd()
}, nodeTransitionMoveDuration - dur);
} else {
onEnd()
}
})
})
this.mindMap.emit('node_active', null, this.activeNodeList)

View File

@ -1,6 +1,5 @@
import Quill from 'quill'
import 'quill/dist/quill.snow.css'
import './css/quill.css'
import html2canvas from 'html2canvas'
import { Image as SvgImage } from '@svgdotjs/svg.js'
import { walk } from './utils'
@ -41,8 +40,43 @@ class RichText {
this.range = null
this.lastRange = null
this.node = null
this.styleEl = null
this.cacheEditingText = ''
this.initOpt()
this.extendQuill()
this.appendCss()
}
// 插入样式
appendCss() {
let cssText = `
.ql-editor {
overflow: hidden;
padding: 0;
height: auto;
line-height: normal;
}
.ql-container {
height: auto;
font-size: inherit;
}
.ql-container.ql-snow {
border: none;
}
`
// .smm-richtext-node-wrap p {
// display: flex;
// }
// .smm-richtext-node-edit-wrap p {
// display: flex;
// }
this.styleEl = document.createElement('style')
this.styleEl.type = 'text/css'
this.styleEl.innerHTML = cssText
document.head.appendChild(this.styleEl)
}
// 处理选项参数
@ -96,9 +130,12 @@ class RichText {
if (!rect) rect = node._textData.node.node.getBoundingClientRect()
this.mindMap.emit('before_show_text_edit')
this.mindMap.renderer.textEdit.registerTmpShortcut()
const paddingX = 5
const paddingY = 3
if (!this.textEditNode) {
this.textEditNode = document.createElement('div')
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;box-shadow: 0 0 20px rgba(0,0,0,.5);outline: none; word-break: break-all;padding: 3px 5px;margin-left: -5px;margin-top: -3px;`
this.textEditNode.classList.add('smm-richtext-node-edit-wrap')
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;box-shadow: 0 0 20px rgba(0,0,0,.5);outline: none; word-break: break-all;padding: ${paddingY}px ${paddingX}px;margin-left: -${paddingX}px;margin-top: -${paddingY}px;`
this.textEditNode.addEventListener('click', e => {
e.stopPropagation()
})
@ -112,14 +149,14 @@ class RichText {
let bgColor = node.style.merge('fillColor')
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
this.textEditNode.style.backgroundColor = bgColor === 'transparent' ? '#fff' : bgColor
this.textEditNode.style.minWidth = originWidth + 'px'
this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
this.textEditNode.style.minHeight = originHeight + 'px'
this.textEditNode.style.left =
rect.left + (rect.width - originWidth) / 2 + 'px'
this.textEditNode.style.top =
rect.top + (rect.height - originHeight) / 2 + 'px'
this.textEditNode.style.display = 'block'
this.textEditNode.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + 'px'
this.textEditNode.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + paddingX * 2 + 'px'
this.textEditNode.style.transform = `scale(${rect.width / originWidth}, ${
rect.height / originHeight
})`
@ -127,9 +164,9 @@ class RichText {
// 还不是富文本的情况
let text = node.nodeData.data.text.split(/\n/gim).join('<br>')
let html = `<p>${text}</p>`
this.textEditNode.innerHTML = html
this.textEditNode.innerHTML = this.cacheEditingText || html
} else {
this.textEditNode.innerHTML = node.nodeData.data.text
this.textEditNode.innerHTML = this.cacheEditingText || node.nodeData.data.text
}
this.initQuillEditor()
document.querySelector('.ql-editor').style.minHeight = originHeight + 'px'
@ -139,6 +176,7 @@ class RichText {
// 如果是非富文本的情况,需要手动应用文本样式
this.setTextStyleIfNotRichText(node)
}
this.cacheEditingText = ''
}
// 如果是非富文本的情况,需要手动应用文本样式
@ -155,14 +193,19 @@ class RichText {
this.formatAllText(style)
}
// 获取当前正在编辑的内容
getEditText() {
let html = this.quill.container.firstChild.innerHTML
// 去除最后的空行
return html.replace(/<p><br><\/p>$/, '')
}
// 隐藏文本编辑控件,即完成编辑
hideEditText(nodes) {
if (!this.showTextEdit) {
return
}
let html = this.quill.container.firstChild.innerHTML
// 去除最后的空行
html = html.replace(/<p><br><\/p>$/, '')
let html = this.getEditText()
let list = nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList
list.forEach(node => {
this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
@ -458,6 +501,7 @@ class RichText {
// 插件被移除前做的事情
beforePluginRemove() {
this.transformAllNodesToNormalNode()
document.head.removeChild(this.styleEl)
}
}

View File

@ -6,16 +6,21 @@ export default class TextEdit {
constructor(renderer) {
this.renderer = renderer
this.mindMap = renderer.mindMap
// 当前编辑的节点
this.currentNode = null
// 文本编辑框
this.textEditNode = null
// 文本编辑框是否显示
this.showTextEdit = false
// 如果编辑过程中缩放画布了,那么缓存当前编辑的内容
this.cacheEditingText = ''
this.bindEvent()
}
// 事件
bindEvent() {
this.show = this.show.bind(this)
this.onScale = this.onScale.bind(this)
// 节点双击事件
this.mindMap.on('node_dblclick', this.show)
// 点击事件
@ -48,6 +53,7 @@ export default class TextEdit {
}
this.show(this.renderer.activeNodeList[0])
})
this.mindMap.on('scale', this.onScale)
}
// 注册临时快捷键
@ -60,6 +66,7 @@ export default class TextEdit {
// 显示文本编辑框
show(node) {
this.currentNode = node
let { offsetLeft, offsetTop } = checkNodeOuter(this.mindMap, node)
this.mindMap.view.translateXY(offsetLeft, offsetTop)
let rect = node._textData.node.node.getBoundingClientRect()
@ -70,6 +77,19 @@ export default class TextEdit {
this.showEditTextBox(node, rect)
}
// 处理画布缩放
onScale() {
if (!this.currentNode) return
if (this.mindMap.richText) {
this.mindMap.richText.cacheEditingText = this.mindMap.richText.getEditText()
this.mindMap.richText.showTextEdit = false
} else {
this.cacheEditingText = this.getEditText()
this.showTextEdit = false
}
this.show(this.currentNode)
}
// 显示文本编辑框
showEditTextBox(node, rect) {
this.mindMap.emit('before_show_text_edit')
@ -89,7 +109,7 @@ export default class TextEdit {
let scale = this.mindMap.view.scale
let lineHeight = node.style.merge('lineHeight')
let fontSize = node.style.merge('fontSize')
let textLines = node.nodeData.data.text.split(/\n/gim)
let textLines = (this.cacheEditingText || node.nodeData.data.text).split(/\n/gim)
node.style.domText(this.textEditNode, scale, textLines.length)
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
this.textEditNode.innerHTML = textLines.join('<br>')
@ -104,7 +124,10 @@ export default class TextEdit {
}
this.showTextEdit = true
// 选中文本
this.selectNodeText()
if (!this.cacheEditingText) {
this.selectNodeText()
}
this.cacheEditingText = ''
}
// 选中文本
@ -116,8 +139,14 @@ export default class TextEdit {
selection.addRange(range)
}
// 获取当前正在编辑的内容
getEditText() {
return getStrWithBrFromHtml(this.textEditNode.innerHTML)
}
// 隐藏文本编辑框
hideEditTextBox() {
this.currentNode = null
if (this.mindMap.richText) {
return this.mindMap.richText.hideEditText()
}
@ -125,7 +154,7 @@ export default class TextEdit {
return
}
this.renderer.activeNodeList.forEach(node => {
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
let str = this.getEditText()
this.mindMap.execCommand('SET_NODE_TEXT', node, str)
if (node.isGeneralization) {
// 概要节点

View File

@ -1,11 +0,0 @@
.ql-editor {
overflow: hidden;
padding: 0;
height: auto;
line-height: normal;
}
.ql-container {
height: auto;
font-size: inherit;
}

View File

@ -57,6 +57,7 @@ function createRichTextNode() {
div.innerHTML = html
div.style.cssText = `position: fixed; left: -999999px;`
let el = div.children[0]
el.classList.add('smm-richtext-node-wrap')
el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml')
el.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + 'px'
this.mindMap.el.appendChild(div)
@ -100,11 +101,13 @@ function createTextNode() {
let lines = []
let line = []
while (arr.length) {
line.push(arr.shift())
let text = line.join('')
if (measureText(text, textStyle).width >= maxWidth) {
lines.push(text)
line = []
let str = arr.shift()
let text = [...line, str].join('')
if (measureText(text, textStyle).width <= maxWidth) {
line.push(str)
} else {
lines.push(line.join(''))
line = [str]
}
}
if (line.length > 0) {

View File

@ -1,11 +1,21 @@
# Changelog
## 0.5.6
Fix: 1.Fix the issue of node position disorder during fast and multiple renderings in a short period of time. 2.Fix the issue of dragging the canvas while the node is being edited, causing the edit box and node to separate.
New: 1.Add a maximum history limit.
## 0.5.5-fix.1
Fix: 1.Fix the issue where the edit box is also outside the canvas when editing nodes outside the canvas. 2.After modifying the structure, reset the transformation to prevent the problem of sudden position changes during the first drag after switching the structure during scaling.
optimization: 1.When multiple nodes are selected, as long as there is a cross between the node and the selection area, it is considered selected.
## 0.5.5-fix.2
Fix: 1.Fix mini map error.
## 0.5.5
New: 1.Supports configuring the padding when exporting to PNG, SVG, or PDF. 2.Support the configuration of z-index for node text editing boxes and node comment floating layer elements. 3.Support clicking on areas outside the canvas to end node editing status.

View File

@ -1,9 +1,14 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.5.6</h2>
<p>Fix: 1.Fix the issue of node position disorder during fast and multiple renderings in a short period of time. 2.Fix the issue of dragging the canvas while the node is being edited, causing the edit box and node to separate.</p>
<p>New: 1.Add a maximum history limit.</p>
<h2>0.5.5-fix.1</h2>
<p>Fix: 1.Fix the issue where the edit box is also outside the canvas when editing nodes outside the canvas. 2.After modifying the structure, reset the transformation to prevent the problem of sudden position changes during the first drag after switching the structure during scaling.</p>
<p>optimization: 1.When multiple nodes are selected, as long as there is a cross between the node and the selection area, it is considered selected.</p>
<h2>0.5.5-fix.2</h2>
<p>Fix: 1.Fix mini map error.</p>
<h2>0.5.5</h2>
<p>New: 1.Supports configuring the padding when exporting to PNG, SVG, or PDF. 2.Support the configuration of z-index for node text editing boxes and node comment floating layer elements. 3.Support clicking on areas outside the canvas to end node editing status.</p>
<h2>0.5.4</h2>

View File

@ -58,6 +58,7 @@ const mindMap = new MindMap({
| nodeTextEditZIndexv0.5.5+ | Number | 3000 | | z-index of node text edit box elements |
| nodeNoteTooltipZIndexv0.5.5+ | Number | 3000 | z-index of floating layer elements in node comments | |
| isEndNodeTextEditOnClickOuterv0.5.5+ | Boolean | true | Whether to end the editing status of node text when clicking on an area outside the canvas | |
| maxHistoryCountv0.5.6+ | Number | 1000 | | Maximum number of history records |
### Watermark config

View File

@ -266,6 +266,13 @@
<td>Whether to end the editing status of node text when clicking on an area outside the canvas</td>
<td></td>
</tr>
<tr>
<td>maxHistoryCountv0.5.6+</td>
<td>Number</td>
<td>1000</td>
<td></td>
<td>Maximum number of history records</td>
</tr>
</tbody>
</table>
<h3>Watermark config</h3>

View File

@ -24,9 +24,8 @@ MindMap.xmind
### xmind.parseXmindFile(file)
Parsing the `.xmind` file and returning the parsed data. Note that this is
complete data, including the node tree, theme, and structure. You can use
`mindMap.setFullData(data)` to render the returned data to the canvas.
Parsing the `.xmind` file and returning the parsed data. You can use
`mindMap.setData(data)` to render the returned data to the canvas.
`file`: `File` object
@ -35,9 +34,8 @@ complete data, including the node tree, theme, and structure. You can use
Convert `xmind` data. The `.xmind` file is essentially a `zip` file that can be
decompressed by changing the suffix to zip. Inside, there is a `content.json`
file. If you have parsed this file yourself, you can pass the contents of this
file to this method for conversion. The converted data is the complete data,
including the node tree, theme, structure, etc. You can use
`mindMap.setFullData(data)` to render the returned data to the canvas.
file to this method for conversion. You can use
`mindMap.setData(data)` to render the returned data to the canvas.
`content`: the contents of the `content.json` file within the `.xmind` zip
package

View File

@ -15,17 +15,15 @@
</code></pre>
<h2>Methods</h2>
<h3>xmind.parseXmindFile(file)</h3>
<p>Parsing the <code>.xmind</code> file and returning the parsed data. Note that this is
complete data, including the node tree, theme, and structure. You can use
<code>mindMap.setFullData(data)</code> to render the returned data to the canvas.</p>
<p>Parsing the <code>.xmind</code> file and returning the parsed data. You can use
<code>mindMap.setData(data)</code> to render the returned data to the canvas.</p>
<p><code>file</code>: <code>File</code> object</p>
<h3>xmind.transformXmind(content)</h3>
<p>Convert <code>xmind</code> data. The <code>.xmind</code> file is essentially a <code>zip</code> file that can be
decompressed by changing the suffix to zip. Inside, there is a <code>content.json</code>
file. If you have parsed this file yourself, you can pass the contents of this
file to this method for conversion. The converted data is the complete data,
including the node tree, theme, structure, etc. You can use
<code>mindMap.setFullData(data)</code> to render the returned data to the canvas.</p>
file to this method for conversion. You can use
<code>mindMap.setData(data)</code> to render the returned data to the canvas.</p>
<p><code>content</code>: the contents of the <code>content.json</code> file within the <code>.xmind</code> zip
package</p>
<h3>xmind.transformOldXmind(content)</h3>

View File

@ -1,5 +1,11 @@
# Changelog
## 0.5.6
修复1.修复短时间快速多次渲染时节点位置错乱的问题。 2.修复节点正在编辑中时拖动画布导致编辑框和节点分离的问题。
新增1.添加最大历史记录数限制。
## 0.5.5
新增1.支持配置导出为png、svg、pdf时的内边距。 2.支持配置节点文本编辑框、节点备注浮层元素的z-index。 3.支持点击画布外的区域结束节点编辑状态。
@ -10,6 +16,10 @@
优化1.节点多选时只要节点和选区存在交叉即认为被选中。
## 0.5.5-fix.2
修复1.修复小地图报错。
## 0.5.4
新增1.添加新主题。 2.新增时间轴和鱼骨结构。

View File

@ -1,11 +1,16 @@
<template>
<div>
<h1>Changelog</h1>
<h2>0.5.6</h2>
<p>修复1.修复短时间快速多次渲染时节点位置错乱的问题 2.修复节点正在编辑中时拖动画布导致编辑框和节点分离的问题</p>
<p>新增1.添加最大历史记录数限制</p>
<h2>0.5.5</h2>
<p>新增1.支持配置导出为pngsvgpdf时的内边距 2.支持配置节点文本编辑框节点备注浮层元素的z-index 3.支持点击画布外的区域结束节点编辑状态</p>
<h2>0.5.5-fix.1</h2>
<p>修复1.修复节点在画布外编辑时编辑框也在画布外的问题 2.修改结构后复位变换防止存在缩放时切换结构后第一次拖动时会发生位置突变的问题</p>
<p>优化1.节点多选时只要节点和选区存在交叉即认为被选中</p>
<h2>0.5.5-fix.2</h2>
<p>修复1.修复小地图报错</p>
<h2>0.5.4</h2>
<p>新增1.添加新主题 2.新增时间轴和鱼骨结构</p>
<p>修复1.修复节点右键和画布右键的冲突问题 2.修复组织结构图目录组织图等节点拖拽时存在线段未隐藏的bug</p>

View File

@ -58,6 +58,7 @@ const mindMap = new MindMap({
| nodeTextEditZIndexv0.5.5+ | Number | 3000 | 节点文本编辑框元素的z-index | |
| nodeNoteTooltipZIndexv0.5.5+ | Number | 3000 | 节点备注浮层元素的z-index | |
| isEndNodeTextEditOnClickOuterv0.5.5+ | Boolean | true | 是否在点击了画布外的区域时结束节点文本的编辑状态 | |
| maxHistoryCountv0.5.6+ | Number | 1000 | 最大历史记录数 | |
### 水印配置

View File

@ -266,6 +266,13 @@
<td>是否在点击了画布外的区域时结束节点文本的编辑状态</td>
<td></td>
</tr>
<tr>
<td>maxHistoryCountv0.5.6+</td>
<td>Number</td>
<td>1000</td>
<td>最大历史记录数</td>
<td></td>
</tr>
</tbody>
</table>
<h3>水印配置</h3>

View File

@ -1,6 +1,6 @@
# 结构
`simple-mind-map`目前支持四种结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图
`simple-mind-map`目前支持四种结构logicalStructure逻辑结构图、mindMap思维导图、organizationStructure组织结构图、catalogOrganization目录组织图、timeline时间轴、timeline2时间轴2、fishbone鱼骨图
可以在实例化`simple-mind-map`时通过选项指定使用的结构:

View File

@ -1,7 +1,7 @@
<template>
<div>
<h1>结构</h1>
<p><code>simple-mind-map</code>目前支持四种结构logicalStructure逻辑结构图mindMap思维导图organizationStructure组织结构图catalogOrganization目录组织图</p>
<p><code>simple-mind-map</code>目前支持四种结构logicalStructure逻辑结构图mindMap思维导图organizationStructure组织结构图catalogOrganization目录组织图timeline时间轴timeline2时间轴2fishbone鱼骨图</p>
<p>可以在实例化<code>simple-mind-map</code>时通过选项指定使用的结构</p>
<pre class="hljs"><code><span class="hljs-keyword">new</span> MindMap({
<span class="hljs-comment">// ...</span>

View File

@ -1,3 +1,101 @@
# 如何渲染富文本的悬浮工具栏
> 要支持节点富文本编辑需要使用富文本插件
> 要支持节点富文本编辑需要使用富文本插件
如果开启了节点富文本编辑,那么可以对节点内的部分文本应用样式,一般当选中文本时上方会出现一个工具栏,有加粗、斜体、改变颜色等等的按钮。
首先要监听`rich_text_selection_change`事件,也就是选中文本的事件:
```js
mindMap.on('rich_text_selection_change', (hasRange, rect, formatInfo) => {
// hasRange是否存在选区
// rectInfo选区的尺寸和位置信息
// formatInfo选区的文本格式化信息
// 显示你的工具栏
})
```
可以通过`hasRange`来判断是否显示工具栏,工具栏的位置可以通过`rectInfo`获取,通过`formatInfo`可以获取当前选中文本的样式信息,比如已经被加粗了,那么你的加粗按钮就可以渲染为激活状态。
### 工具栏定位
```js
let left = rect.left + rect.width / 2 + 'px'
let top = rect.top - 60 + 'px'
```
计算出来的是相对于浏览器窗口左上角的位置所以你的工具栏元素最好是添加在body元素下面并且使用固定定位或相对定位另外`z-index`的属性最好也设置的高一点,否则在弹窗等场景下可能会被挡住。
### 加粗/取消加粗
```js
mindMap.richText.formatText({
bold: true/false
})
```
### 斜体/取消斜体
```js
mindMap.richText.formatText({
italic: true/false
})
```
### 下划线/取消下划线
```js
mindMap.richText.formatText({
underline: true/false
})
```
### 删除线/取消删除线
```js
mindMap.richText.formatText({
strike: true/false
})
```
### 设置字体
```js
mindMap.richText.formatText({
font: '宋体, SimSun, Songti SC'
})
```
### 设置字号
```js
mindMap.richText.formatText({
font: 16 + 'px'
})
```
### 设置文字颜色
```js
mindMap.richText.formatText({
color: '#fff'
})
```
### 设置文字背景颜色
```js
mindMap.richText.formatText({
background: '#fff'
})
```
### 清除样式
```js
mindMap.richText.removeFormat()
```
## 完整示例
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVk+P20QU/yqDUWUHEiegcjHZUlpA6mERWhUJialWjj2OB8Yzlj1Otkp96akUJCQOcOFQceHeA6J74ct0u+Vb8N6M/202aXMjUaKZN7/3fm/m/ZnZOJ/mub+qmBM48zIqeK5JyXSV36KSZ7kqNNmQgiVjouSxqqRm8ZiUaSiEWp+whNQkKVRGXLDgdhrHXMbHYW6XqFOCWLBJBtJJFubUoZIQKgXTBGWIPCKyEoJKKiMlS3AhVev7SolFWMAa8HtJKEo2atcFS3SzMOuEWqGhq7KoKgom9ReqyEJ9TyaqQWxqgPSKy6Vgd5SIYdUbkaNbZIM+XlP2V6GomL+wyHfetI76ze78gkfpfXam/cQgcegZAkIQGryRCHHobL3t79cyZoXgkh3mdDWA7/W8Ax3ofoffv4crJrc2EqWhXLK7SigM8wGbiBqoW7AY8u0gH41O0Kt0PnQZ7Q2YBxnJ1m0mt6aYCEisoioD3/wl058LhsM7D+/Fntto3lVSh7Ddwh2NrVYc6jCw1vFDHRRQZyCyYg1Oo5g6r569eP308eXjF7ZW8FM3xhAYpVzEcD4I/ra3sWVuJ8s208vzny7P/9wmu0q4g/RBvzbE/U8etMNG1upxyfWJUvpLFbOvVMk1VxI0XWwe7pi4EYQOwvTAwOvRx7Yt9TmlpOdiXp2is6clEyxCE6c2a8GCl4blCY7H0FMiPSY2+TBf+4QCP5IeOeoPA92waW16UqR909Xet+M1j3VKpuRDELj5GWQu1fiFJndVCbvehNycdTg8KwDuKSFQG4TD932vd5o8ekRMY9w6VyxWJZgv1NLbY7ZRalQG7btjbU8AN2JKEH7zqb1y4LKBiWZwT4SawYyQecxXJBJhWR5Rp4nIZyxT1DHLDYDH/WpXeACZT2F1CGwtaesVdchqwhMQDFwFYVDqh4KBeIOxCEyMxnixBPhXd+RgdVFBLCS5HQkefW8st5cIoDabHS3MXBufEPfi519f/fXk4umzy+e/uQQ6UzOs6/nUWn0bS9f691H1zb7je/n3jxdPfrk8/8dQ9rNDWAd9Ghj//eP31z8839LqT7wdzaeDgMLUHK1B3G7eCdTxp/Zx0PRZn5WZH5Uldbpi9AexbzPX1EZAPpjNbhgcIXlX3gUDRr5iZsGkI/7e3c6R1lSvGC4gxyttFW11BmTWzEwGtJPr9CnjyxTgN2ez/Kxl3s37XsuchcWSA29rNQ/jmMtlK+hchwK376C3eayLUJZYzJCrOMST/8abfDS7YVsbWIR6M0Fwxo4NAb7H/O9KJeH5Z+zTZgFC0PVt6sDrzjZrfwpDv4Bbk2cMozVZFGpdsgKMUKfpuztefFb3eqxRq/Gtdur/AJ09jnE=" />

View File

@ -4,7 +4,66 @@
<blockquote>
<p>要支持节点富文本编辑需要使用富文本插件</p>
</blockquote>
<p>如果开启了节点富文本编辑那么可以对节点内的部分文本应用样式一般当选中文本时上方会出现一个工具栏有加粗斜体改变颜色等等的按钮</p>
<p>首先要监听<code>rich_text_selection_change</code>事件也就是选中文本的事件</p>
<pre class="hljs"><code>mindMap.on(<span class="hljs-string">&#x27;rich_text_selection_change&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">hasRange, rect, formatInfo</span>) =&gt;</span> {
<span class="hljs-comment">// hasRange</span>
<span class="hljs-comment">// rectInfo</span>
<span class="hljs-comment">// formatInfo</span>
<span class="hljs-comment">// </span>
})
</code></pre>
<p>可以通过<code>hasRange</code>来判断是否显示工具栏工具栏的位置可以通过<code>rectInfo</code>获取通过<code>formatInfo</code>可以获取当前选中文本的样式信息比如已经被加粗了那么你的加粗按钮就可以渲染为激活状态</p>
<h3>工具栏定位</h3>
<pre class="hljs"><code><span class="hljs-keyword">let</span> left = rect.left + rect.width / <span class="hljs-number">2</span> + <span class="hljs-string">&#x27;px&#x27;</span>
<span class="hljs-keyword">let</span> top = rect.top - <span class="hljs-number">60</span> + <span class="hljs-string">&#x27;px&#x27;</span>
</code></pre>
<p>计算出来的是相对于浏览器窗口左上角的位置所以你的工具栏元素最好是添加在body元素下面并且使用固定定位或相对定位另外<code>z-index</code>的属性最好也设置的高一点否则在弹窗等场景下可能会被挡住</p>
<h3>加粗/取消加粗</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">bold</span>: <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span>
})
</code></pre>
<h3>斜体/取消斜体</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">italic</span>: <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span>
})
</code></pre>
<h3>下划线/取消下划线</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">underline</span>: <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span>
})
</code></pre>
<h3>删除线/取消删除线</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">strike</span>: <span class="hljs-literal">true</span>/<span class="hljs-literal">false</span>
})
</code></pre>
<h3>设置字体</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">font</span>: <span class="hljs-string">&#x27;宋体, SimSun, Songti SC&#x27;</span>
})
</code></pre>
<h3>设置字号</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">font</span>: <span class="hljs-number">16</span> + <span class="hljs-string">&#x27;px&#x27;</span>
})
</code></pre>
<h3>设置文字颜色</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">color</span>: <span class="hljs-string">&#x27;#fff&#x27;</span>
})
</code></pre>
<h3>设置文字背景颜色</h3>
<pre class="hljs"><code>mindMap.richText.formatText({
<span class="hljs-attr">background</span>: <span class="hljs-string">&#x27;#fff&#x27;</span>
})
</code></pre>
<h3>清除样式</h3>
<pre class="hljs"><code>mindMap.richText.removeFormat()
</code></pre>
<h2>完整示例</h2>
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVk+P20QU/yqDUWUHEiegcjHZUlpA6mERWhUJialWjj2OB8Yzlj1Otkp96akUJCQOcOFQceHeA6J74ct0u+Vb8N6M/202aXMjUaKZN7/3fm/m/ZnZOJ/mub+qmBM48zIqeK5JyXSV36KSZ7kqNNmQgiVjouSxqqRm8ZiUaSiEWp+whNQkKVRGXLDgdhrHXMbHYW6XqFOCWLBJBtJJFubUoZIQKgXTBGWIPCKyEoJKKiMlS3AhVev7SolFWMAa8HtJKEo2atcFS3SzMOuEWqGhq7KoKgom9ReqyEJ9TyaqQWxqgPSKy6Vgd5SIYdUbkaNbZIM+XlP2V6GomL+wyHfetI76ze78gkfpfXam/cQgcegZAkIQGryRCHHobL3t79cyZoXgkh3mdDWA7/W8Ax3ofoffv4crJrc2EqWhXLK7SigM8wGbiBqoW7AY8u0gH41O0Kt0PnQZ7Q2YBxnJ1m0mt6aYCEisoioD3/wl058LhsM7D+/Fntto3lVSh7Ddwh2NrVYc6jCw1vFDHRRQZyCyYg1Oo5g6r569eP308eXjF7ZW8FM3xhAYpVzEcD4I/ra3sWVuJ8s208vzny7P/9wmu0q4g/RBvzbE/U8etMNG1upxyfWJUvpLFbOvVMk1VxI0XWwe7pi4EYQOwvTAwOvRx7Yt9TmlpOdiXp2is6clEyxCE6c2a8GCl4blCY7H0FMiPSY2+TBf+4QCP5IeOeoPA92waW16UqR909Xet+M1j3VKpuRDELj5GWQu1fiFJndVCbvehNycdTg8KwDuKSFQG4TD932vd5o8ekRMY9w6VyxWJZgv1NLbY7ZRalQG7btjbU8AN2JKEH7zqb1y4LKBiWZwT4SawYyQecxXJBJhWR5Rp4nIZyxT1DHLDYDH/WpXeACZT2F1CGwtaesVdchqwhMQDFwFYVDqh4KBeIOxCEyMxnixBPhXd+RgdVFBLCS5HQkefW8st5cIoDabHS3MXBufEPfi519f/fXk4umzy+e/uQQ6UzOs6/nUWn0bS9f691H1zb7je/n3jxdPfrk8/8dQ9rNDWAd9Ghj//eP31z8839LqT7wdzaeDgMLUHK1B3G7eCdTxp/Zx0PRZn5WZH5Uldbpi9AexbzPX1EZAPpjNbhgcIXlX3gUDRr5iZsGkI/7e3c6R1lSvGC4gxyttFW11BmTWzEwGtJPr9CnjyxTgN2ez/Kxl3s37XsuchcWSA29rNQ/jmMtlK+hchwK376C3eayLUJZYzJCrOMST/8abfDS7YVsbWIR6M0Fwxo4NAb7H/O9KJeH5Z+zTZgFC0PVt6sDrzjZrfwpDv4Bbk2cMozVZFGpdsgKMUKfpuztefFb3eqxRq/Gtdur/AJ09jnE=" />
</div>
</template>

View File

@ -1,3 +1,245 @@
# 导入和导出
编写中。。。
## 导出
> 要使用导出功能需要使用导出插件。
目前支持导出为`.smm`、`.json`、`.svg`、`.png`、`.pdf`、`.md`文件。
`.smm`是`simple-mind-map`自己定义的一种文件,其实就是`json`文件,换了一个扩展名而已。
导出直接调用`export`方法即可。
### 导出为smm、json
这两种文件的导出是一样的:
```js
mindMap.export(type, isDownload, fileName, withConfig)
```
`withConfig`指定导出的数据中是否要包含节点数据外的配置数据,比如使用的布局、主题等,传`true`,导出的结构如下:
```js
{
layout,
root,
theme: {
template,
config
},
view
}
```
如果传`false`,导出的数据只有`root`部分,也就是纯节点树。
示例:
```js
mindMap.export('smm', true, '文件名', true)
mindMap.export('json', true, '文件名', false)
```
### 导出为png、pdf
导出这两种文件很简单:
```js
mindMap.export('png', true, '文件名')
mindMap.export('pdf', true, '文件名')
```
如果开启了节点富文本编辑,那么导出会非常慢,因为需要挨个转换节点,所以如果导出操作很频繁的话建议关闭节点非文本编辑功能。
### 导出为svg
导出为`svg`可以传递的参数如下:
```js
mindMap.export(type, isDownload, fileName, domToImage = false, plusCssText = '')
```
如果开启了节点富文本编辑功能,那么可以通过`domToImage`参数控制导出的`svg`中是否保留`html`结构,还是转换成图片形式,同样,如果传了`true`,导出会非常耗时,建议导出为`svg`时`domToImage`传`false`。
如果`domToImage`传的是`false`,也就是`svg`中会保留节点的`html`结构,这就又存在一个问题,因为浏览器对每个元素默认会设置一些样式,影响最大的就是`margin`和`padding`,这就有可能会导致节点中的文字错位,所以可以通过`plusCssText`参数传入`css`样式:
```js
mindMap.export(
'svg',
true,
'文件名',
false,
`* {
margin: 0;
padding: 0;
box-sizing: border-box;
}`
)
```
### 导出为md
导出为`markdown`文件只要传递默认的三个参数即可:
```js
mindMap.export('md', true, '文件名')
```
## 导入
目前支持从`.smm`、`.json`、`.xmind`、`.xlsx`、`.md`格式的文件导入。
### 导入smm、json
这两个文件导入很简单,直接读取文件内容,转成对象,然后调用相关方法渲染到画布即可。
因为导出这两种类型时可以选择是否包含配置数据,所以导入的时候调用的方法也是不一样的:
```js
let data = JSON.parse('json数据')
// 如果数据中存在root属性那么代表是包含配置的完整数据则使用setFullData方法导入数据
if (data.root) {
mindMap.setFullData(data)
} else {
// 否则使用setData方法导入
mindMap.setData(data)
}
// 导入数据后有可能新数据渲染在可视区域外了,所以为了更好的体验,可以复位一下视图的变换
mindMap.view.reset()
```
### 导入xmind
要导入`xmind`文件,需要引入`xmind`的解析方法:
```js
import xmind from 'simple-mind-map/src/parse/xmind.js'
```
如果使用的是`umd`文件,可以这样获取:
```js
MindMap.xmind
```
如果你是通过`input type=file`等方式获取到的`File`文件对象,那么可以直接传递给`parseXmindFile`方法解析,注意返回的是一个`Promise`实例,会返回解析后的节点树数据,使用`setData`方法渲染到画布即可。
```js
let data = await xmind.parseXmindFile(file)
mindMap.setData(data)
```
`.xmind`文件本质上是一个压缩包,改成`zip`后缀可以解压缩,里面存在一个`content.json`文件,如果你自己解析出了这个文件,那么可以把这个文件内容传递给这个`transformXmind`方法进行转换:
```js
let data = await xmind.transformXmind(fileContent)
mindMap.setData(data)
```
另外如果导入的是`xmind8`版本的数据,需要使用`transformOldXmind`方法。
### 导入xlsx
这个文件的导入没有内置方法,需要你自己开发,以下是一个使用`xlsx`库的方式:
```js
import { read, utils } from 'xlsx'
// 文件转buffer
export const fileToBuffer = file => {
return new Promise(r => {
const reader = new FileReader()
reader.onload = () => {
r(reader.result)
}
reader.readAsArrayBuffer(file)
})
}
// File文件对象
const transformXLSXToJson = async (file) => {
const wb = read(await fileToBuffer(file))
const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {
header: 1
})
if (data.length <= 0) {
return
}
let max = 0
data.forEach(arr => {
if (arr.length > max) {
max = arr.length
}
})
let layers = []
let walk = layer => {
if (!layers[layer]) {
layers[layer] = []
}
for (let i = 0; i < data.length; i++) {
if (data[i][layer]) {
let node = {
data: {
text: data[i][layer]
},
children: [],
_row: i
}
layers[layer].push(node)
}
}
if (layer < max - 1) {
walk(layer + 1)
}
}
walk(0)
let getParent = (arr, row) => {
for (let i = arr.length - 1; i >= 0; i--) {
if (row >= arr[i]._row) {
return arr[i]
}
}
}
for (let i = 1; i < layers.length; i++) {
let arr = layers[i]
for (let j = 0; j < arr.length; j++) {
let item = arr[j]
let parent = getParent(layers[i - 1], item._row)
if (parent) {
parent.children.push(item)
}
}
}
return layers[0][0]
}
let data = transformXLSXToJson('xlsx文件对象')
mindMap.setData(data)
```
### 导入md
要导入`markdown`文件需要引入相应的解析方法:
```js
import markdown from 'simple-mind-map/src/parse/markdown.js'
```
如果使用的是umd格式的文件那么可以通过如下方式获取
```js
MindMap.markdown
```
获取到`md`文件的内容后调用`transformMarkdownTo`方法转换即可,返回一个`Promise`实例:
```js
let data = await markdown.transformMarkdownTo('md文件内容')
mindMap.setData(data)
```
### 完整示例
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFV81u20YQfpUN24JUoVAK0JMrB3YbB0gApYGTQ4EwhzW5kuiQu8TuypJhC0iDJkHaBsglPfXQQ4Oil7intnb7NvVf36KzfxRNUXUuQQ3bImdnvm925tsf7XnrRRHujIm34vVEzNNCIkHkuLge0TQvGJdoD3EyaCNG+2xMJUnaSIxwlrHJJhmgGRpwliMfEPwyop/SpI8LMxR5AswZuZqD9WqOi8iLKEIRzYhEyqY8VxEdZ1lEI9rpoJODv06evjn9/vnxn79FNGZUSGC/RYuxBMeAtNDqdbSnQBTEIM0ImEkoMR8SGap38aD70I1zMoThThSFgcjz/ami3N8WjO5PMzHdz5PWhx3lmw5QcAWcQ0mEDBRKSHFOWi1DhRDOCJeBf37w+z+PX5x++0sIcH8//ipUWOpTI+sHwFWfeWLm4LcMAIe6cpgiQjNHWKalQCCRpeQjTJOM3MtzPagBZ4hkgpQwmv5ShC+V13IMyPxSiI1pTLKlEPnlOfSrCUQUfk3bf/r67NWzalUvSqAsgRKBBljQwSbBCeFKTWSCbpaGQFPNHUIOH+viPpmaLOvDjGYMJ0pUO6A4y4GQ5Lvu0VAmWGLwun3vizthgbkgAQQ4HXIixpm0rTfdlrsFYQMTdmV1Fflsa5vE0i/ro1lGnE30BDY4ZzzwTRVOnj09eXt4+sOL84MDJygrJPUDa/YGwAYK247OUIxlPIIFo3AqHKqcDHqTsaEdswHNDdHCamqF1hLMH4tdGtdbUilWpVR4gtNyfzDIpnIaS3Vs3pCGSS2ZUvOEGmYC8m6aiFb0solA+NnrN3WsHPNHCZs0SrS/tCjvS6eG7N3UerEFbh6h5JiKAeN531rus/9Q83uRm9n2X/96+vKtK6jlUSteU5XzU8tJWULOmCzJ7HESQthNOE/q4tEb1aJrzU39c6M7KZmouROpelPN9PnR8R9HapNyqZKpOvvWxW2wqXxVrprLYRmHwFdBfhv6MyZt5Fb3q5dgGmBIsImnoMM6zV2qjjXNYqZUp4GYJhYHXx7nwSKGFabVSGArRrIVlLB4nBMqQ9DERkbU42e7t5LAt5GfMypxSgn3W20Tpeq6MhdD5ClD5FVMxixB5Moceac/Hp5/8+TsyaG5KGipWDDlGI/SLOGEKucHc4waXCNLnen46Luzo5/rZBcJG0j11WLR73/KwD1am4tLaSo3YW3cYQm5y0QqU0Yh0s/IQIIu/BhaB216qN1nrU9BFiCNXsfcAeH2By+SwMUNSwJvCPWSdAfFGRZiNfJsu2+QnEWeHrYOaTIfLcUALr0OjFYdHZJkLNvCysUMRrKX6pueOixhXG13kYfWtBHe7UWw9Ae4rbGUsObW4iyNH4FLdSWC34XV2usY78ujYYFVg2E51WLnU3JPvU6lYvAq5G5mirdmb8aRF3bMddhtwETkYSxE5EEH1K0YobBSXKeeSZrI0Qq61u1+pP0QKsqecgKM6Q7RA1oO6u+DehMc1DwQb8G+PJYmUJ0RA7mCuvZNsmL+skg/IulwBO6fdLvF1DE3835cbrlwlKTA61ALnCQpHTpDmXpoNfGOGV9zGdiky3cABD3rHnhtz3RAfQHRd0v4vqPhIzsAHSjXauTB1xmzQMMOPIYcdso0J6pZV7fgeibg8N2GCLvWGr7imNjFVqsod+55s38BRuykJA==" />

View File

@ -1,8 +1,182 @@
<template>
<div>
<h1>导入和导出</h1>
<p>编写中</p>
<h2>导出</h2>
<blockquote>
<p>要使用导出功能需要使用导出插件</p>
</blockquote>
<p>目前支持导出为<code>.smm</code><code>.json</code><code>.svg</code><code>.png</code><code>.pdf</code><code>.md</code>文件</p>
<p><code>.smm</code><code>simple-mind-map</code>自己定义的一种文件其实就是<code>json</code>文件换了一个扩展名而已</p>
<p>导出直接调用<code>export</code>方法即可</p>
<h3>导出为smmjson</h3>
<p>这两种文件的导出是一样的</p>
<pre class="hljs"><code>mindMap.export(type, isDownload, fileName, withConfig)
</code></pre>
<p><code>withConfig</code>指定导出的数据中是否要包含节点数据外的配置数据比如使用的布局主题等<code>true</code>导出的结构如下</p>
<pre class="hljs"><code>{
layout,
root,
<span class="hljs-attr">theme</span>: {
template,
config
},
view
}
</code></pre>
<p>如果传<code>false</code>导出的数据只有<code>root</code>部分也就是纯节点树</p>
<p>示例</p>
<pre class="hljs"><code>mindMap.export(<span class="hljs-string">&#x27;smm&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>, <span class="hljs-literal">true</span>)
mindMap.export(<span class="hljs-string">&#x27;json&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>, <span class="hljs-literal">false</span>)
</code></pre>
<h3>导出为pngpdf</h3>
<p>导出这两种文件很简单</p>
<pre class="hljs"><code>mindMap.export(<span class="hljs-string">&#x27;png&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>)
mindMap.export(<span class="hljs-string">&#x27;pdf&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>)
</code></pre>
<p>如果开启了节点富文本编辑那么导出会非常慢因为需要挨个转换节点所以如果导出操作很频繁的话建议关闭节点非文本编辑功能</p>
<h3>导出为svg</h3>
<p>导出为<code>svg</code>可以传递的参数如下</p>
<pre class="hljs"><code>mindMap.export(type, isDownload, fileName, domToImage = <span class="hljs-literal">false</span>, plusCssText = <span class="hljs-string">&#x27;&#x27;</span>)
</code></pre>
<p>如果开启了节点富文本编辑功能那么可以通过<code>domToImage</code>参数控制导出的<code>svg</code>中是否保留<code>html</code>结构还是转换成图片形式同样如果传了<code>true</code>导出会非常耗时建议导出为<code>svg</code><code>domToImage</code><code>false</code></p>
<p>如果<code>domToImage</code>传的是<code>false</code>也就是<code>svg</code>中会保留节点的<code>html</code>结构这就又存在一个问题因为浏览器对每个元素默认会设置一些样式影响最大的就是<code>margin</code><code>padding</code>这就有可能会导致节点中的文字错位所以可以通过<code>plusCssText</code>参数传入<code>css</code>样式</p>
<pre class="hljs"><code>mindMap.export(
<span class="hljs-string">&#x27;svg&#x27;</span>,
<span class="hljs-literal">true</span>,
<span class="hljs-string">&#x27;文件名&#x27;</span>,
<span class="hljs-literal">false</span>,
<span class="hljs-string">`* {
margin: 0;
padding: 0;
box-sizing: border-box;
}`</span>
)
</code></pre>
<h3>导出为md</h3>
<p>导出为<code>markdown</code>文件只要传递默认的三个参数即可</p>
<pre class="hljs"><code>mindMap.export(<span class="hljs-string">&#x27;md&#x27;</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">&#x27;文件名&#x27;</span>)
</code></pre>
<h2>导入</h2>
<p>目前支持从<code>.smm</code><code>.json</code><code>.xmind</code><code>.xlsx</code><code>.md</code>格式的文件导入</p>
<h3>导入smmjson</h3>
<p>这两个文件导入很简单直接读取文件内容转成对象然后调用相关方法渲染到画布即可</p>
<p>因为导出这两种类型时可以选择是否包含配置数据所以导入的时候调用的方法也是不一样的</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> data = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-string">&#x27;json数据&#x27;</span>)
<span class="hljs-comment">// root使setFullData</span>
<span class="hljs-keyword">if</span> (data.root) {
mindMap.setFullData(data)
} <span class="hljs-keyword">else</span> {
<span class="hljs-comment">// 使setData</span>
mindMap.setData(data)
}
<span class="hljs-comment">// </span>
mindMap.view.reset()
</code></pre>
<h3>导入xmind</h3>
<p>要导入<code>xmind</code>文件需要引入<code>xmind</code>的解析方法</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> xmind <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/parse/xmind.js&#x27;</span>
</code></pre>
<p>如果使用的是<code>umd</code>文件可以这样获取</p>
<pre class="hljs"><code>MindMap.xmind
</code></pre>
<p>如果你是通过<code>input type=file</code>等方式获取到的<code>File</code>文件对象那么可以直接传递给<code>parseXmindFile</code>方法解析注意返回的是一个<code>Promise</code>实例会返回解析后的节点树数据使用<code>setData</code>方法渲染到画布即可</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> xmind.parseXmindFile(file)
mindMap.setData(data)
</code></pre>
<p><code>.xmind</code>文件本质上是一个压缩包改成<code>zip</code>后缀可以解压缩里面存在一个<code>content.json</code>文件如果你自己解析出了这个文件那么可以把这个文件内容传递给这个<code>transformXmind</code>方法进行转换</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> xmind.transformXmind(fileContent)
mindMap.setData(data)
</code></pre>
<p>另外如果导入的是<code>xmind8</code>版本的数据需要使用<code>transformOldXmind</code>方法</p>
<h3>导入xlsx</h3>
<p>这个文件的导入没有内置方法需要你自己开发以下是一个使用<code>xlsx</code>库的方式</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> { read, utils } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;xlsx&#x27;</span>
<span class="hljs-comment">// buffer</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fileToBuffer = <span class="hljs-function"><span class="hljs-params">file</span> =&gt;</span> {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> {
<span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> FileReader()
reader.onload = <span class="hljs-function">() =&gt;</span> {
r(reader.result)
}
reader.readAsArrayBuffer(file)
})
}
<span class="hljs-comment">// File</span>
<span class="hljs-keyword">const</span> transformXLSXToJson = <span class="hljs-keyword">async</span> (file) =&gt; {
<span class="hljs-keyword">const</span> wb = read(<span class="hljs-keyword">await</span> fileToBuffer(file))
<span class="hljs-keyword">const</span> data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[<span class="hljs-number">0</span>]], {
<span class="hljs-attr">header</span>: <span class="hljs-number">1</span>
})
<span class="hljs-keyword">if</span> (data.length &lt;= <span class="hljs-number">0</span>) {
<span class="hljs-keyword">return</span>
}
<span class="hljs-keyword">let</span> max = <span class="hljs-number">0</span>
data.forEach(<span class="hljs-function"><span class="hljs-params">arr</span> =&gt;</span> {
<span class="hljs-keyword">if</span> (arr.length &gt; max) {
max = arr.length
}
})
<span class="hljs-keyword">let</span> layers = []
<span class="hljs-keyword">let</span> walk = <span class="hljs-function"><span class="hljs-params">layer</span> =&gt;</span> {
<span class="hljs-keyword">if</span> (!layers[layer]) {
layers[layer] = []
}
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; data.length; i++) {
<span class="hljs-keyword">if</span> (data[i][layer]) {
<span class="hljs-keyword">let</span> node = {
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">text</span>: data[i][layer]
},
<span class="hljs-attr">children</span>: [],
<span class="hljs-attr">_row</span>: i
}
layers[layer].push(node)
}
}
<span class="hljs-keyword">if</span> (layer &lt; max - <span class="hljs-number">1</span>) {
walk(layer + <span class="hljs-number">1</span>)
}
}
walk(<span class="hljs-number">0</span>)
<span class="hljs-keyword">let</span> getParent = <span class="hljs-function">(<span class="hljs-params">arr, row</span>) =&gt;</span> {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = arr.length - <span class="hljs-number">1</span>; i &gt;= <span class="hljs-number">0</span>; i--) {
<span class="hljs-keyword">if</span> (row &gt;= arr[i]._row) {
<span class="hljs-keyword">return</span> arr[i]
}
}
}
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt; layers.length; i++) {
<span class="hljs-keyword">let</span> arr = layers[i]
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; arr.length; j++) {
<span class="hljs-keyword">let</span> item = arr[j]
<span class="hljs-keyword">let</span> parent = getParent(layers[i - <span class="hljs-number">1</span>], item._row)
<span class="hljs-keyword">if</span> (parent) {
parent.children.push(item)
}
}
}
<span class="hljs-keyword">return</span> layers[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]
}
<span class="hljs-keyword">let</span> data = transformXLSXToJson(<span class="hljs-string">&#x27;xlsx文件对象&#x27;</span>)
mindMap.setData(data)
</code></pre>
<h3>导入md</h3>
<p>要导入<code>markdown</code>文件需要引入相应的解析方法</p>
<pre class="hljs"><code><span class="hljs-keyword">import</span> markdown <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;simple-mind-map/src/parse/markdown.js&#x27;</span>
</code></pre>
<p>如果使用的是umd格式的文件那么可以通过如下方式获取</p>
<pre class="hljs"><code>MindMap.markdown
</code></pre>
<p>获取到<code>md</code>文件的内容后调用<code>transformMarkdownTo</code>方法转换即可返回一个<code>Promise</code>实例</p>
<pre class="hljs"><code><span class="hljs-keyword">let</span> data = <span class="hljs-keyword">await</span> markdown.transformMarkdownTo(<span class="hljs-string">&#x27;md文件内容&#x27;</span>)
mindMap.setData(data)
</code></pre>
<h3>完整示例</h3>
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFV81u20YQfpUN24JUoVAK0JMrB3YbB0gApYGTQ4EwhzW5kuiQu8TuypJhC0iDJkHaBsglPfXQQ4Oil7intnb7NvVf36KzfxRNUXUuQQ3bImdnvm925tsf7XnrRRHujIm34vVEzNNCIkHkuLge0TQvGJdoD3EyaCNG+2xMJUnaSIxwlrHJJhmgGRpwliMfEPwyop/SpI8LMxR5AswZuZqD9WqOi8iLKEIRzYhEyqY8VxEdZ1lEI9rpoJODv06evjn9/vnxn79FNGZUSGC/RYuxBMeAtNDqdbSnQBTEIM0ImEkoMR8SGap38aD70I1zMoThThSFgcjz/ami3N8WjO5PMzHdz5PWhx3lmw5QcAWcQ0mEDBRKSHFOWi1DhRDOCJeBf37w+z+PX5x++0sIcH8//ipUWOpTI+sHwFWfeWLm4LcMAIe6cpgiQjNHWKalQCCRpeQjTJOM3MtzPagBZ4hkgpQwmv5ShC+V13IMyPxSiI1pTLKlEPnlOfSrCUQUfk3bf/r67NWzalUvSqAsgRKBBljQwSbBCeFKTWSCbpaGQFPNHUIOH+viPpmaLOvDjGYMJ0pUO6A4y4GQ5Lvu0VAmWGLwun3vizthgbkgAQQ4HXIixpm0rTfdlrsFYQMTdmV1Fflsa5vE0i/ro1lGnE30BDY4ZzzwTRVOnj09eXt4+sOL84MDJygrJPUDa/YGwAYK247OUIxlPIIFo3AqHKqcDHqTsaEdswHNDdHCamqF1hLMH4tdGtdbUilWpVR4gtNyfzDIpnIaS3Vs3pCGSS2ZUvOEGmYC8m6aiFb0solA+NnrN3WsHPNHCZs0SrS/tCjvS6eG7N3UerEFbh6h5JiKAeN531rus/9Q83uRm9n2X/96+vKtK6jlUSteU5XzU8tJWULOmCzJ7HESQthNOE/q4tEb1aJrzU39c6M7KZmouROpelPN9PnR8R9HapNyqZKpOvvWxW2wqXxVrprLYRmHwFdBfhv6MyZt5Fb3q5dgGmBIsImnoMM6zV2qjjXNYqZUp4GYJhYHXx7nwSKGFabVSGArRrIVlLB4nBMqQ9DERkbU42e7t5LAt5GfMypxSgn3W20Tpeq6MhdD5ClD5FVMxixB5Moceac/Hp5/8+TsyaG5KGipWDDlGI/SLOGEKucHc4waXCNLnen46Luzo5/rZBcJG0j11WLR73/KwD1am4tLaSo3YW3cYQm5y0QqU0Yh0s/IQIIu/BhaB216qN1nrU9BFiCNXsfcAeH2By+SwMUNSwJvCPWSdAfFGRZiNfJsu2+QnEWeHrYOaTIfLcUALr0OjFYdHZJkLNvCysUMRrKX6pueOixhXG13kYfWtBHe7UWw9Ae4rbGUsObW4iyNH4FLdSWC34XV2usY78ujYYFVg2E51WLnU3JPvU6lYvAq5G5mirdmb8aRF3bMddhtwETkYSxE5EEH1K0YobBSXKeeSZrI0Qq61u1+pP0QKsqecgKM6Q7RA1oO6u+DehMc1DwQb8G+PJYmUJ0RA7mCuvZNsmL+skg/IulwBO6fdLvF1DE3835cbrlwlKTA61ALnCQpHTpDmXpoNfGOGV9zGdiky3cABD3rHnhtz3RAfQHRd0v4vqPhIzsAHSjXauTB1xmzQMMOPIYcdso0J6pZV7fgeibg8N2GCLvWGr7imNjFVqsod+55s38BRuykJA==" />
</div>
</template>

View File

@ -1,3 +1,102 @@
# 如何持久化数据
编写中。。。
在线`demo`的数据是存储在电脑本地的,也就是`localStorage`里,当然,你也可以存储到数据库中。
## 保存数据
保存数据,一般有两种做法,一是让用户手动保存,二是当画布上的数据改变后自动保存,显然,第二中体验更好一点。
要获取画布的数据,可以使用`getData`方法,可以传递一个参数,`true`指定返回的数据中包含配置数据,`false`指定只返回节点树数据。
```js
const data = mindMap.getData(true)
```
包含配置的完整数据结构:
```js
{
layout,
root,
theme: {
template,
config
},
view
}
```
你可以直接把获取到的数据保存起来即可。
如果要自动保存,那么肯定需要监听相关事件:
```js
this.$bus.$on('data_change', data => {
// 节点树数据改变
// data即完整数据中的root部分
})
this.$bus.$on('view_data_change', data => {
// 视图数据改变
// data即完整数据中的view部分
})
```
主题和结构的改变一般是开发者提供一个ui界面让用户选择所以可以自行触发保存。
## 回显数据
当从数据库获取到了保存的数据,那么怎么渲染到画布上呢,首先可以直接在`new`一个`MindMap`实例时直接传入:
```js
// 从数据中取出各个部分
let { root, layout, theme, view } = storeData
let mindMap = new MindMap({
el: container,
data: root,
layout: layout,
theme: theme.template,
themeConfig: theme.config,
viewData: view,
// ...
})
```
其次如果是包含配置的完整数据也可以调用`setFullData`方法:
```js
mindMap.setFullData(data)
```
如果是纯节点数据可以调用`setData`方法:
```js
mindMap.setData(data)
```
修改结构可以调用`setLayout`方法:
```js
mindMap.setLayout(layout)
```
设置主题可以调用`setTheme`方法:
```js
mindMap.setTheme(theme)
```
设置主题配置可以调用`setThemeConfig`方法:
```js
mindMap.setThemeConfig(themeConfig)
```
设置视图数据可以调用`view.setTransformData`方法:
```js
mindMap.view.setTransformData(view)
```
### 完整示例
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVc1u00AQfpXRIpQEpXYqcQpuVaAggdSCypHtYWNvkoX1ruVdN42qXHpEBU7lzI1bxQEJtc9D0z4Gs/6Lm0QIiQOWLO3OzPd945md9Ql5nCTeUcZJnwQmTEViwXCbJdtUiTjRqYUTSPmwC1rt6UxZHnXBjJmUenLAhzCDYapjaCFDq0bsCRXtsaRwUWLQLPlGjNaNmCWUUAVAleQWnM1FboHKpKSKKt+H208/rz9/ub44m5//mJ9/n3+8oCrUylgYcfsc43aZZQhhZqpCaHdgaxtOHCeTPLXtl29e7XvGpkKNxHDaLiU8xDpc26YZ73Q6VM3uyN1+OL05vVyR+yepIZOmoVVXsN0galSAT6rKtXMXAJd9iHSYxVxZx/pMcrd8Mn0RtVsl8qlWlgnF01anW6Ai1O4X7O6hxBkoaZgKs+XH1pkpmX+9LL6/6I17ZiWZCwzHQkYpVy747YJjiW6tyrLSr6uzm6tvy2J3BdeIHi58zbj/lEG1LG0VTihhD7S2+zrir7URVmiFyJbkQ9vqQivE1mGbDvPwWecRHgs8GoFfjB0OHG4sx1lhluMOIIjEEYSSGbNFSdnuXR5rSnJ3GSCihbc+DBgS+OhtBlZMVms5YC6k+pBgkFmrFeyEUoTvMaQxaBi2OpCBXyD+yHAH3ZyvJfQi0WoV+I064NbYqSxKslNeMZR4fnGvlCPjcRN7oTGUYF3d9QLgNUpWnYmJiOy4D5u93v08DiCpO5VyVBRHPHfkTXbvveXSVlQLIBsYLTNbAAFcv/vQK3dWJ4vNqvyYi9EYwx/2eslxpbxe90GlHLN0JFC3Yk1YFOEVVBnq1L2y03+Z8WaVQZl0vUdCPKV5D0iXFB1wN7n3zmiFP46cnpYO7EA9gZTgf6EYO8/HpZfi/Sdi7pq1MUj1xPAUSSgpJ2jNv6LArrbaocrcZmT2G71jRY0=" />

View File

@ -1,8 +1,69 @@
<template>
<div>
<h1>如何持久化数据</h1>
<p>编写中</p>
<p>在线<code>demo</code>的数据是存储在电脑本地的也就是<code>localStorage</code>当然你也可以存储到数据库中</p>
<h2>保存数据</h2>
<p>保存数据一般有两种做法一是让用户手动保存二是当画布上的数据改变后自动保存显然第二中体验更好一点</p>
<p>要获取画布的数据可以使用<code>getData</code>方法可以传递一个参数<code>true</code>指定返回的数据中包含配置数据<code>false</code>指定只返回节点树数据</p>
<pre class="hljs"><code><span class="hljs-keyword">const</span> data = mindMap.getData(<span class="hljs-literal">true</span>)
</code></pre>
<p>包含配置的完整数据结构</p>
<pre class="hljs"><code>{
layout,
root,
<span class="hljs-attr">theme</span>: {
template,
config
},
view
}
</code></pre>
<p>你可以直接把获取到的数据保存起来即可</p>
<p>如果要自动保存那么肯定需要监听相关事件</p>
<pre class="hljs"><code><span class="hljs-built_in">this</span>.$bus.$on(<span class="hljs-string">&#x27;data_change&#x27;</span>, <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
<span class="hljs-comment">// </span>
<span class="hljs-comment">// dataroot</span>
})
<span class="hljs-built_in">this</span>.$bus.$on(<span class="hljs-string">&#x27;view_data_change&#x27;</span>, <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
<span class="hljs-comment">// </span>
<span class="hljs-comment">// dataview</span>
})
</code></pre>
<p>主题和结构的改变一般是开发者提供一个ui界面让用户选择所以可以自行触发保存</p>
<h2>回显数据</h2>
<p>当从数据库获取到了保存的数据那么怎么渲染到画布上呢首先可以直接在<code>new</code>一个<code>MindMap</code>实例时直接传入</p>
<pre class="hljs"><code><span class="hljs-comment">// </span>
<span class="hljs-keyword">let</span> { root, layout, theme, view } = storeData
<span class="hljs-keyword">let</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
<span class="hljs-attr">el</span>: container,
<span class="hljs-attr">data</span>: root,
<span class="hljs-attr">layout</span>: layout,
<span class="hljs-attr">theme</span>: theme.template,
<span class="hljs-attr">themeConfig</span>: theme.config,
<span class="hljs-attr">viewData</span>: view,
<span class="hljs-comment">// ...</span>
})
</code></pre>
<p>其次如果是包含配置的完整数据也可以调用<code>setFullData</code>方法</p>
<pre class="hljs"><code>mindMap.setFullData(data)
</code></pre>
<p>如果是纯节点数据可以调用<code>setData</code>方法</p>
<pre class="hljs"><code>mindMap.setData(data)
</code></pre>
<p>修改结构可以调用<code>setLayout</code>方法</p>
<pre class="hljs"><code>mindMap.setLayout(layout)
</code></pre>
<p>设置主题可以调用<code>setTheme</code>方法</p>
<pre class="hljs"><code>mindMap.setTheme(theme)
</code></pre>
<p>设置主题配置可以调用<code>setThemeConfig</code>方法</p>
<pre class="hljs"><code>mindMap.setThemeConfig(themeConfig)
</code></pre>
<p>设置视图数据可以调用<code>view.setTransformData</code>方法</p>
<pre class="hljs"><code>mindMap.view.setTransformData(view)
</code></pre>
<h3>完整示例</h3>
<iframe style="width: 100%; height: 455px; border: none;" src="https://wanglin2.github.io/playground/#eNrFVc1u00AQfpXRIpQEpXYqcQpuVaAggdSCypHtYWNvkoX1ruVdN42qXHpEBU7lzI1bxQEJtc9D0z4Gs/6Lm0QIiQOWLO3OzPd945md9Ql5nCTeUcZJnwQmTEViwXCbJdtUiTjRqYUTSPmwC1rt6UxZHnXBjJmUenLAhzCDYapjaCFDq0bsCRXtsaRwUWLQLPlGjNaNmCWUUAVAleQWnM1FboHKpKSKKt+H208/rz9/ub44m5//mJ9/n3+8oCrUylgYcfsc43aZZQhhZqpCaHdgaxtOHCeTPLXtl29e7XvGpkKNxHDaLiU8xDpc26YZ73Q6VM3uyN1+OL05vVyR+yepIZOmoVVXsN0galSAT6rKtXMXAJd9iHSYxVxZx/pMcrd8Mn0RtVsl8qlWlgnF01anW6Ai1O4X7O6hxBkoaZgKs+XH1pkpmX+9LL6/6I17ZiWZCwzHQkYpVy747YJjiW6tyrLSr6uzm6tvy2J3BdeIHi58zbj/lEG1LG0VTihhD7S2+zrir7URVmiFyJbkQ9vqQivE1mGbDvPwWecRHgs8GoFfjB0OHG4sx1lhluMOIIjEEYSSGbNFSdnuXR5rSnJ3GSCihbc+DBgS+OhtBlZMVms5YC6k+pBgkFmrFeyEUoTvMaQxaBi2OpCBXyD+yHAH3ZyvJfQi0WoV+I064NbYqSxKslNeMZR4fnGvlCPjcRN7oTGUYF3d9QLgNUpWnYmJiOy4D5u93v08DiCpO5VyVBRHPHfkTXbvveXSVlQLIBsYLTNbAAFcv/vQK3dWJ4vNqvyYi9EYwx/2eslxpbxe90GlHLN0JFC3Yk1YFOEVVBnq1L2y03+Z8WaVQZl0vUdCPKV5D0iXFB1wN7n3zmiFP46cnpYO7EA9gZTgf6EYO8/HpZfi/Sdi7pq1MUj1xPAUSSgpJ2jNv6LArrbaocrcZmT2G71jRY0=" />
</div>
</template>

View File

@ -24,13 +24,13 @@ MindMap.xmind
### xmind.parseXmindFile(file)
解析`.xmind`文件,返回解析后的数据,注意是完整的数据,包含节点树、主题、结构等,可以使用`mindMap.setFullData(data)`来将返回的数据渲染到画布上
解析`.xmind`文件,返回解析后的数据,可以使用`mindMap.setData(data)`来将返回的数据渲染到画布上
`file``File`对象
### xmind.transformXmind(content)
转换`xmind`数据,`.xmind`文件本质上是一个压缩包,改成`zip`后缀可以解压缩,里面存在一个`content.json`文件,如果你自己解析出了这个文件,那么可以把这个文件内容传递给这个方法进行转换,转换后的数据,注意是完整的数据,包含节点树、主题、结构等,可以使用`mindMap.setFullData(data)`来将返回的数据渲染到画布上
转换`xmind`数据,`.xmind`文件本质上是一个压缩包,改成`zip`后缀可以解压缩,里面存在一个`content.json`文件,如果你自己解析出了这个文件,那么可以把这个文件内容传递给这个方法进行转换,转换后的数据,可以使用`mindMap.setData(data)`来将返回的数据渲染到画布上
`content``.xmind`压缩包内的`content.json`文件内容

View File

@ -15,10 +15,10 @@
</code></pre>
<h2>方法</h2>
<h3>xmind.parseXmindFile(file)</h3>
<p>解析<code>.xmind</code>文件返回解析后的数据注意是完整的数据包含节点树主题结构等可以使用<code>mindMap.setFullData(data)</code>来将返回的数据渲染到画布上</p>
<p>解析<code>.xmind</code>文件返回解析后的数据可以使用<code>mindMap.setData(data)</code>来将返回的数据渲染到画布上</p>
<p><code>file</code><code>File</code>对象</p>
<h3>xmind.transformXmind(content)</h3>
<p>转换<code>xmind</code>数据<code>.xmind</code>文件本质上是一个压缩包改成<code>zip</code>后缀可以解压缩里面存在一个<code>content.json</code>文件如果你自己解析出了这个文件那么可以把这个文件内容传递给这个方法进行转换转换后的数据注意是完整的数据包含节点树主题结构等可以使用<code>mindMap.setFullData(data)</code>来将返回的数据渲染到画布上</p>
<p>转换<code>xmind</code>数据<code>.xmind</code>文件本质上是一个压缩包改成<code>zip</code>后缀可以解压缩里面存在一个<code>content.json</code>文件如果你自己解析出了这个文件那么可以把这个文件内容传递给这个方法进行转换转换后的数据可以使用<code>mindMap.setData(data)</code>来将返回的数据渲染到画布上</p>
<p><code>content</code><code>.xmind</code>压缩包内的<code>content.json</code>文件内容</p>
<h3>xmind.transformOldXmind(content)</h3>
<blockquote>

View File

@ -13,7 +13,7 @@
{{ $t('contextmenu.insertSiblingNode') }}
<span class="desc">Enter</span>
</div>
<div class="item" @click="exec('INSERT_CHILD_NODE')">
<div class="item" @click="exec('INSERT_CHILD_NODE')" :class="{ disabled: isGeneralization }">
{{ $t('contextmenu.insertChildNode') }}
<span class="desc">Tab</span>
</div>
@ -45,11 +45,11 @@
{{ $t('contextmenu.deleteNode') }}
<span class="desc">Delete</span>
</div>
<div class="item" @click="exec('COPY_NODE')">
<div class="item" @click="exec('COPY_NODE')" :class="{ disabled: isGeneralization }">
{{ $t('contextmenu.copyNode') }}
<span class="desc">Ctrl + C</span>
</div>
<div class="item" @click="exec('CUT_NODE')">
<div class="item" @click="exec('CUT_NODE')" :class="{ disabled: isGeneralization }">
{{ $t('contextmenu.cutNode') }}
<span class="desc">Ctrl + X</span>
</div>
@ -140,10 +140,10 @@ export default {
]
},
insertNodeBtnDisabled() {
return !this.node || this.node.isRoot
return !this.node || this.node.isRoot || this.node.isGeneralization
},
upNodeBtnDisabled() {
if (!this.node || this.node.isRoot) {
if (!this.node || this.node.isRoot || this.node.isGeneralization) {
return true
}
let isFirst =
@ -153,7 +153,7 @@ export default {
return isFirst
},
downNodeBtnDisabled() {
if (!this.node || this.node.isRoot) {
if (!this.node || this.node.isRoot || this.node.isGeneralization) {
return true
}
let children = this.node.parent.children
@ -163,6 +163,9 @@ export default {
}) ===
children.length - 1
return isLast
},
isGeneralization() {
return this.node.isGeneralization
}
},
created() {

View File

@ -17,11 +17,14 @@
* @Date: 2021-06-24 22:53:10
* @Desc: 字数及节点数量统计
*/
let countEl = document.createElement('div')
export default {
name: 'Count',
props: {},
data() {
return {
textStr: '',
words: 0,
num: 0
}
@ -39,9 +42,12 @@ export default {
* @Desc: 监听数据变化
*/
onDataChange(data) {
this.textStr = ''
this.words = 0
this.num = 0
this.walk(data)
countEl.innerHTML = this.textStr
this.words = countEl.textContent.length
},
/**
@ -51,7 +57,7 @@ export default {
*/
walk(data) {
this.num++
this.words += (String(data.data.text) || '').length
this.textStr += String(data.data.text) || ''
if (data.children && data.children.length > 0) {
data.children.forEach(item => {
this.walk(item)

View File

@ -111,7 +111,7 @@ export default {
}
},
mounted() {
this.showNewFeatureInfo()
// this.showNewFeatureInfo()
this.getData()
this.init()
this.$bus.$on('execCommand', this.execCommand)
@ -308,7 +308,8 @@ export default {
'mode_change',
'node_tree_render_end',
'rich_text_selection_change',
'transforming-dom-to-images'
'transforming-dom-to-images',
'generalization_node_contextmenu'
].forEach(event => {
this.mindMap.on(event, (...args) => {
this.$bus.$emit(event, ...args)

View File

@ -150,6 +150,7 @@ export default {
async handleXmind(file) {
try {
let data = await xmind.parseXmindFile(file.raw)
console.log(data);
this.$bus.$emit('setData', data)
this.$message.success('导入成功')
} catch (error) {