Merge branch 'feature' into feature/icon-merge
This commit is contained in:
commit
a59a283d74
@ -14,6 +14,7 @@ import TouchEvent from './src/plugins/TouchEvent.js'
|
|||||||
import Search from './src/plugins/Search.js'
|
import Search from './src/plugins/Search.js'
|
||||||
import Painter from './src/plugins/Painter.js'
|
import Painter from './src/plugins/Painter.js'
|
||||||
import Scrollbar from './src/plugins/Scrollbar.js'
|
import Scrollbar from './src/plugins/Scrollbar.js'
|
||||||
|
import Formula from './src/plugins/Formula.js'
|
||||||
import xmind from './src/parse/xmind.js'
|
import xmind from './src/parse/xmind.js'
|
||||||
import markdown from './src/parse/markdown.js'
|
import markdown from './src/parse/markdown.js'
|
||||||
import icons from './src/svg/icons.js'
|
import icons from './src/svg/icons.js'
|
||||||
@ -43,5 +44,6 @@ MindMap.usePlugin(MiniMap)
|
|||||||
.usePlugin(Search)
|
.usePlugin(Search)
|
||||||
.usePlugin(Painter)
|
.usePlugin(Painter)
|
||||||
.usePlugin(Scrollbar)
|
.usePlugin(Scrollbar)
|
||||||
|
.usePlugin(Formula)
|
||||||
|
|
||||||
export default MindMap
|
export default MindMap
|
||||||
|
|||||||
96
simple-mind-map/package-lock.json
generated
96
simple-mind-map/package-lock.json
generated
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@wh/simple-mind-map",
|
"name": "simple-mind-map",
|
||||||
"version": "0.0.1",
|
"version": "0.7.1-fix.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@wh/simple-mind-map",
|
"version": "0.7.1-fix.2",
|
||||||
"version": "0.0.1",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@svgdotjs/svg.js": "^3.0.16",
|
"@svgdotjs/svg.js": "^3.0.16",
|
||||||
@ -14,6 +13,7 @@
|
|||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
|
"katex": "^0.16.8",
|
||||||
"mdast-util-from-markdown": "^1.3.0",
|
"mdast-util-from-markdown": "^1.3.0",
|
||||||
"quill": "^1.3.6",
|
"quill": "^1.3.6",
|
||||||
"tern": "^0.24.3",
|
"tern": "^0.24.3",
|
||||||
@ -191,7 +191,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/acorn-loose": {
|
"node_modules/acorn-loose": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn-loose/-/acorn-loose-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-6.1.0.tgz",
|
||||||
"integrity": "sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==",
|
"integrity": "sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^6.2.0"
|
"acorn": "^6.2.0"
|
||||||
@ -202,7 +202,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/acorn-loose/node_modules/acorn": {
|
"node_modules/acorn-loose/node_modules/acorn": {
|
||||||
"version": "6.4.2",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||||
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
|
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -213,7 +213,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/acorn-walk": {
|
"node_modules/acorn-walk": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
|
||||||
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
|
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
@ -401,6 +401,14 @@
|
|||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@ -554,7 +562,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-2.3.0.tgz",
|
||||||
"integrity": "sha512-n6e4bsCpzsP0OB76X+vEWhySUQI8GHPVFVK+3QkX35tbryy2WoeGeK5kQ+oxzgDVHjIZyz5fyS60Mi3EpQLc0Q==",
|
"integrity": "sha512-n6e4bsCpzsP0OB76X+vEWhySUQI8GHPVFVK+3QkX35tbryy2WoeGeK5kQ+oxzgDVHjIZyz5fyS60Mi3EpQLc0Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
@ -568,7 +576,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/errno": {
|
"node_modules/errno": {
|
||||||
"version": "0.1.8",
|
"version": "0.1.8",
|
||||||
"resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||||
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prr": "~1.0.1"
|
"prr": "~1.0.1"
|
||||||
@ -926,7 +934,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||||
},
|
},
|
||||||
"node_modules/grapheme-splitter": {
|
"node_modules/grapheme-splitter": {
|
||||||
@ -1204,6 +1212,21 @@
|
|||||||
"setimmediate": "^1.0.5"
|
"setimmediate": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/katex": {
|
||||||
|
"version": "0.16.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz",
|
||||||
|
"integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==",
|
||||||
|
"funding": [
|
||||||
|
"https://opencollective.com/katex",
|
||||||
|
"https://github.com/sponsors/katex"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^8.3.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"katex": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kleur": {
|
"node_modules/kleur": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||||
@ -1291,7 +1314,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/memory-fs": {
|
"node_modules/memory-fs": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/memory-fs/-/memory-fs-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz",
|
||||||
"integrity": "sha512-QTNXnl79X97kZ9jJk/meJrtDuvgvRakX5LU7HZW1L7MsXHuSTwoMIzN9tOLLH3Xfsj/gbsSqX/ovnsqz246zKQ==",
|
"integrity": "sha512-QTNXnl79X97kZ9jJk/meJrtDuvgvRakX5LU7HZW1L7MsXHuSTwoMIzN9tOLLH3Xfsj/gbsSqX/ovnsqz246zKQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"errno": "^0.1.3",
|
"errno": "^0.1.3",
|
||||||
@ -1752,7 +1775,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/object-assign": {
|
"node_modules/object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -1921,7 +1944,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/prr": {
|
"node_modules/prr": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
||||||
},
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
@ -2217,7 +2240,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "0.2.9",
|
"version": "0.2.9",
|
||||||
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-0.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz",
|
||||||
"integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==",
|
"integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
@ -2225,7 +2248,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tern": {
|
"node_modules/tern": {
|
||||||
"version": "0.24.3",
|
"version": "0.24.3",
|
||||||
"resolved": "https://registry.npmmirror.com/tern/-/tern-0.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/tern/-/tern-0.24.3.tgz",
|
||||||
"integrity": "sha512-Z8uvtdWIlFn1GWy0HW5FhZ8VDryZwoJUdnjZU25C7/PBOltLIn1uv+WF3rVq6S1761YbsmbZYRP/l0ZJBCkvrw==",
|
"integrity": "sha512-Z8uvtdWIlFn1GWy0HW5FhZ8VDryZwoJUdnjZU25C7/PBOltLIn1uv+WF3rVq6S1761YbsmbZYRP/l0ZJBCkvrw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^6.0.0",
|
"acorn": "^6.0.0",
|
||||||
@ -2242,7 +2265,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tern/node_modules/acorn": {
|
"node_modules/tern/node_modules/acorn": {
|
||||||
"version": "6.4.2",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||||
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
|
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -2253,7 +2276,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tern/node_modules/resolve-from": {
|
"node_modules/tern/node_modules/resolve-from": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
|
||||||
"integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==",
|
"integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@ -2538,7 +2561,7 @@
|
|||||||
},
|
},
|
||||||
"acorn-loose": {
|
"acorn-loose": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn-loose/-/acorn-loose-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-6.1.0.tgz",
|
||||||
"integrity": "sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==",
|
"integrity": "sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"acorn": "^6.2.0"
|
"acorn": "^6.2.0"
|
||||||
@ -2546,14 +2569,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "6.4.2",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||||
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
|
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acorn-walk": {
|
"acorn-walk": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
|
||||||
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
|
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
|
||||||
},
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
@ -2685,6 +2708,11 @@
|
|||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@ -2797,7 +2825,7 @@
|
|||||||
},
|
},
|
||||||
"enhanced-resolve": {
|
"enhanced-resolve": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-2.3.0.tgz",
|
||||||
"integrity": "sha512-n6e4bsCpzsP0OB76X+vEWhySUQI8GHPVFVK+3QkX35tbryy2WoeGeK5kQ+oxzgDVHjIZyz5fyS60Mi3EpQLc0Q==",
|
"integrity": "sha512-n6e4bsCpzsP0OB76X+vEWhySUQI8GHPVFVK+3QkX35tbryy2WoeGeK5kQ+oxzgDVHjIZyz5fyS60Mi3EpQLc0Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
@ -2808,7 +2836,7 @@
|
|||||||
},
|
},
|
||||||
"errno": {
|
"errno": {
|
||||||
"version": "0.1.8",
|
"version": "0.1.8",
|
||||||
"resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||||
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prr": "~1.0.1"
|
"prr": "~1.0.1"
|
||||||
@ -3081,7 +3109,7 @@
|
|||||||
},
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||||
},
|
},
|
||||||
"grapheme-splitter": {
|
"grapheme-splitter": {
|
||||||
@ -3287,6 +3315,14 @@
|
|||||||
"setimmediate": "^1.0.5"
|
"setimmediate": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"katex": {
|
||||||
|
"version": "0.16.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz",
|
||||||
|
"integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==",
|
||||||
|
"requires": {
|
||||||
|
"commander": "^8.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"kleur": {
|
"kleur": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||||
@ -3354,7 +3390,7 @@
|
|||||||
},
|
},
|
||||||
"memory-fs": {
|
"memory-fs": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/memory-fs/-/memory-fs-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz",
|
||||||
"integrity": "sha512-QTNXnl79X97kZ9jJk/meJrtDuvgvRakX5LU7HZW1L7MsXHuSTwoMIzN9tOLLH3Xfsj/gbsSqX/ovnsqz246zKQ==",
|
"integrity": "sha512-QTNXnl79X97kZ9jJk/meJrtDuvgvRakX5LU7HZW1L7MsXHuSTwoMIzN9tOLLH3Xfsj/gbsSqX/ovnsqz246zKQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"errno": "^0.1.3",
|
"errno": "^0.1.3",
|
||||||
@ -3599,7 +3635,7 @@
|
|||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||||
},
|
},
|
||||||
"object-is": {
|
"object-is": {
|
||||||
@ -3717,7 +3753,7 @@
|
|||||||
},
|
},
|
||||||
"prr": {
|
"prr": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
@ -3926,12 +3962,12 @@
|
|||||||
},
|
},
|
||||||
"tapable": {
|
"tapable": {
|
||||||
"version": "0.2.9",
|
"version": "0.2.9",
|
||||||
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-0.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz",
|
||||||
"integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A=="
|
"integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A=="
|
||||||
},
|
},
|
||||||
"tern": {
|
"tern": {
|
||||||
"version": "0.24.3",
|
"version": "0.24.3",
|
||||||
"resolved": "https://registry.npmmirror.com/tern/-/tern-0.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/tern/-/tern-0.24.3.tgz",
|
||||||
"integrity": "sha512-Z8uvtdWIlFn1GWy0HW5FhZ8VDryZwoJUdnjZU25C7/PBOltLIn1uv+WF3rVq6S1761YbsmbZYRP/l0ZJBCkvrw==",
|
"integrity": "sha512-Z8uvtdWIlFn1GWy0HW5FhZ8VDryZwoJUdnjZU25C7/PBOltLIn1uv+WF3rVq6S1761YbsmbZYRP/l0ZJBCkvrw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"acorn": "^6.0.0",
|
"acorn": "^6.0.0",
|
||||||
@ -3945,12 +3981,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "6.4.2",
|
"version": "6.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||||
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
|
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
|
||||||
},
|
},
|
||||||
"resolve-from": {
|
"resolve-from": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
|
||||||
"integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ=="
|
"integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
|
"katex": "^0.16.8",
|
||||||
"mdast-util-from-markdown": "^1.3.0",
|
"mdast-util-from-markdown": "^1.3.0",
|
||||||
"quill": "^1.3.6",
|
"quill": "^1.3.6",
|
||||||
"tern": "^0.24.3",
|
"tern": "^0.24.3",
|
||||||
|
|||||||
@ -365,7 +365,7 @@ export const cssContent = `
|
|||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smm-node:hover .smm-hover-node{
|
.smm-node:not(.smm-node-dragging):hover .smm-hover-node{
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -188,5 +188,18 @@ export const defaultOpt = {
|
|||||||
// 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动
|
// 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动
|
||||||
autoMoveWhenMouseInEdgeOnDrag: true,
|
autoMoveWhenMouseInEdgeOnDrag: true,
|
||||||
// 是否首次加载fit view
|
// 是否首次加载fit view
|
||||||
fit: false
|
fit: false,
|
||||||
|
// 拖拽多个节点时随鼠标移动的示意矩形的样式配置
|
||||||
|
dragMultiNodeRectConfig: {
|
||||||
|
width: 40,
|
||||||
|
height: 20,
|
||||||
|
fill: '' // 填充颜色,如果不传默认使用连线的颜色
|
||||||
|
},
|
||||||
|
// 节点拖拽时新位置的示意矩形的填充颜色,如果不传默认使用连线的颜色
|
||||||
|
dragPlaceholderRectFill: '',
|
||||||
|
// 节点拖拽时的透明度配置
|
||||||
|
dragOpacityConfig: {
|
||||||
|
cloneNodeOpacity: 0.5, // 跟随鼠标移动的克隆节点或矩形的透明度
|
||||||
|
beingDragNodeOpacity: 0.3 // 被拖拽节点的透明度
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,12 @@ import {
|
|||||||
walk,
|
walk,
|
||||||
bfsWalk,
|
bfsWalk,
|
||||||
loadImage,
|
loadImage,
|
||||||
isUndef
|
isUndef,
|
||||||
|
getTopAncestorsFomNodeList,
|
||||||
|
addDataToAppointNodes,
|
||||||
|
createUidForAppointNodes,
|
||||||
|
formatDataToArray,
|
||||||
|
getNodeIndex
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { shapeList } from './node/Shape'
|
import { shapeList } from './node/Shape'
|
||||||
import { lineStyleProps } from '../../themes/default'
|
import { lineStyleProps } from '../../themes/default'
|
||||||
@ -40,7 +45,6 @@ const layouts = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 渲染
|
// 渲染
|
||||||
|
|
||||||
class Render {
|
class Render {
|
||||||
// 构造函数
|
// 构造函数
|
||||||
constructor(opt = {}) {
|
constructor(opt = {}) {
|
||||||
@ -132,9 +136,18 @@ class Render {
|
|||||||
// 插入同级节点
|
// 插入同级节点
|
||||||
this.insertNode = this.insertNode.bind(this)
|
this.insertNode = this.insertNode.bind(this)
|
||||||
this.mindMap.command.add('INSERT_NODE', this.insertNode)
|
this.mindMap.command.add('INSERT_NODE', this.insertNode)
|
||||||
|
// 插入多个同级节点
|
||||||
|
this.insertMultiNode = this.insertMultiNode.bind(this)
|
||||||
|
this.mindMap.command.add('INSERT_MULTI_NODE', this.insertMultiNode)
|
||||||
// 插入子节点
|
// 插入子节点
|
||||||
this.insertChildNode = this.insertChildNode.bind(this)
|
this.insertChildNode = this.insertChildNode.bind(this)
|
||||||
this.mindMap.command.add('INSERT_CHILD_NODE', this.insertChildNode)
|
this.mindMap.command.add('INSERT_CHILD_NODE', this.insertChildNode)
|
||||||
|
// 插入多个子节点
|
||||||
|
this.insertMultiChildNode = this.insertMultiChildNode.bind(this)
|
||||||
|
this.mindMap.command.add(
|
||||||
|
'INSERT_MULTI_CHILD_NODE',
|
||||||
|
this.insertMultiChildNode
|
||||||
|
)
|
||||||
// 上移节点
|
// 上移节点
|
||||||
this.upNode = this.upNode.bind(this)
|
this.upNode = this.upNode.bind(this)
|
||||||
this.mindMap.command.add('UP_NODE', this.upNode)
|
this.mindMap.command.add('UP_NODE', this.upNode)
|
||||||
@ -202,6 +215,9 @@ class Render {
|
|||||||
// 设置节点标签
|
// 设置节点标签
|
||||||
this.setNodeTag = this.setNodeTag.bind(this)
|
this.setNodeTag = this.setNodeTag.bind(this)
|
||||||
this.mindMap.command.add('SET_NODE_TAG', this.setNodeTag)
|
this.mindMap.command.add('SET_NODE_TAG', this.setNodeTag)
|
||||||
|
// 设置节点公式
|
||||||
|
this.insertFormula = this.insertFormula.bind(this)
|
||||||
|
this.mindMap.command.add('INSERT_FORMULA', this.insertFormula)
|
||||||
// 添加节点概要
|
// 添加节点概要
|
||||||
this.addGeneralization = this.addGeneralization.bind(this)
|
this.addGeneralization = this.addGeneralization.bind(this)
|
||||||
this.mindMap.command.add('ADD_GENERALIZATION', this.addGeneralization)
|
this.mindMap.command.add('ADD_GENERALIZATION', this.addGeneralization)
|
||||||
@ -386,15 +402,6 @@ class Render {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取节点在同级里的索引位置
|
|
||||||
getNodeIndex(node) {
|
|
||||||
return node.parent
|
|
||||||
? node.parent.children.findIndex(item => {
|
|
||||||
return item.uid === node.uid
|
|
||||||
})
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全选
|
// 全选
|
||||||
selectAll() {
|
selectAll() {
|
||||||
walk(
|
walk(
|
||||||
@ -439,58 +446,117 @@ class Render {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 规范指定节点数据
|
// 插入同级节点
|
||||||
formatAppointNodes(appointNodes) {
|
|
||||||
if (!appointNodes) return []
|
|
||||||
return Array.isArray(appointNodes) ? appointNodes : [appointNodes]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插入同级节点,多个节点只会操作第一个节点
|
|
||||||
insertNode(
|
insertNode(
|
||||||
openEdit = true,
|
openEdit = true,
|
||||||
appointNodes = [],
|
appointNodes = [],
|
||||||
appointData = null,
|
appointData = null,
|
||||||
appointChildren = []
|
appointChildren = []
|
||||||
) {
|
) {
|
||||||
appointNodes = this.formatAppointNodes(appointNodes)
|
appointNodes = formatDataToArray(appointNodes)
|
||||||
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.textEdit.hideEditTextBox()
|
this.textEdit.hideEditTextBox()
|
||||||
let {
|
const {
|
||||||
defaultInsertSecondLevelNodeText,
|
defaultInsertSecondLevelNodeText,
|
||||||
defaultInsertBelowSecondLevelNodeText
|
defaultInsertBelowSecondLevelNodeText
|
||||||
} = this.mindMap.opt
|
} = this.mindMap.opt
|
||||||
let list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
const list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
||||||
let first = list[0]
|
const handleMultiNodes = list.length > 1
|
||||||
if (first.isGeneralization) {
|
const isRichText = !!this.mindMap.richText
|
||||||
return
|
const params = {
|
||||||
|
expand: true,
|
||||||
|
richText: isRichText,
|
||||||
|
resetRichText: isRichText,
|
||||||
|
isActive: handleMultiNodes || !openEdit // 如果同时对多个节点插入子节点,那么需要把新增的节点设为激活状态。如果不进入编辑状态,那么也需要手动设为激活状态
|
||||||
}
|
}
|
||||||
if (first.isRoot) {
|
// 动态指定的子节点数据也需要添加相关属性
|
||||||
this.insertChildNode(openEdit, appointNodes, appointData)
|
appointChildren = addDataToAppointNodes(appointChildren, {
|
||||||
} else {
|
...params
|
||||||
let text =
|
})
|
||||||
first.layerIndex === 1
|
const needDestroyNodeList = {}
|
||||||
? defaultInsertSecondLevelNodeText
|
list.forEach(node => {
|
||||||
: defaultInsertBelowSecondLevelNodeText
|
if (node.isGeneralization || node.isRoot) {
|
||||||
if (first.layerIndex === 1) {
|
return
|
||||||
first.parent.destroy()
|
|
||||||
}
|
}
|
||||||
let index = this.getNodeIndex(first)
|
const parent = node.parent
|
||||||
let isRichText = !!this.mindMap.richText
|
const isOneLayer = node.layerIndex === 1
|
||||||
first.parent.nodeData.children.splice(index + 1, 0, {
|
// 插入二级节点时根节点需要重新渲染
|
||||||
inserting: openEdit,
|
if (isOneLayer && !needDestroyNodeList[parent.uid]) {
|
||||||
|
needDestroyNodeList[parent.uid] = parent
|
||||||
|
}
|
||||||
|
// 新插入节点的默认文本
|
||||||
|
const text = isOneLayer
|
||||||
|
? defaultInsertSecondLevelNodeText
|
||||||
|
: defaultInsertBelowSecondLevelNodeText
|
||||||
|
// 计算插入位置
|
||||||
|
const index = parent.nodeData.children.findIndex(item => {
|
||||||
|
return item.data.uid === node.uid
|
||||||
|
})
|
||||||
|
parent.nodeData.children.splice(index + 1, 0, {
|
||||||
|
inserting: handleMultiNodes ? false : openEdit, // 如果同时对多个节点插入子节点,那么无需进入编辑模式,
|
||||||
data: {
|
data: {
|
||||||
text: text,
|
text: text,
|
||||||
expand: true,
|
...params,
|
||||||
richText: isRichText,
|
|
||||||
resetRichText: isRichText,
|
|
||||||
...(appointData || {})
|
...(appointData || {})
|
||||||
},
|
},
|
||||||
children: [...appointChildren]
|
children: [...appointChildren]
|
||||||
})
|
})
|
||||||
this.mindMap.render()
|
})
|
||||||
|
Object.keys(needDestroyNodeList).forEach(key => {
|
||||||
|
needDestroyNodeList[key].destroy()
|
||||||
|
})
|
||||||
|
// 如果同时对多个节点插入子节点,需要清除原来激活的节点
|
||||||
|
if (handleMultiNodes || !openEdit) {
|
||||||
|
this.clearActive()
|
||||||
}
|
}
|
||||||
|
this.mindMap.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入多个同级节点
|
||||||
|
insertMultiNode(appointNodes, nodeList) {
|
||||||
|
if (!nodeList || nodeList.length <= 0) return
|
||||||
|
appointNodes = formatDataToArray(appointNodes)
|
||||||
|
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.textEdit.hideEditTextBox()
|
||||||
|
const list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
||||||
|
const isRichText = !!this.mindMap.richText
|
||||||
|
const params = {
|
||||||
|
expand: true,
|
||||||
|
richText: isRichText,
|
||||||
|
resetRichText: isRichText,
|
||||||
|
isActive: true
|
||||||
|
}
|
||||||
|
nodeList = addDataToAppointNodes(nodeList, params)
|
||||||
|
const needDestroyNodeList = {}
|
||||||
|
list.forEach(node => {
|
||||||
|
if (node.isGeneralization || node.isRoot) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parent = node.parent
|
||||||
|
const isOneLayer = node.layerIndex === 1
|
||||||
|
// 插入二级节点时根节点需要重新渲染
|
||||||
|
if (isOneLayer && !needDestroyNodeList[parent.uid]) {
|
||||||
|
needDestroyNodeList[parent.uid] = parent
|
||||||
|
}
|
||||||
|
// 计算插入位置
|
||||||
|
const index = parent.nodeData.children.findIndex(item => {
|
||||||
|
return item.data.uid === node.uid
|
||||||
|
})
|
||||||
|
parent.nodeData.children.splice(
|
||||||
|
index + 1,
|
||||||
|
0,
|
||||||
|
...createUidForAppointNodes(simpleDeepClone(nodeList))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
Object.keys(needDestroyNodeList).forEach(key => {
|
||||||
|
needDestroyNodeList[key].destroy()
|
||||||
|
})
|
||||||
|
this.clearActive()
|
||||||
|
this.mindMap.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 插入子节点
|
// 插入子节点
|
||||||
@ -500,16 +566,28 @@ class Render {
|
|||||||
appointData = null,
|
appointData = null,
|
||||||
appointChildren = []
|
appointChildren = []
|
||||||
) {
|
) {
|
||||||
appointNodes = this.formatAppointNodes(appointNodes)
|
appointNodes = formatDataToArray(appointNodes)
|
||||||
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.textEdit.hideEditTextBox()
|
this.textEdit.hideEditTextBox()
|
||||||
let {
|
const {
|
||||||
defaultInsertSecondLevelNodeText,
|
defaultInsertSecondLevelNodeText,
|
||||||
defaultInsertBelowSecondLevelNodeText
|
defaultInsertBelowSecondLevelNodeText
|
||||||
} = this.mindMap.opt
|
} = this.mindMap.opt
|
||||||
let list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
const list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
||||||
|
const handleMultiNodes = list.length > 1
|
||||||
|
const isRichText = !!this.mindMap.richText
|
||||||
|
const params = {
|
||||||
|
expand: true,
|
||||||
|
richText: isRichText,
|
||||||
|
resetRichText: isRichText,
|
||||||
|
isActive: handleMultiNodes || !openEdit // 如果同时对多个节点插入子节点,那么需要把新增的节点设为激活状态。如果不进入编辑状态,那么也需要手动设为激活状态
|
||||||
|
}
|
||||||
|
// 动态指定的子节点数据也需要添加相关属性
|
||||||
|
appointChildren = addDataToAppointNodes(appointChildren, {
|
||||||
|
...params
|
||||||
|
})
|
||||||
list.forEach(node => {
|
list.forEach(node => {
|
||||||
if (node.isGeneralization) {
|
if (node.isGeneralization) {
|
||||||
return
|
return
|
||||||
@ -517,17 +595,14 @@ class Render {
|
|||||||
if (!node.nodeData.children) {
|
if (!node.nodeData.children) {
|
||||||
node.nodeData.children = []
|
node.nodeData.children = []
|
||||||
}
|
}
|
||||||
let text = node.isRoot
|
const text = node.isRoot
|
||||||
? defaultInsertSecondLevelNodeText
|
? defaultInsertSecondLevelNodeText
|
||||||
: defaultInsertBelowSecondLevelNodeText
|
: defaultInsertBelowSecondLevelNodeText
|
||||||
let isRichText = !!this.mindMap.richText
|
|
||||||
node.nodeData.children.push({
|
node.nodeData.children.push({
|
||||||
inserting: openEdit,
|
inserting: handleMultiNodes ? false : openEdit, // 如果同时对多个节点插入子节点,那么无需进入编辑模式
|
||||||
data: {
|
data: {
|
||||||
text: text,
|
text: text,
|
||||||
expand: true,
|
...params,
|
||||||
richText: isRichText,
|
|
||||||
resetRichText: isRichText,
|
|
||||||
...(appointData || {})
|
...(appointData || {})
|
||||||
},
|
},
|
||||||
children: [...appointChildren]
|
children: [...appointChildren]
|
||||||
@ -538,6 +613,45 @@ class Render {
|
|||||||
node.destroy()
|
node.destroy()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// 如果同时对多个节点插入子节点,需要清除原来激活的节点
|
||||||
|
if (handleMultiNodes || !openEdit) {
|
||||||
|
this.clearActive()
|
||||||
|
}
|
||||||
|
this.mindMap.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入多个子节点
|
||||||
|
insertMultiChildNode(appointNodes, childList) {
|
||||||
|
if (!childList || childList.length <= 0) return
|
||||||
|
appointNodes = formatDataToArray(appointNodes)
|
||||||
|
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.textEdit.hideEditTextBox()
|
||||||
|
const list = appointNodes.length > 0 ? appointNodes : this.activeNodeList
|
||||||
|
const isRichText = !!this.mindMap.richText
|
||||||
|
const params = {
|
||||||
|
expand: true,
|
||||||
|
richText: isRichText,
|
||||||
|
resetRichText: isRichText,
|
||||||
|
isActive: true
|
||||||
|
}
|
||||||
|
childList = addDataToAppointNodes(childList, params)
|
||||||
|
list.forEach(node => {
|
||||||
|
if (node.isGeneralization) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!node.nodeData.children) {
|
||||||
|
node.nodeData.children = []
|
||||||
|
}
|
||||||
|
node.nodeData.children.push(...childList)
|
||||||
|
// 插入子节点时自动展开子节点
|
||||||
|
node.nodeData.data.expand = true
|
||||||
|
if (node.isRoot) {
|
||||||
|
node.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.clearActive()
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,19 +712,19 @@ class Render {
|
|||||||
// 复制节点
|
// 复制节点
|
||||||
copy() {
|
copy() {
|
||||||
this.beingCopyData = this.copyNode()
|
this.beingCopyData = this.copyNode()
|
||||||
this.setCoptyDataToClipboard(this.beingCopyData)
|
this.setCopyDataToClipboard(this.beingCopyData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 剪切节点
|
// 剪切节点
|
||||||
cut() {
|
cut() {
|
||||||
this.mindMap.execCommand('CUT_NODE', copyData => {
|
this.mindMap.execCommand('CUT_NODE', copyData => {
|
||||||
this.beingCopyData = copyData
|
this.beingCopyData = copyData
|
||||||
this.setCoptyDataToClipboard(copyData)
|
this.setCopyDataToClipboard(copyData)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将粘贴或剪切的数据设置到用户剪切板中
|
// 将粘贴或剪切的数据设置到用户剪切板中
|
||||||
setCoptyDataToClipboard(data) {
|
setCopyDataToClipboard(data) {
|
||||||
if (navigator.clipboard) {
|
if (navigator.clipboard) {
|
||||||
navigator.clipboard.writeText(
|
navigator.clipboard.writeText(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@ -701,13 +815,9 @@ class Render {
|
|||||||
}
|
}
|
||||||
if (smmData) {
|
if (smmData) {
|
||||||
this.mindMap.execCommand(
|
this.mindMap.execCommand(
|
||||||
'INSERT_CHILD_NODE',
|
'INSERT_MULTI_CHILD_NODE',
|
||||||
false,
|
|
||||||
[],
|
[],
|
||||||
{
|
Array.isArray(smmData) ? smmData : [smmData]
|
||||||
...smmData.data
|
|
||||||
},
|
|
||||||
[...smmData.children]
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
this.mindMap.execCommand('INSERT_CHILD_NODE', false, [], {
|
this.mindMap.execCommand('INSERT_CHILD_NODE', false, [], {
|
||||||
@ -741,86 +851,70 @@ class Render {
|
|||||||
|
|
||||||
// 将节点移动到另一个节点的前面
|
// 将节点移动到另一个节点的前面
|
||||||
insertBefore(node, exist) {
|
insertBefore(node, exist) {
|
||||||
if (node.isRoot) {
|
this.insertTo(node, exist, 'before')
|
||||||
return
|
|
||||||
}
|
|
||||||
// 如果是二级节点变成了下级节点,或是下级节点变成了二级节点,节点样式需要更新
|
|
||||||
let nodeLayerChanged =
|
|
||||||
(node.layerIndex === 1 && exist.layerIndex !== 1) ||
|
|
||||||
(node.layerIndex !== 1 && exist.layerIndex === 1)
|
|
||||||
// 移动节点
|
|
||||||
let nodeParent = node.parent
|
|
||||||
let nodeBorthers = nodeParent.children
|
|
||||||
let nodeIndex = nodeBorthers.findIndex(item => {
|
|
||||||
return item.uid === node.uid
|
|
||||||
})
|
|
||||||
if (nodeIndex === -1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nodeBorthers.splice(nodeIndex, 1)
|
|
||||||
nodeParent.nodeData.children.splice(nodeIndex, 1)
|
|
||||||
|
|
||||||
// 目标节点
|
|
||||||
let existParent = exist.parent
|
|
||||||
let existBorthers = existParent.children
|
|
||||||
let existIndex = existBorthers.findIndex(item => {
|
|
||||||
return item.uid === exist.uid
|
|
||||||
})
|
|
||||||
if (existIndex === -1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
existBorthers.splice(existIndex, 0, node)
|
|
||||||
existParent.nodeData.children.splice(existIndex, 0, node.nodeData)
|
|
||||||
this.mindMap.render(() => {
|
|
||||||
if (nodeLayerChanged) {
|
|
||||||
node.reRender()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将节点移动到另一个节点的后面
|
// 将节点移动到另一个节点的后面
|
||||||
insertAfter(node, exist) {
|
insertAfter(node, exist) {
|
||||||
if (node.isRoot) {
|
this.insertTo(node, exist, 'after')
|
||||||
return
|
}
|
||||||
}
|
|
||||||
// 如果是二级节点变成了下级节点,或是下级节点变成了二级节点,节点样式需要更新
|
|
||||||
let nodeLayerChanged =
|
|
||||||
(node.layerIndex === 1 && exist.layerIndex !== 1) ||
|
|
||||||
(node.layerIndex !== 1 && exist.layerIndex === 1)
|
|
||||||
// 移动节点
|
|
||||||
let nodeParent = node.parent
|
|
||||||
let nodeBorthers = nodeParent.children
|
|
||||||
let nodeIndex = nodeBorthers.findIndex(item => {
|
|
||||||
return item.uid === node.uid
|
|
||||||
})
|
|
||||||
if (nodeIndex === -1) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nodeBorthers.splice(nodeIndex, 1)
|
|
||||||
nodeParent.nodeData.children.splice(nodeIndex, 1)
|
|
||||||
|
|
||||||
// 目标节点
|
// 将节点移动到另一个节点的前面或后面
|
||||||
let existParent = exist.parent
|
insertTo(node, exist, dir = 'before') {
|
||||||
let existBorthers = existParent.children
|
let nodeList = formatDataToArray(node)
|
||||||
let existIndex = existBorthers.findIndex(item => {
|
nodeList = nodeList.filter(item => {
|
||||||
return item.uid === exist.uid
|
return !item.isRoot
|
||||||
})
|
})
|
||||||
if (existIndex === -1) {
|
if (dir === 'after') {
|
||||||
return
|
nodeList.reverse()
|
||||||
}
|
}
|
||||||
existIndex++
|
nodeList.forEach(item => {
|
||||||
existBorthers.splice(existIndex, 0, node)
|
this.checkNodeLayerChange(item, exist)
|
||||||
existParent.nodeData.children.splice(existIndex, 0, node.nodeData)
|
// 移动节点
|
||||||
this.mindMap.render(() => {
|
let nodeParent = item.parent
|
||||||
if (nodeLayerChanged) {
|
let nodeBorthers = nodeParent.children
|
||||||
node.reRender()
|
let nodeIndex = nodeBorthers.findIndex(item2 => {
|
||||||
|
return item.uid === item2.uid
|
||||||
|
})
|
||||||
|
if (nodeIndex === -1) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
nodeBorthers.splice(nodeIndex, 1)
|
||||||
|
nodeParent.nodeData.children.splice(nodeIndex, 1)
|
||||||
|
|
||||||
|
// 目标节点
|
||||||
|
let existParent = exist.parent
|
||||||
|
let existBorthers = existParent.children
|
||||||
|
let existIndex = existBorthers.findIndex(item2 => {
|
||||||
|
return item2.uid === exist.uid
|
||||||
|
})
|
||||||
|
if (existIndex === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (dir === 'after') {
|
||||||
|
existIndex++
|
||||||
|
}
|
||||||
|
existBorthers.splice(existIndex, 0, item)
|
||||||
|
existParent.nodeData.children.splice(existIndex, 0, item.nodeData)
|
||||||
})
|
})
|
||||||
|
this.mindMap.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是富文本模式,那么某些层级变化需要更新样式
|
||||||
|
checkNodeLayerChange(node, toNode) {
|
||||||
|
if (this.mindMap.richText) {
|
||||||
|
let nodeLayerChanged =
|
||||||
|
(node.layerIndex === 1 && toNode.layerIndex !== 1) ||
|
||||||
|
(node.layerIndex !== 1 && toNode.layerIndex === 1)
|
||||||
|
if (nodeLayerChanged) {
|
||||||
|
node.nodeData.data.resetRichText = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除节点
|
// 移除节点
|
||||||
removeNode(appointNodes = []) {
|
removeNode(appointNodes = []) {
|
||||||
appointNodes = this.formatAppointNodes(appointNodes)
|
appointNodes = formatDataToArray(appointNodes)
|
||||||
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -892,32 +986,40 @@ class Render {
|
|||||||
|
|
||||||
// 移除某个指定节点
|
// 移除某个指定节点
|
||||||
removeOneNode(node) {
|
removeOneNode(node) {
|
||||||
let index = this.getNodeIndex(node)
|
let index = getNodeIndex(node)
|
||||||
node.remove()
|
node.remove()
|
||||||
node.parent.children.splice(index, 1)
|
node.parent.children.splice(index, 1)
|
||||||
node.parent.nodeData.children.splice(index, 1)
|
node.parent.nodeData.children.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制节点,多个节点只会操作第一个节点
|
// 复制节点
|
||||||
copyNode() {
|
copyNode() {
|
||||||
if (this.activeNodeList.length <= 0) {
|
if (this.activeNodeList.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return copyNodeTree({}, this.activeNodeList[0], true)
|
const nodeList = getTopAncestorsFomNodeList(this.activeNodeList)
|
||||||
|
return nodeList.map(node => {
|
||||||
|
return copyNodeTree({}, node, true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 剪切节点,多个节点只会操作第一个节点
|
// 剪切节点
|
||||||
cutNode(callback) {
|
cutNode(callback) {
|
||||||
if (this.activeNodeList.length <= 0) {
|
if (this.activeNodeList.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let node = this.activeNodeList[0]
|
const nodeList = getTopAncestorsFomNodeList(this.activeNodeList).filter(
|
||||||
if (node.isRoot) {
|
node => {
|
||||||
return null
|
return !node.isRoot
|
||||||
}
|
}
|
||||||
let copyData = copyNodeTree({}, node, true)
|
)
|
||||||
this.removeActiveNode(node)
|
const copyData = nodeList.map(node => {
|
||||||
this.removeOneNode(node)
|
return copyNodeTree({}, node, true)
|
||||||
|
})
|
||||||
|
nodeList.forEach(node => {
|
||||||
|
this.removeActiveNode(node)
|
||||||
|
this.removeOneNode(node)
|
||||||
|
})
|
||||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
if (callback && typeof callback === 'function') {
|
if (callback && typeof callback === 'function') {
|
||||||
@ -925,16 +1027,19 @@ class Render {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动一个节点作为另一个节点的子节点
|
// 移动节点作为另一个节点的子节点
|
||||||
moveNodeTo(node, toNode) {
|
moveNodeTo(node, toNode) {
|
||||||
if (node.isRoot) {
|
let nodeList = formatDataToArray(node)
|
||||||
return
|
nodeList = nodeList.filter(item => {
|
||||||
}
|
return !item.isRoot
|
||||||
// let copyData = copyNodeTree({}, node, false, true)
|
})
|
||||||
this.removeActiveNode(node)
|
nodeList.forEach(item => {
|
||||||
this.removeOneNode(node)
|
this.checkNodeLayerChange(item, toNode)
|
||||||
|
this.removeActiveNode(item)
|
||||||
|
this.removeOneNode(item)
|
||||||
|
toNode.nodeData.children.push(item.nodeData)
|
||||||
|
})
|
||||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||||
toNode.nodeData.children.push(node.nodeData)
|
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
if (toNode.isRoot) {
|
if (toNode.isRoot) {
|
||||||
toNode.destroy()
|
toNode.destroy()
|
||||||
@ -943,11 +1048,16 @@ class Render {
|
|||||||
|
|
||||||
// 粘贴节点到节点
|
// 粘贴节点到节点
|
||||||
pasteNode(data) {
|
pasteNode(data) {
|
||||||
if (this.activeNodeList.length <= 0 || !data) {
|
data = formatDataToArray(data)
|
||||||
|
if (this.activeNodeList.length <= 0 || data.length <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.activeNodeList.forEach(item => {
|
this.activeNodeList.forEach(node => {
|
||||||
item.nodeData.children.push(simpleDeepClone(data))
|
node.nodeData.children.push(
|
||||||
|
...data.map(item => {
|
||||||
|
return simpleDeepClone(item)
|
||||||
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
}
|
}
|
||||||
@ -1171,6 +1281,15 @@ class Render {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置节点公式
|
||||||
|
insertFormula(formula) {
|
||||||
|
// 只在富文本模式下可用,并且需要注册Formula插件
|
||||||
|
if (!this.mindMap.richText || !this.mindMap.formula) return
|
||||||
|
this.activeNodeList.forEach(node => {
|
||||||
|
this.mindMap.formula.insertFormulaToNode(node, formula)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 添加节点概要
|
// 添加节点概要
|
||||||
addGeneralization(data) {
|
addGeneralization(data) {
|
||||||
if (this.activeNodeList.length <= 0) {
|
if (this.activeNodeList.length <= 0) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { getStrWithBrFromHtml, checkNodeOuter } from '../../utils'
|
import { getStrWithBrFromHtml, checkNodeOuter, focusInput, selectAllInput } from '../../utils'
|
||||||
import { ERROR_TYPES } from '../../constants/constant'
|
import { ERROR_TYPES } from '../../constants/constant'
|
||||||
|
|
||||||
// 节点文字编辑类
|
// 节点文字编辑类
|
||||||
@ -188,35 +188,16 @@ export default class TextEdit {
|
|||||||
this.showTextEdit = true
|
this.showTextEdit = true
|
||||||
// 选中文本
|
// 选中文本
|
||||||
// if (!this.cacheEditingText) {
|
// if (!this.cacheEditingText) {
|
||||||
// this.selectNodeText()
|
// selectAllInput(this.textEditNode)
|
||||||
// }
|
// }
|
||||||
if (isInserting || (selectTextOnEnterEditText && !isFromKeyDown)) {
|
if (isInserting || (selectTextOnEnterEditText && !isFromKeyDown)) {
|
||||||
this.selectNodeText()
|
selectAllInput(this.textEditNode)
|
||||||
} else {
|
} else {
|
||||||
this.focus()
|
focusInput(this.textEditNode)
|
||||||
}
|
}
|
||||||
this.cacheEditingText = ''
|
this.cacheEditingText = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 聚焦
|
|
||||||
focus() {
|
|
||||||
let selection = window.getSelection()
|
|
||||||
let range = document.createRange()
|
|
||||||
range.selectNodeContents(this.textEditNode)
|
|
||||||
range.collapse()
|
|
||||||
selection.removeAllRanges()
|
|
||||||
selection.addRange(range)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选中文本
|
|
||||||
selectNodeText() {
|
|
||||||
let selection = window.getSelection()
|
|
||||||
let range = document.createRange()
|
|
||||||
range.selectNodeContents(this.textEditNode)
|
|
||||||
selection.removeAllRanges()
|
|
||||||
selection.addRange(range)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前正在编辑的内容
|
// 获取当前正在编辑的内容
|
||||||
getEditText() {
|
getEditText() {
|
||||||
return getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
return getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class Node {
|
|||||||
constructor(opt = {}) {
|
constructor(opt = {}) {
|
||||||
// 节点数据
|
// 节点数据
|
||||||
this.nodeData = this.handleData(opt.data || {})
|
this.nodeData = this.handleData(opt.data || {})
|
||||||
// id
|
// uid
|
||||||
this.uid = opt.uid
|
this.uid = opt.uid
|
||||||
// 控制实例
|
// 控制实例
|
||||||
this.mindMap = opt.mindMap
|
this.mindMap = opt.mindMap
|
||||||
@ -440,12 +440,14 @@ class Node {
|
|||||||
this.mindMap.emit('node_mouseup', this, e)
|
this.mindMap.emit('node_mouseup', this, e)
|
||||||
})
|
})
|
||||||
this.group.on('mouseenter', e => {
|
this.group.on('mouseenter', e => {
|
||||||
|
if (this.isDrag) return
|
||||||
this._isMouseenter = true
|
this._isMouseenter = true
|
||||||
// 显示展开收起按钮
|
// 显示展开收起按钮
|
||||||
this.showExpandBtn()
|
this.showExpandBtn()
|
||||||
this.mindMap.emit('node_mouseenter', this, e)
|
this.mindMap.emit('node_mouseenter', this, e)
|
||||||
})
|
})
|
||||||
this.group.on('mouseleave', e => {
|
this.group.on('mouseleave', e => {
|
||||||
|
if (!this._isMouseenter) return
|
||||||
this._isMouseenter = false
|
this._isMouseenter = false
|
||||||
this.hideExpandBtn()
|
this.hideExpandBtn()
|
||||||
this.mindMap.emit('node_mouseleave', this, e)
|
this.mindMap.emit('node_mouseleave', this, e)
|
||||||
@ -701,6 +703,61 @@ class Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置节点透明度
|
||||||
|
// 包括连接线和下级节点
|
||||||
|
setOpacity(val) {
|
||||||
|
// 自身及连线
|
||||||
|
this.group.opacity(val)
|
||||||
|
this._lines.forEach(line => {
|
||||||
|
line.opacity(val)
|
||||||
|
})
|
||||||
|
// 子节点
|
||||||
|
this.children.forEach(item => {
|
||||||
|
item.setOpacity(val)
|
||||||
|
})
|
||||||
|
// 概要节点
|
||||||
|
if (this._generalizationNode) {
|
||||||
|
this._generalizationLine.opacity(val)
|
||||||
|
this._generalizationNode.group.opacity(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏子节点
|
||||||
|
hideChildren() {
|
||||||
|
this._lines.forEach(item => {
|
||||||
|
item.hide()
|
||||||
|
})
|
||||||
|
if (this.children && this.children.length) {
|
||||||
|
this.children.forEach(item => {
|
||||||
|
item.hide()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示子节点
|
||||||
|
showChildren() {
|
||||||
|
this._lines.forEach(item => {
|
||||||
|
item.show()
|
||||||
|
})
|
||||||
|
if (this.children && this.children.length) {
|
||||||
|
this.children.forEach(item => {
|
||||||
|
item.show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 被拖拽中
|
||||||
|
startDrag() {
|
||||||
|
this.isDrag = true
|
||||||
|
this.group.addClass('smm-node-dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽结束
|
||||||
|
endDrag() {
|
||||||
|
this.isDrag = false
|
||||||
|
this.group.removeClass('smm-node-dragging')
|
||||||
|
}
|
||||||
|
|
||||||
// 连线
|
// 连线
|
||||||
renderLine(deep = false) {
|
renderLine(deep = false) {
|
||||||
if (this.nodeData.data.expand === false) {
|
if (this.nodeData.data.expand === false) {
|
||||||
|
|||||||
@ -136,6 +136,7 @@ function renderExpandBtn() {
|
|||||||
this._expandBtn.on('dblclick', e => {
|
this._expandBtn.on('dblclick', e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
|
this._expandBtn.addClass('smm-expand-btn')
|
||||||
this.group.add(this._expandBtn)
|
this.group.add(this._expandBtn)
|
||||||
}
|
}
|
||||||
this._showExpandBtn = true
|
this._showExpandBtn = true
|
||||||
|
|||||||
@ -149,8 +149,8 @@ class AssociativeLine {
|
|||||||
) {
|
) {
|
||||||
nodeToIds.set(cur, data.associativeLineTargets)
|
nodeToIds.set(cur, data.associativeLineTargets)
|
||||||
}
|
}
|
||||||
if (data.id) {
|
if (data.uid) {
|
||||||
idToNode.set(data.id, cur)
|
idToNode.set(data.uid, cur)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {},
|
() => {},
|
||||||
@ -158,8 +158,8 @@ class AssociativeLine {
|
|||||||
0
|
0
|
||||||
)
|
)
|
||||||
nodeToIds.forEach((ids, node) => {
|
nodeToIds.forEach((ids, node) => {
|
||||||
ids.forEach((id, index) => {
|
ids.forEach((uid, index) => {
|
||||||
let toNode = idToNode.get(id)
|
let toNode = idToNode.get(uid)
|
||||||
if (!node || !toNode) return
|
if (!node || !toNode) return
|
||||||
const associativeLinePoint = (node.nodeData.data.associativeLinePoint ||
|
const associativeLinePoint = (node.nodeData.data.associativeLinePoint ||
|
||||||
[])[index]
|
[])[index]
|
||||||
@ -234,6 +234,11 @@ class AssociativeLine {
|
|||||||
controlPoints
|
controlPoints
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
// 双击进入关联线文本编辑状态
|
||||||
|
clickPath.dblclick(() => {
|
||||||
|
if (!this.activeLine) return
|
||||||
|
this.showEditTextBox(text)
|
||||||
|
})
|
||||||
// 渲染关联线文字
|
// 渲染关联线文字
|
||||||
this.renderText(this.getText(node, toNode), path, text)
|
this.renderText(this.getText(node, toNode), path, text)
|
||||||
this.lineList.push([path, clickPath, text, node, toNode])
|
this.lineList.push([path, clickPath, text, node, toNode])
|
||||||
@ -252,28 +257,25 @@ class AssociativeLine {
|
|||||||
}) {
|
}) {
|
||||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||||
// 如果当前存在激活节点,那么取消激活节点
|
// 如果当前存在激活节点,那么取消激活节点
|
||||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
||||||
this.clearActiveNodes()
|
// 否则清除当前的关联线的激活状态,如果有的话
|
||||||
} else {
|
this.clearActiveLine()
|
||||||
// 否则清除当前的关联线的激活状态,如果有的话
|
// 保存当前激活的关联线信息
|
||||||
this.clearActiveLine()
|
this.activeLine = [path, clickPath, text, node, toNode]
|
||||||
// 保存当前激活的关联线信息
|
// 让不可见的点击线显示
|
||||||
this.activeLine = [path, clickPath, text, node, toNode]
|
clickPath.stroke({ color: associativeLineActiveColor })
|
||||||
// 让不可见的点击线显示
|
// 如果没有输入过关联线文字,那么显示默认文字
|
||||||
clickPath.stroke({ color: associativeLineActiveColor })
|
if (!this.getText(node, toNode)) {
|
||||||
// 如果没有输入过关联线文字,那么显示默认文字
|
this.renderText(this.mindMap.opt.defaultAssociativeLineText, path, text)
|
||||||
if (!this.getText(node, toNode)) {
|
|
||||||
this.renderText(this.mindMap.opt.defaultAssociativeLineText, path, text)
|
|
||||||
}
|
|
||||||
// 渲染控制点和连线
|
|
||||||
this.renderControls(
|
|
||||||
startPoint,
|
|
||||||
endPoint,
|
|
||||||
controlPoints[0],
|
|
||||||
controlPoints[1]
|
|
||||||
)
|
|
||||||
this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
|
|
||||||
}
|
}
|
||||||
|
// 渲染控制点和连线
|
||||||
|
this.renderControls(
|
||||||
|
startPoint,
|
||||||
|
endPoint,
|
||||||
|
controlPoints[0],
|
||||||
|
controlPoints[1]
|
||||||
|
)
|
||||||
|
this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除所有连接线
|
// 移除所有连接线
|
||||||
@ -395,21 +397,21 @@ class AssociativeLine {
|
|||||||
addLine(fromNode, toNode) {
|
addLine(fromNode, toNode) {
|
||||||
if (!fromNode || !toNode) return
|
if (!fromNode || !toNode) return
|
||||||
// 目标节点如果没有id,则生成一个id
|
// 目标节点如果没有id,则生成一个id
|
||||||
let id = toNode.nodeData.data.id
|
let uid = toNode.nodeData.data.uid
|
||||||
if (!id) {
|
if (!uid) {
|
||||||
id = uuid()
|
uid = uuid()
|
||||||
this.mindMap.execCommand('SET_NODE_DATA', toNode, {
|
this.mindMap.execCommand('SET_NODE_DATA', toNode, {
|
||||||
id
|
uid
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 将目标节点id保存起来
|
// 将目标节点id保存起来
|
||||||
let list = fromNode.nodeData.data.associativeLineTargets || []
|
let list = fromNode.nodeData.data.associativeLineTargets || []
|
||||||
// 连线节点是否存在相同的id,存在则阻止添加关联线
|
// 连线节点是否存在相同的id,存在则阻止添加关联线
|
||||||
const sameLine = list.some(item => item === id)
|
const sameLine = list.some(item => item === uid)
|
||||||
if (sameLine) {
|
if (sameLine) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list.push(id)
|
list.push(uid)
|
||||||
// 保存控制点
|
// 保存控制点
|
||||||
let [startPoint, endPoint] = computeNodePoints(fromNode, toNode)
|
let [startPoint, endPoint] = computeNodePoints(fromNode, toNode)
|
||||||
let controlPoints = computeCubicBezierPathPoints(
|
let controlPoints = computeCubicBezierPathPoints(
|
||||||
@ -458,7 +460,7 @@ class AssociativeLine {
|
|||||||
let newAssociativeLineText = {}
|
let newAssociativeLineText = {}
|
||||||
if (associativeLineText) {
|
if (associativeLineText) {
|
||||||
Object.keys(associativeLineText).forEach(item => {
|
Object.keys(associativeLineText).forEach(item => {
|
||||||
if (item !== toNode.nodeData.data.id) {
|
if (item !== toNode.nodeData.data.uid) {
|
||||||
newAssociativeLineText[item] = associativeLineText[item]
|
newAssociativeLineText[item] = associativeLineText[item]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -483,13 +485,6 @@ class AssociativeLine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除当前激活的节点
|
|
||||||
clearActiveNodes() {
|
|
||||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
|
||||||
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除激活的线
|
// 清除激活的线
|
||||||
clearActiveLine() {
|
clearActiveLine() {
|
||||||
if (this.activeLine) {
|
if (this.activeLine) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { bfsWalk, throttle } from '../utils'
|
import { bfsWalk, throttle, getTopAncestorsFomNodeList } from '../utils'
|
||||||
import Base from '../layouts/Base'
|
import Base from '../layouts/Base'
|
||||||
|
|
||||||
// 节点拖动插件
|
// 节点拖动插件
|
||||||
@ -13,10 +13,14 @@ class Drag extends Base {
|
|||||||
|
|
||||||
// 复位
|
// 复位
|
||||||
reset() {
|
reset() {
|
||||||
|
// 是否正在跳转中
|
||||||
|
this.isDragging = false
|
||||||
|
// 鼠标按下的节点
|
||||||
|
this.mousedownNode = null
|
||||||
|
// 被拖拽中的节点列表
|
||||||
|
this.beingDragNodeList = []
|
||||||
// 当前画布节点列表
|
// 当前画布节点列表
|
||||||
this.nodeList = []
|
this.nodeList = []
|
||||||
// 当前拖拽节点
|
|
||||||
this.node = null
|
|
||||||
// 当前重叠节点
|
// 当前重叠节点
|
||||||
this.overlapNode = null
|
this.overlapNode = null
|
||||||
// 当前上一个同级节点
|
// 当前上一个同级节点
|
||||||
@ -27,16 +31,11 @@ class Drag extends Base {
|
|||||||
this.drawTransform = null
|
this.drawTransform = null
|
||||||
// 克隆节点
|
// 克隆节点
|
||||||
this.clone = null
|
this.clone = null
|
||||||
// 连接线
|
|
||||||
this.line = null
|
|
||||||
// 同级位置占位符
|
// 同级位置占位符
|
||||||
this.placeholder = null
|
this.placeholder = null
|
||||||
// 鼠标按下位置和节点左上角的偏移量
|
// 鼠标按下位置和节点左上角的偏移量
|
||||||
this.offsetX = 0
|
this.offsetX = 0
|
||||||
this.offsetY = 0
|
this.offsetY = 0
|
||||||
// 克隆节点左上角的坐标
|
|
||||||
this.cloneNodeLeft = 0
|
|
||||||
this.cloneNodeTop = 0
|
|
||||||
// 当前鼠标是否按下
|
// 当前鼠标是否按下
|
||||||
this.isMousedown = false
|
this.isMousedown = false
|
||||||
// 拖拽的鼠标位置变量
|
// 拖拽的鼠标位置变量
|
||||||
@ -53,45 +52,42 @@ class Drag extends Base {
|
|||||||
bindEvent() {
|
bindEvent() {
|
||||||
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
|
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
|
||||||
this.mindMap.on('node_mousedown', (node, e) => {
|
this.mindMap.on('node_mousedown', (node, e) => {
|
||||||
if (this.mindMap.opt.readonly || node.isGeneralization) {
|
// 只读模式、不是鼠标左键按下、按下的是概要节点或根节点直接返回
|
||||||
return
|
|
||||||
}
|
|
||||||
if (e.which !== 1 || node.isRoot) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
e.preventDefault()
|
|
||||||
// 计算鼠标按下的位置距离节点左上角的距离
|
|
||||||
this.drawTransform = this.mindMap.draw.transform()
|
|
||||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
|
||||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
|
||||||
this.offsetX = x - (node.left * scaleX + translateX)
|
|
||||||
this.offsetY = y - (node.top * scaleY + translateY)
|
|
||||||
this.node = node
|
|
||||||
this.isMousedown = true
|
|
||||||
this.mouseDownX = x
|
|
||||||
this.mouseDownY = y
|
|
||||||
this.nodeTreeToList()
|
|
||||||
})
|
|
||||||
this.mindMap.on('mousemove', e => {
|
|
||||||
if (this.mindMap.opt.readonly) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!this.isMousedown) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.mindMap.emit('node_dragging', this.node)
|
|
||||||
e.preventDefault()
|
|
||||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
|
||||||
this.mouseMoveX = x
|
|
||||||
this.mouseMoveY = y
|
|
||||||
if (
|
if (
|
||||||
Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
|
this.mindMap.opt.readonly ||
|
||||||
Math.abs(y - this.mouseDownY) <= this.checkDragOffset &&
|
e.which !== 1 ||
|
||||||
!this.node.isDrag
|
node.isGeneralization ||
|
||||||
|
node.isRoot
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mindMap.renderer.clearAllActive()
|
e.preventDefault()
|
||||||
|
this.isMousedown = true
|
||||||
|
// 记录鼠标按下时的节点
|
||||||
|
this.mousedownNode = node
|
||||||
|
// 记录鼠标按下的坐标
|
||||||
|
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||||
|
this.mouseDownX = x
|
||||||
|
this.mouseDownY = y
|
||||||
|
})
|
||||||
|
this.mindMap.on('mousemove', e => {
|
||||||
|
if (this.mindMap.opt.readonly || !this.isMousedown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||||
|
this.mouseMoveX = x
|
||||||
|
this.mouseMoveY = y
|
||||||
|
// 还没开始移动时鼠标位移过小不认为是拖拽
|
||||||
|
if (
|
||||||
|
!this.isDragging &&
|
||||||
|
Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
|
||||||
|
Math.abs(y - this.mouseDownY) <= this.checkDragOffset
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.mindMap.emit('node_dragging')
|
||||||
|
this.handleStartMove()
|
||||||
this.onMove(x, y, e)
|
this.onMove(x, y, e)
|
||||||
})
|
})
|
||||||
this.onMouseup = this.onMouseup.bind(this)
|
this.onMouseup = this.onMouseup.bind(this)
|
||||||
@ -105,9 +101,12 @@ class Drag extends Base {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.isMousedown = false
|
this.isMousedown = false
|
||||||
let _nodeIsDrag = this.node.isDrag
|
// 恢复被拖拽节点的临时设置
|
||||||
this.node.isDrag = false
|
this.beingDragNodeList.forEach(node => {
|
||||||
this.node.show()
|
node.setOpacity(1)
|
||||||
|
node.showChildren()
|
||||||
|
node.endDrag()
|
||||||
|
})
|
||||||
this.removeCloneNode()
|
this.removeCloneNode()
|
||||||
let overlapNodeUid = this.overlapNode
|
let overlapNodeUid = this.overlapNode
|
||||||
? this.overlapNode.nodeData.data.uid
|
? this.overlapNode.nodeData.data.uid
|
||||||
@ -117,17 +116,33 @@ class Drag extends Base {
|
|||||||
// 存在重叠子节点,则移动作为其子节点
|
// 存在重叠子节点,则移动作为其子节点
|
||||||
if (this.overlapNode) {
|
if (this.overlapNode) {
|
||||||
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||||
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
|
this.mindMap.execCommand(
|
||||||
|
'MOVE_NODE_TO',
|
||||||
|
this.beingDragNodeList,
|
||||||
|
this.overlapNode
|
||||||
|
)
|
||||||
} else if (this.prevNode) {
|
} else if (this.prevNode) {
|
||||||
// 存在前一个相邻节点,作为其下一个兄弟节点
|
// 存在前一个相邻节点,作为其下一个兄弟节点
|
||||||
this.mindMap.renderer.setNodeActive(this.prevNode, false)
|
this.mindMap.renderer.setNodeActive(this.prevNode, false)
|
||||||
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
|
this.mindMap.execCommand(
|
||||||
|
'INSERT_AFTER',
|
||||||
|
this.beingDragNodeList,
|
||||||
|
this.prevNode
|
||||||
|
)
|
||||||
} else if (this.nextNode) {
|
} else if (this.nextNode) {
|
||||||
// 存在下一个相邻节点,作为其前一个兄弟节点
|
// 存在下一个相邻节点,作为其前一个兄弟节点
|
||||||
this.mindMap.renderer.setNodeActive(this.nextNode, false)
|
this.mindMap.renderer.setNodeActive(this.nextNode, false)
|
||||||
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
|
this.mindMap.execCommand(
|
||||||
} else if (_nodeIsDrag && this.mindMap.opt.enableFreeDrag) {
|
'INSERT_BEFORE',
|
||||||
// 自定义位置
|
this.beingDragNodeList,
|
||||||
|
this.nextNode
|
||||||
|
)
|
||||||
|
} else if (
|
||||||
|
this.clone &&
|
||||||
|
this.mindMap.opt.enableFreeDrag &&
|
||||||
|
this.beingDragNodeList.length === 1
|
||||||
|
) {
|
||||||
|
// 如果只拖拽了一个节点,那么设置自定义位置
|
||||||
let { x, y } = this.mindMap.toPos(
|
let { x, y } = this.mindMap.toPos(
|
||||||
e.clientX - this.offsetX,
|
e.clientX - this.offsetX,
|
||||||
e.clientY - this.offsetY
|
e.clientY - this.offsetY
|
||||||
@ -135,11 +150,16 @@ class Drag extends Base {
|
|||||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||||
x = (x - translateX) / scaleX
|
x = (x - translateX) / scaleX
|
||||||
y = (y - translateY) / scaleY
|
y = (y - translateY) / scaleY
|
||||||
this.node.left = x
|
this.mousedownNode.left = x
|
||||||
this.node.top = y
|
this.mousedownNode.top = y
|
||||||
this.node.customLeft = x
|
this.mousedownNode.customLeft = x
|
||||||
this.node.customTop = y
|
this.mousedownNode.customTop = y
|
||||||
this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
|
this.mindMap.execCommand(
|
||||||
|
'SET_NODE_CUSTOM_POSITION',
|
||||||
|
this.mousedownNode,
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
)
|
||||||
this.mindMap.render()
|
this.mindMap.render()
|
||||||
}
|
}
|
||||||
this.reset()
|
this.reset()
|
||||||
@ -150,24 +170,131 @@ class Drag extends Base {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 拖动中
|
||||||
|
onMove(x, y, e) {
|
||||||
|
if (!this.isMousedown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 更新克隆节点的位置
|
||||||
|
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||||
|
let cloneNodeLeft = x - this.offsetX
|
||||||
|
let cloneNodeTop = y - this.offsetY
|
||||||
|
x = (cloneNodeLeft - translateX) / scaleX
|
||||||
|
y = (cloneNodeTop - translateY) / scaleY
|
||||||
|
let t = this.clone.transform()
|
||||||
|
this.clone.translate(x - t.translateX, y - t.translateY)
|
||||||
|
// 检测新位置
|
||||||
|
this.checkOverlapNode()
|
||||||
|
// 如果注册了多选节点插件,那么复用它的边缘自动移动画布功能
|
||||||
|
if (this.mindMap.opt.autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
|
||||||
|
this.drawTransform = this.mindMap.draw.transform()
|
||||||
|
this.mindMap.select.clearAutoMoveTimer()
|
||||||
|
this.mindMap.select.onMove(e.clientX, e.clientY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始拖拽时初始化一些数据
|
||||||
|
handleStartMove() {
|
||||||
|
if (!this.isDragging) {
|
||||||
|
this.isDragging = true
|
||||||
|
// 鼠标按下的节点
|
||||||
|
let node = this.mousedownNode
|
||||||
|
// 计算鼠标按下的位置距离节点左上角的距离
|
||||||
|
this.drawTransform = this.mindMap.draw.transform()
|
||||||
|
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||||
|
this.offsetX = this.mouseDownX - (node.left * scaleX + translateX)
|
||||||
|
this.offsetY = this.mouseDownY - (node.top * scaleY + translateY)
|
||||||
|
// 如果鼠标按下的节点是激活节点,那么保存当前所有激活的节点
|
||||||
|
if (node.nodeData.data.isActive) {
|
||||||
|
// 找出这些激活节点中的最顶层节点
|
||||||
|
this.beingDragNodeList = getTopAncestorsFomNodeList(
|
||||||
|
// 过滤掉根节点和概要节点
|
||||||
|
this.mindMap.renderer.activeNodeList.filter(item => {
|
||||||
|
return !item.isRoot && !item.isGeneralization
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 否则只拖拽按下的节点
|
||||||
|
this.beingDragNodeList = [node]
|
||||||
|
}
|
||||||
|
// 将节点树转为节点数组
|
||||||
|
this.nodeTreeToList()
|
||||||
|
// 创建克隆节点
|
||||||
|
this.createCloneNode()
|
||||||
|
// 清除当前所有激活的节点
|
||||||
|
this.mindMap.renderer.clearAllActive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点由树转换成数组,从子节点到根节点
|
||||||
|
nodeTreeToList() {
|
||||||
|
const list = []
|
||||||
|
bfsWalk(this.mindMap.renderer.root, node => {
|
||||||
|
// 过滤掉当前被拖拽的节点
|
||||||
|
if (this.checkIsInBeingDragNodeList(node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!list[node.layerIndex]) {
|
||||||
|
list[node.layerIndex] = []
|
||||||
|
}
|
||||||
|
list[node.layerIndex].push(node)
|
||||||
|
})
|
||||||
|
this.nodeList = list.reduceRight((res, cur) => {
|
||||||
|
return [...res, ...cur]
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
// 创建克隆节点
|
// 创建克隆节点
|
||||||
createCloneNode() {
|
createCloneNode() {
|
||||||
if (!this.clone) {
|
if (!this.clone) {
|
||||||
// 节点
|
const {
|
||||||
this.clone = this.node.group.clone()
|
dragMultiNodeRectConfig,
|
||||||
this.clone.opacity(0.5)
|
dragPlaceholderRectFill,
|
||||||
|
dragOpacityConfig
|
||||||
|
} = this.mindMap.opt
|
||||||
|
const {
|
||||||
|
width: rectWidth,
|
||||||
|
height: rectHeight,
|
||||||
|
fill: rectFill
|
||||||
|
} = dragMultiNodeRectConfig
|
||||||
|
const node = this.beingDragNodeList[0]
|
||||||
|
const lineColor = node.style.merge('lineColor', true)
|
||||||
|
// 如果当前被拖拽的节点数量大于1,那么创建一个矩形示意
|
||||||
|
if (this.beingDragNodeList.length > 1) {
|
||||||
|
this.clone = this.draw
|
||||||
|
.rect()
|
||||||
|
.size(rectWidth, rectHeight)
|
||||||
|
.radius(rectHeight / 2)
|
||||||
|
.fill({
|
||||||
|
color: rectFill || lineColor
|
||||||
|
})
|
||||||
|
this.offsetX = rectWidth / 2
|
||||||
|
this.offsetY = rectHeight / 2
|
||||||
|
} else {
|
||||||
|
// 否则克隆当前的节点
|
||||||
|
this.clone = node.group.clone()
|
||||||
|
// 删除展开收起按钮元素
|
||||||
|
const expandEl = this.clone.findOne('.smm-expand-btn')
|
||||||
|
if (expandEl) {
|
||||||
|
expandEl.remove()
|
||||||
|
}
|
||||||
|
this.mindMap.draw.add(this.clone)
|
||||||
|
}
|
||||||
|
this.clone.opacity(dragOpacityConfig.cloneNodeOpacity)
|
||||||
this.clone.css('z-index', 99999)
|
this.clone.css('z-index', 99999)
|
||||||
this.node.isDrag = true
|
// 同级位置提示元素
|
||||||
this.node.hide()
|
|
||||||
// 连接线
|
|
||||||
this.line = this.draw.path()
|
|
||||||
this.line.opacity(0.5)
|
|
||||||
this.node.styleLine(this.line, this.node)
|
|
||||||
// 同级位置占位符
|
|
||||||
this.placeholder = this.draw.rect().fill({
|
this.placeholder = this.draw.rect().fill({
|
||||||
color: this.node.style.merge('lineColor', true)
|
color: dragPlaceholderRectFill || lineColor
|
||||||
|
})
|
||||||
|
// 当前被拖拽的节点的临时设置
|
||||||
|
this.beingDragNodeList.forEach(node => {
|
||||||
|
// 降低透明度
|
||||||
|
node.setOpacity(dragOpacityConfig.beingDragNodeOpacity)
|
||||||
|
// 隐藏连线及下级节点
|
||||||
|
node.hideChildren()
|
||||||
|
// 设置拖拽状态
|
||||||
|
node.startDrag()
|
||||||
})
|
})
|
||||||
this.mindMap.draw.add(this.clone)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,42 +304,9 @@ class Drag extends Base {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.clone.remove()
|
this.clone.remove()
|
||||||
this.line.remove()
|
|
||||||
this.placeholder.remove()
|
this.placeholder.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拖动中
|
|
||||||
onMove(x, y, e) {
|
|
||||||
if (!this.isMousedown) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.createCloneNode()
|
|
||||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
|
||||||
this.cloneNodeLeft = x - this.offsetX
|
|
||||||
this.cloneNodeTop = y - this.offsetY
|
|
||||||
x = (this.cloneNodeLeft - translateX) / scaleX
|
|
||||||
y = (this.cloneNodeTop - translateY) / scaleY
|
|
||||||
let t = this.clone.transform()
|
|
||||||
this.clone.translate(x - t.translateX, y - t.translateY)
|
|
||||||
// 连接线
|
|
||||||
let parent = this.node.parent
|
|
||||||
this.line.plot(
|
|
||||||
this.quadraticCurvePath(
|
|
||||||
parent.left + parent.width / 2,
|
|
||||||
parent.top + parent.height / 2,
|
|
||||||
x + this.node.width / 2,
|
|
||||||
y + this.node.height / 2
|
|
||||||
)
|
|
||||||
)
|
|
||||||
this.checkOverlapNode()
|
|
||||||
// 如果注册了多选节点插件,那么复用它的边缘自动移动画布功能
|
|
||||||
if (this.mindMap.opt.autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
|
|
||||||
this.drawTransform = this.mindMap.draw.transform()
|
|
||||||
this.mindMap.select.clearAutoMoveTimer()
|
|
||||||
this.mindMap.select.onMove(e.clientX, e.clientY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检测重叠节点
|
// 检测重叠节点
|
||||||
checkOverlapNode() {
|
checkOverlapNode() {
|
||||||
if (!this.drawTransform || !this.placeholder) {
|
if (!this.drawTransform || !this.placeholder) {
|
||||||
@ -226,9 +320,6 @@ class Drag extends Base {
|
|||||||
if (node.nodeData.data.isActive) {
|
if (node.nodeData.data.isActive) {
|
||||||
this.mindMap.renderer.setNodeActive(node, false)
|
this.mindMap.renderer.setNodeActive(node, false)
|
||||||
}
|
}
|
||||||
if (node.uid === this.node.uid || this.node.isParent(node)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.overlapNode || (this.prevNode && this.nextNode)) {
|
if (this.overlapNode || (this.prevNode && this.nextNode)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -484,7 +575,7 @@ class Drag extends Base {
|
|||||||
if (node.layerIndex === 1) {
|
if (node.layerIndex === 1) {
|
||||||
sameDir = item.dir === node.dir
|
sameDir = item.dir === node.dir
|
||||||
}
|
}
|
||||||
return item !== this.node && sameDir
|
return sameDir && !this.checkIsInBeingDragNodeList(item)
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
this.handleVerticalCheck(node, checkList)
|
this.handleVerticalCheck(node, checkList)
|
||||||
@ -535,7 +626,7 @@ class Drag extends Base {
|
|||||||
handleFishbone(node) {
|
handleFishbone(node) {
|
||||||
let checkList = node.parent
|
let checkList = node.parent
|
||||||
? node.parent.children.filter(item => {
|
? node.parent.children.filter(item => {
|
||||||
return item !== this.node && item.layerIndex > 1
|
return item.layerIndex > 1 && !this.checkIsInBeingDragNodeList(item)
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
if (node.layerIndex === 1) {
|
if (node.layerIndex === 1) {
|
||||||
@ -553,8 +644,8 @@ class Drag extends Base {
|
|||||||
// 获取节点的兄弟节点列表通用方法
|
// 获取节点的兄弟节点列表通用方法
|
||||||
commonGetNodeCheckList(node) {
|
commonGetNodeCheckList(node) {
|
||||||
return node.parent
|
return node.parent
|
||||||
? node.parent.children.filter(item => {
|
? [...node.parent.children].filter(item => {
|
||||||
return item !== this.node
|
return !this.checkIsInBeingDragNodeList(item)
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
@ -585,18 +676,11 @@ class Drag extends Base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 节点由树转换成数组,从子节点到根节点
|
// 检查某个节点是否在被拖拽节点内
|
||||||
nodeTreeToList() {
|
checkIsInBeingDragNodeList(node) {
|
||||||
const list = []
|
return !!this.beingDragNodeList.find(item => {
|
||||||
bfsWalk(this.mindMap.renderer.root, node => {
|
return item.uid === node.uid || item.isParent(node)
|
||||||
if (!list[node.layerIndex]) {
|
|
||||||
list[node.layerIndex] = []
|
|
||||||
}
|
|
||||||
list[node.layerIndex].push(node)
|
|
||||||
})
|
})
|
||||||
this.nodeList = list.reduceRight((res, cur) => {
|
|
||||||
return [...res, ...cur]
|
|
||||||
}, [])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class Export {
|
|||||||
let task = imageList.map(async item => {
|
let task = imageList.map(async item => {
|
||||||
let imgUlr = item.attr('href') || item.attr('xlink:href')
|
let imgUlr = item.attr('href') || item.attr('xlink:href')
|
||||||
// 已经是data:URL形式不用转换
|
// 已经是data:URL形式不用转换
|
||||||
if (/^data:/.test(imgUlr)) {
|
if (/^data:/.test(imgUlr) || imgUlr === 'none') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let imgData = await imgToDataUrl(imgUlr)
|
let imgData = await imgToDataUrl(imgUlr)
|
||||||
|
|||||||
53
simple-mind-map/src/plugins/Formula.js
Normal file
53
simple-mind-map/src/plugins/Formula.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import katex from 'katex'
|
||||||
|
import Quill from 'quill'
|
||||||
|
|
||||||
|
// 数学公式支持插件
|
||||||
|
// 该插件在富文本模式下可用
|
||||||
|
class Formula {
|
||||||
|
// 构造函数
|
||||||
|
constructor(opt) {
|
||||||
|
this.opt = opt
|
||||||
|
this.mindMap = opt.mindMap
|
||||||
|
window.katex = katex
|
||||||
|
this.extendQuill()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改formula格式工具
|
||||||
|
extendQuill() {
|
||||||
|
const QuillFormula = Quill.import('formats/formula')
|
||||||
|
|
||||||
|
class CustomFormulaBlot extends QuillFormula {
|
||||||
|
static create(value) {
|
||||||
|
let node = super.create(value)
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
katex.render(value, node, {
|
||||||
|
throwOnError: false,
|
||||||
|
errorColor: '#f00',
|
||||||
|
output: 'mathml' // 增加该配置,默认只输出公式
|
||||||
|
})
|
||||||
|
node.setAttribute('data-value', value)
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quill.register('formats/formula', CustomFormulaBlot, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 给指定的节点插入指定公式
|
||||||
|
insertFormulaToNode(node, formula) {
|
||||||
|
let richTextPlugin = this.mindMap.richText
|
||||||
|
richTextPlugin.showEditText(node)
|
||||||
|
richTextPlugin.quill.insertEmbed(
|
||||||
|
richTextPlugin.quill.getLength() - 1,
|
||||||
|
'formula',
|
||||||
|
formula
|
||||||
|
)
|
||||||
|
richTextPlugin.setTextStyleIfNotRichText(richTextPlugin.node)
|
||||||
|
richTextPlugin.hideEditText([node])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Formula.instanceName = 'formula'
|
||||||
|
|
||||||
|
export default Formula
|
||||||
@ -623,7 +623,7 @@ class RichText {
|
|||||||
// 处理导入数据
|
// 处理导入数据
|
||||||
handleSetData(data) {
|
handleSetData(data) {
|
||||||
let walk = root => {
|
let walk = root => {
|
||||||
if (!root.data.richText) {
|
if (root.data && !root.data.richText) {
|
||||||
root.data.richText = true
|
root.data.richText = true
|
||||||
root.data.resetRichText = true
|
root.data.resetRichText = true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { bfsWalk, throttle } from '../utils'
|
import { bfsWalk, throttle, checkTwoRectIsOverlap } from '../utils'
|
||||||
|
|
||||||
// 节点选择插件
|
// 节点选择插件
|
||||||
class Select {
|
class Select {
|
||||||
@ -210,24 +210,19 @@ class Select {
|
|||||||
left = left * scaleX + translateX
|
left = left * scaleX + translateX
|
||||||
top = top * scaleY + translateY
|
top = top * scaleY + translateY
|
||||||
if (
|
if (
|
||||||
((left >= minx && left <= maxx) || (right >= minx && right <= maxx)) &&
|
checkTwoRectIsOverlap(minx, maxx, miny, maxy, left, right, top, bottom)
|
||||||
((top >= miny && top <= maxy) || (bottom >= miny && bottom <= maxy))
|
|
||||||
) {
|
) {
|
||||||
// this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
|
|
||||||
if (node.nodeData.data.isActive) {
|
if (node.nodeData.data.isActive) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mindMap.renderer.setNodeActive(node, true)
|
this.mindMap.renderer.setNodeActive(node, true)
|
||||||
this.mindMap.renderer.addActiveNode(node)
|
this.mindMap.renderer.addActiveNode(node)
|
||||||
// })
|
|
||||||
} else if (node.nodeData.data.isActive) {
|
} else if (node.nodeData.data.isActive) {
|
||||||
// this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
|
|
||||||
if (!node.nodeData.data.isActive) {
|
if (!node.nodeData.data.isActive) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mindMap.renderer.setNodeActive(node, false)
|
this.mindMap.renderer.setNodeActive(node, false)
|
||||||
this.mindMap.renderer.removeActiveNode(node)
|
this.mindMap.renderer.removeActiveNode(node)
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import { Text } from '@svgdotjs/svg.js'
|
import { Text } from '@svgdotjs/svg.js'
|
||||||
import { getStrWithBrFromHtml } from '../../utils/index'
|
import {
|
||||||
|
getStrWithBrFromHtml,
|
||||||
|
focusInput,
|
||||||
|
selectAllInput
|
||||||
|
} from '../../utils/index'
|
||||||
|
|
||||||
// 创建文字节点
|
// 创建文字节点
|
||||||
function createText(data) {
|
function createText(data) {
|
||||||
@ -36,7 +40,7 @@ function showEditTextBox(g) {
|
|||||||
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
||||||
this.hideEditTextBox()
|
this.hideEditTextBox()
|
||||||
})
|
})
|
||||||
|
// 输入框元素没有创建过,则先创建
|
||||||
if (!this.textEditNode) {
|
if (!this.textEditNode) {
|
||||||
this.textEditNode = document.createElement('div')
|
this.textEditNode = document.createElement('div')
|
||||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
|
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
|
||||||
@ -55,20 +59,27 @@ function showEditTextBox(g) {
|
|||||||
associativeLineTextFontFamily,
|
associativeLineTextFontFamily,
|
||||||
associativeLineTextLineHeight
|
associativeLineTextLineHeight
|
||||||
} = this.mindMap.themeConfig
|
} = this.mindMap.themeConfig
|
||||||
|
let { defaultAssociativeLineText, nodeTextEditZIndex } = this.mindMap.opt
|
||||||
let scale = this.mindMap.view.scale
|
let scale = this.mindMap.view.scale
|
||||||
let [, , , node, toNode] = this.activeLine
|
let [, , , node, toNode] = this.activeLine
|
||||||
let textLines = (
|
let text = this.getText(node, toNode)
|
||||||
this.getText(node, toNode) || this.mindMap.opt.defaultAssociativeLineText
|
let textLines = (text || defaultAssociativeLineText).split(/\n/gim)
|
||||||
).split(/\n/gim)
|
|
||||||
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
|
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
|
||||||
this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
|
this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
|
||||||
this.textEditNode.style.lineHeight =
|
this.textEditNode.style.lineHeight =
|
||||||
textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
||||||
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
this.textEditNode.style.zIndex = nodeTextEditZIndex
|
||||||
this.textEditNode.innerHTML = textLines.join('<br>')
|
this.textEditNode.innerHTML = textLines.join('<br>')
|
||||||
this.textEditNode.style.display = 'block'
|
this.textEditNode.style.display = 'block'
|
||||||
this.updateTextEditBoxPos(g)
|
this.updateTextEditBoxPos(g)
|
||||||
this.showTextEdit = true
|
this.showTextEdit = true
|
||||||
|
// 如果是默认文本要全选输入框
|
||||||
|
if (text === '' || text === defaultAssociativeLineText) {
|
||||||
|
selectAllInput(this.textEditNode)
|
||||||
|
} else {
|
||||||
|
// 否则聚焦即可
|
||||||
|
focusInput(this.textEditNode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理画布缩放
|
// 处理画布缩放
|
||||||
@ -94,10 +105,13 @@ function hideEditTextBox() {
|
|||||||
}
|
}
|
||||||
let [path, , text, node, toNode] = this.activeLine
|
let [path, , text, node, toNode] = this.activeLine
|
||||||
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
||||||
|
// 如果是默认文本,那么不保存
|
||||||
|
let isDefaultText = str === this.mindMap.opt.defaultAssociativeLineText
|
||||||
|
str = isDefaultText ? '' : str
|
||||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||||
associativeLineText: {
|
associativeLineText: {
|
||||||
...(node.nodeData.data.associativeLineText || {}),
|
...(node.nodeData.data.associativeLineText || {}),
|
||||||
[toNode.nodeData.data.id]: str
|
[toNode.nodeData.data.uid]: str
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.textEditNode.style.display = 'none'
|
this.textEditNode.style.display = 'none'
|
||||||
@ -113,7 +127,7 @@ function getText(node, toNode) {
|
|||||||
if (!obj) {
|
if (!obj) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
return obj[toNode.nodeData.data.id] || ''
|
return obj[toNode.nodeData.data.uid] || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染关联线文字
|
// 渲染关联线文字
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// 获取目标节点在起始节点的目标数组中的索引
|
// 获取目标节点在起始节点的目标数组中的索引
|
||||||
export const getAssociativeLineTargetIndex = (node, toNode) => {
|
export const getAssociativeLineTargetIndex = (node, toNode) => {
|
||||||
return node.nodeData.data.associativeLineTargets.findIndex(item => {
|
return node.nodeData.data.associativeLineTargets.findIndex(item => {
|
||||||
return item === toNode.nodeData.data.id
|
return item === toNode.nodeData.data.uid
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -170,9 +170,8 @@ export const copyNodeTree = (
|
|||||||
keepId = false
|
keepId = false
|
||||||
) => {
|
) => {
|
||||||
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
|
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
|
||||||
// 去除节点id,因为节点id不能重复
|
// 去除节点uid,因为节点uid不能重复
|
||||||
if (tree.data.id && !keepId) delete tree.data.id
|
if (tree.data.uid && !keepId) delete tree.data.uid
|
||||||
if (tree.data.uid) delete tree.data.uid
|
|
||||||
if (removeActiveState) {
|
if (removeActiveState) {
|
||||||
tree.data.isActive = false
|
tree.data.isActive = false
|
||||||
}
|
}
|
||||||
@ -705,3 +704,102 @@ export const mergerIconListBy = (arrList, key, name) => {
|
|||||||
return result
|
return result
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从节点实例列表里找出顶层的节点
|
||||||
|
export const getTopAncestorsFomNodeList = list => {
|
||||||
|
let res = []
|
||||||
|
list.forEach(node => {
|
||||||
|
if (
|
||||||
|
!list.find(item => {
|
||||||
|
return item.uid !== node.uid && item.isParent(node)
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
res.push(node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断两个矩形是否重叠
|
||||||
|
export const checkTwoRectIsOverlap = (
|
||||||
|
minx1,
|
||||||
|
maxx1,
|
||||||
|
miny1,
|
||||||
|
maxy1,
|
||||||
|
minx2,
|
||||||
|
maxx2,
|
||||||
|
miny2,
|
||||||
|
maxy2
|
||||||
|
) => {
|
||||||
|
return maxx1 > minx2 && maxx2 > minx1 && maxy1 > miny2 && maxy2 > miny1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聚焦指定输入框
|
||||||
|
export const focusInput = el => {
|
||||||
|
let selection = window.getSelection()
|
||||||
|
let range = document.createRange()
|
||||||
|
range.selectNodeContents(el)
|
||||||
|
range.collapse()
|
||||||
|
selection.removeAllRanges()
|
||||||
|
selection.addRange(range)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 聚焦全选指定输入框
|
||||||
|
export const selectAllInput = el => {
|
||||||
|
let selection = window.getSelection()
|
||||||
|
let range = document.createRange()
|
||||||
|
range.selectNodeContents(el)
|
||||||
|
selection.removeAllRanges()
|
||||||
|
selection.addRange(range)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 给指定的节点列表树数据添加附加数据,会修改原数据
|
||||||
|
export const addDataToAppointNodes = (appointNodes, data = {}) => {
|
||||||
|
const walk = list => {
|
||||||
|
list.forEach(node => {
|
||||||
|
node.data = {
|
||||||
|
...node.data,
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
walk(node.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
walk(appointNodes)
|
||||||
|
return appointNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 给指定的节点列表树数据添加uid,如果不存在的话,会修改原数据
|
||||||
|
export const createUidForAppointNodes = appointNodes => {
|
||||||
|
const walk = list => {
|
||||||
|
list.forEach(node => {
|
||||||
|
if (!node.data) {
|
||||||
|
node.data = {}
|
||||||
|
}
|
||||||
|
if (isUndef(node.data.uid)) {
|
||||||
|
node.data.uid = createUid()
|
||||||
|
}
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
walk(node.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
walk(appointNodes)
|
||||||
|
return appointNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 传入一个数据,如果该数据是数组,那么返回该数组,否则返回一个以该数据为成员的数组
|
||||||
|
export const formatDataToArray = data => {
|
||||||
|
if (!data) return []
|
||||||
|
return Array.isArray(data) ? data : [data]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取节点在同级里的位置索引
|
||||||
|
export const getNodeIndex = node => {
|
||||||
|
return node.parent
|
||||||
|
? node.parent.children.findIndex(item => {
|
||||||
|
return item.uid === node.uid
|
||||||
|
})
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 2479351 */
|
font-family: "iconfont"; /* Project id 2479351 */
|
||||||
src: url('iconfont.woff2?t=1691822758372') format('woff2'),
|
src: url('iconfont.woff2?t=1695365666344') format('woff2'),
|
||||||
url('iconfont.woff?t=1691822758372') format('woff'),
|
url('iconfont.woff?t=1695365666344') format('woff'),
|
||||||
url('iconfont.ttf?t=1691822758372') format('truetype');
|
url('iconfont.ttf?t=1695365666344') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,10 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icongongshi:before {
|
||||||
|
content: "\e617";
|
||||||
|
}
|
||||||
|
|
||||||
.icontouming:before {
|
.icontouming:before {
|
||||||
content: "\e60c";
|
content: "\e60c";
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,60 +1,83 @@
|
|||||||
// 布局结构图片映射
|
// 布局结构图片映射
|
||||||
export const layoutImgMap = {
|
export const layoutImgMap = {
|
||||||
logicalStructure: require('../assets/img/structures/logicalStructure.png'),
|
logicalStructure: require('../assets/img/structures/logicalStructure.png'),
|
||||||
mindMap: require('../assets/img/structures/mindMap.png'),
|
mindMap: require('../assets/img/structures/mindMap.png'),
|
||||||
organizationStructure: require('../assets/img/structures/organizationStructure.png'),
|
organizationStructure: require('../assets/img/structures/organizationStructure.png'),
|
||||||
catalogOrganization: require('../assets/img/structures/catalogOrganization.png'),
|
catalogOrganization: require('../assets/img/structures/catalogOrganization.png'),
|
||||||
timeline: require('../assets/img/structures/timeline.png'),
|
timeline: require('../assets/img/structures/timeline.png'),
|
||||||
timeline2: require('../assets/img/structures/timeline2.png'),
|
timeline2: require('../assets/img/structures/timeline2.png'),
|
||||||
fishbone: require('../assets/img/structures/fishbone.png'),
|
fishbone: require('../assets/img/structures/fishbone.png'),
|
||||||
verticalTimeline: require('../assets/img/structures/verticalTimeline.png'),
|
verticalTimeline: require('../assets/img/structures/verticalTimeline.png')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主题图片映射
|
// 主题图片映射
|
||||||
export const themeMap = {
|
export const themeMap = {
|
||||||
default: require('../assets/img/themes/default.jpg'),
|
default: require('../assets/img/themes/default.jpg'),
|
||||||
classic: require('../assets/img/themes/classic.jpg'),
|
classic: require('../assets/img/themes/classic.jpg'),
|
||||||
minions: require('../assets/img/themes/minions.jpg'),
|
minions: require('../assets/img/themes/minions.jpg'),
|
||||||
pinkGrape: require('../assets/img/themes/pinkGrape.jpg'),
|
pinkGrape: require('../assets/img/themes/pinkGrape.jpg'),
|
||||||
mint: require('../assets/img/themes/mint.jpg'),
|
mint: require('../assets/img/themes/mint.jpg'),
|
||||||
gold: require('../assets/img/themes/gold.jpg'),
|
gold: require('../assets/img/themes/gold.jpg'),
|
||||||
vitalityOrange: require('../assets/img/themes/vitalityOrange.jpg'),
|
vitalityOrange: require('../assets/img/themes/vitalityOrange.jpg'),
|
||||||
greenLeaf: require('../assets/img/themes/greenLeaf.jpg'),
|
greenLeaf: require('../assets/img/themes/greenLeaf.jpg'),
|
||||||
dark2: require('../assets/img/themes/dark2.jpg'),
|
dark2: require('../assets/img/themes/dark2.jpg'),
|
||||||
skyGreen: require('../assets/img/themes/skyGreen.jpg'),
|
skyGreen: require('../assets/img/themes/skyGreen.jpg'),
|
||||||
classic2: require('../assets/img/themes/classic2.jpg'),
|
classic2: require('../assets/img/themes/classic2.jpg'),
|
||||||
classic3: require('../assets/img/themes/classic3.jpg'),
|
classic3: require('../assets/img/themes/classic3.jpg'),
|
||||||
classic4: require('../assets/img/themes/classic4.jpg'),
|
classic4: require('../assets/img/themes/classic4.jpg'),
|
||||||
classicGreen: require('../assets/img/themes/classicGreen.jpg'),
|
classicGreen: require('../assets/img/themes/classicGreen.jpg'),
|
||||||
classicBlue: require('../assets/img/themes/classicBlue.jpg'),
|
classicBlue: require('../assets/img/themes/classicBlue.jpg'),
|
||||||
blueSky: require('../assets/img/themes/blueSky.jpg'),
|
blueSky: require('../assets/img/themes/blueSky.jpg'),
|
||||||
brainImpairedPink: require('../assets/img/themes/brainImpairedPink.jpg'),
|
brainImpairedPink: require('../assets/img/themes/brainImpairedPink.jpg'),
|
||||||
dark: require('../assets/img/themes/dark.jpg'),
|
dark: require('../assets/img/themes/dark.jpg'),
|
||||||
earthYellow: require('../assets/img/themes/earthYellow.jpg'),
|
earthYellow: require('../assets/img/themes/earthYellow.jpg'),
|
||||||
freshGreen: require('../assets/img/themes/freshGreen.jpg'),
|
freshGreen: require('../assets/img/themes/freshGreen.jpg'),
|
||||||
freshRed: require('../assets/img/themes/freshRed.jpg'),
|
freshRed: require('../assets/img/themes/freshRed.jpg'),
|
||||||
romanticPurple: require('../assets/img/themes/romanticPurple.jpg'),
|
romanticPurple: require('../assets/img/themes/romanticPurple.jpg'),
|
||||||
simpleBlack: require('../assets/img/themes/simpleBlack.jpg'),
|
simpleBlack: require('../assets/img/themes/simpleBlack.jpg'),
|
||||||
courseGreen: require('../assets/img/themes/courseGreen.jpg'),
|
courseGreen: require('../assets/img/themes/courseGreen.jpg'),
|
||||||
coffee: require('../assets/img/themes/coffee.jpg'),
|
coffee: require('../assets/img/themes/coffee.jpg'),
|
||||||
redSpirit: require('../assets/img/themes/redSpirit.jpg'),
|
redSpirit: require('../assets/img/themes/redSpirit.jpg'),
|
||||||
blackHumour: require('../assets/img/themes/blackHumour.jpg'),
|
blackHumour: require('../assets/img/themes/blackHumour.jpg'),
|
||||||
lateNightOffice: require('../assets/img/themes/lateNightOffice.jpg'),
|
lateNightOffice: require('../assets/img/themes/lateNightOffice.jpg'),
|
||||||
blackGold: require('../assets/img/themes/blackGold.jpg'),
|
blackGold: require('../assets/img/themes/blackGold.jpg'),
|
||||||
autumn: require('../assets/img/themes/autumn.jpg'),
|
autumn: require('../assets/img/themes/autumn.jpg'),
|
||||||
avocado: require('../assets/img/themes/avocado.jpg'),
|
avocado: require('../assets/img/themes/avocado.jpg'),
|
||||||
orangeJuice: require('../assets/img/themes/orangeJuice.jpg'),
|
orangeJuice: require('../assets/img/themes/orangeJuice.jpg'),
|
||||||
oreo: require('../assets/img/themes/oreo.jpg'),
|
oreo: require('../assets/img/themes/oreo.jpg'),
|
||||||
shallowSea: require('../assets/img/themes/shallowSea.jpg'),
|
shallowSea: require('../assets/img/themes/shallowSea.jpg'),
|
||||||
lemonBubbles: require('../assets/img/themes/lemonBubbles.jpg'),
|
lemonBubbles: require('../assets/img/themes/lemonBubbles.jpg'),
|
||||||
rose: require('../assets/img/themes/rose.jpg'),
|
rose: require('../assets/img/themes/rose.jpg'),
|
||||||
seaBlueLine: require('../assets/img/themes/seaBlueLine.jpg'),
|
seaBlueLine: require('../assets/img/themes/seaBlueLine.jpg'),
|
||||||
neonLamp: require('../assets/img/themes/neonLamp.jpg'),
|
neonLamp: require('../assets/img/themes/neonLamp.jpg'),
|
||||||
darkNightLceBlade: require('../assets/img/themes/darkNightLceBlade.jpg'),
|
darkNightLceBlade: require('../assets/img/themes/darkNightLceBlade.jpg'),
|
||||||
morandi: require('../assets/img/themes/morandi.jpg'),
|
morandi: require('../assets/img/themes/morandi.jpg'),
|
||||||
classic5: require('../assets/img/themes/classic5.jpg'),
|
classic5: require('../assets/img/themes/classic5.jpg'),
|
||||||
dark3: require('../assets/img/themes/dark3.jpg'),
|
dark3: require('../assets/img/themes/dark3.jpg'),
|
||||||
dark4: require('../assets/img/themes/dark4.jpg'),
|
dark4: require('../assets/img/themes/dark4.jpg'),
|
||||||
cactus: require('../assets/img/themes/cactus.jpg'),
|
cactus: require('../assets/img/themes/cactus.jpg')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 公式列表
|
||||||
|
export const formulaList = [
|
||||||
|
'a^2',
|
||||||
|
'a_2',
|
||||||
|
'a^{2+2}',
|
||||||
|
'a_{i,j}',
|
||||||
|
'x_2^3',
|
||||||
|
'\\overbrace{1+2+\\cdots+100}',
|
||||||
|
'\\sum_{k=1}^N k^2',
|
||||||
|
'\\lim_{n \\to \\infty}x_n',
|
||||||
|
'\\int_{-N}^{N} e^x\\, dx',
|
||||||
|
'\\sqrt{3}',
|
||||||
|
'\\sqrt[n]{3}',
|
||||||
|
'\\sin\\theta',
|
||||||
|
'\\log X',
|
||||||
|
'\\log_{10}',
|
||||||
|
'\\log_\\alpha X',
|
||||||
|
'\\lim_{t\\to n}T',
|
||||||
|
'\\frac{1}{2}=0.5',
|
||||||
|
'\\binom{n}{k}',
|
||||||
|
'\\begin{matrix}x & y \\\\z & v\\end{matrix}',
|
||||||
|
'\\begin{cases}3x + 5y + z \\\\7x - 2y + 4z \\\\-6x + 3y + 2z\\end{cases}'
|
||||||
|
]
|
||||||
|
|||||||
@ -103,11 +103,13 @@ export default {
|
|||||||
markdownFile: 'markdown file',
|
markdownFile: 'markdown file',
|
||||||
tips: 'tips: .smm and .json file can be import',
|
tips: 'tips: .smm and .json file can be import',
|
||||||
isTransparent: 'Background is transparent',
|
isTransparent: 'Background is transparent',
|
||||||
pngTips: 'tips: Exporting pictures in rich text mode is time-consuming. It is recommended to export to svg format',
|
pngTips:
|
||||||
|
'tips: Exporting pictures in rich text mode is time-consuming. It is recommended to export to svg format',
|
||||||
svgTips: 'tips: Exporting pictures in rich text mode is time-consuming',
|
svgTips: 'tips: Exporting pictures in rich text mode is time-consuming',
|
||||||
transformingDomToImages: 'Converting nodes: ',
|
transformingDomToImages: 'Converting nodes: ',
|
||||||
notifyTitle: 'Info',
|
notifyTitle: 'Info',
|
||||||
notifyMessage: 'If the download is not triggered, check whether it is blocked by the browser',
|
notifyMessage:
|
||||||
|
'If the download is not triggered, check whether it is blocked by the browser',
|
||||||
paddingX: 'Padding x',
|
paddingX: 'Padding x',
|
||||||
paddingY: 'Padding y',
|
paddingY: 'Padding y',
|
||||||
useMultiPageExport: 'Export multi page'
|
useMultiPageExport: 'Export multi page'
|
||||||
@ -213,15 +215,19 @@ export default {
|
|||||||
export: 'Export',
|
export: 'Export',
|
||||||
shortcutKey: 'Shortcut key',
|
shortcutKey: 'Shortcut key',
|
||||||
associativeLine: 'Associative line',
|
associativeLine: 'Associative line',
|
||||||
painter: 'Painter'
|
painter: 'Painter',
|
||||||
|
formula: 'Formula'
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
newFeatureNoticeTitle: 'New feature reminder',
|
newFeatureNoticeTitle: 'New feature reminder',
|
||||||
newFeatureNoticeMessage: 'This update supports node rich text editing, But there are some defects, The most important impact is that the time to export the image is proportional to the number of nodes, Therefore, if you are more dependent on export requirements, you can use【Base style】-【Other config】-【Enable node rich text editing】Set to turn off rich text editing mode.'
|
newFeatureNoticeMessage:
|
||||||
|
'This update supports node rich text editing, But there are some defects, The most important impact is that the time to export the image is proportional to the number of nodes, Therefore, if you are more dependent on export requirements, you can use【Base style】-【Other config】-【Enable node rich text editing】Set to turn off rich text editing mode.'
|
||||||
},
|
},
|
||||||
mouseAction: {
|
mouseAction: {
|
||||||
tip1: 'Current: Left click to drag the canvas, right click to box select nodes',
|
tip1:
|
||||||
tip2: 'Current: Left click to box select nodes, right click to drag the canvas',
|
'Current: Left click to drag the canvas, right click to box select nodes',
|
||||||
|
tip2:
|
||||||
|
'Current: Left click to box select nodes, right click to drag the canvas'
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
searchPlaceholder: 'Please enter the search content',
|
searchPlaceholder: 'Please enter the search content',
|
||||||
@ -229,5 +235,16 @@ export default {
|
|||||||
replace: 'Replace',
|
replace: 'Replace',
|
||||||
replaceAll: 'Replace all',
|
replaceAll: 'Replace all',
|
||||||
cancel: 'Cancel'
|
cancel: 'Cancel'
|
||||||
|
},
|
||||||
|
nodeIconSidebar: {
|
||||||
|
title: 'Icon/Sticker',
|
||||||
|
icon: 'Icon',
|
||||||
|
sticker: 'Sticker'
|
||||||
|
},
|
||||||
|
formulaSidebar: {
|
||||||
|
title: 'Formula',
|
||||||
|
placeholder: 'Please enter LaText syntax',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
common: 'Common formulas'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,15 +213,17 @@ export default {
|
|||||||
export: '导出',
|
export: '导出',
|
||||||
shortcutKey: '快捷键',
|
shortcutKey: '快捷键',
|
||||||
associativeLine: '关联线',
|
associativeLine: '关联线',
|
||||||
painter: '格式刷'
|
painter: '格式刷',
|
||||||
|
formula: '公式'
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
newFeatureNoticeTitle: '新特性提醒',
|
newFeatureNoticeTitle: '新特性提醒',
|
||||||
newFeatureNoticeMessage: '本次更新支持了节点富文本编辑,但是存在一定缺陷,最主要的影响是导出为图片的时间和节点数量成正比,所以对导出需求比较依赖的话可以通过【基础样式】-【其他配置】-【是否开启节点富文本编辑】设置关掉富文本编辑模式。'
|
newFeatureNoticeMessage:
|
||||||
|
'本次更新支持了节点富文本编辑,但是存在一定缺陷,最主要的影响是导出为图片的时间和节点数量成正比,所以对导出需求比较依赖的话可以通过【基础样式】-【其他配置】-【是否开启节点富文本编辑】设置关掉富文本编辑模式。'
|
||||||
},
|
},
|
||||||
mouseAction: {
|
mouseAction: {
|
||||||
tip1: '当前:左键拖动画布,右键框选节点',
|
tip1: '当前:左键拖动画布,右键框选节点',
|
||||||
tip2: '当前:左键框选节点,右键拖动画布',
|
tip2: '当前:左键框选节点,右键拖动画布'
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
searchPlaceholder: '请输入查找内容',
|
searchPlaceholder: '请输入查找内容',
|
||||||
@ -229,5 +231,16 @@ export default {
|
|||||||
replace: '替换',
|
replace: '替换',
|
||||||
replaceAll: '全部替换',
|
replaceAll: '全部替换',
|
||||||
cancel: '取消'
|
cancel: '取消'
|
||||||
|
},
|
||||||
|
nodeIconSidebar: {
|
||||||
|
title: '图标/贴纸',
|
||||||
|
icon: '图标',
|
||||||
|
sticker: '贴纸'
|
||||||
|
},
|
||||||
|
formulaSidebar: {
|
||||||
|
title: '公式',
|
||||||
|
placeholder: '请输入 LaText 语法',
|
||||||
|
confirm: '完成',
|
||||||
|
common: '常用公式'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,10 @@
|
|||||||
<ShortcutKey></ShortcutKey>
|
<ShortcutKey></ShortcutKey>
|
||||||
<Contextmenu v-if="mindMap" :mindMap="mindMap"></Contextmenu>
|
<Contextmenu v-if="mindMap" :mindMap="mindMap"></Contextmenu>
|
||||||
<RichTextToolbar v-if="mindMap" :mindMap="mindMap"></RichTextToolbar>
|
<RichTextToolbar v-if="mindMap" :mindMap="mindMap"></RichTextToolbar>
|
||||||
<NodeNoteContentShow v-if="mindMap" :mindMap="mindMap"></NodeNoteContentShow>
|
<NodeNoteContentShow
|
||||||
|
v-if="mindMap"
|
||||||
|
:mindMap="mindMap"
|
||||||
|
></NodeNoteContentShow>
|
||||||
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
||||||
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
||||||
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
||||||
@ -20,6 +23,7 @@
|
|||||||
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
|
<NodeIconToolbar v-if="mindMap" :mindMap="mindMap"></NodeIconToolbar>
|
||||||
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
||||||
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
||||||
|
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -40,6 +44,7 @@ import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
|
|||||||
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
|
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
|
||||||
import Painter from 'simple-mind-map/src/plugins/Painter.js'
|
import Painter from 'simple-mind-map/src/plugins/Painter.js'
|
||||||
import ScrollbarPlugin from 'simple-mind-map/src/plugins/Scrollbar.js'
|
import ScrollbarPlugin from 'simple-mind-map/src/plugins/Scrollbar.js'
|
||||||
|
import Formula from 'simple-mind-map/src/plugins/Formula.js'
|
||||||
import OutlineSidebar from './OutlineSidebar'
|
import OutlineSidebar from './OutlineSidebar'
|
||||||
import Style from './Style'
|
import Style from './Style'
|
||||||
import BaseStyle from './BaseStyle'
|
import BaseStyle from './BaseStyle'
|
||||||
@ -72,6 +77,7 @@ import { showLoading, hideLoading } from '@/utils/loading'
|
|||||||
import handleClipboardText from '@/utils/handleClipboardText'
|
import handleClipboardText from '@/utils/handleClipboardText'
|
||||||
import Scrollbar from './Scrollbar.vue'
|
import Scrollbar from './Scrollbar.vue'
|
||||||
import exampleData from 'simple-mind-map/example/exampleData'
|
import exampleData from 'simple-mind-map/example/exampleData'
|
||||||
|
import FormulaSidebar from './FormulaSidebar.vue'
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
MindMap.usePlugin(MiniMap)
|
MindMap.usePlugin(MiniMap)
|
||||||
@ -88,6 +94,7 @@ MindMap.usePlugin(MiniMap)
|
|||||||
.usePlugin(SearchPlugin)
|
.usePlugin(SearchPlugin)
|
||||||
.usePlugin(Painter)
|
.usePlugin(Painter)
|
||||||
.usePlugin(ScrollbarPlugin)
|
.usePlugin(ScrollbarPlugin)
|
||||||
|
.usePlugin(Formula)
|
||||||
|
|
||||||
// 注册自定义主题
|
// 注册自定义主题
|
||||||
customThemeList.forEach(item => {
|
customThemeList.forEach(item => {
|
||||||
@ -120,7 +127,8 @@ export default {
|
|||||||
NodeIconSidebar,
|
NodeIconSidebar,
|
||||||
NodeIconToolbar,
|
NodeIconToolbar,
|
||||||
OutlineEdit,
|
OutlineEdit,
|
||||||
Scrollbar
|
Scrollbar,
|
||||||
|
FormulaSidebar
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -264,10 +272,10 @@ export default {
|
|||||||
// 如果url中存在要打开的文件,那么思维导图数据、主题、布局都使用默认的
|
// 如果url中存在要打开的文件,那么思维导图数据、主题、布局都使用默认的
|
||||||
if (hasFileURL) {
|
if (hasFileURL) {
|
||||||
root = {
|
root = {
|
||||||
"data": {
|
data: {
|
||||||
"text": "根节点"
|
text: '根节点'
|
||||||
},
|
},
|
||||||
"children": []
|
children: []
|
||||||
}
|
}
|
||||||
layout = exampleData.layout
|
layout = exampleData.layout
|
||||||
theme = exampleData.theme
|
theme = exampleData.theme
|
||||||
@ -305,7 +313,7 @@ export default {
|
|||||||
useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
|
useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
|
||||||
customInnerElsAppendTo: null,
|
customInnerElsAppendTo: null,
|
||||||
enableAutoEnterTextEditWhenKeydown: true,
|
enableAutoEnterTextEditWhenKeydown: true,
|
||||||
customHandleClipboardText: handleClipboardText,
|
customHandleClipboardText: handleClipboardText
|
||||||
// isUseCustomNodeContent: true,
|
// isUseCustomNodeContent: true,
|
||||||
// 示例1:组件里用到了router、store、i18n等实例化vue组件时需要用到的东西
|
// 示例1:组件里用到了router、store、i18n等实例化vue组件时需要用到的东西
|
||||||
// customCreateNodeContent: (node) => {
|
// customCreateNodeContent: (node) => {
|
||||||
@ -353,46 +361,33 @@ export default {
|
|||||||
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
||||||
this.manualSave()
|
this.manualSave()
|
||||||
})
|
})
|
||||||
// 转发事件
|
// 转发事件
|
||||||
;[
|
;[
|
||||||
'node_active',
|
'node_active',
|
||||||
'data_change',
|
'data_change',
|
||||||
'view_data_change',
|
'view_data_change',
|
||||||
'back_forward',
|
'back_forward',
|
||||||
'node_contextmenu',
|
'node_contextmenu',
|
||||||
'node_click',
|
'node_click',
|
||||||
'draw_click',
|
'draw_click',
|
||||||
'expand_btn_click',
|
'expand_btn_click',
|
||||||
'svg_mousedown',
|
'svg_mousedown',
|
||||||
'mouseup',
|
'mouseup',
|
||||||
'mode_change',
|
'mode_change',
|
||||||
'node_tree_render_end',
|
'node_tree_render_end',
|
||||||
'rich_text_selection_change',
|
'rich_text_selection_change',
|
||||||
'transforming-dom-to-images',
|
'transforming-dom-to-images',
|
||||||
'generalization_node_contextmenu',
|
'generalization_node_contextmenu',
|
||||||
'painter_start',
|
'painter_start',
|
||||||
'painter_end',
|
'painter_end',
|
||||||
'scrollbar_change'
|
'scrollbar_change'
|
||||||
].forEach(event => {
|
].forEach(event => {
|
||||||
this.mindMap.on(event, (...args) => {
|
this.mindMap.on(event, (...args) => {
|
||||||
this.$bus.$emit(event, ...args)
|
this.$bus.$emit(event, ...args)
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
this.bindSaveEvent()
|
this.bindSaveEvent()
|
||||||
// setTimeout(() => {
|
this.testDynamicCreateNodes()
|
||||||
// 动态给指定节点添加子节点
|
|
||||||
// this.mindMap.execCommand('INSERT_CHILD_NODE', false, this.mindMap.renderer.root, {
|
|
||||||
// text: '自定义内容'
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 动态给指定节点添加同级节点
|
|
||||||
// this.mindMap.execCommand('INSERT_NODE', false, this.mindMap.renderer.root, {
|
|
||||||
// text: '自定义内容'
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 动态删除指定节点
|
|
||||||
// this.mindMap.execCommand('REMOVE_NODE', this.mindMap.renderer.root.children[0])
|
|
||||||
// }, 5000);
|
|
||||||
// 如果应用被接管,那么抛出事件传递思维导图实例
|
// 如果应用被接管,那么抛出事件传递思维导图实例
|
||||||
if (window.takeOverApp) {
|
if (window.takeOverApp) {
|
||||||
this.$bus.$emit('app_inited', this.mindMap)
|
this.$bus.$emit('app_inited', this.mindMap)
|
||||||
@ -486,6 +481,113 @@ export default {
|
|||||||
// 移除节点富文本编辑插件
|
// 移除节点富文本编辑插件
|
||||||
removeRichTextPlugin() {
|
removeRichTextPlugin() {
|
||||||
this.mindMap.removePlugin(RichText)
|
this.mindMap.removePlugin(RichText)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 测试动态插入节点
|
||||||
|
testDynamicCreateNodes() {
|
||||||
|
return
|
||||||
|
setTimeout(() => {
|
||||||
|
// 动态给指定节点添加子节点
|
||||||
|
// this.mindMap.execCommand(
|
||||||
|
// 'INSERT_CHILD_NODE',
|
||||||
|
// false,
|
||||||
|
// this.mindMap.renderer.root,
|
||||||
|
// {
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
201
web/src/pages/Edit/components/FormulaSidebar.vue
Normal file
201
web/src/pages/Edit/components/FormulaSidebar.vue
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<template>
|
||||||
|
<Sidebar ref="sidebar" :title="$t('formulaSidebar.title')">
|
||||||
|
<div class="box" :class="{ isDark: isDark }">
|
||||||
|
<div class="formulaInputBox">
|
||||||
|
<el-input
|
||||||
|
v-model="formulaText"
|
||||||
|
:rows="4"
|
||||||
|
resize="none"
|
||||||
|
type="textarea"
|
||||||
|
:placeholder="$t('formulaSidebar.placeholder')"
|
||||||
|
@keydown.native.stop
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
style="width: 100%; margin-top: 20px;"
|
||||||
|
@click="confirm"
|
||||||
|
>{{ $t('formulaSidebar.confirm') }}</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="title">{{ $t('formulaSidebar.common') }}</div>
|
||||||
|
<div class="formulaList">
|
||||||
|
<div class="formulaItem" v-for="(item, index) in list" :key="index">
|
||||||
|
<div class="overview" v-html="item.overview"></div>
|
||||||
|
<div class="text" @click="formulaText = item.text">
|
||||||
|
{{ item.text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Sidebar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sidebar from './Sidebar'
|
||||||
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
import { formulaList } from '@/config/constant'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FormulaSidebar',
|
||||||
|
components: {
|
||||||
|
Sidebar
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
mindMap: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formulaText: '',
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['activeSidebar', 'isDark', 'localConfig'])
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activeSidebar(val) {
|
||||||
|
if (val === 'formulaSidebar') {
|
||||||
|
this.$refs.sidebar.show = true
|
||||||
|
} else {
|
||||||
|
this.$refs.sidebar.show = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$bus.$on('node_active', this.handleNodeActive)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.$bus.$off('node_active', this.handleNodeActive)
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['setActiveSidebar']),
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.list = formulaList.map(item => {
|
||||||
|
return {
|
||||||
|
overview: window.katex.renderToString(item, {
|
||||||
|
throwOnError: false,
|
||||||
|
output: 'mathml'
|
||||||
|
}),
|
||||||
|
text: item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleNodeActive(...args) {
|
||||||
|
this.activeNodes = [...args[1]]
|
||||||
|
if (this.activeNodes.length <= 0) {
|
||||||
|
this.setActiveSidebar(null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
if (!this.localConfig.openNodeRichText) {
|
||||||
|
return this.$message.warning('非富文本模式下不支持插入公式')
|
||||||
|
}
|
||||||
|
let str = this.formulaText.trim()
|
||||||
|
if (!str) return
|
||||||
|
this.mindMap.execCommand('INSERT_FORMULA', str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.box {
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.isDark {
|
||||||
|
.title {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaList {
|
||||||
|
.formulaItem {
|
||||||
|
.overview,
|
||||||
|
.text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
background-color: #363b3f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-textarea__inner {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin: 10px 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaInputBox {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formulaList {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.formulaItem {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview,
|
||||||
|
.text {
|
||||||
|
width: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview {
|
||||||
|
padding: 10px 0;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
border-left: 1px solid #dcdfe6;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,9 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<Sidebar ref="sidebar" title="图标/贴纸">
|
<Sidebar ref="sidebar" :title="$t('nodeIconSidebar.title')">
|
||||||
<div class="box" :class="{ isDark: isDark }">
|
<div class="box" :class="{ isDark: isDark }">
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane label="图标" name="icon"></el-tab-pane>
|
<el-tab-pane
|
||||||
<el-tab-pane label="贴纸" name="image"></el-tab-pane>
|
:label="$t('nodeIconSidebar.icon')"
|
||||||
|
name="icon"
|
||||||
|
></el-tab-pane>
|
||||||
|
<el-tab-pane
|
||||||
|
:label="$t('nodeIconSidebar.sticker')"
|
||||||
|
name="image"
|
||||||
|
></el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="boxContent">
|
<div class="boxContent">
|
||||||
<!-- 图标 -->
|
<!-- 图标 -->
|
||||||
|
|||||||
@ -134,6 +134,16 @@
|
|||||||
<span class="icon iconfont iconlianjiexian"></span>
|
<span class="icon iconfont iconlianjiexian"></span>
|
||||||
<span class="text">{{ $t('toolbar.associativeLine') }}</span>
|
<span class="text">{{ $t('toolbar.associativeLine') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="toolbarBtn"
|
||||||
|
:class="{
|
||||||
|
disabled: activeNodes.length <= 0 || hasGeneralization
|
||||||
|
}"
|
||||||
|
@click="showFormula"
|
||||||
|
>
|
||||||
|
<span class="icon iconfont icongongshi"></span>
|
||||||
|
<span class="text">{{ $t('toolbar.formula') }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 导出 -->
|
<!-- 导出 -->
|
||||||
<div class="toolbarBlock">
|
<div class="toolbarBlock">
|
||||||
@ -259,6 +269,11 @@ export default {
|
|||||||
this.setActiveSidebar('nodeIconSidebar')
|
this.setActiveSidebar('nodeIconSidebar')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 打开公式侧边栏
|
||||||
|
showFormula() {
|
||||||
|
this.setActiveSidebar('formulaSidebar')
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
* @Date: 2022-11-14 19:17:40
|
* @Date: 2022-11-14 19:17:40
|
||||||
|
|||||||
@ -1,57 +1,69 @@
|
|||||||
import { imgToDataUrl } from 'simple-mind-map/src/utils/index'
|
import { imgToDataUrl } from 'simple-mind-map/src/utils/index'
|
||||||
|
|
||||||
// 处理知犀
|
// 处理知犀
|
||||||
const handleZHIXI = async text => {
|
const handleZHIXI = async data => {
|
||||||
text = text.replace('', '')
|
|
||||||
try {
|
try {
|
||||||
// 只处理一项
|
try {
|
||||||
const node = JSON.parse(text)[0]
|
if (!Array.isArray(data)) {
|
||||||
const newNode = {}
|
data = String(data).replace('', '')
|
||||||
const waitLoadImageList = []
|
data = JSON.parse(data)
|
||||||
const walk = async (root, newRoot) => {
|
|
||||||
newRoot.data = {
|
|
||||||
text: root.data.text,
|
|
||||||
hyperlink: root.data.hyperlink,
|
|
||||||
hyperlinkTitle: root.data.hyperlinkTitle,
|
|
||||||
note: root.data.note
|
|
||||||
}
|
|
||||||
// 图片
|
|
||||||
if (root.data.image) {
|
|
||||||
let resolve = null
|
|
||||||
let promise = new Promise(_resolve => {
|
|
||||||
resolve = _resolve
|
|
||||||
})
|
|
||||||
waitLoadImageList.push(promise)
|
|
||||||
try {
|
|
||||||
newRoot.data.image = await imgToDataUrl(root.data.image)
|
|
||||||
newRoot.data.imageSize = root.data.imageSize
|
|
||||||
resolve()
|
|
||||||
} catch (error) {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 子节点
|
|
||||||
newRoot.children = []
|
|
||||||
if (root.children && root.children.length > 0) {
|
|
||||||
root.children.forEach(item => {
|
|
||||||
// 概要
|
|
||||||
if (item.data.type === 'generalize') {
|
|
||||||
newRoot.data.generalization = {
|
|
||||||
text: item.data.text
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let newChild = {}
|
|
||||||
newRoot.children.push(newChild)
|
|
||||||
walk(item, newChild)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
}
|
}
|
||||||
walk(node, newNode)
|
if (!Array.isArray(data)) {
|
||||||
|
data = []
|
||||||
|
}
|
||||||
|
const newNodeList = []
|
||||||
|
const waitLoadImageList = []
|
||||||
|
const walk = (list, newList) => {
|
||||||
|
list.forEach(async item => {
|
||||||
|
let newRoot = {}
|
||||||
|
newList.push(newRoot)
|
||||||
|
newRoot.data = {
|
||||||
|
text: item.data.text,
|
||||||
|
hyperlink: item.data.hyperlink,
|
||||||
|
hyperlinkTitle: item.data.hyperlinkTitle,
|
||||||
|
note: item.data.note
|
||||||
|
}
|
||||||
|
// 图片
|
||||||
|
if (item.data.image) {
|
||||||
|
let resolve = null
|
||||||
|
let promise = new Promise(_resolve => {
|
||||||
|
resolve = _resolve
|
||||||
|
})
|
||||||
|
waitLoadImageList.push(promise)
|
||||||
|
try {
|
||||||
|
newRoot.data.image = await imgToDataUrl(item.data.image)
|
||||||
|
newRoot.data.imageSize = item.data.imageSize
|
||||||
|
resolve()
|
||||||
|
} catch (error) {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 子节点
|
||||||
|
newRoot.children = []
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
const children = []
|
||||||
|
item.children.forEach(item2 => {
|
||||||
|
// 概要
|
||||||
|
if (item2.data.type === 'generalize') {
|
||||||
|
newRoot.data.generalization = {
|
||||||
|
text: item2.data.text
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
children.push(item2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
walk(children, newRoot.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
walk(data, newNodeList)
|
||||||
await Promise.all(waitLoadImageList)
|
await Promise.all(waitLoadImageList)
|
||||||
return {
|
return {
|
||||||
simpleMindMap: true,
|
simpleMindMap: true,
|
||||||
data: newNode
|
data: newNodeList
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return ''
|
return ''
|
||||||
@ -59,7 +71,15 @@ const handleZHIXI = async text => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClipboardText = async text => {
|
const handleClipboardText = async text => {
|
||||||
// 处理知犀数据
|
// 知犀数据格式1
|
||||||
|
try {
|
||||||
|
let parsedData = JSON.parse(text)
|
||||||
|
if (parsedData.__c_zx_v !== undefined) {
|
||||||
|
const res = await handleZHIXI(parsedData.children)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
// 知犀数据格式2
|
||||||
if (text.includes('')) {
|
if (text.includes('')) {
|
||||||
const res = await handleZHIXI(text)
|
const res = await handleZHIXI(text)
|
||||||
return res
|
return res
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user