diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js
index 55b60e54..30f5b20d 100644
--- a/simple-mind-map/src/core/render/Render.js
+++ b/simple-mind-map/src/core/render/Render.js
@@ -1408,7 +1408,7 @@ class Render {
}
const nodeList = this.activeNodeList.filter(node => {
return (
- !node.isRoot && !node.isGeneralization && !node.checkHasGeneralization()
+ !node.isRoot && !node.isGeneralization && !node.checkHasSelfGeneralization()
)
})
const list = parseAddGeneralizationNodeList(nodeList)
diff --git a/simple-mind-map/src/parse/xmind.js b/simple-mind-map/src/parse/xmind.js
index 378b6ede..c2a2db76 100644
--- a/simple-mind-map/src/parse/xmind.js
+++ b/simple-mind-map/src/parse/xmind.js
@@ -1,12 +1,18 @@
import JSZip from 'jszip'
import xmlConvert from 'xml-js'
+import { getTextFromHtml, isUndef } from '../utils/index'
import {
- getTextFromHtml,
- imgToDataUrl,
- parseDataUrl,
- getImageSize,
- isUndef
-} from '../utils/index'
+ getSummaryText,
+ getSummaryText2,
+ getRoot,
+ getItemByName,
+ getElementsByType,
+ addSummaryData,
+ handleNodeImageFromXmind,
+ handleNodeImageToXmind,
+ getXmindContentXmlData,
+ parseNodeGeneralizationToXmind
+} from '../utils/xmind'
// 解析.xmind文件
const parseXmindFile = file => {
@@ -43,18 +49,18 @@ const parseXmindFile = file => {
// 转换xmind数据
const transformXmind = async (content, files) => {
- let data = JSON.parse(content)[0]
- let nodeTree = data.rootTopic
- let newTree = {}
- let waitLoadImageList = []
- let walk = async (node, newNode) => {
+ const data = JSON.parse(content)[0]
+ const nodeTree = data.rootTopic
+ const newTree = {}
+ const waitLoadImageList = []
+ const walk = async (node, newNode) => {
newNode.data = {
// 节点内容
text: isUndef(node.title) ? '' : node.title
}
// 节点备注
if (node.notes) {
- let notesData = node.notes.realHTML || node.notes.plain
+ const notesData = node.notes.realHTML || node.notes.plain
newNode.data.note = notesData ? notesData.content || '' : ''
}
// 超链接
@@ -65,51 +71,27 @@ const transformXmind = async (content, files) => {
if (node.labels && node.labels.length > 0) {
newNode.data.tag = node.labels
}
- // 概要
- if (node.currentSummary) {
- newNode.data.generalization = {
- text: node.currentSummary.title,
- expand: true,
- isActive: false,
- }
- }
-
// 图片
- if (node.image && /\.(jpg|jpeg|png|gif|webp)$/.test(node.image.src)) {
- // 处理异步逻辑
- let resolve = null
- let promise = new Promise(_resolve => {
- resolve = _resolve
- })
- waitLoadImageList.push(promise)
- try {
- // 读取图片
- let imageType = /\.([^.]+)$/.exec(node.image.src)[1]
- let imageBase64 =
- `data:image/${imageType};base64,` +
- (await files['resources/' + node.image.src.split('/')[1]].async(
- 'base64'
- ))
- newNode.data.image = imageBase64
- // 如果图片尺寸不存在
- if (!node.image.width && !node.image.height) {
- let imageSize = await getImageSize(imageBase64)
- newNode.data.imageSize = {
- width: imageSize.width,
- height: imageSize.height
- }
- } else {
- newNode.data.imageSize = {
- width: node.image.width,
- height: node.image.height
- }
- }
- resolve()
- } catch (error) {
- console.log(error)
- resolve()
- }
+ handleNodeImageFromXmind(node, newNode, waitLoadImageList, files)
+ // 概要
+ const selfSummary = []
+ const childrenSummary = []
+ if (newNode._summary) {
+ selfSummary.push(newNode._summary)
}
+ if (Array.isArray(node.summaries) && node.summaries.length > 0) {
+ node.summaries.forEach(item => {
+ addSummaryData(
+ selfSummary,
+ childrenSummary,
+ () => {
+ return getSummaryText(node, item.topicId)
+ },
+ item.range
+ )
+ })
+ }
+ newNode.data.generalization = selfSummary
// 子节点
newNode.children = []
if (
@@ -117,42 +99,12 @@ const transformXmind = async (content, files) => {
node.children.attached &&
node.children.attached.length > 0
) {
- // 分析概要位置
- // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来
- let summariesPosition = {}
- if (node.summaries && node.summaries.length > 0) {
- node.summaries.forEach(item => {
- // 使用正则表达式提取位置数字,例如 (2,3)
- const match = item.range.match(/\((\d+),(\d+)\)/)
- const firstNumber = match ? parseInt(match[1], 10) : null
- const secondNumber = match ? parseInt(match[2], 10) : null
- summariesPosition[item.topicId] = []
- for (let i = firstNumber; i <= secondNumber; i++) {
- summariesPosition[item.topicId].push(i)
- }
- })
- }
-
- let summariesPositionData = {}
- if (node.children.summary && node.children.summary.length > 0) {
- node.children.summary.forEach(summary => {
- if (Object.prototype.hasOwnProperty.call(summariesPosition, summary.id)) {
- summariesPosition[summary.id].forEach (index => {
- summariesPositionData[index] = summary
- })
- }
- })
- }
-
node.children.attached.forEach((item, index) => {
- let currentSummary = null
- if (Object.prototype.hasOwnProperty.call(summariesPositionData, index)) {
- currentSummary = summariesPositionData[index]
- }
-
- let newChild = {}
+ const newChild = {}
newNode.children.push(newChild)
- item.currentSummary = currentSummary
+ if (childrenSummary[index]) {
+ newChild._summary = childrenSummary[index]
+ }
walk(item, newChild)
})
}
@@ -164,39 +116,21 @@ const transformXmind = async (content, files) => {
// 转换旧版xmind数据,xmind8
const transformOldXmind = content => {
- let data = JSON.parse(content)
- let elements = data.elements
- let root = null
- let getRoot = arr => {
- if (!arr) return
- for (let i = 0; i < arr.length; i++) {
- if (!root && arr[i].name === 'topic') {
- root = arr[i]
- return
- }
- }
- arr.forEach(item => {
- getRoot(item.elements)
- })
- }
- getRoot(elements)
- let newTree = {}
- let getItemByName = (arr, name) => {
- return arr.find(item => {
- return item.name === name
- })
- }
- let walk = (node, newNode) => {
- let nodeElements = node.elements
+ const data = JSON.parse(content)
+ const elements = data.elements
+ const root = getRoot(elements)
+ const newTree = {}
+ const walk = (node, newNode) => {
+ const nodeElements = node.elements
let nodeTitle = getItemByName(nodeElements, 'title')
nodeTitle = nodeTitle && nodeTitle.elements && nodeTitle.elements[0].text
+ // 节点内容
newNode.data = {
- // 节点内容
text: isUndef(nodeTitle) ? '' : nodeTitle
}
+ // 节点备注
try {
- // 节点备注
- let notesElement = getItemByName(nodeElements, 'notes')
+ const notesElement = getItemByName(nodeElements, 'notes')
if (notesElement) {
newNode.data.note =
notesElement.elements[0].elements[0].elements[0].text
@@ -204,8 +138,8 @@ const transformOldXmind = content => {
} catch (error) {
console.log(error)
}
+ // 超链接
try {
- // 超链接
if (
node.attributes &&
node.attributes['xlink:href'] &&
@@ -216,9 +150,9 @@ const transformOldXmind = content => {
} catch (error) {
console.log(error)
}
+ // 标签
try {
- // 标签
- let labelsElement = getItemByName(nodeElements, 'labels')
+ const labelsElement = getItemByName(nodeElements, 'labels')
if (labelsElement) {
newNode.data.tag = labelsElement.elements.map(item => {
return item.elements[0].text
@@ -227,89 +161,50 @@ const transformOldXmind = content => {
} catch (error) {
console.log(error)
}
-
+ const childrenItem = getItemByName(nodeElements, 'children')
// 概要
- if (node.currentSummary) {
- let summaryText = ''
- if (node.currentSummary
- && node.currentSummary.elements
- && node.currentSummary.elements[0]
- && node.currentSummary.elements[0].elements
- && node.currentSummary.elements[0].elements[0]) {
- summaryText = node.currentSummary.elements[0].elements[0].text
+ const selfSummary = []
+ const childrenSummary = []
+ try {
+ if (newNode._summary) {
+ selfSummary.push(newNode._summary)
}
- newNode.data.generalization = {
- text: summaryText,
- expand: true,
- isActive: false,
+ const summariesItem = getItemByName(nodeElements, 'summaries')
+ if (
+ summariesItem &&
+ Array.isArray(summariesItem.elements) &&
+ summariesItem.elements.length > 0
+ ) {
+ summariesItem.elements.forEach(item => {
+ addSummaryData(
+ selfSummary,
+ childrenSummary,
+ () => {
+ return getSummaryText2(childrenItem, item.attributes['topic-id'])
+ },
+ item.attributes.range
+ )
+ })
}
+ } catch (error) {
+ console.log(error)
}
-
+ newNode.data.generalization = selfSummary
// 子节点
newNode.children = []
-
- let _children = getItemByName(nodeElements, 'children')
- if (_children && _children.elements && _children.elements.length > 0) {
- let summaryNode = null
- let summariesNode = getItemByName(nodeElements, 'summaries')
- _children.elements.forEach(item => {
- if (item.name === 'topics' && item.attributes.type === 'summary') {
- summaryNode = item
- return
- }
- })
-
- // 分析概要位置
- // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来
- let summariesPosition = {}
- if (typeof summariesNode != 'undefined' && summariesNode.elements && summariesNode.elements.length > 0) {
- summariesNode.elements.forEach(item => {
- // 使用正则表达式提取位置数字,例如 (2,3)
- const match = item.attributes.range.match(/\((\d+),(\d+)\)/)
- const firstNumber = match ? parseInt(match[1], 10) : null
- const secondNumber = match ? parseInt(match[2], 10) : null
- summariesPosition[item.attributes['topic-id']] = []
- for (let i = firstNumber; i <= secondNumber; i++) {
- summariesPosition[item.attributes['topic-id']].push(i)
- }
- })
- }
-
- let summariesPositionData = {}
- if (summaryNode !== null && summaryNode.elements && summaryNode.elements.length > 0) {
- summaryNode.elements.forEach(summary => {
- if (Object.prototype.hasOwnProperty.call(summariesPosition, summary.attributes.id)) {
- summariesPosition[summary.attributes.id].forEach (index => {
- summariesPositionData[index] = summary
- })
- }
- })
- }
-
- _children.elements.forEach((item, index) => {
- if (item.name === 'topics') {
- if (item.attributes.type !== 'summary') {
- (item.elements || []).forEach((item2, index2) => {
- let newChild = {}
- let currentSummary = null
- if (Object.prototype.hasOwnProperty.call(summariesPositionData, index2)) {
- currentSummary = summariesPositionData[index2]
- }
- newNode.children.push(newChild)
- item2.currentSummary = currentSummary
- walk(item2, newChild)
- })
- }
- } else {
- let newChild = {}
- let currentSummary = null
- if (Object.prototype.hasOwnProperty.call(summariesPositionData, index)) {
- currentSummary = summariesPositionData[index]
- }
- newNode.children.push(newChild)
- item.currentSummary = currentSummary
- walk(item, newChild)
+ if (
+ childrenItem &&
+ childrenItem.elements &&
+ childrenItem.elements.length > 0
+ ) {
+ const children = getElementsByType(childrenItem.elements, 'attached')
+ children.forEach((item, index) => {
+ const newChild = {}
+ newNode.children.push(newChild)
+ if (childrenSummary[index]) {
+ newChild._summary = childrenSummary[index]
}
+ walk(item, newChild)
})
}
}
@@ -323,190 +218,17 @@ const transformToXmind = async (data, name) => {
const id = 'simpleMindMap_' + Date.now()
const imageList = []
// 转换核心数据
- let newTree = {
- legend: {},
- topicPositioning: "fixed",
- theme: {
- "boundary": {
- "styleId": "94a6c549-690c-4f1e-b18f-457f114abcb0",
- "type": "boundary",
- "properties": {
- "fo:font-style": "normal",
- "svg:fill": "#D5E9FC",
- "fo:font-family": "NeverMind",
- "shape-class": "org.xmind.boundaryShape.roundedRect",
- "fo:font-size": "13pt",
- "fo:color": "#FFFFFF",
- "fo:font-weight": "500",
- "line-pattern": "dash",
- "line-color": "#0288D1"
- }
- },
- "subTopic": {
- "styleId": "ddd92ae3-f2b4-48ee-9e47-2dacee6acac4",
- "type": "topic",
- "properties": {
- "fo:text-align": "left",
- "fo:font-style": "normal",
- "svg:fill": "none",
- "fo:font-family": "NeverMind",
- "fo:font-size": "13pt",
- "shape-class": "org.xmind.topicShape.underline",
- "fo:color": "#333333",
- "fo:font-weight": "500",
- "line-class": "org.xmind.branchConnection.roundedElbow"
- }
- },
- "summary": {
- "styleId": "8aa88864-8667-4627-a763-a84973e0109b",
- "type": "summary",
- "properties": {
- "line-width": "2",
- "shape-class": "org.xmind.summaryShape.round",
- "line-color": "#0288D1"
- }
- },
- "calloutTopic": {
- "styleId": "9bffcc6a-0526-4db5-b304-ea3830a42846",
- "type": "topic",
- "properties": {
- "fo:font-style": "normal",
- "fo:font-family": "NeverMind",
- "fo:font-size": "13pt",
- "fo:color": "#FFFFFF",
- "fo:font-weight": "600",
- "callout-shape-class": "org.xmind.calloutTopicShape.balloon.roundedRect"
- }
- },
- "summaryTopic": {
- "styleId": "a82dc72d-29bc-4d81-bd44-3f1bee0ed35c",
- "type": "topic",
- "properties": {
- "fo:font-style": "normal",
- "line-width": "1",
- "svg:fill": "#333333",
- "fo:font-family": "NeverMind",
- "fo:font-size": "13pt",
- "shape-class": "org.xmind.topicShape.roundedRect",
- "border-line-width": "1",
- "fo:font-weight": "600",
- "line-class": "org.xmind.branchConnection.roundedElbow",
- "border-line-color": "none",
- "line-color": "#333333"
- }
- },
- "floatingTopic": {
- "styleId": "8286b472-0630-4970-8bf1-510a831dc2b9",
- "type": "topic",
- "properties": {
- "fo:font-style": "normal",
- "line-width": "1",
- "svg:fill": "#333333",
- "fo:font-family": "NeverMind",
- "fo:font-size": "13pt",
- "shape-class": "org.xmind.topicShape.roundedRect",
- "border-line-width": "0",
- "fo:color": "#FFFFFF",
- "fo:font-weight": "600",
- "line-class": "org.xmind.branchConnection.roundedElbow",
- "border-line-color": "none",
- "line-color": "#333333"
- }
- },
- "importantTopic": {
- "type": "topic",
- "properties": {
- "svg:fill": "#FFFF00",
- "fo:color": "#333333",
- "fo:font-weight": "bold"
- }
- },
- "expiredTopic": {
- "type": "topic",
- "properties": {
- "fo:font-style": "italic",
- "fo:text-decoration": " line-through"
- }
- },
- "centralTopic": {
- "styleId": "9a94e1a0-7e67-48df-a231-7fa0c60b7b97",
- "type": "topic",
- "properties": {
- "fo:font-style": "normal",
- "line-width": "2",
- "svg:fill": "#0288D1",
- "fo:font-family": "NeverMind",
- "fo:font-size": "28pt",
- "shape-class": "org.xmind.topicShape.roundedRect",
- "border-line-width": "0",
- "fo:font-weight": "600",
- "line-class": "org.xmind.branchConnection.curve",
- "line-color": "#333333"
- }
- },
- "mainTopic": {
- "styleId": "7565fe37-2200-4483-b343-91bdf53e563e",
- "type": "topic",
- "properties": {
- "fo:font-style": "normal",
- "fo:text-align": "left",
- "line-width": "1",
- "fo:font-family": "NeverMind",
- "fo:font-size": "20pt",
- "border-line-width": "2",
- "fo:font-weight": "600",
- "line-class": "org.xmind.branchConnection.roundedElbow",
- "line-color": "#333333",
- "border-line-color": "#333333"
- }
- },
- "id": "6518e97a4149b5f96691ab3b5d",
- "relationship": {
- "styleId": "1611e291-8cc1-4500-93a5-69281d5bedf0",
- "type": "relationship",
- "properties": {
- "line-width": "2",
- "fo:font-family": "NeverMind",
- "shape-class": "org.xmind.relationshipShape.curved",
- "fo:font-size": "13pt",
- "fo:color": "#333333",
- "fo:font-weight": "normal",
- "line-color": "#0288D1"
- }
- },
- "minorTopic": {
- "type": "topic",
- "properties": {
- "svg:fill": "#FFCB88",
- "fo:color": "#333333",
- "fo:font-weight": "bold"
- }
- },
- "map": {
- "styleId": "7e90467a-d643-4fa9-84f2-f8f0166e5afb",
- "type": "map",
- "properties": {}
- }
- },
- id,
- }
-
+ let newTree = {}
let waitLoadImageList = []
-
let walk = async (node, newNode, isRoot) => {
let newData = {
id: node.data.uid,
- title: getTextFromHtml(node.data.text),
- extensions: [],
- markers: [],
- labels: [],
- notes: {},
- comments: [],
+ structureClass: 'org.xmind.ui.logic.right',
+ title: getTextFromHtml(node.data.text), // 节点文本
children: {
- attached: [],
- },
+ attached: []
+ }
}
-
// 备注
if (node.data.note !== undefined) {
newData.notes = {
@@ -526,113 +248,64 @@ const transformToXmind = async (data, name) => {
if (node.data.tag !== undefined) {
newData.labels = node.data.tag || []
}
-
// 图片
- if (node.data.image) {
- // 处理异步逻辑
- let resolve = null
- let promise = new Promise(_resolve => {
- resolve = _resolve
- })
- waitLoadImageList.push(promise)
- try {
- let imgName = ''
- let imgData = node.data.image
- // base64之外的其他图片要先转换成data:url
- if (!/^data:/.test(node.data.image)) {
- imgData = await imgToDataUrl(node.data.image)
- }
- // 从data:url中解析出图片类型和ase64
- let dataUrlRes = parseDataUrl(imgData)
- imgName = 'image_' + imageList.length + '.' + dataUrlRes.type
- imageList.push({
- name: imgName,
- data: dataUrlRes.base64
- })
- newData.image = {
- src: 'xap:resources/' + imgName,
- width: node.data.imageSize.width,
- height: node.data.imageSize.height
- }
- resolve()
- } catch (error) {
- console.log(error)
- resolve()
- }
- }
-
+ handleNodeImageToXmind(node, newNode, waitLoadImageList, imageList)
// 样式
// 暂时不考虑样式
if (isRoot) {
+ newData.class = 'topic'
+ newNode.id = id
+ newNode.class = 'sheet'
newNode.title = name
- newNode.structureClass = "org.xmind.ui.map.unbalanced"
+ newNode.extensions = []
+ newNode.topicPositioning = 'fixed'
+ newNode.topicOverlapping = 'overlap'
+ newNode.coreVersion = '2.100.0'
newNode.rootTopic = newData
} else {
Object.keys(newData).forEach(key => {
newNode[key] = newData[key]
})
}
+ // 概要
+ const { summary, summaries } = parseNodeGeneralizationToXmind(node)
+ if (isRoot) {
+ if (summaries.length > 0) {
+ newNode.rootTopic.children.summary = summary
+ newNode.rootTopic.summaries = summaries
+ }
+ } else {
+ if (summaries.length > 0) {
+ newNode.children.summary = summary
+ newNode.summaries = summaries
+ }
+ }
+ // 子节点
if (node.children && node.children.length > 0) {
- let summary = []
- let summaries = []
- node.children.forEach((child,index) => {
- if (child.data.generalization) {
- let summaryTopicId = node.data.uid+'_topic_id_' + index
- let summaryTitle = getTextFromHtml(child.data.generalization.text)
- summary.push({
- id: summaryTopicId,
- title: summaryTitle,
- attributedTitle: [
- {
- text: summaryTitle
- }
- ]
- })
-
- summaries.push({
- id: node.data.uid+'_range_id_' + index,
- range: "("+index+","+index+")",
- topicId: summaryTopicId
- })
- }
+ node.children.forEach(child => {
let newChild = {}
walk(child, newChild)
newData.children.attached.push(newChild)
})
-
- if (isRoot) {
- if (summaries.length > 0) {
- newNode.rootTopic.children.summary = summary
- newNode.rootTopic.summaries = summaries
- }
- } else {
- if (summaries.length > 0) {
- newNode.children.summary = summary
- newNode.summaries = summaries
- }
- }
}
}
walk(data, newTree, true)
-
await Promise.all(waitLoadImageList)
-
const contentData = [newTree]
-
// 创建压缩包
const zip = new JSZip()
zip.file('content.json', JSON.stringify(contentData))
zip.file(
'metadata.json',
- `{"dataStructureVersion":"2","creator":{"name":"mind-map"},"layoutEngineVersion":"3"}`
+ `{"modifier":"","dataStructureVersion":"2","creator":{"name":"mind-map"},"layoutEngineVersion":"3","activeSheetId":"${id}"}`
)
- zip.file(
- 'content.xml',
- ` Warning 警告 Attention Warnung 경고 This file can not be opened normally, please do not modify and save, otherwise the contents will be permanently lost! You can try using XMind 8 Update 3 or later version to open 该文件无法正常打开,请勿修改并保存,否则文件内容将会永久性丢失! 你可以尝试使用 XMind 8 Update 3 或更新版本打开 該文件無法正常打開,請勿修改並保存,否則文件內容將會永久性丟失! 你可以嘗試使用 XMind 8 Update 3 或更新版本打開 この文書は正常に開かないので、修正して保存しないようにしてください。そうでないと、書類の内容が永久に失われます。! XMind 8 Update 3 や更新版を使って開くこともできます Datei kann nicht richtig geöffnet werden. Bitte ändern Sie diese Datei nicht und speichern Sie sie, sonst wird die Datei endgültig gelöscht werden. Bitte versuchen Sie, diese Datei mit XMind 8 Update 3 oder später zu öffnen. Ce fichier ne peut pas ouvert normalement, veuillez le rédiger et sauvegarder, sinon le fichier sera perdu en permanence. Vous pouvez essayer d'ouvrir avec XMind 8 Update 3 ou avec une version plus récente. 파일을 정상적으로 열 수 없으며, 수정 및 저장하지 마십시오. 그렇지 않으면 파일의 내용이 영구적으로 손실됩니다! XMind 8 Update 3 또는 이후 버전을 사용하여 -1 Sheet 1 `
- )
-
+ zip.file('content.xml', getXmindContentXmlData())
const manifestData = {
- 'file-entries': { 'content.json': {}, 'metadata.json': {}, 'Thumbnails/thumbnail.png':{} }
+ 'file-entries': {
+ 'content.json': {},
+ 'metadata.json': {},
+ 'Thumbnails/thumbnail.png': {}
+ }
}
// 图片
if (imageList.length > 0) {
diff --git a/simple-mind-map/src/utils/xmind.js b/simple-mind-map/src/utils/xmind.js
new file mode 100644
index 00000000..373bd7da
--- /dev/null
+++ b/simple-mind-map/src/utils/xmind.js
@@ -0,0 +1,256 @@
+import {
+ getImageSize,
+ imgToDataUrl,
+ parseDataUrl,
+ getTextFromHtml,
+ createUid
+} from './index'
+
+// 解析出新xmind的概要文本
+export const getSummaryText = (node, topicId) => {
+ if (node.children.summary && node.children.summary.length > 0) {
+ for (let i = 0; i < node.children.summary.length; i++) {
+ const cur = node.children.summary[i]
+ if (cur.id === topicId) {
+ return cur.title
+ }
+ }
+ }
+}
+
+// 解析出旧xmind的概要文本
+export const getSummaryText2 = (item, topicId) => {
+ const summaryElements = getElementsByType(item.elements, 'summary')
+ if (summaryElements && summaryElements && summaryElements.length > 0) {
+ for (let i = 0; i < summaryElements.length; i++) {
+ const cur = summaryElements[i]
+ if (cur.attributes.id === topicId) {
+ return cur.elements &&
+ cur.elements[0] &&
+ cur.elements[0].elements &&
+ cur.elements[0].elements[0]
+ ? cur.elements[0].elements[0].text
+ : ''
+ }
+ }
+ }
+ return ''
+}
+
+// 解析旧版xmind数据时,找出根节点
+export const getRoot = list => {
+ let root = null
+ const walk = arr => {
+ if (!arr) return
+ for (let i = 0; i < arr.length; i++) {
+ if (!root && arr[i].name === 'topic') {
+ root = arr[i]
+ return
+ }
+ }
+ arr.forEach(item => {
+ walk(item.elements)
+ })
+ }
+ walk(list)
+ return root
+}
+
+// 解析旧版xmind数据,从一个数组中根据name找出该项
+export const getItemByName = (arr, name) => {
+ return arr.find(item => {
+ return item.name === name
+ })
+}
+
+// 解析旧版xmind数据,从一个数组中根据attributes.type找出该项
+export const getElementsByType = (arr, type) => {
+ return arr.find(el => {
+ return el.attributes.type === type
+ }).elements
+}
+
+// 解析xmind数据,将概要转换为smm支持的结构
+export const addSummaryData = (selfList, childrenList, getText, range) => {
+ const summaryData = {
+ expand: true,
+ isActive: false,
+ text: getText(),
+ range: null
+ }
+ const match = range.match(/\((\d+),(\d+)\)/)
+ if (match) {
+ const startIndex = Number(match[1])
+ const endIndex = Number(match[2])
+ if (startIndex === endIndex) {
+ childrenList[startIndex] = summaryData
+ } else {
+ summaryData.range = [startIndex, endIndex]
+ selfList.push(summaryData)
+ }
+ } else {
+ selfList.push(summaryData)
+ }
+}
+
+// 解析xmind数据时,解析其中的图片数据
+export const handleNodeImageFromXmind = async (
+ node,
+ newNode,
+ promiseList,
+ files
+) => {
+ if (node.image && /\.(jpg|jpeg|png|gif|webp)$/.test(node.image.src)) {
+ // 处理异步逻辑
+ let resolve = null
+ const promise = new Promise(_resolve => {
+ resolve = _resolve
+ })
+ promiseList.push(promise)
+ try {
+ // 读取图片
+ const imageType = /\.([^.]+)$/.exec(node.image.src)[1]
+ const imageBase64 =
+ `data:image/${imageType};base64,` +
+ (await files['resources/' + node.image.src.split('/')[1]].async(
+ 'base64'
+ ))
+ newNode.data.image = imageBase64
+ // 如果图片尺寸不存在
+ if (!node.image.width && !node.image.height) {
+ const imageSize = await getImageSize(imageBase64)
+ newNode.data.imageSize = {
+ width: imageSize.width,
+ height: imageSize.height
+ }
+ } else {
+ newNode.data.imageSize = {
+ width: node.image.width,
+ height: node.image.height
+ }
+ }
+ resolve()
+ } catch (error) {
+ console.log(error)
+ resolve()
+ }
+ }
+}
+
+// 导出为xmind时,处理图片数据
+export const handleNodeImageToXmind = async (
+ node,
+ newData,
+ promiseList,
+ imageList
+) => {
+ if (node.data.image) {
+ // 处理异步逻辑
+ let resolve = null
+ let promise = new Promise(_resolve => {
+ resolve = _resolve
+ })
+ promiseList.push(promise)
+ try {
+ let imgName = ''
+ let imgData = node.data.image
+ console.log(1, imgData)
+ // base64之外的其他图片要先转换成data:url
+ if (!/^data:/.test(node.data.image)) {
+ imgData = await imgToDataUrl(node.data.image)
+ console.log(2, imgData)
+ }
+ // 从data:url中解析出图片类型和ase64
+ let dataUrlRes = parseDataUrl(imgData)
+ console.log(3, dataUrlRes)
+ imgName = 'image_' + imageList.length + '.' + dataUrlRes.type
+ imageList.push({
+ name: imgName,
+ data: dataUrlRes.base64
+ })
+ newData.image = {
+ src: 'xap:resources/' + imgName,
+ width: node.data.imageSize.width,
+ height: node.data.imageSize.height
+ }
+ resolve()
+ } catch (error) {
+ console.log(error)
+ resolve()
+ }
+ }
+}
+
+export const getXmindContentXmlData = () => {
+ return ` Warning 警告 Attention Warnung 경고 This file can not be opened normally, please do not modify and save, otherwise the contents will be permanently lost! You can try using XMind 8 Update 3 or later version to open 该文件无法正常打开,请勿修改并保存,否则文件内容将会永久性丢失! 你可以尝试使用 XMind 8 Update 3 或更新版本打开 該文件無法正常打開,請勿修改並保存,否則文件內容將會永久性丟失! 你可以嘗試使用 XMind 8 Update 3 或更新版本打開 この文書は正常に開かないので、修正して保存しないようにしてください。そうでないと、書類の内容が永久に失われます。! XMind 8 Update 3 や更新版を使って開くこともできます Datei kann nicht richtig geöffnet werden. Bitte ändern Sie diese Datei nicht und speichern Sie sie, sonst wird die Datei endgültig gelöscht werden. Bitte versuchen Sie, diese Datei mit XMind 8 Update 3 oder später zu öffnen. Ce fichier ne peut pas ouvert normalement, veuillez le rédiger et sauvegarder, sinon le fichier sera perdu en permanence. Vous pouvez essayer d'ouvrir avec XMind 8 Update 3 ou avec une version plus récente. 파일을 정상적으로 열 수 없으며, 수정 및 저장하지 마십시오. 그렇지 않으면 파일의 내용이 영구적으로 손실됩니다! XMind 8 Update 3 또는 이후 버전을 사용하여 -1 Sheet 1 `
+}
+
+// 获取节点的概要列表
+const formatGetGeneralization = data => {
+ const generalization = data.generalization
+ return Array.isArray(generalization)
+ ? generalization
+ : generalization
+ ? [generalization]
+ : []
+}
+
+// 获取节点自身的概要,非子节点区间
+const getSelfGeneralization = data => {
+ const list = formatGetGeneralization(data)
+ return list.filter(item => {
+ return !item.range || item.range.length <= 0
+ })
+}
+
+// 获取节点区间概要
+const getRangeGeneralization = data => {
+ const list = formatGetGeneralization(data)
+ return list.filter(item => {
+ return item.range && item.range.length > 0
+ })
+}
+
+// 导出为xmind时,将概要转换为xmind的格式
+export const parseNodeGeneralizationToXmind = node => {
+ const summary = []
+ const summaries = []
+ const collectSummary = (item, startIndex, endIndex) => {
+ const summaryTopicId = createUid()
+ const summaryTitle = getTextFromHtml(item.text)
+ summary.push({
+ id: summaryTopicId,
+ title: summaryTitle,
+ attributedTitle: [
+ {
+ text: summaryTitle
+ }
+ ]
+ })
+ summaries.push({
+ id: createUid(),
+ range: '(' + startIndex + ',' + endIndex + ')',
+ topicId: summaryTopicId
+ })
+ }
+ // 在xmind中,概要都是保存在父节点的
+ // 而在simple-mind-map中,区间概要保存在父节点中,不带区间的保存在自身
+ // 所以先要过滤出自身的区间概要
+ const generalizationList = getRangeGeneralization(node.data)
+ generalizationList.forEach(item => {
+ collectSummary(item, item.range[0], item.range[1])
+ })
+
+ // 遍历子节点,找出子节点自身的概要
+ ;(node.children || []).forEach((child, childIndex) => {
+ const list = getSelfGeneralization(child.data)
+ list.forEach(item => {
+ collectSummary(item, childIndex, childIndex)
+ })
+ })
+
+ return {
+ summary,
+ summaries
+ }
+}