Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
193b293cfe | ||
|
|
615ff3ea25 | ||
|
|
8b9cfd2972 | ||
|
|
03f8cb9290 | ||
|
|
1ea0c7e316 | ||
|
|
a39c8c30e6 | ||
|
|
26ce08c27d | ||
|
|
4bfc98a96f | ||
|
|
7560411922 | ||
|
|
4288e44f3a | ||
|
|
b82c5247fa | ||
|
|
c7d2082944 | ||
|
|
29458ade9c | ||
|
|
49d366628e | ||
|
|
b093153262 | ||
|
|
02f276bc2a | ||
|
|
69cb961cc1 | ||
|
|
7096391f3b | ||
|
|
280ffcf01d | ||
|
|
db3c2b71f5 | ||
|
|
f11f364d00 | ||
|
|
0e8c50d430 | ||
|
|
dd8d250857 | ||
|
|
693ead6b49 | ||
|
|
dc3c91270c | ||
|
|
71ac739964 | ||
|
|
eae5dc5854 | ||
|
|
c45ceac7dc | ||
|
|
3d8702be8a | ||
|
|
084dd9fd84 | ||
|
|
0c6c68820f | ||
|
|
f5ff479f47 | ||
|
|
e9722efe93 | ||
|
|
db1f9c04c1 | ||
|
|
b3e6412dbc | ||
|
|
f58828469c | ||
|
|
cf7a92d9c7 | ||
|
|
ec0d021e92 | ||
|
|
25a2d919fb | ||
|
|
c3f4e2b797 | ||
|
|
a0c07522f9 | ||
|
|
ca0cbdf009 | ||
|
|
6263a49903 | ||
|
|
dce133f8f0 | ||
|
|
7f4f4e2fe0 | ||
|
|
4e4ade5c31 | ||
|
|
5423b42e9d | ||
|
|
9555375907 | ||
|
|
cc19ce168b | ||
|
|
e324813eae | ||
|
|
08a7ba380a | ||
|
|
dd2bfbcf93 | ||
|
|
4ae5c914ca | ||
|
|
6f49577794 | ||
|
|
43a3dd97c7 | ||
|
|
7226e40a6c | ||
|
|
9f090a4474 | ||
|
|
bf5298ab2f | ||
|
|
ffe4fedbc3 | ||
|
|
07ad92e93a | ||
|
|
5a004e40de | ||
|
|
8664bcc00b | ||
|
|
d00f56c7f1 | ||
|
|
4ddce22076 | ||
|
|
fdf4d51a1e | ||
|
|
a9ebe50fff | ||
|
|
f8638088f3 | ||
|
|
081797e83b | ||
|
|
8adf5a7fb8 | ||
|
|
194a920efa | ||
|
|
6b3741741c | ||
|
|
80a7e334e4 | ||
|
|
5d45d7accf | ||
|
|
b893776f82 | ||
|
|
115a0ac480 | ||
|
|
cb43292aa5 | ||
|
|
7b773bd9ad | ||
|
|
38a1e25cc2 | ||
|
|
fd0c471f00 | ||
|
|
97f84933f8 | ||
|
|
321fc69798 | ||
|
|
af2910bec8 | ||
|
|
9deb20f1ca | ||
|
|
0f4d614c4e | ||
|
|
eeba3153ef | ||
|
|
554dab56d3 | ||
|
|
da28f89c52 | ||
|
|
8b0c62430e | ||
|
|
adcf77f60d | ||
|
|
54ae4b3e26 | ||
|
|
b0929da054 | ||
|
|
1528c3d64b | ||
|
|
ecc3ba8784 | ||
|
|
947c4b2b44 | ||
|
|
08c7768b18 | ||
|
|
efebe3f094 |
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
oss.js
|
.DS_Store
|
||||||
|
package-lock.json
|
||||||
15
copy.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const src = path.resolve(__dirname, './dist/index.html')
|
||||||
|
const dest = path.resolve(__dirname, './index.html')
|
||||||
|
|
||||||
|
if (fs.existsSync(dest)) {
|
||||||
|
fs.unlinkSync(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(src)) {
|
||||||
|
fs.copyFileSync(src, dest)
|
||||||
|
fs.unlinkSync(src)
|
||||||
|
}
|
||||||
|
|
||||||
BIN
docs/assets/1.gif
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/assets/2.gif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/assets/2021-07-21-19-54-48.gif
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
docs/assets/3.gif
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/assets/image-20210717174716810.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/assets/image-20210717202607786.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/assets/image-20210717210355763.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
docs/assets/image-20210717224527681.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/assets/image-20210717230604086.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/assets/image-20210717230805200.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/assets/image-20210717230808662.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/assets/image-20210718083006111.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/assets/image-20210718083616076.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/assets/image-20210718092817830.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/assets/image-20210718102434530.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/assets/image-20210718110652705.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/assets/image-20210718111334085.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
docs/assets/image-20210718134525691.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/assets/image-20210718184835414.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
docs/assets/image-20210718191124627.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
docs/assets/image-20210718221814590.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
docs/assets/image-20210718222150055.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/assets/image-20210718222612078.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/assets/image-20210720191943989.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
docs/assets/image-20210720192008277.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/assets/image-20210720200816281.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/assets/image-20210721183307656.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/assets/image-20210721183340310.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/assets/image-20210721183823754.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
docs/assets/image-20210721184140488.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/assets/image-20210721185453825.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
docs/assets/image-20210721190700979.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/assets/swdt.jpg
Normal file
|
After Width: | Height: | Size: 254 KiB |
1317
docs/web思维导图实现的技术点分析.md
Normal file
1
index.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>一个简单的web思维导图实现</title><link href="dist/js/chunk-2d20ec02.81d632f4.js" rel="prefetch"><link href="dist/js/chunk-2d216b67.228f2009.js" rel="prefetch"><link href="dist/js/chunk-e86f1494.f8dd20e2.js" rel="prefetch"><link href="dist/css/app.d29688d8.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.6fd71983.css" rel="preload" as="style"><link href="dist/js/app.88b2cb65.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.094115db.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.6fd71983.css" rel="stylesheet"><link href="dist/css/app.d29688d8.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="dist/js/chunk-vendors.094115db.js"></script><script src="dist/js/app.88b2cb65.js"></script></body></html>
|
||||||
3
simple-mind-map/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# 一个web思维导图的简单实现
|
||||||
|
|
||||||
|
详细文档见:[https://github.com/wanglin2/mind-map](https://github.com/wanglin2/mind-map)
|
||||||
BIN
simple-mind-map/dist/img/blueSky.3c7f8ccb.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
simple-mind-map/dist/img/brainImpairedPink.511fee22.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
simple-mind-map/dist/img/catalogOrganization.380bb277.jpg
vendored
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
simple-mind-map/dist/img/classic.733f273c.jpg
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
simple-mind-map/dist/img/classic2.cdfe2a8d.jpg
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
simple-mind-map/dist/img/classic3.19d6c347.jpg
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
simple-mind-map/dist/img/classic4.087902fc.jpg
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
simple-mind-map/dist/img/classicBlue.4b8243c6.jpg
vendored
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
simple-mind-map/dist/img/classicGreen.c2ae7bde.jpg
vendored
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
simple-mind-map/dist/img/dark.894c1d36.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
simple-mind-map/dist/img/dark2.c49dc11c.jpg
vendored
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
simple-mind-map/dist/img/default.1312a3ba.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
simple-mind-map/dist/img/earthYellow.c35e546d.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
simple-mind-map/dist/img/freshGreen.0e344e3e.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
simple-mind-map/dist/img/freshRed.1c5bde77.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
simple-mind-map/dist/img/gold.3093b3c8.jpg
vendored
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
simple-mind-map/dist/img/greenLeaf.6789e8fc.jpg
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
simple-mind-map/dist/img/logicalStructure.624920ce.jpg
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
simple-mind-map/dist/img/mindMap.223b38aa.jpg
vendored
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
simple-mind-map/dist/img/minions.c2a93f9e.jpg
vendored
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
simple-mind-map/dist/img/mint.7933f60a.jpg
vendored
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
simple-mind-map/dist/img/organizationStructure.8064f4da.jpg
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
simple-mind-map/dist/img/pinkGrape.32c2587b.jpg
vendored
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
simple-mind-map/dist/img/romanticPurple.7607e58a.jpg
vendored
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
simple-mind-map/dist/img/skyGreen.4cfa829a.jpg
vendored
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
simple-mind-map/dist/img/vitalityOrange.5dd9014f.jpg
vendored
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
929
simple-mind-map/example/exampleData.js
Normal file
@@ -0,0 +1,929 @@
|
|||||||
|
const createFullData = () => {
|
||||||
|
return {
|
||||||
|
"image": "/enJFNMHnedQTYTESGfDkctCp2.jpeg",
|
||||||
|
"imageTitle": "图片名称",
|
||||||
|
"imageSize": {
|
||||||
|
"width": 1000,
|
||||||
|
"height": 563
|
||||||
|
},
|
||||||
|
"icon": ['priority_1'],
|
||||||
|
"tag": ["标签1", "标签2"],
|
||||||
|
"hyperlink": "http://lxqnsys.com/",
|
||||||
|
"hyperlinkTitle": "理想青年实验室",
|
||||||
|
"note": "理想青年实验室\n一个有意思的角落",
|
||||||
|
// 自定义位置
|
||||||
|
// "customLeft": 1318,
|
||||||
|
// "customTop": 374.5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-15 22:23:24
|
||||||
|
* @Desc: 节点较多示例数据
|
||||||
|
*/
|
||||||
|
const data1 = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "根节点"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点1",
|
||||||
|
"expand": true,
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
...createFullData()
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
...createFullData()
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点2",
|
||||||
|
"expand": true,
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点3",
|
||||||
|
"expand": true,
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点4",
|
||||||
|
"expand": true,
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题",
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-12 13:49:43
|
||||||
|
* @Desc: 真实场景数据
|
||||||
|
*/
|
||||||
|
const data2 = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "一周安排"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "生活"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "锻炼"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "晨跑"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "7:00-8:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "夜跑"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "20:00-21:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "饮食"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "早餐"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "8:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "午餐"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "11:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "晚餐"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "19:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "休息"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "午休"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "12:30-13:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "晚休"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "23:00-6:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "工作日\n周一至周五"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "日常工作"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "9:00-18:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "工作总结"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "21:00-22:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "学习"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "工作日"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "早间新闻"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "8:00-8:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "阅读"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "21:00-23:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "休息日"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "财务管理"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "9:00-10:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "职场技能"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "14:00-15:30"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "其他书籍"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "16:00-18:00"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "休闲娱乐"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "看电影"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "1~2部"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "逛街"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "1~2次"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-12 14:29:10
|
||||||
|
* @Desc: 极简数据
|
||||||
|
*/
|
||||||
|
const data3 = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "根节点"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data4 = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "根节点"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点1"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点1-1"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点1-2"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点1-2-1"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点1-2-2"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点1-2-3"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点2"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点2-1"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点2-1-1"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点2-1-1-1"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "子节点2-2"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 带概要
|
||||||
|
const data5 = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "根节点"
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "二级节点",
|
||||||
|
"generalization": {
|
||||||
|
"text": "概要",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text": "分支主题"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootData = {
|
||||||
|
"root": {
|
||||||
|
"data": {
|
||||||
|
"text": "根节点"
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// ...data1,
|
||||||
|
// ...data2,
|
||||||
|
// ...data3,
|
||||||
|
// ...data4,
|
||||||
|
...data5,
|
||||||
|
// ...rootData,
|
||||||
|
"theme": {
|
||||||
|
"template": "classic4",
|
||||||
|
"config": {
|
||||||
|
// 自定义配置...
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout": "logicalStructure",
|
||||||
|
// "layout": "mindMap",
|
||||||
|
// "layout": "catalogOrganization"
|
||||||
|
// "layout": "organizationStructure"
|
||||||
|
}
|
||||||
372
simple-mind-map/index.js
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
import View from './src/View'
|
||||||
|
import Event from './src/Event'
|
||||||
|
import Render from './src/Render'
|
||||||
|
import merge from 'deepmerge'
|
||||||
|
import theme from './src/themes'
|
||||||
|
import Style from './src/Style'
|
||||||
|
import KeyCommand from './src/KeyCommand'
|
||||||
|
import Command from './src/Command'
|
||||||
|
import BatchExecution from './src/BatchExecution'
|
||||||
|
import Export from './src/Export'
|
||||||
|
import Select from './src/Select'
|
||||||
|
import Drag from './src/Drag'
|
||||||
|
import {
|
||||||
|
layoutValueList
|
||||||
|
} from './src/utils/constant'
|
||||||
|
import {
|
||||||
|
SVG
|
||||||
|
} from '@svgdotjs/svg.js'
|
||||||
|
|
||||||
|
// 默认选项配置
|
||||||
|
const defaultOpt = {
|
||||||
|
// 是否只读
|
||||||
|
readonly: false,
|
||||||
|
// 布局
|
||||||
|
layout: 'logicalStructure',
|
||||||
|
// 主题
|
||||||
|
theme: 'default', // 内置主题:default(默认主题)
|
||||||
|
// 主题配置,会和所选择的主题进行合并
|
||||||
|
themeConfig: {},
|
||||||
|
// 放大缩小的增量比例
|
||||||
|
scaleRatio: 0.1,
|
||||||
|
// 最多显示几个标签
|
||||||
|
maxTag: 5,
|
||||||
|
// 导出图片时的内边距
|
||||||
|
exportPadding: 20,
|
||||||
|
// 展开收缩按钮尺寸
|
||||||
|
expandBtnSize: 20,
|
||||||
|
// 节点里图片和文字的间距
|
||||||
|
imgTextMargin: 5,
|
||||||
|
// 节点里各种文字信息的间距,如图标和文字的间距
|
||||||
|
textContentMargin: 2,
|
||||||
|
// 多选节点时鼠标移动到边缘时的画布移动偏移量
|
||||||
|
selectTranslateStep: 3,
|
||||||
|
// 多选节点时鼠标移动距边缘多少距离时开始偏移
|
||||||
|
selectTranslateLimit: 20,
|
||||||
|
// 自定义节点备注内容显示
|
||||||
|
customNoteContentShow: null
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
show(){},
|
||||||
|
hide(){}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-06 11:18:47
|
||||||
|
* @Desc: 思维导图
|
||||||
|
*/
|
||||||
|
class MindMap {
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-06 11:19:01
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt = {}) {
|
||||||
|
// 合并选项
|
||||||
|
this.opt = this.handleOpt(merge(defaultOpt, opt))
|
||||||
|
|
||||||
|
// 容器元素
|
||||||
|
this.el = this.opt.el
|
||||||
|
this.elRect = this.el.getBoundingClientRect()
|
||||||
|
|
||||||
|
// 画布宽高
|
||||||
|
this.width = this.elRect.width
|
||||||
|
this.height = this.elRect.height
|
||||||
|
|
||||||
|
// 画布
|
||||||
|
this.svg = SVG().addTo(this.el).size(this.width, this.height)
|
||||||
|
this.draw = this.svg.group()
|
||||||
|
|
||||||
|
// 节点id
|
||||||
|
this.uid = 0
|
||||||
|
|
||||||
|
// 初始化主题
|
||||||
|
this.initTheme()
|
||||||
|
|
||||||
|
// 事件类
|
||||||
|
this.event = new Event({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 按键类
|
||||||
|
this.keyCommand = new KeyCommand({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 命令类
|
||||||
|
this.command = new Command({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 渲染类
|
||||||
|
this.renderer = new Render({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 视图操作类
|
||||||
|
this.view = new View({
|
||||||
|
mindMap: this,
|
||||||
|
draw: this.draw
|
||||||
|
})
|
||||||
|
|
||||||
|
// 导出类
|
||||||
|
this.doExport = new Export({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 选择类
|
||||||
|
this.select = new Select({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 拖动类
|
||||||
|
this.drag = new Drag({
|
||||||
|
mindMap: this
|
||||||
|
})
|
||||||
|
|
||||||
|
// 批量执行类
|
||||||
|
this.batchExecution = new BatchExecution()
|
||||||
|
|
||||||
|
// 初始渲染
|
||||||
|
this.reRender()
|
||||||
|
setTimeout(() => {
|
||||||
|
this.command.addHistory()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:15:22
|
||||||
|
* @Desc: 配置参数处理
|
||||||
|
*/
|
||||||
|
handleOpt(opt) {
|
||||||
|
// 检查布局配置
|
||||||
|
if (!layoutValueList.includes(opt.layout)) {
|
||||||
|
opt.layout = 'logicalStructure'
|
||||||
|
}
|
||||||
|
// 检查主题配置
|
||||||
|
opt.theme = opt.theme && theme[opt.theme] ? opt.theme : 'default'
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-06 18:47:29
|
||||||
|
* @Desc: 渲染,部分渲染
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
this.batchExecution.push('render', () => {
|
||||||
|
this.initTheme()
|
||||||
|
this.renderer.reRender = false
|
||||||
|
this.renderer.render()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-08 22:05:11
|
||||||
|
* @Desc: 重新渲染
|
||||||
|
*/
|
||||||
|
reRender() {
|
||||||
|
this.batchExecution.push('render', () => {
|
||||||
|
this.draw.clear()
|
||||||
|
this.initTheme()
|
||||||
|
this.renderer.reRender = true
|
||||||
|
this.renderer.render()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 21:16:52
|
||||||
|
* @Desc: 容器尺寸变化,调整尺寸
|
||||||
|
*/
|
||||||
|
resize() {
|
||||||
|
this.elRect = this.el.getBoundingClientRect()
|
||||||
|
this.width = this.elRect.width
|
||||||
|
this.height = this.elRect.height
|
||||||
|
this.svg.size(this.width, this.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-24 13:25:50
|
||||||
|
* @Desc: 监听事件
|
||||||
|
*/
|
||||||
|
on(event, fn) {
|
||||||
|
this.event.on(event, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-24 13:51:35
|
||||||
|
* @Desc: 触发事件
|
||||||
|
*/
|
||||||
|
emit(event, ...args) {
|
||||||
|
this.event.emit(event, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-24 13:53:54
|
||||||
|
* @Desc: 解绑事件
|
||||||
|
*/
|
||||||
|
off(event, fn) {
|
||||||
|
this.event.off(event, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-05 13:32:43
|
||||||
|
* @Desc: 设置主题
|
||||||
|
*/
|
||||||
|
initTheme() {
|
||||||
|
// 合并主题配置
|
||||||
|
this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig)
|
||||||
|
// 设置背景样式
|
||||||
|
Style.setBackgroundStyle(this.el, this.themeConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-05 13:52:08
|
||||||
|
* @Desc: 设置主题
|
||||||
|
*/
|
||||||
|
setTheme(theme) {
|
||||||
|
this.renderer.clearAllActive()
|
||||||
|
this.opt.theme = theme
|
||||||
|
this.reRender()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-25 23:52:37
|
||||||
|
* @Desc: 获取当前主题
|
||||||
|
*/
|
||||||
|
getTheme() {
|
||||||
|
return this.opt.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-05 13:50:17
|
||||||
|
* @Desc: 设置主题配置
|
||||||
|
*/
|
||||||
|
setThemeConfig(config) {
|
||||||
|
this.opt.themeConfig = config
|
||||||
|
this.reRender()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-01 10:38:34
|
||||||
|
* @Desc: 获取自定义主题配置
|
||||||
|
*/
|
||||||
|
getCustomThemeConfig() {
|
||||||
|
return this.opt.themeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-05 14:01:29
|
||||||
|
* @Desc: 获取某个主题配置值
|
||||||
|
*/
|
||||||
|
getThemeConfig(prop) {
|
||||||
|
return prop === undefined ? this.themeConfig : this.themeConfig[prop]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-13 16:17:06
|
||||||
|
* @Desc: 获取当前布局结构
|
||||||
|
*/
|
||||||
|
getLayout() {
|
||||||
|
return this.opt.layout
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-13 16:17:33
|
||||||
|
* @Desc: 设置布局结构
|
||||||
|
*/
|
||||||
|
setLayout(layout) {
|
||||||
|
// 检查布局配置
|
||||||
|
if (!layoutValueList.includes(layout)) {
|
||||||
|
layout = 'logicalStructure'
|
||||||
|
}
|
||||||
|
this.opt.layout = layout
|
||||||
|
this.renderer.setLayout()
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 13:01:00
|
||||||
|
* @Desc: 执行命令
|
||||||
|
*/
|
||||||
|
execCommand(...args) {
|
||||||
|
this.command.exec(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-03 22:58:12
|
||||||
|
* @Desc: 动态设置思维导图数据
|
||||||
|
*/
|
||||||
|
setData(data) {
|
||||||
|
this.execCommand('CLEAR_ACTIVE_NODE')
|
||||||
|
this.command.clearHistory()
|
||||||
|
this.renderer.renderTree = data
|
||||||
|
this.reRender()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:06:38
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
async export(...args) {
|
||||||
|
let result = await this.doExport.export(...args)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 09:20:03
|
||||||
|
* @Desc: 转换位置
|
||||||
|
*/
|
||||||
|
toPos(x, y) {
|
||||||
|
return {
|
||||||
|
x: x - this.elRect.left,
|
||||||
|
y: y - this.elRect.top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-06-08 14:12:38
|
||||||
|
* @Desc: 设置只读模式、编辑模式
|
||||||
|
*/
|
||||||
|
setMode(mode) {
|
||||||
|
if (!['readonly', 'edit'].includes(mode)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.opt.readonly = mode === 'readonly'
|
||||||
|
if (this.opt.readonly) {
|
||||||
|
// 取消当前激活的元素
|
||||||
|
this.renderer.clearAllActive()
|
||||||
|
}
|
||||||
|
this.emit('mode_change', mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MindMap
|
||||||
37
simple-mind-map/package.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "simple-mind-map",
|
||||||
|
"version": "0.2.3",
|
||||||
|
"description": "一个简单的web在线思维导图",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "街角小林",
|
||||||
|
"email": "1013335014@qq.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "理想青年实验室",
|
||||||
|
"url": "http://lxqnsys.com/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/wanglin2/mind-map"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"module": "index.js",
|
||||||
|
"main": "./dist/simpleMindMap.umd.min.js",
|
||||||
|
"dependencies": {
|
||||||
|
"@svgdotjs/svg.js": "^3.0.16",
|
||||||
|
"canvg": "^3.0.7",
|
||||||
|
"deepmerge": "^1.5.2",
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"jspdf": "^2.5.1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"javascript",
|
||||||
|
"svg",
|
||||||
|
"mind-map",
|
||||||
|
"mindMap",
|
||||||
|
"MindMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
85
simple-mind-map/src/BatchExecution.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-27 13:16:23
|
||||||
|
* @Desc: 在下一个事件循环里执行任务
|
||||||
|
*/
|
||||||
|
const nextTick = function (fn, ctx) {
|
||||||
|
let pending = false
|
||||||
|
let timerFunc = null
|
||||||
|
let handle = () => {
|
||||||
|
pending = false
|
||||||
|
ctx ? fn.call(ctx) : fn()
|
||||||
|
}
|
||||||
|
// 支持MutationObserver接口的话使用MutationObserver
|
||||||
|
if (typeof MutationObserver !== 'undefined') {
|
||||||
|
let counter = 1
|
||||||
|
let observer = new MutationObserver(handle)
|
||||||
|
let textNode = document.createTextNode(counter)
|
||||||
|
observer.observe(textNode, {
|
||||||
|
characterData: true// 设为 true 表示监视指定目标节点或子节点树中节点所包含的字符数据的变化
|
||||||
|
})
|
||||||
|
timerFunc = function () {
|
||||||
|
counter = (counter + 1) % 2// counter会在0和1两者循环变化
|
||||||
|
textNode.data = counter// 节点变化会触发回调handle,
|
||||||
|
}
|
||||||
|
} else {// 否则使用定时器
|
||||||
|
timerFunc = setTimeout
|
||||||
|
}
|
||||||
|
return function (cb, ctx) {
|
||||||
|
if (pending) return
|
||||||
|
pending = true
|
||||||
|
timerFunc(handle, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-26 22:40:52
|
||||||
|
* @Desc: 批量执行
|
||||||
|
*/
|
||||||
|
class BatchExecution {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-26 22:41:41
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.has = {}
|
||||||
|
this.queue = []
|
||||||
|
this.nextTick = nextTick(this.flush, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-27 12:54:04
|
||||||
|
* @Desc: 添加任务
|
||||||
|
*/
|
||||||
|
push(name, fn) {
|
||||||
|
if (this.has[name]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.has[name] = true
|
||||||
|
this.queue.push({
|
||||||
|
name,
|
||||||
|
fn
|
||||||
|
})
|
||||||
|
this.nextTick()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-27 13:09:24
|
||||||
|
* @Desc: 执行队列
|
||||||
|
*/
|
||||||
|
flush() {
|
||||||
|
let fns = this.queue.slice(0)
|
||||||
|
this.queue = []
|
||||||
|
fns.forEach(({ name, fn }) => {
|
||||||
|
this.has[name] = false
|
||||||
|
fn()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BatchExecution
|
||||||
152
simple-mind-map/src/Command.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import { copyRenderTree, simpleDeepClone } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 13:10:06
|
||||||
|
* @Desc: 命令类
|
||||||
|
*/
|
||||||
|
class Command {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 13:10:24
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt = {}) {
|
||||||
|
this.opt = opt
|
||||||
|
this.mindMap = opt.mindMap
|
||||||
|
this.commands = {}
|
||||||
|
this.history = []
|
||||||
|
this.activeHistoryIndex = 0
|
||||||
|
// 注册快捷键
|
||||||
|
this.registerShortcutKeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-03 23:06:55
|
||||||
|
* @Desc: 清空历史数据
|
||||||
|
*/
|
||||||
|
clearHistory() {
|
||||||
|
this.history = []
|
||||||
|
this.activeHistoryIndex = 0
|
||||||
|
this.mindMap.emit('back_forward', 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-02 23:23:19
|
||||||
|
* @Desc: 注册快捷键
|
||||||
|
*/
|
||||||
|
registerShortcutKeys() {
|
||||||
|
this.mindMap.keyCommand.addShortcut('Control+z', () => {
|
||||||
|
this.mindMap.execCommand('BACK')
|
||||||
|
})
|
||||||
|
this.mindMap.keyCommand.addShortcut('Control+y', () => {
|
||||||
|
this.mindMap.execCommand('FORWARD')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 13:12:30
|
||||||
|
* @Desc: 执行命令
|
||||||
|
*/
|
||||||
|
exec(name, ...args) {
|
||||||
|
if (this.commands[name]) {
|
||||||
|
this.commands[name].forEach((fn) => {
|
||||||
|
fn(...args)
|
||||||
|
})
|
||||||
|
if (name === 'BACK' || name === 'FORWARD') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.addHistory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 13:13:01
|
||||||
|
* @Desc: 添加命令
|
||||||
|
*/
|
||||||
|
add(name, fn) {
|
||||||
|
if (this.commands[name]) {
|
||||||
|
this.commands[name].push(fn)
|
||||||
|
} else {
|
||||||
|
this.commands[name] = [fn]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-15 23:02:41
|
||||||
|
* @Desc: 移除命令
|
||||||
|
*/
|
||||||
|
remove(name, fn) {
|
||||||
|
if (!this.commands[name]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!fn) {
|
||||||
|
this.commands[name] = []
|
||||||
|
delete this.commands[name]
|
||||||
|
} else {
|
||||||
|
let index = this.commands[name].find((item) => {
|
||||||
|
return item === fn;
|
||||||
|
})
|
||||||
|
if (index !== -1) {
|
||||||
|
this.commands[name].splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 14:35:43
|
||||||
|
* @Desc: 添加回退数据
|
||||||
|
*/
|
||||||
|
addHistory() {
|
||||||
|
let data = this.getCopyData()
|
||||||
|
this.history.push(simpleDeepClone(data))
|
||||||
|
this.activeHistoryIndex = this.history.length - 1
|
||||||
|
this.mindMap.emit('data_change', data)
|
||||||
|
this.mindMap.emit('back_forward', this.activeHistoryIndex, this.history.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 22:34:53
|
||||||
|
* @Desc: 回退
|
||||||
|
*/
|
||||||
|
back(step = 1) {
|
||||||
|
if (this.activeHistoryIndex - step >= 0) {
|
||||||
|
this.activeHistoryIndex -= step
|
||||||
|
this.mindMap.emit('back_forward', this.activeHistoryIndex, this.history.length)
|
||||||
|
return simpleDeepClone(this.history[this.activeHistoryIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-12 10:45:31
|
||||||
|
* @Desc: 前进
|
||||||
|
*/
|
||||||
|
forward(step = 1) {
|
||||||
|
let len = this.history.length
|
||||||
|
if (this.activeHistoryIndex + step <= len - 1) {
|
||||||
|
this.activeHistoryIndex += step
|
||||||
|
this.mindMap.emit('back_forward', this.activeHistoryIndex,)
|
||||||
|
return simpleDeepClone(this.history[this.activeHistoryIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-05-04 15:02:58
|
||||||
|
* @Desc: 获取渲染树数据副本
|
||||||
|
*/
|
||||||
|
getCopyData() {
|
||||||
|
return copyRenderTree({}, this.mindMap.renderer.renderTree)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Command
|
||||||
317
simple-mind-map/src/Drag.js
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
import {
|
||||||
|
bfsWalk,
|
||||||
|
throttle
|
||||||
|
} from './utils'
|
||||||
|
import Base from './layouts/Base'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 17:38:55
|
||||||
|
* @Desc: 节点拖动类
|
||||||
|
*/
|
||||||
|
class Drag extends Base {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:35:16
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor({
|
||||||
|
mindMap
|
||||||
|
}) {
|
||||||
|
super(mindMap.renderer)
|
||||||
|
this.mindMap = mindMap
|
||||||
|
this.reset()
|
||||||
|
this.bindEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 19:33:56
|
||||||
|
* @Desc: 复位
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
// 当前拖拽节点
|
||||||
|
this.node = null
|
||||||
|
// 当前重叠节点
|
||||||
|
this.overlapNode = null
|
||||||
|
// 当前上一个同级节点
|
||||||
|
this.prevNode = null
|
||||||
|
// 当前下一个同级节点
|
||||||
|
this.nextNode = null
|
||||||
|
// 画布的变换数据
|
||||||
|
this.drawTransform = null
|
||||||
|
// 克隆节点
|
||||||
|
this.clone = null
|
||||||
|
// 连接线
|
||||||
|
this.line = null
|
||||||
|
// 同级位置占位符
|
||||||
|
this.placeholder = null
|
||||||
|
// 鼠标按下位置和节点左上角的偏移量
|
||||||
|
this.offsetX = 0
|
||||||
|
this.offsetY = 0
|
||||||
|
// 克隆节点左上角的坐标
|
||||||
|
this.cloneNodeLeft = 0
|
||||||
|
this.cloneNodeTop = 0
|
||||||
|
// 当前鼠标是否按下
|
||||||
|
this.isMousedown = false
|
||||||
|
// 拖拽的鼠标位置变量
|
||||||
|
this.mouseDownX = 0
|
||||||
|
this.mouseDownY = 0
|
||||||
|
this.mouseMoveX = 0
|
||||||
|
this.mouseMoveY = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:36:36
|
||||||
|
* @Desc: 绑定事件
|
||||||
|
*/
|
||||||
|
bindEvent() {
|
||||||
|
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
|
||||||
|
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
|
||||||
|
this.offsetX = e.clientX - (node.left * scaleX + translateX)
|
||||||
|
this.offsetY = e.clientY - (node.top * scaleY + translateY)
|
||||||
|
//
|
||||||
|
this.node = node
|
||||||
|
this.isMousedown = true
|
||||||
|
let {
|
||||||
|
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) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.isMousedown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
let {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
} = this.mindMap.toPos(e.clientX, e.clientY)
|
||||||
|
this.mouseMoveX = x
|
||||||
|
this.mouseMoveY = y
|
||||||
|
if ((Math.abs(x - this.mouseDownX) <= 10 && Math.abs(y - this.mouseDownY) <= 10) && !this.node.isDrag) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.mindMap.renderer.clearAllActive()
|
||||||
|
this.onMove(x, y)
|
||||||
|
})
|
||||||
|
this.onMouseup = this.onMouseup.bind(this)
|
||||||
|
this.mindMap.on('node_mouseup', this.onMouseup)
|
||||||
|
this.mindMap.on('mouseup', this.onMouseup)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 19:38:02
|
||||||
|
* @Desc: 鼠标松开事件
|
||||||
|
*/
|
||||||
|
onMouseup(e) {
|
||||||
|
if (!this.isMousedown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.isMousedown = false
|
||||||
|
let _nodeIsDrag = this.node.isDrag
|
||||||
|
this.node.isDrag = false
|
||||||
|
this.node.show()
|
||||||
|
this.removeCloneNode()
|
||||||
|
// 存在重叠子节点,则移动作为其子节点
|
||||||
|
if (this.overlapNode) {
|
||||||
|
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||||
|
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
|
||||||
|
} else if (this.prevNode) { // 存在前一个相邻节点,作为其下一个兄弟节点
|
||||||
|
this.mindMap.renderer.setNodeActive(this.prevNode, false)
|
||||||
|
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
|
||||||
|
} else if (this.nextNode) { // 存在下一个相邻节点,作为其前一个兄弟节点
|
||||||
|
this.mindMap.renderer.setNodeActive(this.nextNode, false)
|
||||||
|
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
|
||||||
|
} else if (_nodeIsDrag) {
|
||||||
|
// 自定义位置
|
||||||
|
let {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
} = this.mindMap.toPos(e.clientX - this.offsetX, e.clientY - this.offsetY)
|
||||||
|
let {
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
translateX,
|
||||||
|
translateY
|
||||||
|
} = this.drawTransform
|
||||||
|
x = (x - translateX) / scaleX
|
||||||
|
y = (y - translateY) / scaleY
|
||||||
|
this.node.left = x
|
||||||
|
this.node.top = y
|
||||||
|
this.node.customLeft = x
|
||||||
|
this.node.customTop = y
|
||||||
|
this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
|
||||||
|
this.mindMap.render()
|
||||||
|
}
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 19:34:53
|
||||||
|
* @Desc: 创建克隆节点
|
||||||
|
*/
|
||||||
|
createCloneNode() {
|
||||||
|
if (!this.clone) {
|
||||||
|
// 节点
|
||||||
|
this.clone = this.node.group.clone()
|
||||||
|
this.clone.opacity(0.5)
|
||||||
|
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.style.line(this.line)
|
||||||
|
// 同级位置占位符
|
||||||
|
this.placeholder = this.draw.rect().fill({
|
||||||
|
color: this.node.style.merge('lineColor', true)
|
||||||
|
})
|
||||||
|
this.mindMap.draw.add(this.clone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 19:35:16
|
||||||
|
* @Desc: 移除克隆节点
|
||||||
|
*/
|
||||||
|
removeCloneNode() {
|
||||||
|
if (!this.clone) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.clone.remove()
|
||||||
|
this.line.remove()
|
||||||
|
this.placeholder.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-23 18:53:47
|
||||||
|
* @Desc: 拖动中
|
||||||
|
*/
|
||||||
|
onMove(x, y) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 10:20:43
|
||||||
|
* @Desc: 检测重叠节点
|
||||||
|
*/
|
||||||
|
checkOverlapNode() {
|
||||||
|
if (!this.drawTransform) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
translateX,
|
||||||
|
translateY
|
||||||
|
} = this.drawTransform
|
||||||
|
let checkRight = this.cloneNodeLeft + this.node.width * scaleX
|
||||||
|
let checkBottom = this.cloneNodeTop + this.node.height * scaleX
|
||||||
|
this.overlapNode = null
|
||||||
|
this.prevNode = null
|
||||||
|
this.nextNode = null
|
||||||
|
this.placeholder.size(0, 0)
|
||||||
|
bfsWalk(this.mindMap.renderer.root, (node) => {
|
||||||
|
if (node.nodeData.data.isActive) {
|
||||||
|
this.mindMap.renderer.setNodeActive(node, false)
|
||||||
|
}
|
||||||
|
if (node === this.node || this.node.isParent(node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.overlapNode || this.prevNode && this.nextNode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
} = node
|
||||||
|
let _left = left
|
||||||
|
let _top = top
|
||||||
|
let _bottom = top + height
|
||||||
|
let right = (left + width) * scaleX + translateX
|
||||||
|
let bottom = (top + height) * scaleY + translateY
|
||||||
|
left = left * scaleX + translateX
|
||||||
|
top = top * scaleY + translateY
|
||||||
|
// 检测是否重叠
|
||||||
|
if (!this.overlapNode) {
|
||||||
|
if (
|
||||||
|
left <= checkRight && right >= this.cloneNodeLeft &&
|
||||||
|
top <= checkBottom && bottom >= this.cloneNodeTop
|
||||||
|
) {
|
||||||
|
this.overlapNode = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检测兄弟节点位置
|
||||||
|
if (!this.prevNode && !this.nextNode && this.node.isBrother(node)) {
|
||||||
|
if (left <= checkRight && right >= this.cloneNodeLeft) {
|
||||||
|
if (this.cloneNodeTop > bottom && this.cloneNodeTop <= bottom + 10) {
|
||||||
|
this.prevNode = node
|
||||||
|
this.placeholder.size(node.width, 10).move(_left, _bottom)
|
||||||
|
} else if (checkBottom < top && checkBottom >= top - 10) {
|
||||||
|
this.nextNode = node
|
||||||
|
this.placeholder.size(node.width, 10).move(_left, _top - 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (this.overlapNode) {
|
||||||
|
this.mindMap.renderer.setNodeActive(this.overlapNode, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Drag
|
||||||
@@ -1,149 +1,182 @@
|
|||||||
import EventEmitter from 'eventemitter3'
|
import EventEmitter from 'eventemitter3'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* javascript comment
|
* javascript comment
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
* @Date: 2021-04-07 14:53:09
|
* @Date: 2021-04-07 14:53:09
|
||||||
* @Desc: 事件类
|
* @Desc: 事件类
|
||||||
*/
|
*/
|
||||||
class Event extends EventEmitter {
|
class Event extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* javascript comment
|
* javascript comment
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
* @Date: 2021-04-07 14:53:25
|
* @Date: 2021-04-07 14:53:25
|
||||||
* @Desc: 构造函数
|
* @Desc: 构造函数
|
||||||
*/
|
*/
|
||||||
constructor(opt = {}) {
|
constructor(opt = {}) {
|
||||||
super()
|
super()
|
||||||
this.opt = opt
|
this.opt = opt
|
||||||
this.mindMap = opt.mindMap
|
this.mindMap = opt.mindMap
|
||||||
this.isMousedown = false
|
this.isLeftMousedown = false
|
||||||
this.mousedownPos = {
|
this.mousedownPos = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
}
|
}
|
||||||
this.mousemovePos = {
|
this.mousemovePos = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
}
|
}
|
||||||
this.mousemoveOffset = {
|
this.mousemoveOffset = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
}
|
}
|
||||||
this.bindFn()
|
this.bindFn()
|
||||||
this.bind()
|
this.bind()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* javascript comment
|
* javascript comment
|
||||||
* @Author: 王林25
|
* @Author: 王林25
|
||||||
* @Date: 2021-04-07 15:52:24
|
* @Date: 2021-04-07 15:52:24
|
||||||
* @Desc: 绑定函数上下文
|
* @Desc: 绑定函数上下文
|
||||||
*/
|
*/
|
||||||
bindFn() {
|
bindFn() {
|
||||||
this.onDrawClick = this.onDrawClick.bind(this)
|
this.onDrawClick = this.onDrawClick.bind(this)
|
||||||
this.onMousedown = this.onMousedown.bind(this)
|
this.onMousedown = this.onMousedown.bind(this)
|
||||||
this.onMousemove = this.onMousemove.bind(this)
|
this.onMousemove = this.onMousemove.bind(this)
|
||||||
this.onMouseup = this.onMouseup.bind(this)
|
this.onMouseup = this.onMouseup.bind(this)
|
||||||
this.onMousewheel = this.onMousewheel.bind(this)
|
this.onMousewheel = this.onMousewheel.bind(this)
|
||||||
}
|
this.onContextmenu = this.onContextmenu.bind(this)
|
||||||
|
this.onSvgMousedown = this.onSvgMousedown.bind(this)
|
||||||
/**
|
}
|
||||||
* javascript comment
|
|
||||||
* @Author: 王林25
|
/**
|
||||||
* @Date: 2021-04-07 14:53:43
|
* javascript comment
|
||||||
* @Desc: 绑定事件
|
* @Author: 王林25
|
||||||
*/
|
* @Date: 2021-04-07 14:53:43
|
||||||
bind() {
|
* @Desc: 绑定事件
|
||||||
this.mindMap.draw.on('click', this.onDrawClick)
|
*/
|
||||||
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
|
bind() {
|
||||||
window.addEventListener('mousemove', this.onMousemove)
|
this.mindMap.svg.on('click', this.onDrawClick)
|
||||||
window.addEventListener('mouseup', this.onMouseup)
|
this.mindMap.el.addEventListener('mousedown', this.onMousedown)
|
||||||
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
this.mindMap.svg.on('mousedown', this.onSvgMousedown)
|
||||||
}
|
window.addEventListener('mousemove', this.onMousemove)
|
||||||
|
window.addEventListener('mouseup', this.onMouseup)
|
||||||
/**
|
// 兼容火狐浏览器
|
||||||
* javascript comment
|
if(window.navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
|
||||||
* @Author: 王林25
|
this.mindMap.el.addEventListener('DOMMouseScroll', this.onMousewheel)
|
||||||
* @Date: 2021-04-07 15:40:51
|
} else {
|
||||||
* @Desc: 解绑事件
|
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)
|
||||||
*/
|
}
|
||||||
unbind() {
|
this.mindMap.svg.on('contextmenu', this.onContextmenu)
|
||||||
this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
|
}
|
||||||
window.removeEventListener('mousemove', this.onMousemove)
|
|
||||||
window.removeEventListener('mouseup', this.onMouseup)
|
/**
|
||||||
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
* javascript comment
|
||||||
}
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-07 15:40:51
|
||||||
/**
|
* @Desc: 解绑事件
|
||||||
* @Author: 王林
|
*/
|
||||||
* @Date: 2021-04-24 13:19:39
|
unbind() {
|
||||||
* @Desc: 画布的单击事件
|
this.mindMap.svg.off('click', this.onDrawClick)
|
||||||
*/
|
this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
|
||||||
onDrawClick(e) {
|
window.removeEventListener('mousemove', this.onMousemove)
|
||||||
this.emit('draw_click', e)
|
window.removeEventListener('mouseup', this.onMouseup)
|
||||||
}
|
this.mindMap.el.removeEventListener('mousewheel', this.onMousewheel)
|
||||||
|
this.mindMap.svg.off('contextmenu', this.onContextmenu)
|
||||||
/**
|
}
|
||||||
* javascript comment
|
|
||||||
* @Author: 王林25
|
/**
|
||||||
* @Date: 2021-04-07 15:17:35
|
* @Author: 王林
|
||||||
* @Desc: 鼠标按下事件
|
* @Date: 2021-04-24 13:19:39
|
||||||
*/
|
* @Desc: 画布的单击事件
|
||||||
onMousedown(e) {
|
*/
|
||||||
e.preventDefault()
|
onDrawClick(e) {
|
||||||
this.isMousedown = true
|
this.emit('draw_click', e)
|
||||||
this.mousedownPos.x = e.clientX
|
}
|
||||||
this.mousedownPos.y = e.clientY
|
|
||||||
this.emit('mousedown', e, this)
|
/**
|
||||||
}
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-16 13:37:30
|
||||||
/**
|
* @Desc: svg画布的鼠标按下事件
|
||||||
* javascript comment
|
*/
|
||||||
* @Author: 王林25
|
onSvgMousedown(e) {
|
||||||
* @Date: 2021-04-07 15:18:32
|
this.emit('svg_mousedown', e)
|
||||||
* @Desc: 鼠标移动事件
|
}
|
||||||
*/
|
|
||||||
onMousemove(e) {
|
/**
|
||||||
e.preventDefault()
|
* javascript comment
|
||||||
this.mousemovePos.x = e.clientX
|
* @Author: 王林25
|
||||||
this.mousemovePos.y = e.clientY
|
* @Date: 2021-04-07 15:17:35
|
||||||
this.mousemoveOffset.x = e.clientX - this.mousedownPos.x
|
* @Desc: 鼠标按下事件
|
||||||
this.mousemoveOffset.y = e.clientY - this.mousedownPos.y
|
*/
|
||||||
this.emit('mousemove', e, this)
|
onMousedown(e) {
|
||||||
if (this.isMousedown) {
|
// e.preventDefault()
|
||||||
this.emit('drag', e, this)
|
// 鼠标左键
|
||||||
}
|
if (e.which === 1) {
|
||||||
}
|
this.isLeftMousedown = true
|
||||||
|
}
|
||||||
/**
|
this.mousedownPos.x = e.clientX
|
||||||
* javascript comment
|
this.mousedownPos.y = e.clientY
|
||||||
* @Author: 王林25
|
this.emit('mousedown', e, this)
|
||||||
* @Date: 2021-04-07 15:18:57
|
}
|
||||||
* @Desc: 鼠标松开事件
|
|
||||||
*/
|
/**
|
||||||
onMouseup(e) {
|
* javascript comment
|
||||||
this.isMousedown = false
|
* @Author: 王林25
|
||||||
this.emit('mouseup', e, this)
|
* @Date: 2021-04-07 15:18:32
|
||||||
}
|
* @Desc: 鼠标移动事件
|
||||||
|
*/
|
||||||
/**
|
onMousemove(e) {
|
||||||
* javascript comment
|
// e.preventDefault()
|
||||||
* @Author: 王林25
|
this.mousemovePos.x = e.clientX
|
||||||
* @Date: 2021-04-07 15:46:27
|
this.mousemovePos.y = e.clientY
|
||||||
* @Desc: 鼠标滚动
|
this.mousemoveOffset.x = e.clientX - this.mousedownPos.x
|
||||||
*/
|
this.mousemoveOffset.y = e.clientY - this.mousedownPos.y
|
||||||
onMousewheel(e) {
|
this.emit('mousemove', e, this)
|
||||||
e.stopPropagation()
|
if (this.isLeftMousedown) {
|
||||||
e.preventDefault()
|
this.emit('drag', e, this)
|
||||||
let dir
|
}
|
||||||
if (e.wheelDeltaY > 0) {
|
}
|
||||||
dir = 'up'
|
|
||||||
} else {
|
/**
|
||||||
dir = 'down'
|
* javascript comment
|
||||||
}
|
* @Author: 王林25
|
||||||
this.emit('mousewheel', e, dir, this)
|
* @Date: 2021-04-07 15:18:57
|
||||||
}
|
* @Desc: 鼠标松开事件
|
||||||
}
|
*/
|
||||||
|
onMouseup(e) {
|
||||||
|
this.isLeftMousedown = false
|
||||||
|
this.emit('mouseup', e, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-07 15:46:27
|
||||||
|
* @Desc: 鼠标滚动
|
||||||
|
*/
|
||||||
|
onMousewheel(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
let dir
|
||||||
|
if ((e.wheelDeltaY || e.detail) > 0) {
|
||||||
|
dir = 'up'
|
||||||
|
} else {
|
||||||
|
dir = 'down'
|
||||||
|
}
|
||||||
|
this.emit('mousewheel', e, dir, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:34:13
|
||||||
|
* @Desc: 鼠标右键菜单事件
|
||||||
|
*/
|
||||||
|
onContextmenu(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.emit('contextmenu', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Event
|
export default Event
|
||||||
264
simple-mind-map/src/Export.js
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
import { imgToDataUrl, downloadFile } from './utils'
|
||||||
|
import JsPDF from 'jspdf'
|
||||||
|
const URL = window.URL || window.webkitURL || window
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:05:16
|
||||||
|
* @Desc: 导出类
|
||||||
|
*/
|
||||||
|
class Export {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:05:42
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt) {
|
||||||
|
this.mindMap = opt.mindMap
|
||||||
|
this.exportPadding = this.mindMap.opt.exportPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-02 07:44:06
|
||||||
|
* @Desc: 导出
|
||||||
|
*/
|
||||||
|
async export(type, isDownload = true, name = '思维导图') {
|
||||||
|
if (this[type]) {
|
||||||
|
let result = await this[type](name)
|
||||||
|
if (isDownload && type !== 'pdf') {
|
||||||
|
downloadFile(result, name + '.' + type)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 14:57:40
|
||||||
|
* @Desc: 获取svg数据
|
||||||
|
*/
|
||||||
|
async getSvgData() {
|
||||||
|
const svg = this.mindMap.svg
|
||||||
|
const draw = this.mindMap.draw
|
||||||
|
// 保存原始信息
|
||||||
|
const origWidth = svg.width()
|
||||||
|
const origHeight = svg.height()
|
||||||
|
const origTransform = draw.transform()
|
||||||
|
const elRect = this.mindMap.el.getBoundingClientRect()
|
||||||
|
// 去除放大缩小的变换效果
|
||||||
|
draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY)
|
||||||
|
// 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法
|
||||||
|
const rect = draw.rbox()
|
||||||
|
// 将svg设置为实际内容的宽高
|
||||||
|
svg.size(rect.width, rect.height)
|
||||||
|
// 把实际内容变换
|
||||||
|
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
|
||||||
|
// 克隆一份数据
|
||||||
|
const clone = svg.clone()
|
||||||
|
// 恢复原先的大小和变换信息
|
||||||
|
svg.size(origWidth, origHeight)
|
||||||
|
draw.transform(origTransform)
|
||||||
|
// 把图片的url转换成data:url类型,否则导出会丢失图片
|
||||||
|
let imageList = clone.find('image')
|
||||||
|
let task = imageList.map(async (item) => {
|
||||||
|
let imgUlr = item.attr('href') || item.attr('xlink:href')
|
||||||
|
let imgData = await imgToDataUrl(imgUlr)
|
||||||
|
item.attr('href', imgData)
|
||||||
|
})
|
||||||
|
await Promise.all(task)
|
||||||
|
return {
|
||||||
|
node: clone,
|
||||||
|
str: clone.svg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:25:19
|
||||||
|
* @Desc: svg转png
|
||||||
|
*/
|
||||||
|
svgToPng(svgSrc) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||||
|
img.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
img.onload = async () => {
|
||||||
|
try {
|
||||||
|
let canvas = document.createElement('canvas')
|
||||||
|
canvas.width = img.width + this.exportPadding * 2
|
||||||
|
canvas.height = img.height + this.exportPadding * 2
|
||||||
|
let ctx = canvas.getContext('2d')
|
||||||
|
// 绘制背景
|
||||||
|
await this.drawBackgroundToCanvas(ctx, canvas.width, canvas.height)
|
||||||
|
// 图片绘制到canvas里
|
||||||
|
ctx.drawImage(img, 0, 0, img.width, img.height, this.exportPadding, this.exportPadding, img.width, img.height)
|
||||||
|
resolve(canvas.toDataURL())
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.onerror = (e) => {
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
img.src = svgSrc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:32:07
|
||||||
|
* @Desc: 在canvas上绘制思维导图背景
|
||||||
|
*/
|
||||||
|
drawBackgroundToCanvas(ctx, width, height) {
|
||||||
|
return new Promise((resolve, rejct) => {
|
||||||
|
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig
|
||||||
|
// 背景颜色
|
||||||
|
ctx.save()
|
||||||
|
ctx.rect(0, 0, width, height)
|
||||||
|
ctx.fillStyle = backgroundColor
|
||||||
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
// 背景图片
|
||||||
|
if (backgroundImage && backgroundImage !== 'none') {
|
||||||
|
ctx.save()
|
||||||
|
let img = new Image()
|
||||||
|
img.src = backgroundImage
|
||||||
|
img.onload = () => {
|
||||||
|
let pat = ctx.createPattern(img, backgroundRepeat)
|
||||||
|
ctx.rect(0, 0, width, height)
|
||||||
|
ctx.fillStyle = pat
|
||||||
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
img.onerror = (e) => {
|
||||||
|
rejct(e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-01 22:09:51
|
||||||
|
* @Desc: 导出为png
|
||||||
|
* 方法1.把svg的图片都转化成data:url格式,再转换
|
||||||
|
* 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
|
||||||
|
*/
|
||||||
|
async png() {
|
||||||
|
let { str } = await this.getSvgData()
|
||||||
|
// 转换成blob数据
|
||||||
|
let blob = new Blob([str], {
|
||||||
|
type: 'image/svg+xml'
|
||||||
|
})
|
||||||
|
// 转换成data:url数据
|
||||||
|
let svgUrl = URL.createObjectURL(blob)
|
||||||
|
// 绘制到canvas上
|
||||||
|
let imgDataUrl = await this.svgToPng(svgUrl)
|
||||||
|
URL.revokeObjectURL(svgUrl)
|
||||||
|
return imgDataUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-08-08 19:23:08
|
||||||
|
* @Desc: 导出为pdf
|
||||||
|
*/
|
||||||
|
async pdf(name) {
|
||||||
|
let img = await this.png()
|
||||||
|
let pdf = new JsPDF('', 'pt', 'a4')
|
||||||
|
let a4Width = 595
|
||||||
|
let a4Height = 841
|
||||||
|
let a4Ratio = a4Width / a4Height
|
||||||
|
let image = new Image()
|
||||||
|
image.onload = () => {
|
||||||
|
let imageWidth = image.width
|
||||||
|
let imageHeight = image.height
|
||||||
|
let imageRatio = imageWidth / imageHeight
|
||||||
|
let w, h
|
||||||
|
if (imageWidth <= a4Width && imageHeight <= a4Height) {
|
||||||
|
// 使用图片原始宽高
|
||||||
|
w = imageWidth
|
||||||
|
h = imageHeight
|
||||||
|
} else if (a4Ratio > imageRatio) {
|
||||||
|
// 以a4Height为高度,缩放图片宽度
|
||||||
|
w = imageRatio * a4Height
|
||||||
|
h = a4Height
|
||||||
|
} else {
|
||||||
|
// 以a4Width为宽度,缩放图片高度
|
||||||
|
w = a4Width
|
||||||
|
h = a4Width / imageRatio
|
||||||
|
}
|
||||||
|
pdf.addImage(img, 'PNG', (a4Width - w) / 2, (a4Height - h) / 2, w, h)
|
||||||
|
pdf.save(name)
|
||||||
|
}
|
||||||
|
image.src = img
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 15:32:07
|
||||||
|
* @Desc: 在svg上绘制思维导图背景
|
||||||
|
*/
|
||||||
|
drawBackgroundToSvg(svg) {
|
||||||
|
return new Promise(async (resolve, rejct) => {
|
||||||
|
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig
|
||||||
|
// 背景颜色
|
||||||
|
svg.css('background-color', backgroundColor)
|
||||||
|
// 背景图片
|
||||||
|
if (backgroundImage && backgroundImage !== 'none') {
|
||||||
|
let imgDataUrl = await imgToDataUrl(backgroundImage)
|
||||||
|
svg.css('background-image', `url(${imgDataUrl})`)
|
||||||
|
svg.css('background-repeat', backgroundRepeat)
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 14:54:07
|
||||||
|
* @Desc: 导出为svg
|
||||||
|
*/
|
||||||
|
async svg() {
|
||||||
|
let { node } = await this.getSvgData()
|
||||||
|
await this.drawBackgroundToSvg(node)
|
||||||
|
let str = node.svg()
|
||||||
|
// 转换成blob数据
|
||||||
|
let blob = new Blob([str], {
|
||||||
|
type: 'image/svg+xml'
|
||||||
|
})
|
||||||
|
return URL.createObjectURL(blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-03 22:19:17
|
||||||
|
* @Desc: 导出为json
|
||||||
|
*/
|
||||||
|
json () {
|
||||||
|
let data = this.mindMap.command.getCopyData()
|
||||||
|
let str = JSON.stringify(data)
|
||||||
|
let blob = new Blob([str])
|
||||||
|
return URL.createObjectURL(blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-03 22:24:24
|
||||||
|
* @Desc: 专有文件,其实就是json文件
|
||||||
|
*/
|
||||||
|
smm () {
|
||||||
|
return this.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Export
|
||||||
@@ -16,9 +16,51 @@ export default class KeyCommand {
|
|||||||
this.shortcutMap = {
|
this.shortcutMap = {
|
||||||
//Enter: [fn]
|
//Enter: [fn]
|
||||||
}
|
}
|
||||||
|
this.shortcutMapCache = {}
|
||||||
|
this.isPause = false
|
||||||
this.bindEvent()
|
this.bindEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-08-14 08:57:55
|
||||||
|
* @Desc: 暂停快捷键响应
|
||||||
|
*/
|
||||||
|
pause() {
|
||||||
|
this.isPause = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-08-14 08:58:43
|
||||||
|
* @Desc: 恢复快捷键响应
|
||||||
|
*/
|
||||||
|
recovery() {
|
||||||
|
this.isPause = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-08-16 16:29:01
|
||||||
|
* @Desc: 保存当前注册的快捷键数据,然后清空快捷键数据
|
||||||
|
*/
|
||||||
|
save() {
|
||||||
|
this.shortcutMapCache = this.shortcutMap
|
||||||
|
this.shortcutMap = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-08-16 16:29:38
|
||||||
|
* @Desc: 恢复保存的快捷键数据,然后清空缓存数据
|
||||||
|
*/
|
||||||
|
restore() {
|
||||||
|
this.shortcutMap = this.shortcutMapCache
|
||||||
|
this.shortcutMapCache = {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-24 15:23:22
|
* @Date: 2021-04-24 15:23:22
|
||||||
@@ -26,6 +68,9 @@ export default class KeyCommand {
|
|||||||
*/
|
*/
|
||||||
bindEvent() {
|
bindEvent() {
|
||||||
window.addEventListener('keydown', (e) => {
|
window.addEventListener('keydown', (e) => {
|
||||||
|
if (this.isPause) {
|
||||||
|
return
|
||||||
|
}
|
||||||
Object.keys(this.shortcutMap).forEach((key) => {
|
Object.keys(this.shortcutMap).forEach((key) => {
|
||||||
if (this.checkKey(e, key)) {
|
if (this.checkKey(e, key)) {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@@ -78,7 +123,9 @@ export default class KeyCommand {
|
|||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
arr.push(keyMap['Shift'])
|
arr.push(keyMap['Shift'])
|
||||||
}
|
}
|
||||||
arr.push(e.keyCode)
|
if (!arr.includes(e.keyCode)) {
|
||||||
|
arr.push(e.keyCode)
|
||||||
|
}
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,4 +160,41 @@ export default class KeyCommand {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-27 14:06:16
|
||||||
|
* @Desc: 移除快捷键命令
|
||||||
|
*/
|
||||||
|
removeShortcut(key, fn) {
|
||||||
|
key.split(/\s*\|\s*/).forEach((item) => {
|
||||||
|
if (this.shortcutMap[item]) {
|
||||||
|
if (fn) {
|
||||||
|
let index = this.shortcutMap[item].findIndex((f) => {
|
||||||
|
return f === fn
|
||||||
|
})
|
||||||
|
if (index !== -1) {
|
||||||
|
this.shortcutMap[item].splice(index, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.shortcutMap[item] = []
|
||||||
|
delete this.shortcutMap[item]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-08-14 08:49:58
|
||||||
|
* @Desc: 获取指定快捷键的处理函数
|
||||||
|
*/
|
||||||
|
getShortcutFn(key) {
|
||||||
|
let res = []
|
||||||
|
key.split(/\s*\|\s*/).forEach((item) => {
|
||||||
|
res = this.shortcutMap[item] || []
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
1210
simple-mind-map/src/Node.js
Normal file
1010
simple-mind-map/src/Render.js
Normal file
191
simple-mind-map/src/Select.js
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
import { bfsWalk, throttle } from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:34:51
|
||||||
|
* @Desc: 选择节点类
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Select {
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:35:16
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor({ mindMap }) {
|
||||||
|
this.mindMap = mindMap
|
||||||
|
this.rect = null
|
||||||
|
this.isMousedown = false
|
||||||
|
this.mouseDownX = 0
|
||||||
|
this.mouseDownY = 0
|
||||||
|
this.mouseMoveX = 0
|
||||||
|
this.mouseMoveY = 0
|
||||||
|
this.bindEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-10 22:36:36
|
||||||
|
* @Desc: 绑定事件
|
||||||
|
*/
|
||||||
|
bindEvent() {
|
||||||
|
this.checkInNodes = throttle(this.checkInNodes, 500, this)
|
||||||
|
this.mindMap.on('mousedown', (e) => {
|
||||||
|
if (this.mindMap.opt.readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!e.ctrlKey && e.which !== 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.isMousedown = true
|
||||||
|
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||||
|
this.mouseDownX = x
|
||||||
|
this.mouseDownY = y
|
||||||
|
this.createRect(x, y)
|
||||||
|
})
|
||||||
|
this.mindMap.on('mousemove', (e) => {
|
||||||
|
if (this.mindMap.opt.readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.isMousedown) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||||
|
this.mouseMoveX = x
|
||||||
|
this.mouseMoveY = y
|
||||||
|
if (Math.abs(x - this.mouseDownX) <= 10 && Math.abs(y - this.mouseDownY) <= 10) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clearTimeout(this.autoMoveTimer)
|
||||||
|
this.onMove(x, y)
|
||||||
|
})
|
||||||
|
this.mindMap.on('mouseup', (e) => {
|
||||||
|
if (this.mindMap.opt.readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.isMousedown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.mindMap.emit('node_active', null, this.mindMap.renderer.activeNodeList)
|
||||||
|
clearTimeout(this.autoMoveTimer)
|
||||||
|
this.isMousedown = false
|
||||||
|
if (this.rect) this.rect.remove()
|
||||||
|
this.rect = null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-13 07:55:49
|
||||||
|
* @Desc: 鼠标移动事件
|
||||||
|
*/
|
||||||
|
onMove (x, y) {
|
||||||
|
// 绘制矩形
|
||||||
|
this.rect.plot([
|
||||||
|
[this.mouseDownX, this.mouseDownY],
|
||||||
|
[this.mouseMoveX, this.mouseDownY],
|
||||||
|
[this.mouseMoveX, this.mouseMoveY],
|
||||||
|
[this.mouseDownX, this.mouseMoveY]
|
||||||
|
])
|
||||||
|
this.checkInNodes()
|
||||||
|
// 检测边缘移动
|
||||||
|
let step = this.mindMap.opt.selectTranslateStep
|
||||||
|
let limit = this.mindMap.opt.selectTranslateLimit
|
||||||
|
let count = 0
|
||||||
|
// 左边缘
|
||||||
|
if (x <= this.mindMap.elRect.left + limit) {
|
||||||
|
this.mouseDownX += step
|
||||||
|
this.mindMap.view.translateX(step)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
// 右边缘
|
||||||
|
if (x >= this.mindMap.elRect.right - limit) {
|
||||||
|
this.mouseDownX -= step
|
||||||
|
this.mindMap.view.translateX(-step)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
// 上边缘
|
||||||
|
if (y <= this.mindMap.elRect.top + limit) {
|
||||||
|
this.mouseDownY += step
|
||||||
|
this.mindMap.view.translateY(step)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
// 下边缘
|
||||||
|
if (y >= this.mindMap.elRect.bottom - limit) {
|
||||||
|
this.mouseDownY -= step
|
||||||
|
this.mindMap.view.translateY(-step)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
this.startAutoMove(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-22 08:02:23
|
||||||
|
* @Desc: 开启自动移动
|
||||||
|
*/
|
||||||
|
startAutoMove(x, y) {
|
||||||
|
this.autoMoveTimer = setTimeout(() => {
|
||||||
|
this.onMove(x, y)
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 10:19:37
|
||||||
|
* @Desc: 创建矩形
|
||||||
|
*/
|
||||||
|
createRect(x, y) {
|
||||||
|
this.rect = this.mindMap.svg.polygon().stroke({
|
||||||
|
color: '#0984e3'
|
||||||
|
}).fill({
|
||||||
|
color: 'rgba(9,132,227,0.3)'
|
||||||
|
}).plot([[x, y]])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 10:20:43
|
||||||
|
* @Desc: 检测在选区里的节点
|
||||||
|
*/
|
||||||
|
checkInNodes() {
|
||||||
|
let { scaleX, scaleY, translateX, translateY } = this.mindMap.draw.transform()
|
||||||
|
let minx = Math.min(this.mouseDownX, this.mouseMoveX)
|
||||||
|
let miny = Math.min(this.mouseDownY, this.mouseMoveY)
|
||||||
|
let maxx = Math.max(this.mouseDownX, this.mouseMoveX)
|
||||||
|
let maxy = Math.max(this.mouseDownY, this.mouseMoveY)
|
||||||
|
bfsWalk(this.mindMap.renderer.root, (node) => {
|
||||||
|
let { left, top, width, height } = node
|
||||||
|
let right = (left + width) * scaleX + translateX
|
||||||
|
let bottom = (top + height) * scaleY + translateY
|
||||||
|
left = left * scaleX + translateX
|
||||||
|
top = top * scaleY + translateY
|
||||||
|
if (
|
||||||
|
left >= minx &&
|
||||||
|
right <= maxx &&
|
||||||
|
top >= miny &&
|
||||||
|
bottom <= maxy
|
||||||
|
) {
|
||||||
|
this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
|
||||||
|
if (node.nodeData.data.isActive) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
this.mindMap.renderer.setNodeActive(node, true)
|
||||||
|
this.mindMap.renderer.addActiveNode(node)
|
||||||
|
})
|
||||||
|
} else if (node.nodeData.data.isActive) {
|
||||||
|
this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
|
||||||
|
if (!node.nodeData.data.isActive) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
this.mindMap.renderer.setNodeActive(node, false)
|
||||||
|
this.mindMap.renderer.removeActiveNode(node)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Select
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { tagColorList } from './utils/constant';
|
||||||
|
const rootProp = ['paddingX', 'paddingY']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
@@ -29,6 +31,15 @@ class Style {
|
|||||||
this.themeConfig = themeConfig
|
this.themeConfig = themeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-12 07:40:14
|
||||||
|
* @Desc: 更新主题配置
|
||||||
|
*/
|
||||||
|
updateThemeConfig(themeConfig) {
|
||||||
|
this.themeConfig = themeConfig
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-11 12:02:55
|
* @Date: 2021-04-11 12:02:55
|
||||||
@@ -37,23 +48,25 @@ class Style {
|
|||||||
merge(prop, root, isActive) {
|
merge(prop, root, isActive) {
|
||||||
// 三级及以下节点
|
// 三级及以下节点
|
||||||
let defaultConfig = this.themeConfig.node
|
let defaultConfig = this.themeConfig.node
|
||||||
if (root) {// 直接使用最外层样式
|
if (root || rootProp.includes(prop)) {// 直接使用最外层样式
|
||||||
defaultConfig = this.themeConfig
|
defaultConfig = this.themeConfig
|
||||||
|
} else if (this.ctx.isGeneralization) {// 概要节点
|
||||||
|
defaultConfig = this.themeConfig.generalization
|
||||||
} else if (this.ctx.layerIndex === 0) {// 根节点
|
} else if (this.ctx.layerIndex === 0) {// 根节点
|
||||||
defaultConfig = this.themeConfig.root
|
defaultConfig = this.themeConfig.root
|
||||||
} else if (this.ctx.layerIndex === 1) {// 二级节点
|
} else if (this.ctx.layerIndex === 1) {// 二级节点
|
||||||
defaultConfig = this.themeConfig.secondLevel
|
defaultConfig = this.themeConfig.second
|
||||||
}
|
}
|
||||||
// 激活状态
|
// 激活状态
|
||||||
if (isActive !== undefined ? isActive : this.ctx.isActive) {
|
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||||
if (this.ctx.activeStyle && this.ctx.activeStyle[prop] !== undefined) {
|
if (this.ctx.nodeData.data.activeStyle && this.ctx.nodeData.data.activeStyle[prop] !== undefined) {
|
||||||
return this.ctx.activeStyle[prop];
|
return this.ctx.nodeData.data.activeStyle[prop];
|
||||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||||
return defaultConfig.active[prop]
|
return defaultConfig.active[prop]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 优先使用节点本身的样式
|
// 优先使用节点本身的样式
|
||||||
return this.ctx[prop] !== undefined ? this.ctx[prop] : defaultConfig[prop]
|
return this.ctx.nodeData.data[prop] !== undefined ? this.ctx.nodeData.data[prop] : defaultConfig[prop]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,12 +106,47 @@ class Style {
|
|||||||
* @Date: 2021-04-13 08:14:34
|
* @Date: 2021-04-13 08:14:34
|
||||||
* @Desc: html文字节点
|
* @Desc: html文字节点
|
||||||
*/
|
*/
|
||||||
domText(node) {
|
domText(node, fontSizeScale = 1) {
|
||||||
node.style.fontFamily = this.merge('fontFamily')
|
node.style.fontFamily = this.merge('fontFamily')
|
||||||
node.style.fontSize = this.merge('fontSize') + 'px'
|
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||||
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-20 20:02:18
|
||||||
|
* @Desc: 标签文字
|
||||||
|
*/
|
||||||
|
tagText(node, index) {
|
||||||
|
node.fill({
|
||||||
|
color: tagColorList[index].color
|
||||||
|
}).css({
|
||||||
|
'font-size': '12px'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-06-20 21:04:11
|
||||||
|
* @Desc: 标签矩形
|
||||||
|
*/
|
||||||
|
tagRect(node, index) {
|
||||||
|
node.fill({
|
||||||
|
color: tagColorList[index].background
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-03 22:37:19
|
||||||
|
* @Desc: 内置图标
|
||||||
|
*/
|
||||||
|
iconNode(node) {
|
||||||
|
node.attr({
|
||||||
|
fill: this.merge('color')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-11 14:50:49
|
* @Date: 2021-04-11 14:50:49
|
||||||
@@ -108,6 +156,15 @@ class Style {
|
|||||||
node.stroke({ width: this.merge('lineWidth', true), color: this.merge('lineColor', true) }).fill({ color: 'none' })
|
node.stroke({ width: this.merge('lineWidth', true), color: this.merge('lineColor', true) }).fill({ color: 'none' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2022-07-30 16:19:03
|
||||||
|
* @Desc: 概要连线
|
||||||
|
*/
|
||||||
|
generalizationLine(node) {
|
||||||
|
node.stroke({ width: this.merge('generalizationLineWidth', true), color: this.merge('generalizationLineColor', true) }).fill({ color: 'none' })
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
* @Date: 2021-04-11 20:03:59
|
* @Date: 2021-04-11 20:03:59
|
||||||
146
simple-mind-map/src/TextEdit.js
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import {
|
||||||
|
getStrWithBrFromHtml
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-06-19 11:11:28
|
||||||
|
* @Desc: 节点文字编辑类
|
||||||
|
*/
|
||||||
|
export default class TextEdit {
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-06-19 11:22:57
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(renderer) {
|
||||||
|
this.renderer = renderer
|
||||||
|
this.mindMap = renderer.mindMap
|
||||||
|
// 文本编辑框
|
||||||
|
this.textEditNode = null
|
||||||
|
// 文本编辑框是否显示
|
||||||
|
this.showTextEdit = false
|
||||||
|
this.bindEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-24 13:27:04
|
||||||
|
* @Desc: 事件
|
||||||
|
*/
|
||||||
|
bindEvent() {
|
||||||
|
this.show = this.show.bind(this)
|
||||||
|
// 节点双击事件
|
||||||
|
this.mindMap.on('node_dblclick', this.show)
|
||||||
|
// 点击事件
|
||||||
|
this.mindMap.on('draw_click', () => {
|
||||||
|
// 隐藏文本编辑框
|
||||||
|
this.hideEditTextBox()
|
||||||
|
})
|
||||||
|
// 展开收缩按钮点击事件
|
||||||
|
this.mindMap.on('expand_btn_click', () => {
|
||||||
|
this.hideEditTextBox()
|
||||||
|
})
|
||||||
|
// 节点激活前事件
|
||||||
|
this.mindMap.on('before_node_active', () => {
|
||||||
|
this.hideEditTextBox()
|
||||||
|
})
|
||||||
|
// 注册编辑快捷键
|
||||||
|
this.mindMap.keyCommand.addShortcut('F2', () => {
|
||||||
|
if (this.renderer.activeNodeList.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.show(this.renderer.activeNodeList[0])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2022-08-16 16:27:02
|
||||||
|
* @Desc: 注册临时快捷键
|
||||||
|
*/
|
||||||
|
registerTmpShortcut() {
|
||||||
|
// 注册回车快捷键
|
||||||
|
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
||||||
|
this.hideEditTextBox()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-13 22:15:56
|
||||||
|
* @Desc: 显示文本编辑框
|
||||||
|
*/
|
||||||
|
show(node) {
|
||||||
|
this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-13 22:13:02
|
||||||
|
* @Desc: 显示文本编辑框
|
||||||
|
*/
|
||||||
|
showEditTextBox(node, rect) {
|
||||||
|
this.mindMap.emit('before_show_text_edit')
|
||||||
|
this.registerTmpShortcut()
|
||||||
|
if (!this.textEditNode) {
|
||||||
|
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;`
|
||||||
|
this.textEditNode.setAttribute('contenteditable', true)
|
||||||
|
document.body.appendChild(this.textEditNode)
|
||||||
|
}
|
||||||
|
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
||||||
|
this.textEditNode.innerHTML = node.nodeData.data.text.split(/\n/img).join('<br>')
|
||||||
|
this.textEditNode.style.minWidth = rect.width + 10 + 'px'
|
||||||
|
this.textEditNode.style.minHeight = rect.height + 6 + 'px'
|
||||||
|
this.textEditNode.style.left = rect.left + 'px'
|
||||||
|
this.textEditNode.style.top = rect.top + 'px'
|
||||||
|
this.textEditNode.style.display = 'block'
|
||||||
|
this.showTextEdit = true
|
||||||
|
// 选中文本
|
||||||
|
this.selectNodeText()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-08-02 23:13:50
|
||||||
|
* @Desc: 选中文本
|
||||||
|
*/
|
||||||
|
selectNodeText() {
|
||||||
|
let selection = window.getSelection()
|
||||||
|
let range = document.createRange()
|
||||||
|
range.selectNodeContents(this.textEditNode)
|
||||||
|
selection.removeAllRanges()
|
||||||
|
selection.addRange(range)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-04-24 13:48:16
|
||||||
|
* @Desc: 隐藏文本编辑框
|
||||||
|
*/
|
||||||
|
hideEditTextBox() {
|
||||||
|
if (!this.showTextEdit) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.renderer.activeNodeList.forEach((node) => {
|
||||||
|
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
||||||
|
this.mindMap.execCommand('SET_NODE_TEXT', node, str)
|
||||||
|
if (node.isGeneralization) {
|
||||||
|
// 概要节点
|
||||||
|
node.generalizationBelongNode.updateGeneralization()
|
||||||
|
}
|
||||||
|
this.mindMap.render()
|
||||||
|
})
|
||||||
|
this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList)
|
||||||
|
this.textEditNode.style.display = 'none'
|
||||||
|
this.textEditNode.innerHTML = ''
|
||||||
|
this.textEditNode.style.fontFamily = 'inherit'
|
||||||
|
this.textEditNode.style.fontSize = 'inherit'
|
||||||
|
this.textEditNode.style.fontWeight = 'normal'
|
||||||
|
this.showTextEdit = false
|
||||||
|
}
|
||||||
|
}
|
||||||
193
simple-mind-map/src/View.js
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-07 14:45:24
|
||||||
|
* @Desc: 视图操作类
|
||||||
|
*/
|
||||||
|
class View {
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-07 14:45:40
|
||||||
|
* @Desc: 构造函数
|
||||||
|
*/
|
||||||
|
constructor(opt = {}) {
|
||||||
|
this.opt = opt
|
||||||
|
this.mindMap = this.opt.mindMap
|
||||||
|
this.scale = 1
|
||||||
|
this.sx = 0
|
||||||
|
this.sy = 0
|
||||||
|
this.x = 0
|
||||||
|
this.y = 0
|
||||||
|
this.firstDrag = true
|
||||||
|
this.setTransformData(this.mindMap.opt.viewData)
|
||||||
|
this.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-04-07 15:38:51
|
||||||
|
* @Desc: 绑定
|
||||||
|
*/
|
||||||
|
bind() {
|
||||||
|
// 快捷键
|
||||||
|
this.mindMap.keyCommand.addShortcut('Control+=', () => {
|
||||||
|
this.enlarge()
|
||||||
|
})
|
||||||
|
this.mindMap.keyCommand.addShortcut('Control+-', () => {
|
||||||
|
this.narrow()
|
||||||
|
})
|
||||||
|
this.mindMap.keyCommand.addShortcut('Control+Enter', () => {
|
||||||
|
this.reset()
|
||||||
|
})
|
||||||
|
this.mindMap.svg.on('dblclick', () => {
|
||||||
|
this.reset()
|
||||||
|
})
|
||||||
|
// 拖动视图
|
||||||
|
this.mindMap.event.on('mousedown', () => {
|
||||||
|
this.sx = this.x
|
||||||
|
this.sy = this.y
|
||||||
|
})
|
||||||
|
this.mindMap.event.on('drag', (e, event) => {
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
// 按住ctrl键拖动为多选
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.firstDrag) {
|
||||||
|
this.firstDrag = false
|
||||||
|
// 清除激活节点
|
||||||
|
this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
|
||||||
|
}
|
||||||
|
this.x = this.sx + event.mousemoveOffset.x
|
||||||
|
this.y = this.sy + event.mousemoveOffset.y
|
||||||
|
this.transform()
|
||||||
|
})
|
||||||
|
this.mindMap.event.on('mouseup', () => {
|
||||||
|
this.firstDrag = true
|
||||||
|
})
|
||||||
|
// 放大缩小视图
|
||||||
|
this.mindMap.event.on('mousewheel', (e, dir) => {
|
||||||
|
// // 放大
|
||||||
|
if (dir === 'down') {
|
||||||
|
this.enlarge()
|
||||||
|
} else { // 缩小
|
||||||
|
this.narrow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-22 18:30:24
|
||||||
|
* @Desc: 获取当前变换状态数据
|
||||||
|
*/
|
||||||
|
getTransformData() {
|
||||||
|
return {
|
||||||
|
transform: this.mindMap.draw.transform(),
|
||||||
|
state: {
|
||||||
|
scale: this.scale,
|
||||||
|
x: this.x,
|
||||||
|
y: this.y,
|
||||||
|
sx: this.sx,
|
||||||
|
sy: this.sy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-11-22 19:54:17
|
||||||
|
* @Desc: 动态设置变换状态数据
|
||||||
|
*/
|
||||||
|
setTransformData(viewData) {
|
||||||
|
if (viewData) {
|
||||||
|
Object.keys(viewData.state).forEach((prop) => {
|
||||||
|
this[prop] = viewData.state[prop]
|
||||||
|
})
|
||||||
|
this.mindMap.draw.transform({
|
||||||
|
...viewData.transform
|
||||||
|
})
|
||||||
|
this.mindMap.emit('view_data_change', this.getTransformData())
|
||||||
|
this.mindMap.emit('scale', this.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-13 15:49:06
|
||||||
|
* @Desc: 平移x方向
|
||||||
|
*/
|
||||||
|
translateX(step) {
|
||||||
|
this.x += step
|
||||||
|
this.transform()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* javascript comment
|
||||||
|
* @Author: 王林25
|
||||||
|
* @Date: 2021-07-13 15:48:52
|
||||||
|
* @Desc: 平移y方向
|
||||||
|
*/
|
||||||
|
translateY(step) {
|
||||||
|
this.y += step
|
||||||
|
this.transform()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 17:13:14
|
||||||
|
* @Desc: 应用变换
|
||||||
|
*/
|
||||||
|
transform() {
|
||||||
|
this.mindMap.draw.transform({
|
||||||
|
scale: this.scale,
|
||||||
|
// origin: 'center center',
|
||||||
|
translate: [this.x, this.y],
|
||||||
|
})
|
||||||
|
this.mindMap.emit('view_data_change', this.getTransformData())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-11 17:41:35
|
||||||
|
* @Desc: 恢复
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
this.scale = 1
|
||||||
|
this.x = 0
|
||||||
|
this.y = 0
|
||||||
|
this.transform()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 17:10:34
|
||||||
|
* @Desc: 缩小
|
||||||
|
*/
|
||||||
|
narrow() {
|
||||||
|
if (this.scale - this.mindMap.opt.scaleRatio > 0.1) {
|
||||||
|
this.scale -= this.mindMap.opt.scaleRatio
|
||||||
|
} else {
|
||||||
|
this.scale = 0.1
|
||||||
|
}
|
||||||
|
this.transform()
|
||||||
|
this.mindMap.emit('scale', this.scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 王林
|
||||||
|
* @Date: 2021-07-04 17:10:41
|
||||||
|
* @Desc: 放大
|
||||||
|
*/
|
||||||
|
enlarge() {
|
||||||
|
this.scale += this.mindMap.opt.scaleRatio
|
||||||
|
this.transform()
|
||||||
|
this.mindMap.emit('scale', this.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default View
|
||||||
BIN
simple-mind-map/src/assets/blueSky.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
simple-mind-map/src/assets/brainImpairedPink.jpg
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
simple-mind-map/src/assets/catalogOrganization.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
simple-mind-map/src/assets/classic.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
simple-mind-map/src/assets/classic2.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
simple-mind-map/src/assets/classic3.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
simple-mind-map/src/assets/classic4.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
simple-mind-map/src/assets/classicBlue.jpg
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
simple-mind-map/src/assets/classicGreen.jpg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
simple-mind-map/src/assets/dark.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
simple-mind-map/src/assets/dark2.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
simple-mind-map/src/assets/default.jpg
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
simple-mind-map/src/assets/earthYellow.jpg
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
simple-mind-map/src/assets/freshGreen.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
simple-mind-map/src/assets/freshRed.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
simple-mind-map/src/assets/gold.jpg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
simple-mind-map/src/assets/greenLeaf.jpg
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
simple-mind-map/src/assets/logicalStructure.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
simple-mind-map/src/assets/mindMap.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
simple-mind-map/src/assets/minions.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |